Classic text effect
How do I make an classic text effect?
Letters fly in and out using random parameters and easing functions. What is a classic text effect? How do you make a classic text effect? This script and codes were developed by Sakri Rosenstrom on 06 September 2022, Tuesday.
Classic text effect - Script Codes HTML Codes
<!DOCTYPE html>
<html >
<head> <meta charset="UTF-8"> <title>Classic text effect</title> <link rel="stylesheet" href="css/style.css">
</head>
<body> <div id="canvasContainer"></div>
<span id="textInputSpan"> Enter your name (max 8 chars) : <input id="textInput" maxlength="8" type="text" width="150" /> <button onclick="changeText()">GO!</button>
</span> <script src="js/index.js"></script>
</body>
</html>
Classic text effect - Script Codes CSS Codes
html, body{ margin : 0px; width : 100%; height : 100%; overflow: hidden; background-color: #FFFFFF;
}
#canvasContainer{ margin : 0px; width : 100%; height : 100%;
}
#textInputSpan{ position: absolute;
}
Classic text effect - Script Codes JS Codes
/* * * @author Sakri Rosenstrom * * http://www.sakri.net * https://twitter.com/sakri * http://www.devstate.net * Sources for this can be found at: * https://github.com/sakri/sakriNetCommonJS */
(function (window){ var Sakri = window.Sakri || {}; window.Sakri = window.Sakri || Sakri; Sakri.MathUtil = {}; //used for radiansToDegrees and degreesToRadians Sakri.MathUtil.PI_180 = Math.PI/180; Sakri.MathUtil.ONE80_PI = 180/Math.PI; //precalculations for values of 90, 270 and 360 in radians Sakri.MathUtil.PI2 = Math.PI*2; Sakri.MathUtil.HALF_PI = Math.PI/2; Sakri.MathUtil.PI_AND_HALF = Math.PI+ Math.PI/2; Sakri.MathUtil.NEGATIVE_HALF_PI = -Math.PI/2; //keep degrees between 0 and 360 Sakri.MathUtil.constrainDegreeTo360 = function(degree){ return (360 + degree % 360) % 360;//hmmm... looks a bit weird?! }; Sakri.MathUtil.constrainRadianTo2PI = function(rad){ return (Sakri.MathUtil.PI2 + rad % Sakri.MathUtil.PI2) % Sakri.MathUtil.PI2;//equally so... }; Sakri.MathUtil.radiansToDegrees = function(rad){ return rad*Sakri.MathUtil.ONE80_PI; }; Sakri.MathUtil.degreesToRadians = function(degree){ return degree * Sakri.MathUtil.PI_180; }; //return number between 1 and 0 Sakri.MathUtil.normalize = function(value, minimum, maximum){ return (value - minimum) / (maximum - minimum); }; //map normalized number to values Sakri.MathUtil.interpolate = function(normValue, minimum, maximum){ return minimum + (maximum - minimum) * normValue; }; //map a value from one set to another Sakri.MathUtil.map = function(value, min1, max1, min2, max2){ return Sakri.MathUtil.interpolate( Sakri.MathUtil.normalize(value, min1, max1), min2, max2); }; Sakri.MathUtil.clamp = function(min,max,value){ if(value < min){ return min; } if(value > max){ return max; } return value; }; Sakri.MathUtil.clampRGB = function(value){ return Sakri.MathUtil.clamp(0, 255, value); }; Sakri.MathUtil.getRandomNumberInRange = function(min, max){ return min + Math.random() * (max - min); }; Sakri.MathUtil.getRandomIntegerInRange = function(min, max){ return Math.round(Sakri.MathUtil.getRandomNumberInRange(min, max)); };
}(window));
//has a dependency on Sakri.MathUtil
(function (window){ var Sakri = window.Sakri || {}; window.Sakri = window.Sakri || Sakri; Sakri.Geom = {}; //================================================== //=====================::POINT::==================== //================================================== Sakri.Geom.Point = function (x,y){ this.x = isNaN(x) ? 0 : x; this.y = isNaN(y) ? 0 : y; }; Sakri.Geom.Point.prototype.clone = function(){ return new Sakri.Geom.Point(this.x,this.y); }; Sakri.Geom.Point.prototype.update = function(x, y){ this.x = isNaN(x) ? this.x : x; this.y = isNaN(y) ? this.y : y; }; Sakri.Geom.Point.prototype.add = function(x, y){ this.x += isNaN(x) ? 0 : x; this.y += isNaN(y) ? 0 : y; }; Sakri.Geom.Point.prototype.equals = function(point){ return this.x==point.x && this.y==point.y; }; Sakri.Geom.Point.prototype.toString = function(){ return "{x:"+this.x+" , y:"+this.y+"}"; }; Sakri.Geom.Point.interpolate = function(pointA, pointB, normal){ return new Sakri.Geom.Point(Sakri.MathUtil.interpolate(normal, pointA.x, pointB.x) , Sakri.MathUtil.interpolate(normal, pointA.y, pointB.y)); }; Sakri.Geom.Point.distanceBetweenTwoPoints = function( point1, point2 ){ //console.log("Math.pow(point2.x - point1.x,2) : ",Math.pow(point2.x - point1.x,2)); return Math.sqrt( Math.pow(point2.x - point1.x,2) + Math.pow(point2.y - point1.y,2) ); }; Sakri.Geom.Point.angleBetweenTwoPoints = function(p1,p2){ return Math.atan2(p1.y-p2.y, p1.x-p2.x); }; Sakri.Geom.mirrorPointInRectangle = function(point,rect){ return new Sakri.Geom.Point(rect.width-point.x,rect.height-point.y); }; Sakri.Geom.randomizePoint = function(point,randomValue){ return new Sakri.Geom.Point(-randomValue+Math.random()*randomValue+point.x,-randomValue+Math.random()*randomValue+point.y); }; //================================================== //===================::RECTANGLE::================== //================================================== Sakri.Geom.Rectangle = function (x, y, width, height){ this.update(x, y, width, height); }; Sakri.Geom.Rectangle.prototype.update = function(x, y, width, height){ this.x = isNaN(x) ? 0 : x; this.y = isNaN(y) ? 0 : y; this.width = isNaN(width) ? 0 : width; this.height = isNaN(height) ? 0 : height; }; //TODO : doesn't work Sakri.Geom.Rectangle.prototype.inflate = function(x, y){ this.x -= isNaN(x) ? 0 : x; this.y -= isNaN(y) ? 0 : y; this.width += isNaN(x) ? 0 : x * 2; this.height += isNaN(y) ? 0 : y * 2; }; Sakri.Geom.Rectangle.prototype.updateToRect = function(rect){ this.x = rect.x; this.y = rect.y; this.width = rect.width; this.height = rect.height; }; Sakri.Geom.Rectangle.prototype.scaleX = function(scaleBy){ this.width *= scaleBy; }; Sakri.Geom.Rectangle.prototype.scaleY = function(scaleBy){ this.height *= scaleBy; }; Sakri.Geom.Rectangle.prototype.scale = function(scaleBy){ this.scaleX(scaleBy); this.scaleY(scaleBy); }; Sakri.Geom.Rectangle.prototype.getRight = function(){ return this.x + this.width; }; Sakri.Geom.Rectangle.prototype.getBottom = function(){ return this.y + this.height; }; Sakri.Geom.Rectangle.prototype.getCenter = function(){ return new Sakri.Geom.Point(this.getCenterX(), this.getCenterY()); }; Sakri.Geom.Rectangle.prototype.getCenterX = function(){ return this.x + this.width/2; }; Sakri.Geom.Rectangle.prototype.getCenterY=function(){ return this.y + this.height/2; }; Sakri.Geom.Rectangle.prototype.containsPoint = function(x, y){ return x >= this.x && y >= this.y && x <= this.getRight() && y <= this.getBottom(); }; Sakri.Geom.Rectangle.prototype.containsRect = function(rect){ return this.containsPoint(rect.x, rect.y) && this.containsPoint(rect.getRight(), rect.getBottom()); }; Sakri.Geom.Rectangle.prototype.isSquare = function(){ return this.width == this.height; }; Sakri.Geom.Rectangle.prototype.isLandscape = function(){ return this.width > this.height; }; Sakri.Geom.Rectangle.prototype.isPortrait = function(){ return this.width < this.height; }; Sakri.Geom.Rectangle.prototype.getSmallerSide = function(){ return Math.min(this.width, this.height); }; Sakri.Geom.Rectangle.prototype.getBiggerSide = function(){ return Math.max(this.width,this.height); }; Sakri.Geom.Rectangle.prototype.getArea = function(){ return this.width * this.height; }; Sakri.Geom.Rectangle.prototype.floor = function(){ this.x = Math.floor(this.x); this.y = Math.floor(this.y); this.width = Math.floor(this.width); this.height = Math.floor(this.height); }; Sakri.Geom.Rectangle.prototype.ceil = function(){ this.x = Math.ceil(this.x); this.y = Math.ceil(this.y); this.width = Math.ceil(this.width); this.height = Math.ceil(this.height); }; Sakri.Geom.Rectangle.prototype.round = function(){ this.x=Math.round(this.x); this.y=Math.round(this.y); this.width=Math.round(this.width); this.height=Math.round(this.height); }; Sakri.Geom.Rectangle.prototype.roundIn = function(){ this.x = Math.ceil(this.x); this.y = Math.ceil(this.y); this.width = Math.floor(this.width); this.height = Math.floor(this.height); }; Sakri.Geom.Rectangle.prototype.roundOut = function(){ this.x = Math.floor(this.x); this.y = Math.floor(this.y); this.width = Math.ceil(this.width); this.height = Math.ceil(this.height); }; Sakri.Geom.Rectangle.prototype.clone = function(){ return new Sakri.Geom.Rectangle(this.x, this.y, this.width, this.height); }; Sakri.Geom.Rectangle.prototype.toString = function(){ return "Rectangle{x:"+this.x+" , y:"+this.y+" , width:"+this.width+" , height:"+this.height+"}"; }; //================================================== //=====================::TRANSFORM::=================== //================================================== Sakri.Geom.setIdentityMatrixToContext = function(context){ context.setTransform(1,0,0,1,0,0); }; //(1,0,0,1,0,0); Sakri.Geom.Transform = function (scaleX, skewX, skewY, scaleY, tx, ty){ this.update(isNaN(scaleX) ? 1 : scaleX, isNaN(skewX) ? 0 : skewX, isNaN(skewY) ? 0 : skewY, isNaN(scaleY) ? 1 : scaleY, isNaN( tx) ? 0 : tx, isNaN(ty) ? 0 : ty); }; Sakri.Geom.Transform.prototype.update = function (scaleX, skewX, skewY, scaleY, tx, ty){ this.scaleX = scaleX; this.skewX = skewX; this.skewY = skewY; this.scaleY = scaleY; this.tx = tx; this.ty = ty; }; Sakri.Geom.Transform.prototype.toString = function() { return "SimpleGeometry.Transform{scaleX:"+this.scaleX+" ,skewX:"+this.skewX+" ,skewY:"+this.skewY+" ,scaleY:"+this.scaleY+" ,tx:"+this.tx+" ,ty:"+this.ty+"}"; };
}(window));
(function (window){ var Sakri = window.Sakri || {}; window.Sakri = window.Sakri || Sakri; Sakri.BitmapUtil = {}; //TODO : rename "canvas" to "source", if it's an img, create a canvas and draw the img into it Sakri.BitmapUtil.getFirstNonTransparentPixelTopDown = function(canvas){ var context = canvas.getContext("2d"); var y, i, rowData; for(y=0; y<canvas.height; y++){ rowData = context.getImageData(0, y, canvas.width, 1).data; for(i=0; i<rowData.length; i+=4){ if(rowData[i+0] + rowData[i+1] + rowData[i+2] + rowData[i+3] > 0){ return new Sakri.Geom.Point(i/4, y); } } } return null; }; Sakri.BitmapUtil.getFirstNonTransparentPixelBottomUp = function(canvas){ var context = canvas.getContext("2d"); var y, i, rowData; for(y = canvas.height - 1; y>-1; y--){ rowData = context.getImageData(0, y, canvas.width, 1).data; for(i=0; i<rowData.length; i+=4){ if(rowData[i+0] + rowData[i+1] + rowData[i+2] + rowData[i+3] > 0){ return new Sakri.Geom.Point(i/4, y); } } } return null; }; Sakri.BitmapUtil.getFirstNonTransparentPixelLeftToRight = function(canvas){ var context = canvas.getContext("2d"); var x, i, colData; for(x = 0; x < canvas.width; x++){ colData = context.getImageData(x, 0, 1, canvas.height).data; for(i=0; i<colData.length; i+=4){ if(colData[i+0] + colData[i+1] + colData[i+2] + colData[i+3] > 0){ return new Sakri.Geom.Point(x, i/4); } } } return null; }; Sakri.BitmapUtil.getFirstNonTransparentPixelRightToLeft = function(canvas){ var context = canvas.getContext("2d"); var x, i, colData; for(x = canvas.width-1; x >-1; x--){ colData = context.getImageData(x, 0, 1, canvas.height).data; for(i=0; i<colData.length; i+=4){ if(colData[i+0] + colData[i+1] + colData[i+2] + colData[i+3] > 0){ return new Sakri.Geom.Point(x, i/4); } } } return null; }; //cuts out rows and columns of pixels without color data from the top, bottom, left and right Sakri.BitmapUtil.trimImage = function(image){ var trimCanvas = Sakri.BitmapUtil.createTrimmedCanvas(image); image.src = trimCanvas.toDataURL(); }; Sakri.BitmapUtil.trimCanvas = function(canvas){ var trimCanvas = Sakri.BitmapUtil.createTrimmedCanvas(canvas); canvas.width = trimCanvas.width; canvas.height = trimCanvas.height; var context = canvas.getContext("2d"); context.drawImage(trimCanvas, 0, 0); }; Sakri.BitmapUtil.getCanvasTrimRectangle = function(canvas){ var rect = new Sakri.Geom.Rectangle(); rect.x = Sakri.BitmapUtil.getFirstNonTransparentPixelLeftToRight(canvas).x; rect.y = Sakri.BitmapUtil.getFirstNonTransparentPixelTopDown(canvas).y; rect.width = Sakri.BitmapUtil.getFirstNonTransparentPixelRightToLeft(canvas).x - rect.x + 1; rect.height = Sakri.BitmapUtil.getFirstNonTransparentPixelBottomUp(canvas).y - rect.y + 1; return rect; } Sakri.BitmapUtil.createTrimmedCanvas = function(imageOrCanvas){ var trimCanvas = document.createElement("canvas"); var trimContext = trimCanvas.getContext("2d"); trimCanvas.width = imageOrCanvas.width; trimCanvas.height = imageOrCanvas.height; trimContext.drawImage(imageOrCanvas, 0, 0); var rect = Sakri.BitmapUtil.getCanvasTrimRectangle(trimCanvas); //console.log("createTrimmedCanvas() ", rect.toString()); trimCanvas.width = rect.width; trimCanvas.height = rect.height; trimContext = trimCanvas.getContext("2d"); trimContext.drawImage(imageOrCanvas, rect.x, rect.y, rect.width, rect.height, 0, 0, rect.width, rect.height); return trimCanvas; };
}(window));
/** * Created by sakri on 27-1-14. * has a dependecy on Sakri.Geom * has a dependecy on Sakri.BitmapUtil */
(function (window){ var Sakri = window.Sakri || {}; window.Sakri = window.Sakri || Sakri; Sakri.CanvasTextUtil = {}; Sakri.CanvasTextUtil.resizeCanvasToString = function(canvas, string, fontProps){ var context = canvas.getContext('2d'); context.font = fontProps.getFontString(); context.textBaseline = "top"; var textWidth = context.measureText(string).width; canvas.width = textWidth; canvas.height = fontProps.fontSize * 1.5;//normally descenders shouldn't go below this //after a resize of a canvas, we have to reset these properties context.font = fontProps.getFontString(); context.textBaseline = "top"; context.fillStyle = "#FF0000"; context.fillText(string, 0, 0); var textHeight = Sakri.BitmapUtil.getFirstNonTransparentPixelBottomUp(canvas).y + 4;//this returns a point canvas.width = textWidth; canvas.height = textHeight; } //this method renders text into a canvas, then resizes the image by shrinkPercent //loops through the non transparent pixels of the resized image and returns those as an array //fontProperties should be an object of type Sakri.CanvasTextProperties Sakri.CanvasTextUtil.createTextParticles = function(text, shrinkPercent, fontProps){ var canvas = document.createElement('canvas'); Sakri.CanvasTextUtil.resizeCanvasToString(canvas, text, fontProps); var context = canvas.getContext('2d'); //after a resize of a canvas, we have to reset these properties context.font = fontProps.getFontString();; context.textBaseline = "top"; context.fillStyle = "#FF0000"; context.fillText(text, 0, 0); var shrunkenCanvas = document.createElement('canvas'); shrunkenCanvas.width = Math.round(canvas.width * shrinkPercent); shrunkenCanvas.height = Math.round(canvas.height * shrinkPercent); var shrunkenContext = shrunkenCanvas.getContext('2d'); shrunkenContext.drawImage(canvas, 0, 0, shrunkenCanvas.width , shrunkenCanvas.height ); var pixels = shrunkenContext.getImageData(0, 0, shrunkenCanvas.width, shrunkenCanvas.height); var data = pixels.data; var particles = []; var i, x, y; for(i = 0; i < data.length; i += 4) { if(data[i]>200){ x = ((i/4)%shrunkenCanvas.width)/shrinkPercent; y = Math.floor((i/4)/shrunkenCanvas.width)/shrinkPercent; particles.push(new Sakri.Geom.Point(x, y)); } } delete canvas;//not sure if necessary?! delete shrunkenCanvas; return particles; }; Sakri.CanvasTextUtil.createImagesFromString = function(string, fillStyle, strokeStyle, strokeWidth, fontProps){ var fontString = fontProps.getFontString(); var characters = string.split(""); var images = []; var context, image, metrics, i, character; var canvas = document.createElement("canvas"); for(i=0; i<characters.length; i++){ character = characters[i]; Sakri.CanvasTextUtil.resizeCanvasToString(canvas, character, fontProps); context = canvas.getContext("2d"); //these properties have to be set twice as they vanish after setting a canvas width and height context = canvas.getContext("2d"); context.textBaseline = "top"; context.font = fontString; image = new Image(); image.width = canvas.width; image.height = canvas.height; if(fillStyle){ context.fillStyle = fillStyle; context.fillText (character,0, 0); } if(strokeStyle){ context.strokeStyle = strokeStyle; context.lineWidth = strokeWidth; context.strokeText(character, 0, 0); } image.src = canvas.toDataURL(); images[i] = image; } delete canvas; return images; }; //TODO: implement Sakri.CanvasTextUtil.fitTextIntoRect = function(string, fontProps, rect, canvas, fillStyle){ if(!canvas){ var canvas = document.createElement("canvas"); } if(!fillStyle){ fillStyle = "#000000"; } var context = canvas.getContext('2d'); context.font = fontProps.getFontString(); context.textBaseline = "top"; var fontSize = fontProps.fontSize; context.font = "bold "+fontSize+"px sans-serif"; var width = context.measureText(string).width; if(width < context.width){ while(context.measureText(string).width < rect.width && rect < bounds.height){ fontSize++; context.font = "bold "+fontSize+"px sans-serif"; } }else if(width > context.width){ while(context.measureText(string).width > rect.width && rect > bounds.height){ fontSize--; context.font = "bold "+fontSize+"px sans-serif"; } } canvas.width = context.measureText(string).width; canvas.height = fontSize * 1.5;//1.5 should be enough to cover all descenders context.font = "bold "+fontSize+"px sans-serif"; context.textBaseline = "top"; context.fillStyle = fillStyle; context.fillText(string, 0,0); return Sakri.BitmapUtil.createTrimmedCanvas(canvas); } //========================================================================================= //==============::CANVAS TEXT PROPERTIES::==================================== //======================================================== Sakri.CanvasTextProperties = function(fontWeight, fontStyle, fontSize, fontFace){ this.setFontWeight(fontWeight); this.setFontStyle(fontStyle); this.setFontSize(fontSize); this.fontFace = fontFace ? fontFace : "sans-serif"; }; Sakri.CanvasTextProperties.NORMAL = "normal"; Sakri.CanvasTextProperties.BOLD = "bold"; Sakri.CanvasTextProperties.BOLDER = "bolder"; Sakri.CanvasTextProperties.LIGHTER = "lighter"; Sakri.CanvasTextProperties.ITALIC = "italic"; Sakri.CanvasTextProperties.OBLIQUE = "oblique"; Sakri.CanvasTextProperties.prototype.setFontWeight = function(fontWeight){ switch (fontWeight){ case Sakri.CanvasTextProperties.NORMAL: case Sakri.CanvasTextProperties.BOLD: case Sakri.CanvasTextProperties.BOLDER: case Sakri.CanvasTextProperties.LIGHTER: this.fontWeight = fontWeight; break; default: this.fontWeight = Sakri.CanvasTextProperties.NORMAL; } }; Sakri.CanvasTextProperties.prototype.setFontStyle = function(fontStyle){ switch (fontStyle){ case Sakri.CanvasTextProperties.NORMAL: case Sakri.CanvasTextProperties.ITALIC: case Sakri.CanvasTextProperties.OBLIQUE: this.fontStyle = fontStyle; break; default: this.fontStyle = Sakri.CanvasTextProperties.NORMAL; } }; Sakri.CanvasTextProperties.prototype.setFontSize = function(fontSize){ if(fontSize && fontSize.indexOf && fontSize.indexOf("px")>-1){ var size = fontSize.split("px")[0]; fontProperites.fontSize = isNaN(size) ? 24 : size;//24 is just an arbitrary number return; } this.fontSize = isNaN(fontSize) ? 24 : fontSize;//24 is just an arbitrary number }; Sakri.CanvasTextProperties.prototype.getFontString = function(){ return this.fontWeight + " " + this.fontStyle + " " + this.fontSize + "px " + this.fontFace; };
}(window));
//=========================::UNIT ANIMATOR::===============================
//animates a number from 0-1 (with optional easing) for a given duration and a framerate
//this is used to animate or tweeen visuals which are set up using interpolation
(function (window){ var Sakri = window.Sakri || {}; window.Sakri = window.Sakri || Sakri; //constructor, duration and framerate must be in milliseconds Sakri.UnitAnimator = function(duration, framerate, updateCallBack, completeCallBack){ this.easingFunction = Sakri.UnitAnimator.easeLinear;//default this.reset(duration, framerate, updateCallBack, completeCallBack); }; //t is "time" this.millisecondsAnimated //b is the "beginning" value //c is "change" or the difference of end-start value //d is this.duration //classic Robert Penner easing functions //http://www.robertpenner.com/easing/ Sakri.UnitAnimator.easeLinear = function(t, b, c, d){ return c * (t / d) + b; }; //SINE Sakri.UnitAnimator.easeInSine = function (t, b, c, d){ return -c * Math.cos(t/d * Sakri.MathUtil.HALF_PI) + c + b; }; Sakri.UnitAnimator.easeOutSine = function (t, b, c, d){ return c * Math.sin(t/d * Sakri.MathUtil.HALF_PI) + b; }; Sakri.UnitAnimator.easeInOutSine = function (t, b, c, d){ return -c/2 * (Math.cos(Math.PI*t/d) - 1) + b; }; //BOUNCE Sakri.UnitAnimator.easeInBounce = function(t, b, c, d){ return c - Sakri.UnitAnimator.easeOutBounce (d-t, 0, c, d) + b; }; Sakri.UnitAnimator.easeOutBounce = function(t, b, c, d){ if ((t/=d) < (1/2.75)) { return c*(7.5625*t*t) + b; } else if (t < (2/2.75)) { return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b; } else if (t < (2.5/2.75)) { return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b; } else { return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b; } }; Sakri.UnitAnimator.easeInOutBounce = function (t, b, c, d){ if (t < d/2){ return Sakri.UnitAnimator.easeInBounce (t*2, 0, c, d) * .5 + b; } return Sakri.UnitAnimator.easeOutBounce (t*2-d, 0, c, d) * .5 + c*.5 + b; }; //ELASTIC Sakri.UnitAnimator.easeInElastic = function(t, b, c, d, a, p){ var s; if (t==0){ return b; } if ((t/=d)==1){ return b+c; } if (!p){ p=d*.3; } if (!a || a < Math.abs(c)) { a=c; s=p/4; }else{ s = p/Sakri.MathUtil.PI2 * Math.asin (c/a); } return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*Sakri.MathUtil.PI2/p )) + b; }; Sakri.UnitAnimator.easeOutElastic = function(t, b, c, d, a, p){ var s; if (t==0){ return b; } if ((t/=d)==1){ return b+c; } if (!p){ p=d*.3; } if (!a || a < Math.abs(c)) { a=c; s=p/4; }else{ s = p/Sakri.MathUtil.PI2 * Math.asin (c/a); } return (a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*Sakri.MathUtil.PI2/p ) + c + b); }; Sakri.UnitAnimator.easeInOutElastic = function(t, b, c, d, a, p){ var s; if (t==0){ return b; } if ((t/=d/2)==2){ return b+c; } if (!p){ p=d*(.3*1.5); } if (!a || a < Math.abs(c)) { a=c; s=p/4; }else{ s = p/Sakri.MathUtil.PI2 * Math.asin (c/a); } if (t < 1){ return -.5*(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*Sakri.MathUtil.PI2/p )) + b; } return a*Math.pow(2,-10*(t-=1)) * Math.sin( (t*d-s)*Sakri.MathUtil.PI2/p )*.5 + c + b; }; Sakri.UnitAnimator.easingFunctions = [Sakri.UnitAnimator.easeLinear, Sakri.UnitAnimator.easeInSine, Sakri.UnitAnimator.easeOutSine, Sakri.UnitAnimator.easeInOutSine, Sakri.UnitAnimator.easeInBounce, Sakri.UnitAnimator.easeOutBounce, Sakri.UnitAnimator.easeInOutBounce, Sakri.UnitAnimator.easeInElastic, Sakri.UnitAnimator.easeOutElastic, Sakri.UnitAnimator.easeInOutElastic ]; Sakri.UnitAnimator.getRandomEasingFunction = function(){ return Sakri.UnitAnimator.easingFunctions[Math.floor( Math.random()*Sakri.UnitAnimator.easingFunctions.length )]; }; Sakri.UnitAnimator.prototype.setRandomEasingFunction = function(){ this.easingFunction = Sakri.UnitAnimator.getRandomEasingFunction(); }; Sakri.UnitAnimator.prototype.setEasingFunction = function(easingFunction){ if(Sakri.UnitAnimator.easingFunctions.indexOf(easingFunction) > -1){ this.easingFunction = easingFunction; } }; //easing (t, b, c, d) //@t is the current time (or position) of the tween. This can be seconds or frames, steps, seconds, ms, whatever � as long as the unit is the same as is used for the total time [3]. //@b is the beginning value of the property. //@c is the change between the beginning and destination value of the property. //@d is the total time of the tween. Sakri.UnitAnimator.prototype.getAnimationPercent = function(){ return this.easingFunction(Sakri.MathUtil.normalize(this.millisecondsAnimated,0,this.duration),0,1,1); }; Sakri.UnitAnimator.prototype.isAnimating = function(){ return !isNaN(this.intervalId); }; Sakri.UnitAnimator.prototype.reset = function(duration,framerate,updateCallBack,completeCallBack){ this.duration = duration; this.framerate = framerate; if(framerate > duration){ //throw error?! } this.updateCallBack = updateCallBack; this.completeCallBack = completeCallBack; this.millisecondsAnimated = 0;//keeps track of how long the animation has been running }; Sakri.UnitAnimator.prototype.start = function(easingFunction){ //console.log("Sakri.UnitAnimator.start()"); if(easingFunction){ this.setEasingFunction(easingFunction); } var _this = this; this.intervalId = setInterval(function(){_this.update();}, this.framerate);//TODO : find easier to explain solution }; Sakri.UnitAnimator.prototype.pause = function(){ if(!isNaN(this.intervalId)){ clearInterval(this.intervalId); } delete this.intervalId; }; //refactor, make private Sakri.UnitAnimator.prototype.update = function(){ //console.log("Sakri.UnitAnimator.update()",this.getAnimationPercent()); this.millisecondsAnimated += this.framerate; if(this.millisecondsAnimated >= this.duration){ //console.log("Sakri.UnitAnimator.update() animation complete"); this.pause(); this.millisecondsAnimated = this.duration; this.dispatchUpdate(); this.dispatchComplete(); return; } this.dispatchUpdate(); }; Sakri.UnitAnimator.prototype.dispatchUpdate = function(){ if(this.updateCallBack){ //console.log("Sakri.UnitAnimator.dispatchUpdate()",this.getAnimationPercent()); this.updateCallBack(); } }; Sakri.UnitAnimator.prototype.dispatchComplete = function(){ if(this.completeCallBack){ this.completeCallBack(); } };
}(window));
//has a dependency on Sakri.Geom, extends Sakri.Geom.Point
//=========================::BLOCK SET ANIMATOR::===============================
(function (window){ var Sakri = window.Sakri || {}; window.Sakri = window.Sakri || Sakri; //width and height are used for sizing/scaling to fit. Sakri.BlockSetAnimator = function(x, y){ Sakri.Geom.Point.call(this,x,y); //call super constructor. this.frameRate = 20; this.intervalId = -1;//make private this.easingFunction = Sakri.UnitAnimator.easeOutSine; this.animator = new Sakri.UnitAnimator(1000,20); this.animator.easingFunction = Sakri.UnitAnimator.easeLinear; }; //subclass extends superclass Sakri.BlockSetAnimator.prototype = Object.create(Sakri.Geom.Point.prototype); Sakri.BlockSetAnimator.prototype.constructor = Sakri.Geom.Point; Sakri.BlockSetAnimator.prototype.setEasingFunction = function(easingFunction){ this.easingFunction = easingFunction; }; //Image or Canvas items, or sprite sheet?! Sakri.BlockSetAnimator.prototype.setImages = function(images){ this.blocks = []; var blockX = this.x; for(var i=0; i<images.length; i++){ this.blocks[i] = new Sakri.AnimationBlock(blockX, this.y, images[i]); blockX += this.blocks[i].width; } }; Sakri.BlockSetAnimator.prototype.isAnimating = function(){ return this.animator && this.animator.isAnimating(); }; //Sakri.BlockSetAnimator.prototype.setAnimation = function(transformFrom, transformTo, alphaFrom, alphaTo){ Sakri.BlockSetAnimator.prototype.setAnimation = function(blockTransformFrom, blockTransformTo){ this.transformFrom = blockTransformFrom; this.transformTo = blockTransformTo; }; //duration is for the entire animation, delay is the amount of delay between the start of individual block animations //both numbers are expressed in milliseconds Sakri.BlockSetAnimator.prototype.start = function(duration, delay, completeCallBack, updateCallBack){ //console.log("Sakri.BlockSetAnimator.start()", duration, delay, this.blocks.length); if(!this.blocks || this.blocks.length==0){ console.log("Sakri.BlockSetAnimator.start() ERROR : no blocks have been set"); return; } this.millisecondsAnimated = 0; this.duration = duration; this.blockAnimationDuration = this.duration - delay * (this.blocks.length-1); //console.log(this.duration, blockAnimationDuration); this.completeCallBack = completeCallBack ? completeCallBack : undefined; this.updateCallBack = updateCallBack ? updateCallBack : undefined; for(var i=0; i<this.blocks.length; i++){ this.blocks[i].animationBeginsAt = delay * i; this.blocks[i].animationEndsAt = delay * i + this.blockAnimationDuration; this.blocks[i].copyTransformValues(this.transformFrom); //console.log("block : ",this.blocks[i].animationBeginsAt, this.blocks[i].animationEndsAt); } var _this = this; this.animator.reset(duration, this.frameRate, function(){_this.update()}, function(){_this.complete()}); this.animator.start(); }; Sakri.BlockSetAnimator.prototype.stop = function(){ this.animator.pause(); } //only one animator //"main" animator has a linear ease //the allocated time is chopped up into "segments" for each Sakri.AnimationBlock //the segment is then normalized, and this normal is used for the easing function Sakri.BlockSetAnimator.prototype.pause = function(){ //console.log("Sakri.BlockSetAnimator.prototype.pause()"); //clearInterval(this.intervalId); }; Sakri.BlockSetAnimator.prototype.resume = function(){ //console.log("Sakri.BlockSetAnimator.prototype.resume()"); }; Sakri.BlockSetAnimator.prototype.reset= function(){ //console.log("Sakri.BlockSetAnimator.prototype.reset()"); }; Sakri.BlockSetAnimator.prototype.reverse = function(){ //console.log("Sakri.BlockSetAnimator.prototype.reverse()"); }; Sakri.BlockSetAnimator.prototype.update = function(){ //console.log("Sakri.BlockSetAnimator.update()",this.millisecondsAnimated); this.millisecondsAnimated += this.frameRate; this.dispatchUpdate(); }; //easing (t, b, c, d) //@t is the current time (or position) of the tween. //@b is the beginning value of the property. //@c is the change between the beginning and destination value of the property. //@d is the total time of the tween. Sakri.BlockSetAnimator.prototype.setBlockTransform = function(block){ var normal = Sakri.MathUtil.normalize(this.millisecondsAnimated, block.animationBeginsAt, block.animationEndsAt); block.transform.rotation = this.easingFunction(normal, this.transformFrom.rotation, this.transformTo.rotation-this.transformFrom.rotation, 1); block.transform.scale = this.easingFunction(normal, this.transformFrom.scale, this.transformTo.scale-this.transformFrom.scale, 1); block.transform.alpha = this.easingFunction(normal, this.transformFrom.alpha, this.transformTo.alpha-this.transformFrom.alpha, 1); block.transform.x = this.easingFunction(normal, this.transformFrom.x, this.transformTo.x - this.transformFrom.x, 1); block.transform.y = this.easingFunction(normal, this.transformFrom.y, this.transformTo.y - this.transformFrom.y, 1); }; Sakri.BlockSetAnimator.prototype.render = function(context){ //console.log("render()"); var block; Sakri.Geom.setIdentityMatrixToContext(context); for(var i=0; i<this.blocks.length; i++){ block = this.blocks[i]; if(this.millisecondsAnimated <= block.animationBeginsAt){ block.copyTransformValues(this.transformFrom); }else if(this.millisecondsAnimated >= block.animationEndsAt){ block.copyTransformValues(this.transformTo); }else{ this.setBlockTransform(block, i); } context.translate(block.x + block.transform.x -block.getTranslateX(), block.y + block.transform.y - block.getTranslateY()); context.rotate(block.transform.rotation); context.scale(block.transform.scale, block.transform.scale); context.globalAlpha = block.transform.alpha; context.drawImage(block.image,block.getTranslateX(),block.getTranslateY()); Sakri.Geom.setIdentityMatrixToContext(context); } context.globalAlpha = 1; }; Sakri.BlockSetAnimator.prototype.dispatchUpdate = function(){ if(this.updateCallBack){ this.updateCallBack(); } }; Sakri.BlockSetAnimator.prototype.complete = function(){ this.dispatchComplete(); }; Sakri.BlockSetAnimator.prototype.dispatchComplete = function(){ if(this.completeCallBack){ this.completeCallBack(); } }; //=========================::ANIMATION BLOCK::=============================== Sakri.AnimationBlock = function(x,y,image){ Sakri.Geom.Rectangle.call(this, x, y, image.width, image.height); //call super constructor. this.image = image; this.transform = new Sakri.Geom.Transform(); this.skipRender = true; this.animationBeginsAt = 0; this.animationEndsAt = 0; }; //subclass extends superclass Sakri.AnimationBlock.prototype = Object.create(Sakri.Geom.Rectangle.prototype); Sakri.AnimationBlock.prototype.constructor = Sakri.Geom.Rectangle; Sakri.AnimationBlock.prototype.copyTransformValues = function(transform){ this.transform.scale = transform.scale; this.transform.rotation = transform.rotation; this.transform.x = transform.x; this.transform.y = transform.y; this.transform.alpha = transform.alpha; this.transform.horizontalAlign = transform.horizontalAlign; this.transform.verticalAlign = transform.verticalAlign; }; Sakri.AnimationBlock.prototype.getTranslateX = function(){ switch(this.transform.horizontalAlign){ case 1: return -this.width / 2; case 2: return -this.width; } return 0; }; Sakri.AnimationBlock.prototype.getTranslateY = function(){ switch(this.transform.verticalAlign){ case 1: return -this.height / 2; case 2: return -this.height; } return 0; }; //=========================::ANIMATION BLOCK TRANFORM::=============================== Sakri.AnimationBlockTransform = function(x, y, scale, rotation, alpha, horizontalAlign, verticalAlign){ this.x = isNaN(x) ? 0 : x; this.y = isNaN(y) ? 0 : y; this.scale = isNaN(scale) ? 1 : scale; this.rotation = isNaN(rotation) ? 0 : rotation; this.alpha = isNaN(alpha) ? 1 : alpha; //0 = left, 1 = center, 2 = right this.horizontalAlign = isNaN(horizontalAlign) && horizontalAlign<3 ? 0 : horizontalAlign; //0 = top, 1 = center, 2 = bottom this.verticalAlign = isNaN(verticalAlign) && verticalAlign<3 ? 0 : verticalAlign; };
}(window));
//========================
//general properties for demo set up
//========================
var canvas;
var context;
var canvasContainer;
var htmlBounds;
var bounds;
var minimumStageWidth = 250;
var minimumStageHeight = 250;
var maxStageWidth = 1000;
var maxStageHeight = 400;
var resizeTimeoutId = -1;
var readyStateCheckInterval = setInterval( function() { if (document.readyState === "complete") { clearInterval(readyStateCheckInterval); init(); }
}, 10);
function init(){ canvasContainer = document.getElementById("canvasContainer"); window.onresize = resizeHandler; commitResize();
}
function getWidth( element ){return Math.max(element.scrollWidth,element.offsetWidth,element.clientWidth );}
function getHeight( element ){return Math.max(element.scrollHeight,element.offsetHeight,element.clientHeight );}
//avoid running resize scripts repeatedly if a browser window is being resized by dragging
function resizeHandler(){ context.clearRect(0,0,canvas.width, canvas.height); clearTimeout(resizeTimeoutId); clearTimeoutsAndIntervals(); resizeTimeoutId = setTimeout(commitResize, 300 );
}
function commitResize(){ if(canvas){ canvasContainer.removeChild(canvas); } canvas = document.createElement('canvas'); canvas.style.position = "absolute"; context = canvas.getContext("2d"); canvasContainer.appendChild(canvas); htmlBounds = new Sakri.Geom.Rectangle(0,0, getWidth(canvasContainer) , getHeight(canvasContainer)); if(htmlBounds.width >= maxStageWidth){ canvas.width = maxStageWidth; canvas.style.left = htmlBounds.getCenterX() - (maxStageWidth/2)+"px"; }else{ canvas.width = htmlBounds.width; canvas.style.left ="0px"; } if(htmlBounds.height > maxStageHeight){ canvas.height = maxStageHeight; canvas.style.top = htmlBounds.getCenterY() - (maxStageHeight/2)+"px"; }else{ canvas.height = htmlBounds.height; canvas.style.top ="0px"; } bounds = new Sakri.Geom.Rectangle(0,0, canvas.width, canvas.height); context.clearRect(0, 0, canvas.width, canvas.height); context.font = fontProperties.getFontString(); context.textBaseline = "top"; if(bounds.width<minimumStageWidth || bounds.height<minimumStageHeight){ stageTooSmallHandler(); return; } var textInputSpan = document.getElementById("textInputSpan");
textInputSpan.style.top = htmlBounds.getCenterY() + (bounds.height/2 + 10)+"px"; textInputSpan.style.left = (htmlBounds.getCenterX() - getWidth(textInputSpan)/2)+"px"; startDemo();
}
function stageTooSmallHandler(){ var warning = "Sorry, bigger screen required :("; context.font = "bold normal 24px sans-serif"; context.fillText(warning, bounds.getCenterX() - context.measureText(warning).width/2, bounds.getCenterY()-12);
}
//========================
//Demo specific properties
//========================
var blockSetAnimator = new Sakri.BlockSetAnimator();
var words = ["SAKRI", "DEVSTATE","CODEPEN"];
var bgColor;
var strokeColor = "#000000";
var strokeWidth = 2;
var wordIndex = 0;
var fontProperties = new Sakri.CanvasTextProperties(Sakri.CanvasTextProperties.BOLD, null, 160);
var isIntro;
var timeoutId;
var strokeWidth = 3;
var colors = ["#698384", "#841118", "#c26c2e", "#517c24", "#cca835", "#166586", "#9ba78c", "#b68679"];
function clearTimeoutsAndIntervals(){ clearTimeout(timeoutId); if(blockSetAnimator){ blockSetAnimator.stop(); }
}
function startDemo(){ isIntro = true; showNextAnimation();
}
function getTallestImageHeight(images){ var tallest = 0; for(var i = 0; i<images.length; i++){ if(images[i].height>tallest){ tallest = images[i].height; } } return tallest;
}
function getBGColor(textColor){ var color = colors[Math.floor(Math.random()*colors.length)]; while(color==textColor){ color = colors[Math.floor(Math.random()*colors.length)]; } return color;
}
function showNextAnimation(){ var textColor = colors[Math.floor(Math.random()*colors.length)]; var images = Sakri.CanvasTextUtil.createImagesFromString(words[wordIndex], textColor, strokeColor, strokeWidth, fontProperties); bgColor = getBGColor(textColor); context.fillStyle = bgColor; context.fillRect(0, 0, canvas.width, canvas.height); context.font = fontProperties.getFontString(); blockSetAnimator.x = bounds.getCenterX() - context.measureText(words[wordIndex]).width/2; blockSetAnimator.y = bounds.getCenterY() - getTallestImageHeight(images)/2; blockSetAnimator.setImages(images); runRandomAnimation(); wordIndex++; wordIndex %= words.length;
}
function getIntroEasingFunction(){ var anim = Sakri.UnitAnimator; var easing = [anim.easeLinear, anim.easeOutSine, anim.easeOutBounce, anim.easeOutElastic]; return easing[Math.floor( Math.random()*easing.length )];
}
function getEndtroEasingFunction(){ var anim = Sakri.UnitAnimator; var easing = [anim.easeLinear, anim.easeInSine, anim.easeInBounce, anim.easeInElastic]; return easing[Math.floor( Math.random()*easing.length )];
}
function runRandomAnimation(){ var anim = Sakri.UnitAnimator; var easingFunction = isIntro ? getIntroEasingFunction() : getEndtroEasingFunction(); var rotation, minTransform, maxTransform; if( easingFunction == anim.easeLinear || easingFunction == anim.easeOutSine || anim.easeInSine){ rotation = -Math.PI*3 + Math.random() * Math.PI*6; minTranform = -200; maxTranform = 400; }else{ rotation = -Math.PI*1.5 + Math.random() * Math.PI*3; minTranform = -100; maxTranform = 200; } var scale = Math.random() * 3; var hAlign = Math.floor(Math.random()*3); var vAlign = Math.floor(Math.random()*3); var transformA = new Sakri.AnimationBlockTransform(minTranform + Math.random()*maxTranform, minTranform + Math.random()*maxTranform, scale, rotation, 0, hAlign, vAlign ); var transformB = new Sakri.AnimationBlockTransform(0, 0, 1, 0, 1, hAlign, vAlign); if(isIntro){ blockSetAnimator.setAnimation(transformA, transformB); }else{ blockSetAnimator.setAnimation(transformB, transformA); } blockSetAnimator.setEasingFunction(easingFunction); blockSetAnimator.start (2000, 250, blockSetAnimationComplete , animationUpdate); isIntro = !isIntro;
}
function animationUpdate(){ //context.clearRect(bounds.x, bounds.y, bounds.width, bounds.height); context.fillStyle = bgColor; context.globalAlpha = .8; context.fillRect(bounds.x, bounds.y, bounds.width, bounds.height); context.globalAlpha = 1; blockSetAnimator.render(context);
}
function blockSetAnimationComplete(){ context.fillStyle = bgColor; context.fillRect(bounds.x, bounds.y, bounds.width, bounds.height); blockSetAnimator.render(context); timeoutId = setTimeout(isIntro ? showNextAnimation : runRandomAnimation, 1000);
}
var maxCharacters = 8;
function changeText(){ var textInput = document.getElementById("textInput"); if(textInput.value && textInput.text!=""){ if(textInput.value.length > maxCharacters){ alert("Sorry, there is only room for "+maxCharacters+" characters. Try a shorter name."); return; } if(textInput.value.indexOf(" ")>-1){ alert("Sorry, no support for spaces right now :("); return; } clearTimeoutsAndIntervals(); words = [textInput.value]; wordIndex = 0; isIntro = true; showNextAnimation(); }
}
Developer | Sakri Rosenstrom |
Username | sakri |
Uploaded | September 06, 2022 |
Rating | 3.5 |
Size | 11,186 Kb |
Views | 24,288 |
Find the perfect freelance services for your business! Fiverr's mission is to change how the world works together. Fiverr connects businesses with freelancers offering digital services in 500+ categories. Find Developer!
Name | Size |
TextPlosion | 6,204 Kb |
Flappy Text | 8,763 Kb |
Marching Squares Visualized | 7,074 Kb |
Flappy Lego | 7,262 Kb |
Retro Geometry Text Effect | 14,008 Kb |
Flood Erase | 4,602 Kb |
Ghost Text | 10,419 Kb |
Circular Wander Text | 9,998 Kb |
He-Man effect | 8,574 Kb |
Circular Wander | 11,203 Kb |
Jasper is the AI Content Generator that helps you and your team break through creative blocks to create amazing, original content 10X faster. Discover all the ways the Jasper AI Content Platform can help streamline your creative workflows. Start For Free!
Name | Username | Size |
Basecamp 3 Document | Lachlanjc | 3,811 Kb |
Parallax-ish Sliding Content | Jdsteinbach | 2,748 Kb |
Calendar | Miroot | 2,033 Kb |
Gradient-ui-button-mark-fx | Tabspace | 1,881 Kb |
Acorrdian 2016 | Milanodituti | 3,720 Kb |
CSS Flip Animation | Bbodine1 | 2,525 Kb |
Lecture 1 | Law | 0 Kb |
React Template | Isac | 1,241 Kb |
Lazy Load for Background Images | The_ruther4d | 2,977 Kb |
Animated bar chart | CreativePunch | 3,124 Kb |
Surf anonymously, prevent hackers from acquiring your IP address, send anonymous email, and encrypt your Internet connection. High speed, ultra secure, and easy to use. Instant setup. Hide Your IP Now!