Created
March 17, 2019 19:41
-
-
Save alterebro/a9318764b9e0921d91102113fac1e30a to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ------------------------------------- | |
// The amazing always useful LERP function: | |
function lerp (start, end, t) { | |
return start * (1 - t) + end * t; | |
} | |
// ------------------------------------- | |
const linearInterpolation = function(canvas) { | |
// Options | |
let el = canvas; | |
let height = 1200; | |
let width = 1200; | |
let padding = 50; | |
let animation_frames = 60; | |
// Internal | |
let _el = document.querySelector(el); | |
_el.setAttribute('width', width); | |
_el.setAttribute('height', height); | |
_el.setAttribute('style', `width: 100%; height: auto; max-width: ${width/2}px; max-height: ${height/2}px; cursor: pointer;`); | |
let ctx = _el.getContext('2d'); | |
let animation = null; | |
let counter = 0; | |
let running = false; | |
let even = true; | |
function init() { | |
ctx.lineJoin = 'miter'; | |
ctx.fillStyle = '#999'; | |
ctx.strokeStyle = '#999'; | |
ctx.font = "32px sans-serif"; | |
ctx.textAlign = "center"; | |
draw(); | |
} | |
function draw() { | |
// Erase Sketch | |
ctx.clearRect(0, 0, width, height); | |
// Legend | |
ctx.fillText("Click to Play/Stop", width/2, padding); | |
// Calculate our t variable | |
const t = parseFloat(((counter%animation_frames)/(animation_frames-1)).toFixed(2)); | |
// Status Bar | |
const statusbar_height = 20; | |
const statusbar_width_max = width - (padding*2); | |
const statusbar_width = lerp(0, statusbar_width_max, t); | |
if ( even ) { | |
ctx.fillRect(padding, height-padding - statusbar_height, statusbar_width, statusbar_height); | |
} else { | |
ctx.fillRect(padding + statusbar_width, height-padding - statusbar_height, statusbar_width_max - statusbar_width, statusbar_height); | |
} | |
// StatusBar Box | |
ctx.lineWidth = 4; | |
ctx.strokeRect(padding, height-padding - statusbar_height, statusbar_width_max, statusbar_height); | |
// ------------------------------------- | |
// Specific Actions depending on example | |
switch (canvas) { | |
case '#lerp-range' : | |
// Circle | |
let circle_stroke = null; | |
let circle_radius = null; | |
if ( even ) { | |
circle_stroke = lerp(100, 10, t); | |
circle_radius = lerp(width/8, width/4, t) | |
} else { | |
circle_stroke = lerp(10, 100, t); | |
circle_radius = lerp(width/4, width/8, t) | |
} | |
ctx.lineWidth = circle_stroke; | |
ctx.beginPath(); | |
ctx.ellipse(width/2, (height/2) - statusbar_height, circle_radius, circle_radius, Math.PI / 4, 0, 2 * Math.PI); | |
ctx.stroke(); | |
break; | |
case '#lerp-points' : | |
const point_radius = width/16; | |
const points = [ | |
{ x : (width/2) - (point_radius*3), y : (height/2) - (point_radius*3) }, | |
{ x : (width/2) + (point_radius*3), y : (height/2) + (point_radius*3) }, | |
]; | |
// Points | |
ctx.beginPath(); | |
ctx.ellipse(points[0].x, points[0].y, point_radius, point_radius, Math.PI/4, 0, 2*Math.PI); | |
ctx.stroke(); | |
ctx.beginPath(); | |
ctx.ellipse(points[1].x, points[1].y, point_radius, point_radius, Math.PI/4, 0, 2*Math.PI); | |
ctx.stroke(); | |
// Dot | |
let dot_x = null; | |
let dot_y = null; | |
if (even) { | |
dot_x = lerp(points[0].x, points[1].x, t); | |
dot_y = lerp(points[0].y, points[1].y, t); | |
} else { | |
dot_x = lerp(points[1].x, points[0].x, t); | |
dot_y = lerp(points[1].y, points[0].y, t); | |
} | |
ctx.beginPath(); | |
ctx.arc(dot_x, dot_y, point_radius-20, 0, 2*Math.PI); | |
ctx.fill(); | |
break; | |
case '#lerp-spring' : | |
const _point_radius = width/16; | |
const _spacing = (width/8); | |
const _x = padding + _spacing; | |
const _y = padding + _spacing; | |
const _w = width - ((padding*2) + (_spacing*2)); | |
const _h = height - ((padding*2) + (_spacing*2) + statusbar_height); | |
const _points = [ | |
{ 'x' : _x + (_w/2), 'y' : _y + (_h/2) }, | |
{ 'x' : _x, 'y' : _y + (_h/2) }, | |
{ 'x' : _x, 'y' : _y }, | |
{ 'x' : _x + _w, 'y' : _y + _h }, | |
] | |
// Set default chasing dot coords if is not defined yet | |
_chasing_dot = (typeof _chasing_dot === 'undefined') ? {'x' : _points[3].x, 'y': _points[3].y} : _chasing_dot; | |
// Set new t and target point | |
let _current_point = Math.round(t); | |
_current_point += (even) ? 0 : 2; | |
let _t = ((t>.5) ? t-.5 : t) * 2; | |
_t = parseFloat(_t.toFixed(2)); | |
// Guidelines | |
ctx.strokeStyle = '#ddd'; | |
ctx.rect(_x, _y, _w, _h); | |
ctx.stroke(); | |
ctx.beginPath(); | |
ctx.moveTo(_x, _y + (_h/2)); | |
ctx.lineTo(_x + _w, _y + (_h/2)); | |
ctx.moveTo(_x + (_w/2), _y); | |
ctx.lineTo(_x + (_w/2), _y + _h); | |
ctx.stroke(); | |
ctx.strokeStyle = '#999'; | |
// Target circle | |
ctx.beginPath(); | |
ctx.ellipse(_points[_current_point].x, _points[_current_point].y, _point_radius, _point_radius, Math.PI/4, 0, 2*Math.PI); | |
ctx.stroke(); | |
// Chasing dot | |
const _dot_x = lerp(_chasing_dot.x, _points[_current_point].x, 0.05 ); | |
const _dot_y = lerp(_chasing_dot.y, _points[_current_point].y, 0.05 ); | |
ctx.beginPath(); | |
ctx.arc(_dot_x, _dot_y, _point_radius-20, 0, 2*Math.PI); | |
ctx.fill(); | |
_chasing_dot.x = _dot_x; | |
_chasing_dot.y = _dot_y; | |
break; | |
case '#lerp-color' : | |
const RGBs = [ | |
{'r': 96, 'g': 172, 'b': 212}, | |
{'r': 35, 'g': 35, 'b': 35}, | |
]; | |
let r = null; | |
let g = null; | |
let b = null; | |
if (even) { | |
r = lerp(RGBs[0].r, RGBs[1].r, t); | |
g = lerp(RGBs[0].g, RGBs[1].g, t); | |
b = lerp(RGBs[0].b, RGBs[1].b, t); | |
} else { | |
r = lerp(RGBs[1].r, RGBs[0].r, t); | |
g = lerp(RGBs[1].g, RGBs[0].g, t); | |
b = lerp(RGBs[1].b, RGBs[0].b, t); | |
} | |
ctx.fillStyle = `rgb(${r}, ${g}, ${b})`; | |
ctx.beginPath(); | |
ctx.arc(width/2, (height/2) - statusbar_height, width/4, 0, 2*Math.PI); | |
ctx.fill(); | |
// Get back to the previous fill color | |
ctx.fillStyle = '#999'; | |
break; | |
default : break; | |
} | |
// End code for specific examples | |
// ------------------------------------- | |
// Iterate... | |
animation = window.requestAnimationFrame(draw); | |
running = true; | |
counter++; | |
// Stop on first frame | |
if (counter == 1) { stop() } | |
if (t === 1) { even = !even } | |
} | |
function stop() { | |
window.cancelAnimationFrame(animation); | |
running = false; | |
} | |
_el.addEventListener('click', function() { | |
if ( running ) { stop() } else { draw() } | |
}); | |
init(); | |
} | |
// ------------------------------------- | |
// Run them all | |
linearInterpolation('#lerp-range'); | |
linearInterpolation('#lerp-points'); | |
linearInterpolation('#lerp-spring'); | |
linearInterpolation('#lerp-color'); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment