Easing functions are a type of function that takes a numeric input between 0 and 1. That number runs through the specified function and returns another number between 0 and 1. This special property helps us make any computation we want while remaining within specific bounds.
The purpose of an easing function is to get non-linear values from linear value inputs. When used for animation, easing can be used to create more natural movements and for creating physics like effects such as bouncing. Have a look at the following diagram to see what happens if different values are being used:
let x = 1; let y = 1; let easing = 0.05; let currentPos; let targetPos; function setup() { createCanvas(720, 400); noStroke(); } function draw() { background(237, 34, 93); let targetX = mouseX; let dx = targetX - x; x += dx * easing; //easing in the X axis let targetY = mouseY; let dy = targetY - y; y += dy * easing; //easing in the Y axis ellipse(x, y, 66, 66); currentPos=createVector(round(x),round(y)); targetPos=createVector(mouseX,mouseY); } function mousePressed() { if(targetPos.sub(currentPos) > [2,0,0] ) { for(let i = mouseX; i<width; i++){ x = mouseX + i ; } } }
The code below uses a bell curve to generate the animation. The advantage of using this function is that the size of the points return to there original state once the transformation is over. There is however a boundless number of functions that can be used for animation, many of which have been documented by Robert Penner for several programming languages.
let arrayWidth = 20; let arrayHeight = 20; let dist_x = 20; let dist_y = 20; let shapeWidth = 10; let shapeHeight = 10; let duration = 120; let scaleTimer = 0; let amplitude = 2; let wavelength = 30; let xOffset; let yOffset; var reactorPosition; function setup() { createCanvas(800, 700); xOffset = floor(width/2-(dist_x*arrayWidth/2)); yOffset = floor(height/2-(dist_y*arrayHeight/2)); reactorPosition = createVector(0, 0); noStroke(); fill(0); } function draw() { background(255); scaleTimer+=3; push(); translate(xOffset, yOffset); for (let i = 0; i<arrayWidth; i++ ) { for (let j = 0; j<arrayHeight; j++ ) { rectMode(CENTER); var myPos = createVector(i*dist_x, j*dist_y); var reactorDistance = dist(reactorPosition.x, reactorPosition.y, myPos.x, myPos.y); var myStartTime = int(scaleTimer-reactorDistance); var scaler = bellCurve(myStartTime, shapeWidth, amplitude, wavelength); ellipse(myPos.x, myPos.y, scaler, scaler); } } pop(); } function mouse_X() { return (mouseX - xOffset); //correct positions matrix translations } function mouse_Y() { return (mouseY - xOffset); //correct positions matrix translations } function mouseClicked() { scaleTimer = -100; reactorPosition.x = mouse_X(); reactorPosition.y = mouse_Y(); } function bellCurve(t, a, b, c) { // see https://en.wikipedia.org/wiki/Gaussian_function // t = time // a = start value // b = amplitude // c = wavelength var scaler = 1+(c/sqrt((c*c)+(t*t)))*b; //bell curve return scaler*a; }
What other wave functions could be used to generate patterns in this way, and how could it be made more responsive? Change the following code so the movement is influenced by the user using different easing method.
var gridWidth = 20; var gridHeight = 20; var shapeWidth = 20; var shapeHeight = 20; var dist_x = 20; var dist_y = 20; var duration = 40; var duration2 = 50; var scaleTimer = 0; var amplitude = 2; var xOffset; var yOffset; function setup() { createCanvas(800, 800); xOffset = floor(width/2-(dist_x*gridWidth/2)); yOffset = floor(height/2-(dist_y*gridHeight/2)); reactorPosition = createVector(0, 0); } function draw() { background(0); //fill(10); stroke(0); scaleTimer++; push(); //saves current position of the coordinate system translate(xOffset, yOffset);//translate grid to center for (var i = 0; i<gridWidth; i++ ) { for (var j = 0; j<gridHeight; j++ ) { let reactorDistance = dist(reactorPosition.x, reactorPosition.y, i*dist_x, j*dist_y); let myStartTime = int(scaleTimer-reactorDistance); let angle = radians(myStartTime)*1.5; let _scale = sin(angle)*amplitude; ellipse(i*dist_x, j*dist_y, shapeWidth*_scale, shapeHeight*_scale); } } pop(); } function mouse_X() { return (mouseX - xOffset); //correct positions matrix translations } function mouse_Y() { return (mouseY - xOffset); //correct positions matrix translations } function mouseClicked() { scaleTimer = 0; reactorPosition.x = mouse_X(); reactorPosition.y = mouse_Y(); }