Skip welcome & menu and move to editor
Welcome to JS Bin
Load cached copy from
 
<!DOCTYPE html>
<html>
<head>
<meta name="description" content="http://i.imgur.com/4ibsGlI.gif" />
<meta charset=utf-8 />
<title>JS Bin</title>
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
  <canvas id="canvas" width="450px" height="450px"></canvas>
  <script type="text/javascript" src="rad.js"></script>
</body>
</html>
 
/*
      solution for:
      http://i.imgur.com/4ibsGlI.gif
      
      by @msvaljek
*/
var canvas = document.getElementById('canvas'),
    ctx = canvas.getContext('2d'),
    cwidth = canvas.width,
    cheight = canvas.height;
window.requestAnimFrame = (function(){
  return window.requestAnimationFrame ||
  window.webkitRequestAnimationFrame ||
  window.mozRequestAnimationFrame ||
  function( callback ) {
    window.setTimeout(callback, 1000 / 60);
  };
})();
var PiRad = function () {
  this.state = 'begin';
  this.circleColor = 'rgb(31, 31, 255)';
  this.crossColor = 'rgb(235, 235, 235)';
  this.markerColor = 'rgb(255, 0, 0)';
  this.textColor = 'rgb(255, 208, 22)';
  this.innerCircleFill = 'rgb(255, 242, 204)';
  this.innerCircleStroke = 'rgb(255, 203, 47)';
};
PiRad.prototype.changeState = function (newState, timeout) {
  var that = this;
  (function() {
    if (newState !== this.nextState) {
      setTimeout(function() {that.state = newState;}, timeout);
      this.nextState = newState;
    }
  })();
};
PiRad.prototype.draw = function () {
  var that = this;
  ctx.lineWidth = 1;
  ctx.strokeStyle = this.crossColor;
  ctx.beginPath();
  ctx.moveTo(25, cheight / 2);
  ctx.lineTo(cwidth - 25, cheight / 2);
  ctx.stroke();
  ctx.beginPath();
  ctx.moveTo(cwidth / 2, 25);
  ctx.lineTo(cwidth / 2, cheight - 25);
  ctx.stroke();
  this.drawSmallCircle();
  if (this.state === 'begin') {
    this.nextState = '';
    this.smallCircleColor = 'red';
    this.movingDot = {
      x: cwidth / 2,
      y: cheight / 2,
      dx: 5,
      a: 0,
      da: 0.2
    };
    this.movingCenter = {
      x: cwidth / 2,
      y: cheight / 2,
      a: Math.PI,
      da: 0.1
    };
    this.r = 150;
    this.innerR = 40;
    this.textOut = {
      x: 200,
      y: 270
    };
    this.marker = {
      a: -1,
      b: 0,
      s: 0.05
    };
    this.lines = [];
    this.circleMarks = [];
    that.state = 'idle';
    this.changeState('moveRedDotOut', 1000);
  } else if (this.state === 'moveRedDotOut') {
    this.drawRedDotWithConnectionToCenter();
    if ((this.movingDot.x - cwidth / 2) >= this.r) {
      this.movingDot.x = cwidth / 2 + this.r;
      this.changeState('moveRedDotAround', 2000);
    } else {
      this.movingDot.x += this.movingDot.dx;
    }
  } else if (this.state === 'moveRedDotAround') {
    if (this.movingDot.a - this.movingDot.da > Math.PI * -2) {
      this.movingDot.a -= this.movingDot.da;
    } else {
      this.movingDot.a = -2 * Math.PI;
      this.changeState('drawRAndStartWait', 1000);
    }
    this.movingDot.x = cwidth / 2 + Math.cos(this.movingDot.a) * this.r;
    this.movingDot.y = cheight / 2 + Math.sin(this.movingDot.a) * this.r;
    this.drawCircleToAngle(this.movingDot.a);
    this.drawRedDotWithConnectionToCenter();
  } else if (this.state === 'drawRAndStartWait') {
    this.drawR();
    this.changeState('hideR', 3000);
  } else if (this.state === 'hideR') {
    this.drawCircleToAngle(this.movingDot.a);
    this.drawRedDotWithConnectionToCenter();
    this.changeState('moveRedLineUp', 2000);
  } else if (this.state === 'moveRedLineUp') {
    this.smallCircleColor = 'black';
    if (this.movingCenter.a + this.movingCenter.da < 3 * Math.PI / 2) {
      this.movingCenter.a += this.movingCenter.da;
    } else {
      this.movingCenter.a = 3 * Math.PI / 2;
      this.changeState('stickRedLineToCircle', 3000);
    }
    this.movingCenter.x = this.movingDot.x + Math.cos(this.movingCenter.a) * this.r;
    this.movingCenter.y = this.movingDot.y + Math.sin(this.movingCenter.a) * this.r;
    this.drawCircleToAngle(this.movingDot.a);
    this.drawRedDotWithMovingCenter();
  } else if (this.state === 'stickRedLineToCircle') {
    var endx = cwidth / 2 + Math.cos(-1) * this.r;
    var endy = cheight / 2 + Math.sin(-1) * this.r;
    if (endx < this.movingCenter.x) {
      this.movingCenter.x -= 2;
    } else {
      this.movingCenter.x = endx;
    }
    if (endy > this.movingCenter.y) {
      this.movingCenter.y += 0.7;
    } else {
      this.movingCenter.y = endy;
    }
    if (this.movingCenter.x == endx && this.movingCenter.y == endy) {
      this.changeState('markFirstSegment', 2000);
    }
    this.drawCircleToAngle(this.movingDot.a);
    this.drawRedDotWithMovingCenterCurved();
  } else if (this.state === 'markFirstSegment') {
    this.drawMarkedSegments();
    this.changeState('outputOneRad', 2000);
  } else if (this.state === 'outputOneRad') {
    this.drawSomeText('1 rad');
    this.drawMarkedSegments();
    this.changeState('startMarking', 2000);
  } else if (this.state === 'startMarking') {
    this.circleMarks[0] = 0;
    this.lines[0] = -1;
    if (this.marker.a > -2) {
      this.marker.a -= this.marker.s;
      this.marker.b = this.marker.a + 1;
    } else {
      this.marker.a = -2;
      this.marker.b = -1;
      this.state = 'mark2Rad';
    }
    this.drawSomeText('1 rad');
    this.drawMarkedSegments();
  } else if (this.state === 'mark2Rad') {
    this.drawSomeText('2 rad');
    this.drawMarkedSegments();
    this.changeState('startMarking3', 2000);
  } else if (this.state === 'startMarking3') {
    this.circleMarks[1] = -1;
    this.lines[1] = -2;
    if (this.marker.a > -3) {
      this.marker.a -= this.marker.s;
      this.marker.b = this.marker.a + 1;
    } else {
      this.marker.a = -3;
      this.marker.b = -2;
      this.state = 'mark3Rad';
    }
    this.drawSomeText('2 rad');
    this.drawMarkedSegments();
  } else if (this.state === 'mark3Rad') {
    this.drawSomeText('3 rad');
    this.drawMarkedSegments();
    this.changeState('startMarkingPi', 2000);
  } else if (this.state === 'startMarkingPi') {
    this.circleMarks[2] = -2;
    this.lines[2] = -3;
    if (this.marker.a > -Math.PI) {
      this.marker.a -= this.marker.s / 8;
    } else {
      this.marker.a = -Math.PI;
    }
    if (this.marker.b > -3) {
      this.marker.b -= this.marker.s / 2;
    } else {
      this.marker.b = -3;
    }
    if (this.marker.a === -Math.PI && this.marker.b === -3) {
      this.state = 'markPi';
    } else {
      this.drawSomeText('3 rad');
    }
    this.drawMarkedSegments();
  } else if (this.state === 'markPi') {
    this.drawSomeText('π rad');
    this.drawMarkedSegments();
    this.changeState('removePiMarkings', 2000);
  } else if (this.state === 'removePiMarkings') {
    this.circleMarks.length = 0;
    this.circleMarks[0] = 0;
    this.circleMarks[1] = Math.PI;
    this.lines.length = 0;
    this.marker.b = this.marker.a;
    this.drawSomeText('π rad');
    this.drawMarkedSegments({hideRedMarkers: true});
    this.changeState('movePiTextUp', 2000);
  } else if (this.state === 'movePiTextUp') {
    if (this.textOut.y > 170) {
      this.textOut.y -= 5;
    }
    this.drawMarkedSegments({hideRedMarkers: true});
    this.drawSomeText('π rad');
    this.changeState('moveToTwoPi', 2000);
  } else if (this.state === 'moveToTwoPi') {
    if (this.marker.a > -2 * Math.PI) {
      this.marker.a -= this.marker.s;
    } else {
      this.marker.a = -2 * Math.PI;
      this.textOut.x -= 25;
      this.state = 'mark2Pi';
    }
    this.circleMarks[2] = this.marker.a;
    this.marker.b = this.marker.a;
    this.drawMarkedSegments({hideRedMarkers: true});
    this.drawSomeText('π rad');
  } else if (this.state === 'mark2Pi') {
    this.circleMarks.length = 0;
    this.circleMarks[0] = 0;
    this.drawSomeText('2π rad');
    this.drawMarkedSegments({hideRedMarkers: true});
    this.changeState('displayFinal', 2000);
  } else if (this.state === 'displayFinal') {
    this.circleMarks.length = 0;
    this.drawSomeText('2π rad');
    this.drawMarkedSegments({hideRedMarkers: true, hideInnerCircle: true});
    this.changeState('begin', 4000);
  }
};
PiRad.prototype.drawRedDotWithConnectionToCenter = function () {
  ctx.beginPath();
  ctx.fillStyle = this.smallCircleColor;
  ctx.arc(this.movingDot.x, this.movingDot.y, 4, 0, 2 * Math.PI);
  ctx.fill();
  ctx.lineWidth = 2;
  ctx.strokeStyle = this.markerColor;
  ctx.beginPath();
  ctx.moveTo(cwidth / 2, cheight / 2);
  ctx.lineTo(this.movingDot.x, this.movingDot.y);
  ctx.stroke();
};
PiRad.prototype.drawRedDotWithMovingCenter = function () {
  ctx.strokeStyle = ctx.fillStyle = this.markerColor;
  ctx.beginPath();
  ctx.arc(this.movingDot.x, this.movingDot.y, 4, 0, 2 * Math.PI);
  ctx.fill();
  ctx.beginPath();
  ctx.arc(this.movingCenter.x, this.movingCenter.y, 4, 0, 2 * Math.PI);
  ctx.fill();
  ctx.lineWidth = 2;
  ctx.beginPath();
  ctx.moveTo(this.movingCenter.x, this.movingCenter.y);
  ctx.lineTo(this.movingDot.x, this.movingDot.y);
  ctx.stroke();
};
PiRad.prototype.drawRedDotWithMovingCenterCurved = function () {
  ctx.strokeStyle = ctx.fillStyle = this.markerColor;
  ctx.beginPath();
  ctx.arc(this.movingDot.x, this.movingDot.y, 4, 0, 2 * Math.PI);
  ctx.fill();
  ctx.beginPath();
  ctx.arc(this.movingCenter.x, this.movingCenter.y, 4, 0, 2 * Math.PI);
  ctx.fill();
  var endx = ~~(cwidth / 2 + Math.cos(-1) * this.r);
  var endy = ~~(cheight / 2 + Math.sin(-1) * this.r);
  var distance = ~~(Math.sqrt(Math.pow(endx - this.movingCenter.x, 2) + Math.pow(endy - this.movingCenter.y, 2)));
  var factor = 1.12 + distance / 400;
  var x = ~~(cwidth / 2 + Math.cos(-0.5) * this.r * factor);
  var y = ~~(cheight / 2 + Math.sin(-0.5) * this.r * factor);
  ctx.lineWidth = 2;
  ctx.beginPath();
  ctx.moveTo(this.movingDot.x, this.movingDot.y);
  ctx.quadraticCurveTo(x, y, this.movingCenter.x, this.movingCenter.y);
  ctx.stroke();
};
PiRad.prototype.drawR = function () {
    this.drawCircleToAngle(this.movingDot.a);
    this.drawRedDotWithConnectionToCenter();
    ctx.fillStyle = this.markerColor;
    ctx.font = '60px arial italic';
    ctx.fillText('r', 290, 210);
};
PiRad.prototype.drawSomeText = function (text) {
    ctx.fillStyle = this.textColor;
    ctx.font = '40px arial italic bold';
    ctx.fillText(text, this.textOut.x, this.textOut.y);
};
PiRad.prototype.drawCircleToAngle = function (angle) {
  ctx.beginPath();
  ctx.strokeStyle = this.circleColor;
  ctx.lineWidth = 1;
  ctx.arc(cwidth / 2, cheight / 2, this.r, 0, angle, true);
  ctx.stroke();
};
PiRad.prototype.drawInnerCircleToAngle = function (angle) {
  ctx.strokeStyle = this.innerCircleStroke;
  ctx.fillStyle = this.innerCircleFill;
  ctx.lineWidth = 1;
  ctx.beginPath();
  ctx.moveTo(cwidth / 2, cheight / 2);
  ctx.arc(cwidth / 2, cheight / 2, this.innerR, 0, angle, true);
  ctx.closePath();
  ctx.fill();
  ctx.stroke();
};
PiRad.prototype.drawSmallCircle = function () {
  ctx.beginPath();
  ctx.fillStyle = this.smallCircleColor;
  ctx.arc(cwidth / 2, cheight / 2, 4, 0, 2 * Math.PI);
  ctx.fill();
};
PiRad.prototype.drawMarkedSegments = function (config) {
    if (!config || !config.hideInnerCircle) {
      this.drawCircleToAngle(2 * Math.PI);
      this.drawInnerCircleToAngle(this.marker.a);
    }
    ctx.strokeStyle = this.innerCircleStroke;
    for (var i = 0; i < this.lines.length; i++) {
        ctx.lineWidth = 0.5;
        ctx.beginPath();
        ctx.moveTo(cwidth / 2, cheight / 2);
        ctx.lineTo(cwidth / 2 + Math.cos(this.lines[i]) * this.r, cheight / 2 + Math.sin(this.lines[i]) * this.r);
        ctx.stroke();
    }
    for (var j = 0; j < this.circleMarks.length; j++) {
      ctx.fillStyle = this.innerCircleStroke;
      ctx.beginPath();
      ctx.arc(cwidth / 2 + Math.cos(this.circleMarks[j]) * this.r, cheight / 2 + Math.sin(this.circleMarks[j]) * this.r, 4, 0, 2 * Math.PI);
      ctx.fill();
    }
    var bx = cwidth / 2 + Math.cos(this.marker.b) * this.r,
        by = cheight / 2 + Math.sin(this.marker.b) * this.r,
        ax = cwidth / 2 + Math.cos(this.marker.a) * this.r,
        ay = cheight / 2 + Math.sin(this.marker.a) * this.r;
    if (!config || !config.hideInnerCircle) {
      ctx.lineWidth = 2;
      ctx.beginPath();
      ctx.moveTo(cwidth / 2, cheight / 2);
      ctx.lineTo(cwidth / 2 + this.r, cheight / 2);
      ctx.stroke();
      ctx.beginPath();
      ctx.moveTo(cwidth / 2, cheight / 2);
      ctx.lineTo(ax, ay);
      ctx.stroke();
      this.drawSmallCircle();
    } else {
      ctx.lineWidth = 2;
    }
    ctx.strokeStyle = this.innerCircleStroke;
    ctx.beginPath();
    ctx.arc(cwidth / 2, cheight / 2, this.r, 0, this.marker.b, true);
    ctx.stroke();
    if (!config || !config.hideRedMarkers) {
      ctx.lineWidth = 2;
      ctx.strokeStyle = ctx.fillStyle = this.markerColor;
      ctx.beginPath();
      ctx.arc(ax, ay, 4, 0, 2 * Math.PI);
      ctx.fill();
      ctx.beginPath();
      ctx.arc(bx, by, 4, 0, 2 * Math.PI);
      ctx.fill();
      ctx.beginPath();
      ctx.arc(cwidth / 2, cheight / 2, this.r, this.marker.a, this.marker.b, false);
      ctx.stroke();
    }
};
var piRad = new PiRad();
(function animloop() {
  requestAnimFrame(animloop);
  ctx.clearRect(0, 0, cwidth, cheight);
  piRad.draw();
})();
Output

You can jump to the latest bin by adding /latest to your URL

Dismiss x
public
Bin info
msvalpro
0viewers