JSFiddle - React, Tailwind, and code Playground
by LeroyRon
HTML
<script src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/222599/canvas-pointer.js?v=20150516"></script>
<canvas id="canvas"></canvas>
CSS
html {
overflow: hidden;
touch-action: none;
content-zooming: none;
}
body {
position: absolute;
margin: 0;
padding: 0;
background: #000;
width: 100%;
height: 100%;
}
#canvas {
position:absolute;
width:100%;
height:100%;
cursor: pointer;
background: #dedede;
}
JavaScript
// Math ref: http://www.ryanjuckett.com/programming/analytic-two-bone-ik-in-2d/
!function() {
"use strict";
function Segment () {
this.x = 0;
this.y = 0;
this.len = 0;
this.len2 = 0;
}
Segment.prototype = {
set length (len) {
this.len = len;
this.len2 = len * len;
}
}
function line (x0, y0, x1, y1, color, width, d0, d1) {
ctx.beginPath();
ctx.strokeStyle = color;
ctx.fillStyle = color;
ctx.lineWidth = width;
ctx.setLineDash([d0,d1]);
ctx.moveTo(x0, y0);
ctx.lineTo(x1, y1);
ctx.stroke();
ctx.moveTo(x0, y0);
ctx.arc(x0, y0, width * 2, 0, 2 * Math.PI);
ctx.moveTo(x1, y1);
ctx.arc(x1, y1, width * 2, 0, 2 * Math.PI);
ctx.fill();
}
function inverse_kinematic () {
var angle, theta1, theta2, targetSqrDist;
// target position
var ix = pointer.x - origin.x;
var iy = pointer.y - origin.y;
// target square distance
targetSqrDist = ix * ix + iy * iy;
// first segment
angle = Math.max(-1, Math.min( 1,
(targetSqrDist + segment1.len2 - segment2.len2) / (2 * segment1.len * Math.sqrt(targetSqrDist))
));
theta1 = Math.atan2(iy, ix) - Math.acos(angle);
segment1.x = origin.x + segment1.len * Math.cos(theta1);
segment1.y = origin.y + segment1.len * Math.sin(theta1);
// second segment
angle = Math.max(-1, Math.min( 1,
(targetSqrDist - segment1.len2 - segment2.len2) / (2 * segment1.len * segment2.len)
));
theta2 = Math.acos(angle);
segment2.x = segment1.x + segment2.len * Math.cos(theta2 + theta1);
segment2.y = segment1.y + segment2.len * Math.sin(theta2 + theta1);
// draw
line (origin.x, origin.y, segment1.x, segment1.y, "navy", 8, 1, 0);
line (segment1.x, segment1.y, segment2.x, segment2.y, "gray", 8, 1, 0);
line (origin.x, origin.y, pointer.x, pointer.y, "red", 4, 2, 2);
}
// main loop
function run() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
inverse_kinematic();
}
// init
var canvas = ge1doot.canvas("canvas");
var ctx =...