Joints, Bones and Kinematics in Javascript
This is for training, practice and demonstration. The code could be used freely for your own discovery. But please share !!!
HTML
<canvas id='kinematics' width="736" height="674"></canvas>
<img class="bgimage" src="http://i.imgur.com/KihZxn8.jpg" />
<lable>Solve Angle (neckJoints[1]): °Out</lable>
<lable id='sout' name='sliderOut'> </lable>
<input id="sliderOut" type="range" min='0' max='180' step="1" value="110" oninput="document.getElementById('sout').innerHTML = this.value.lpad('0', 3);" onchange="document.getElementById('sout').innerHTML = this.value.lpad('0', 3);" />
<lable>°In</lable>
<lable id='sin'name='sliderIn'> </lable>
<input id="sliderIn" type="range" min='0' max='180' step="1" value="110" oninput="document.getElementById('sin').innerHTML = this.value.lpad('0', 3);" onchange="document.getElementById('sin').innerHTML = this.value.lpad('0', 3);" />
<script>
//Math & String Utils
// Converts from degrees to radians.
Math.radians = function(degrees) {
return degrees * Math.PI / 180;
}
// Converts from radians to degrees.
Math.degrees = function(radians) {
return radians * 180 / Math.PI;
}
Math.slope = function(p0, p1)
{
return Math.atan2(p0.y - p1.y, p0.x - p1.x);
}
Math.angle = function(p0, p1, p2)
{
if (!p0 || !p1 || !p2)
return
var a = Math.pow(p1.x - p0.x, 2) + Math.pow(p1.y - p0.y, 2),
b = Math.pow(p1.x - p2.x, 2) + Math.pow(p1.y - p2.y, 2),
c = Math.pow(p2.x - p0.x, 2) + Math.pow(p2.y - p0.y, 2);
return Math.acos((a + b - c) / Math.sqrt(4 * a * b));
}
Math.distance = function (x1, y1, x2, y2)
{
var xdist = x1 - x2;
var ydist = y1 - y2;
return Math.sqrt(xdist*xdist+ydist*ydist);
}
String.prototype.lpad = function(padString, length) {
var str = this;
while (str.length < length)
str = padString + str;
return str;
}
var canvas = document.getElementById('kinematics');
var ctx = canvas.getContext('2d');
ctx.font = '12px Arial';
canvas.width = 736;
canvas.height = 674;
</script>
CSS
body {margin: 0px;background: #0e0e0e;color: #FFF;}
img.bgimage {position: absolute;top: 0px;left: 0px;select: none;background-image: linear-gradient(45deg, #eee 25%, transparent 25%, transparent 75%, #eee 75%, #eee 100%),linear-gradient(45deg, #eee 25%, transparent 25%, transparent 75%, #eee 75%, #eee 100%);opacity: 0.50;}
canvas#kinematics {position: absolute;top: 0px;left: 0px;width: 736px;height: 674px;z-index: 1;}
a, span {position: relative;top: 0px;left: 0px;color: #FFF;z-index: 2;}
lable {top: -6px;}
input, lable {position: relative;bottom: 0px;left: 0px;z-index: 3;}
JavaScript
var framerate = 1000 / 30;
var _points = [];// store points for all IK chains
var _ikIndex = 0;// current IK chain selected
var _pActive = 0;// active point
var _distance = 25;// distance space for each point
var _lock = true;// lock IK chain at its base
var _precisionSteps = 5;
var _dragging = false;
// Joint Properties
// x, y, lock, active, floor, parentIK, distance, IKHandle, FREEHandle, ENDHandle,
//@ point.a = "angle", point.s = "slope", point.d = "direction"
var neckJoints = [
{x: 480, y: 70, lock: true, active: true, distance: 50, IKHandle: true},
{
x: 467,
y: 105,
out: document.getElementById('sliderOut'),
in: document.getElementById('sliderIn')
},
{x: 493, y: 148},
{x: 505, y: 195},
{x: 462, y: 231},
{x: 410, y: 250, ENDHandle: true}
];
var wingJoints = [
{x: 247, y: 41, lock: true, distance: 115, IKHandle: true},
{x: 346, y: 84},
{x: 308, y: 182},
{x: 410, y: 250, ENDHandle: true}
];
var legJoints = [
{x: 306, y: 583, lock: true, floor: true, distance: 150, IKHandle: true},
{x: 257, y: 487},
{x: 321, y: 320},
{x: 199, y: 281, ENDHandle: true}
];
var talonJoints = [
{parentIK: legJoints[0], lock: false, floor: true, distance: 50},
{x: 379, y: 588, FREEHandle: true},
{x: 424, y: 604, FREEHandle: true},
{x: 388, y: 628, FREEHandle: true},
{x: 262, y: 605, FREEHandle: true}
];
function init() {
// Update point position on mouse move
initPoints(neckJoints);
initPoints(wingJoints);
initPoints(legJoints);
initPoints(talonJoints);
_ikIndex = 0;
function initPoints(points) {
_ikIndex = _points.length;
_points.push(points);
movePoints(points[0].x, points[0].y);
}
canvas.ontouchstart = canvas.onmousedown = function(event) {
event.preventDefault();
var mouseX = event.offsetX ? event.offsetX : event.targetTouches[0].pageX;
var mouseY = event.offsetY ? event.offsetY : event.targetTouches[0].pageY;
console.log('{x:' + mouseX + ', y:' + mouseY + '},');
var...