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      =...