JSFiddle - React, Tailwind, and code Playground
by Nikhil krishnan
CSS
html,
body,
div,
span,
applet,
object,
iframe,
h1,
h2,
h3,
h4,
h5,
h6,
p,
blockquote,
pre,
a,
abbr,
acronym,
address,
big,
cite,
code,
del,
dfn,
em,
img,
ins,
kbd,
q,
s,
samp,
small,
strike,
strong,
sub,
sup,
tt,
var,
b,
u,
i,
center,
dl,
dt,
dd,
ol,
ul,
li,
fieldset,
form,
label,
legend,
table,
caption,
tbody,
tfoot,
thead,
tr,
th,
td,
article,
aside,
canvas,
details,
embed,
figure,
figcaption,
footer,
header,
hgroup,
menu,
nav,
output,
ruby,
section,
summary,
time,
mark,
audio,
video {
margin: 0;
padding: 0;
border: 0;
font-size: 100%;
font: inherit;
vertical-align: baseline;
}
/* HTML5 display-role reset for older browsers */
article,
aside,
details,
figcaption,
figure,
footer,
header,
hgroup,
menu,
nav,
section {
display: block;
}
body {
line-height: 1;
}
ol,
ul {
list-style: none;
}
blockquote,
q {
quotes: none;
}
blockquote:before,
blockquote:after,
q:before,
q:after {
content: '';
content: none;
}
table {
border-collapse: collapse;
border-spacing: 0;
}
*,
*:before,
*:after {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
html,body{
height: 100%;
}
JavaScript
var c = document.querySelector("canvas"),
ctx = c.getContext("2d"),
// the fixed point chain
pointsFixed = [
{x: 50, y: 50},
{x: 100, y: 60},
{x: 90, y: 90},
{x: 120, y: 110},
{x: 200, y: 80},
{x: 250, y: 130}
],
// for the IK chain - dragged by the *last* point
points = [
{x: 50, y: 50},
{x: 100, y: 60},
{x: 90, y: 90},
{x: 120, y: 110},
{x: 200, y: 80},
{x: 250, y: 130}
],
min = 40, max = 70,
isDown = false,
// for animation
isPlaying = false,
t, step = 0.1; // t = [0, 1]
// set canvas size
resize();
window.onresize = resize;
function resize() {
c.width = window.innerWidth;
c.height = window.innerHeight;
calc();
render(points)
}
// handle mouse
c.onmousedown = function(e) {
var pos = getXY(e),
p = points[points.length - 1];
isDown = (pos.x > p.x - 7 && pos.x < p.x + 7 && pos.y > p.y - 7 && pos.y < p.y + 7);
};
window.onmousemove = function(e) {
if (!isDown) return;
points[points.length - 1] = getXY(e); // override last point with mouse position
// update chain and canvas
calc();
render(points);
};
window.onmouseup = function() {
if (isDown) {
isDown = false;
t = 0; // reset t for new animation
isPlaying = true; // allow looping
animate(); // start the animation
}
};
// adjusted mouse position
function getXY(e) {
var rect = c.getBoundingClientRect();
return {
x: e.clientX - rect.left,
y: e.clientY - rect.top
}
}
// IK chain calculations
function calc() {
var angle, i, p1, p2, dx, dy, distance;
for(i = points.length - 1; i > 0; i--) {
p1 = points[i];
p2 = points[i-1];
dx = p2.x - p1.x;
dy = p2.y - p1.y;
angle = Math.atan2(dy, dx);
distance = Math.max(min, Math.min(max, Math.sqrt(dx*dx + dy*dy)));
p2.x = p1.x + distance * Math.cos(angle);
p2.y = p1.y + distance *...