Particles
How do I make an particles?
Particles from an emitter moving behind some text. FPS counter included to measure performance. Select from two strategies : using fillRect() and setting pixels with get/putImageData(). There is a widget to change the number of particles. I get 60fps using fillrect on 10,000 particles, with putImageData I get 100,000 with 55fps.. What is a particles? How do you make a particles? This script and codes were developed by Sakri Rosenstrom on 13 September 2022, Tuesday.
Particles - Script Codes HTML Codes
<!DOCTYPE html>
<html >
<head> <meta charset="UTF-8"> <title>Particles</title> <link rel="stylesheet" href="css/style.css">
</head>
<body> <div id="canvasContainer"></div>
<span id="textInputSpan"> Enter your name (max 10 chars) : <input id="textInput" maxlength="10" type="text" width="150" /> <button onclick="changeText()">GO!</button> method: <select id="strategySelect" onchange="changeSettings()" > <option value="drawRect">drawRect()</option> <option value="drawRectColor">drawRect() color</option> <option value="perPixel">perPixel()</option> <option value="perPixelColor">perPixel() color</option> </select> particles : <select id="particlesSelect" onchange="changeSettings()" />
</span> <script src="js/index.js"></script>
</body>
</html>
Particles - Script Codes CSS Codes
html, body{ margin : 0px; width : 100%; height : 100%; overflow: hidden; background-color: #000000; font-family: sans-serif;
}
#canvasContainer{ margin : 0px; width : 100%; height : 100%;
}
#textInputSpan{ position: absolute; color: #FFFFFF; font-family: sans-serif;
}
Particles - Script Codes JS Codes
/* * Stats.js 1.1 * https://code.google.com/p/mrdoob/wiki/stats_js * */ function Stats() { this.init(); } Stats.prototype = { init: function() { this.frames = 0; this.framesMin = 100; this.framesMax = 0; this.time = new Date().getTime(); this.timePrev = new Date().getTime(); this.container = document.createElement("div"); this.container.style.position = 'absolute'; this.container.style.fontFamily = 'Arial'; this.container.style.fontSize = '10px'; this.container.style.backgroundColor = '#000020'; this.container.style.opacity = '0.9'; this.container.style.width = '80px'; this.container.style.paddingTop = '2px'; this.framesText = document.createElement("div"); this.framesText.style.color = '#00ffff'; this.framesText.style.marginLeft = '3px'; this.framesText.style.marginBottom = '3px'; this.framesText.innerHTML = '<strong>FPS</strong>'; this.container.appendChild(this.framesText); this.canvas = document.createElement("canvas"); this.canvas.width = 74; this.canvas.height = 30; this.canvas.style.display = 'block'; this.canvas.style.marginLeft = '3px'; this.canvas.style.marginBottom = '3px'; this.container.appendChild(this.canvas); this.context = this.canvas.getContext("2d"); this.context.fillStyle = '#101030'; this.context.fillRect(0, 0, this.canvas.width, this.canvas.height ); this.contextImageData = this.context.getImageData(0, 0, this.canvas.width, this.canvas.height); setInterval( bargs( function( _this ) { _this.update(); return false; }, this ), 1000 ); }, getDisplayElement: function() { return this.container; }, tick: function() { this.frames++; }, update: function() { this.time = new Date().getTime(); this.fps = Math.round((this.frames * 1000 ) / (this.time - this.timePrev)); //.toPrecision(2); this.framesMin = Math.min(this.framesMin, this.fps); this.framesMax = Math.max(this.framesMax, this.fps); this.framesText.innerHTML = '<strong>' + this.fps + ' FPS</strong> (' + this.framesMin + '-' + this.framesMax + ')'; this.contextImageData = this.context.getImageData(1, 0, this.canvas.width - 1, 30); this.context.putImageData(this.contextImageData, 0, 0); this.context.fillStyle = '#101030'; this.context.fillRect(this.canvas.width - 1, 0, 1, 30); this.index = ( Math.floor(30 - Math.min(30, (this.fps / 60) * 30)) ); this.context.fillStyle = '#80ffff'; this.context.fillRect(this.canvas.width - 1, this.index, 1, 1); this.context.fillStyle = '#00ffff'; this.context.fillRect(this.canvas.width - 1, this.index + 1, 1, 30 - this.index); this.timePrev = this.time; this.frames = 0; } } // Hack by Spite function bargs( _fn ) { var args = []; for( var n = 1; n < arguments.length; n++ ) args.push( arguments[ n ] ); return function () { return _fn.apply( this, args ); }; } (function (window){ var Sakri = window.Sakri || {}; window.Sakri = window.Sakri || Sakri; Sakri.MathUtil = {}; //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.hexToRgb = function(hex) { // Expand shorthand form (e.g. "03F") to full form (e.g. "0033FF") var shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i; hex = hex.replace(shorthandRegex, function(m, r, g, b) { return r + r + g + g + b + b; }); var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); return result ? { r: parseInt(result[1], 16), g: parseInt(result[2], 16), b: parseInt(result[3], 16) } : null; } 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; }; //================================================== //===================::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; }; 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.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+"}"; }; }(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 = {}; //returns the biggest font size that best fits into given width Sakri.CanvasTextUtil.getFontSizeForWidth = function(string, fontProps, width, canvas, fillStyle, maxFontSize){ if(!canvas){ var canvas = document.createElement("canvas"); } if(!fillStyle){ fillStyle = "#000000"; } if(isNaN(maxFontSize)){ maxFontSize = 500; } var context = canvas.getContext('2d'); context.font = fontProps.getFontString(); context.textBaseline = "top"; var copy = fontProps.clone(); //console.log("getFontSizeForWidth() 1 : ", copy.fontSize); context.font = copy.getFontString(); var textWidth = context.measureText(string).width; //SOME DISAGREEMENT WHETHER THIS SHOOULD BE WITH && or || if(textWidth < width){ while(context.measureText(string).width < width){ copy.fontSize++; context.font = copy.getFontString(); if(copy.fontSize > maxFontSize){ console.log("getFontSizeForWidth() max fontsize reached"); return null; } } }else if(textWidth > width){ while(context.measureText(string).width > width){ copy.fontSize--; context.font = copy.getFontString(); if(copy.fontSize < 0){ console.log("getFontSizeForWidth() min fontsize reached"); return null; } } } //console.log("getFontSizeForWidth() 2 : ", copy.fontSize); return copy.fontSize; }; //========================================================================================= //==============::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.clone = function(){ return new Sakri.CanvasTextProperties(this.fontWeight, this.fontStyle, this.fontSize, this.fontFace); }; 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){ window.requestAnimationFrame = window.__requestAnimationFrame || window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || (function () { return function (callback, element) { var lastTime = element.__lastTime; if (lastTime === undefined) { lastTime = 0; } var currTime = Date.now(); var timeToCall = Math.max(1, 33 - (currTime - lastTime)); window.setTimeout(callback, timeToCall); element.__lastTime = currTime + timeToCall; }; })(); var Sakri = window.Sakri || {}; window.Sakri = window.Sakri || Sakri; //constructor, duration and framerate must be in milliseconds Sakri.UnitAnimator = function(duration, canvas, updateCallBack, completeCallBack){ this.easingFunction = Sakri.UnitAnimator.easeLinear;//default this.animating = false; this.canvas = canvas; var scope = this; this.loopFunction = function(){scope.loop();}; this.reset(duration, 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.reset = function(duration, updateCallBack, completeCallBack){ this.duration = duration; this.updateCallBack = updateCallBack; this.completeCallBack = completeCallBack; }; Sakri.UnitAnimator.prototype.start = function(easingFunction){ //console.log("Sakri.UnitAnimator.start()"); if(easingFunction){ this.setEasingFunction(easingFunction); } this.animating = true; this.animationStart = Date.now(); this.millisecondsAnimated = 0;//keeps track of how long the animation has been running this.loop(); }; Sakri.UnitAnimator.prototype.loop = function(){ if(!this.animating){ return; } this.update(); window.requestAnimationFrame(this.loopFunction, canvas); } Sakri.UnitAnimator.prototype.pause = function(){ this.animating = false; }; //refactor, make private Sakri.UnitAnimator.prototype.update = function(){ //console.log("Sakri.UnitAnimator.update()",this.getAnimationPercent()); this.millisecondsAnimated = Date.now() - this.animationStart; 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)); //============::ACTUAL DEMO::================= window.requestAnimationFrame = window.__requestAnimationFrame || window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || (function () { return function (callback, element) { var lastTime = element.__lastTime; if (lastTime === undefined) { lastTime = 0; } var currTime = Date.now(); var timeToCall = Math.max(1, 33 - (currTime - lastTime)); window.setTimeout(callback, timeToCall); element.__lastTime = currTime + timeToCall; }; })(); var readyStateCheckInterval = setInterval( function() { if (document.readyState === "complete") { clearInterval(readyStateCheckInterval); init(); } }, 10); //======================== //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 = 600; var resizeTimeoutId = -1; var stats; function init(){ canvasContainer = document.getElementById("canvasContainer"); window.onresize = resizeHandler; stats = new Stats(); canvasContainer.appendChild( stats.getDisplayElement() ); 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); if(bounds.width<minimumStageWidth || bounds.height<minimumStageHeight){ stageTooSmallHandler(); return; } var textInputSpan = document.getElementById("textInputSpan"); textInputSpan.style.top = htmlBounds.getCenterY() + (bounds.height/2) + 20 +"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 animating = false; var particles = []; var numParticles = 4000; var currentText = "SAKRI"; var fontRect; var fontProperties = new Sakri.CanvasTextProperties(Sakri.CanvasTextProperties.BOLD, null, 100); var animator; var particleSource = new Sakri.Geom.Point();; var particleSourceStart = new Sakri.Geom.Point(); var particleSourceTarget = new Sakri.Geom.Point(); var redParticles = ["#fe7a51" , "#fdd039" , "#fd3141"]; var greenParticles = ["#dbffa6" , "#fcf8fd" , "#99de5e"]; var pinkParticles = ["#fef4f7" , "#f2a0c0" , "#fb3c78"]; var yellowParticles = ["#fdfbd5" , "#fff124" , "#f4990e"]; var blueParticles = ["#9ca2df" , "#222a6d" , "#333b8d"]; var particleColorSets = [redParticles, greenParticles, pinkParticles, yellowParticles, blueParticles]; var particleColorIndex = 0; var renderParticleFunction; var renderBounds; var particleCountOptions = [2000, 4000, 6000, 8000, 10000, 15000, 20000 ]; var pixelParticleCountOptions = [10000, 40000, 60000, 80000, 100000, 150000 ]; function clearTimeoutsAndIntervals(){ animating = false; } function startDemo(){ //makes sure we don't try to access pixels outside of the canvas renderBounds = bounds.clone(); renderBounds.x += 10; renderBounds.y += 10; renderBounds.width -= 20; renderBounds.height -= 20; switch(document.getElementById("strategySelect").value){ case "drawRect": renderParticleFunction = renderParticlesDrawRect; setParticleNumberOptions(particleCountOptions); numParticles = parseInt(document.getElementById("particlesSelect").value); createParticles(); break; case "drawRectColor": renderParticleFunction = renderParticlesDrawRectWithColor; setParticleNumberOptions(particleCountOptions); numParticles = parseInt(document.getElementById("particlesSelect").value); createDrawRectColorParticles(); break; case "perPixel": renderParticleFunction = renderParticlesPerPixel; setParticleNumberOptions(pixelParticleCountOptions); numParticles = parseInt(document.getElementById("particlesSelect").value); createParticles(); break; case "perPixelColor": renderParticleFunction = renderParticlesPerPixelColor; setParticleNumberOptions(pixelParticleCountOptions); numParticles = parseInt(document.getElementById("particlesSelect").value); createPixelColorParticles(); break; } fontRect = new Sakri.Geom.Rectangle(bounds.x + bounds.width*.1, 0, bounds.width - bounds.width*.2, bounds.height); fontProperties.fontSize = 100; fontProperties.fontSize = Sakri.CanvasTextUtil.getFontSizeForWidth(currentText, fontProperties, fontRect.width, canvas); fontRect.y = bounds.getCenterY() - fontProperties.fontSize/2; fontRect.height = fontProperties.fontSize; context.font = fontProperties.getFontString(); particleSource.x = particleSourceStart.x = Sakri.MathUtil.getRandomNumberInRange(fontRect.x, fontRect.getRight()); particleSource.y = particleSourceStart.y = Sakri.MathUtil.getRandomNumberInRange(fontRect.y, fontRect.getBottom()); animator = new Sakri.UnitAnimator(2000, canvas, animatorUpdate, animatorComplete); nextParticleSourceTween(); animating = true; loop(); } function nextParticleSourceTween(){ particleColorIndex++; particleColorIndex %= particleColorSets.length; particleSourceTarget.x = Sakri.MathUtil.getRandomNumberInRange(fontRect.x, fontRect.getRight()); particleSourceTarget.y = Sakri.MathUtil.getRandomNumberInRange(fontRect.y, fontRect.getBottom()); animator.setEasingFunction = Sakri.UnitAnimator.getRandomEasingFunction(); animator.start(); } function animatorUpdate(){ particleSource.x = particleSourceStart.x + (particleSourceTarget.x - particleSourceStart.x) * animator.getAnimationPercent(); particleSource.y = particleSourceStart.y + (particleSourceTarget.y - particleSourceStart.y) * animator.getAnimationPercent(); } function animatorComplete(){ particleSourceStart.x = particleSourceTarget.x; particleSourceStart.y = particleSourceTarget.y; setTimeout(nextParticleSourceTween, 100); } function getParticleColor(){ var set = particleColorSets[particleColorIndex]; return set[Math.floor(Math.random()*set.length)]; } function createDrawRectColorParticles(){ particles = []; for(var i=0; i<numParticles * 5; i+=5){ particles[i] = particleSource.x;//x particles[i+1] = particleSource.y;//y particles[i+2] = -5 + Math.random()*10;//xSpeed particles[i+3] = -5 + Math.random()*10;//ySpeed particles[i+4] = getParticleColor();//color } } function createParticles(){ particles = []; for(var i=0; i<numParticles * 4; i+=4){ particles[i] = particleSource.x;//x particles[i+1] = particleSource.y;//y particles[i+2] = -5 + Math.random()*10;//xSpeed particles[i+3] = -5 + Math.random()*10;//ySpeed } } function createPixelColorParticles(){ particles = []; var rgb; for(var i=0; i<numParticles * 7; i+=7){ particles[i] = particleSource.x;//x particles[i+1] = particleSource.y;//y particles[i+2] = -5 + Math.random()*10;//xSpeed particles[i+3] = -5 + Math.random()*10;//ySpeed rgb = Sakri.MathUtil.hexToRgb(getParticleColor()); particles[i+4] = rgb.r; particles[i+5] = rgb.g; particles[i+6] = rgb.b; } } function loop(){ if(!animating){ return; } stats.tick(); //fill bg context.fillStyle = "#000000"; context.globalAlpha = .05; context.fillRect(0,0,canvas.width, canvas.height); context.globalAlpha = 1; //render particles renderParticleFunction(); //render text context.globalAlpha = .5; context.fillStyle = "#000000"; context.fillText(currentText, fontRect.x, bounds.getCenterY() - fontProperties.fontSize/2); context.globalAlpha = 1; window.requestAnimationFrame(loop, canvas); } function renderParticlesDrawRectWithColor(){ for(var i=0; i<particles.length; i+=5 ){ particles[i] += particles[i+2]; particles[i+1] += particles[i+3]; particles[i+3] += .05; context.fillStyle = particles[i+4]; context.fillRect(particles[i], particles[i+1], 1, 1); if(!bounds.containsPoint(particles[i], particles[i+1] )){ particles[i] = particleSource.x;//x particles[i+1] = particleSource.y;//y particles[i+2] = -5 + Math.random()*10;//xSpeed particles[i+3] = -5 + Math.random()*10;//ySpeed particles[i+4] = getParticleColor();//color } } } function renderParticlesDrawRect(){ context.fillStyle = "#FFFFFF"; for(var i=0; i<particles.length; i+=4 ){ particles[i] += particles[i+2]; particles[i+1] += particles[i+3]; particles[i+3] += .05; context.fillRect(particles[i], particles[i+1], 1, 1); if(!bounds.containsPoint(particles[i], particles[i+1] )){ particles[i] = particleSource.x;//x particles[i+1] = particleSource.y;//y particles[i+2] = -5 + Math.random()*10;//xSpeed particles[i+3] = -5 + Math.random()*10;//ySpeed } } } function renderParticlesPerPixel(){ var imageData = context.getImageData(0, 0, canvas.width, canvas.height); var data = imageData.data; var rowWidth = imageData.width * 4; var index; var i, length = particles.length; for(i=0; i<length; i+=4 ){ particles[i] += particles[i+2]; particles[i+1] += particles[i+3]; particles[i+3] += .05; index = Math.round(particles[i]) * 4 + Math.round(particles[i+1]) * rowWidth; data[index] += 50; data[index + 1] += 50; data[index + 2] += 50; if(!renderBounds.containsPoint(particles[i], particles[i+1] )){ particles[i] = particleSource.x;//x particles[i+1] = particleSource.y;//y particles[i+2] = -5 + Math.random()*10;//xSpeed particles[i+3] = -5 + Math.random()*10;//ySpeed } } context.putImageData(imageData, 0, 0); } function renderParticlesPerPixelColor(){ var imageData = context.getImageData(0, 0, canvas.width, canvas.height); var data = imageData.data; var rowWidth = imageData.width * 4; var index; var i, rgb, length = particles.length; for(i=0; i<length; i+=7 ){ particles[i] += particles[i+2]; particles[i+1] += particles[i+3]; particles[i+3] += .05; index = Math.round(particles[i]) * 4 + Math.round(particles[i+1]) * rowWidth; data[index] = particles[i+4]; data[index + 1] = particles[i+5]; data[index + 2] = particles[i+6]; if(!renderBounds.containsPoint(particles[i], particles[i+1] )){ particles[i] = particleSource.x;//x particles[i+1] = particleSource.y;//y particles[i+2] = -5 + Math.random()*10;//xSpeed particles[i+3] = -5 + Math.random()*10;//ySpeed rgb = Sakri.MathUtil.hexToRgb(getParticleColor()); particles[i+4] = rgb.r; particles[i+5] = rgb.g; particles[i+6] = rgb.b; } } context.putImageData(imageData, 0, 0); } var maxCharacters = 10; 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; } currentText = textInput.value; clearTimeoutsAndIntervals(); animating = false; setTimeout(commitResize, 100); } } function changeSettings(){ clearTimeoutsAndIntervals(); animating = false; setTimeout(commitResize, 100); } function setParticleNumberOptions(values){ var selector = document.getElementById("particlesSelect"); if(selector.options.length>0 && parseInt(selector.options[0].value) == values[0] ){ return; } while(selector.options.length){ selector.remove(selector.options.length-1); } for(var i=0;i <values.length; i++){ selector.options[i] = new Option(values[i], values[i], i==0, i==0); } }
Developer | Sakri Rosenstrom |
Username | sakri |
Uploaded | September 13, 2022 |
Rating | 4 |
Size | 9,207 Kb |
Views | 26,312 |
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 |
He-Man effect | 8,574 Kb |
TextPlosion | 6,204 Kb |
Canvas Vasarely | 3,290 Kb |
Cloud Text | 8,351 Kb |
Circular Wander Text | 9,998 Kb |
Flappy Text | 8,763 Kb |
Jello Text | 12,971 Kb |
Flappy Bird 32px by 32px | 4,800 Kb |
Flappy Van Persie | 152,740 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 |
Playing with FlexBox | _Billy_Brown | 3,162 Kb |
Scroll using CSS | Casperovic | 2,159 Kb |
Shopping List | Markmurray | 6,015 Kb |
Experiments with Vertical Centering | KatieK2 | 3,924 Kb |
A form arranged using automatic placement. | Vikasford | 2,103 Kb |
A Pen by Jim Savage | Madebyjam | 2,418 Kb |
Flexbox slider | Rendro | 3,459 Kb |
Loading... | Adamjacob | 2,384 Kb |
Button shaking | SusanneLundblad | 2,227 Kb |
CSS3 Latte Art Logo | Esambino | 2,036 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!