Skip to content

Instantly share code, notes, and snippets.

@alterebro
Created March 17, 2019 19:41
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save alterebro/a9318764b9e0921d91102113fac1e30a to your computer and use it in GitHub Desktop.
Save alterebro/a9318764b9e0921d91102113fac1e30a to your computer and use it in GitHub Desktop.
// -------------------------------------
// 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