canvas可调参数彩色线条流动动画效果代码
代码语言:html
所属分类:动画
代码描述:canvas可调参数彩色线条流动动画效果代码
下面为部分代码预览,完整代码请点击下载或在bfwstudio webide中打开
<!DOCTYPE html> <html lang="en" > <head> <meta charset="UTF-8"> <style> body { font-family: Arial, Helvetica, "Liberation Sans", FreeSans, sans-serif; background-color: #000; margin:0; padding:0; border-width:0; cursor: pointer; caret-color: transparent; } input[type=text] { caret-color: auto; } #menu { font-size: 80%; margin: 0; padding: 5px; position: absolute; left: 5px; top: 5px; border-radius: 10px; background-color: rgba(255, 255, 128, 0.9); color: black; z-index: 10; } #menu.hidden #showhide{ display: none; } #controls { margin-top: 0px; margin-bottom: 0px; } #menu button { margin-right: 5px; margin-left: 5px; border-radius: 5px; } #menu .center { text-align: center; } #colorspan { width: 3em; margin: 0 5px; padding: 0 1em; border: 1px solid black; } #colorspan.colorful { background: linear-gradient(to right, orange 20%, green 21%, green 40%, fuchsia 41%, fuchsia 60%,yellow 61%, yellow 80%, blue 81%, blue); } </style> </head> <body > <div id ="menu"> <p id="controls">close controls</p> <div id="showhide"> <hr> <p>speed field :</p> <p><input type="range" min=30 max=150 step="any" value=70 id="wavelength"> wavelength</p> <p><input type="range" min=0 max=1 step="any" value=0.5 id="amplitude"> amplitude</p> <hr> <p>particles :</p> <p><input type="range" min=0 max=400 step="any" value=180 id="hue"> color <span id=colorspan></span></p> <p><input type="range" min=1 max=30 step="any" value=10 id="diam"> diameter</p> <p><input type="checkbox" id="randomdiam"> random diameter</p> <p><input type="checkbox" id="ftl" checked> from top left</p> <p><input type="checkbox" id="fbr"> from bottom right</p> <hr> <p class=center><button id=pattern>Draw pattern</button></p> <p id="patternstatus">In progress. Please wait</p> <hr> <p>click canvas to reset</p> </div> <!-- showhide --> </div> <!-- menu --> <script > "use strict"; window.addEventListener("load", function () { const speed = 3; // intensity of field at the triangle vertices const nbParticles = 100; const lifeTime = 10000 / speed; let ui, uiv; let canv, ctx; // canvas and context let maxx, maxy; // canvas dimensions let nbx, nby; // number of triangles let triangles; // array of triangles let particles; // array of particles let fields; let messages; let triWidth, triHeight; // length of triangle side let lineColor; let nbx2, nby2, midx, midy; let nbAlive; let nbGen; // shortcuts for Math. const mrandom = Math.random; const mfloor = Math.floor; const mround = Math.round; const mceil = Math.ceil; const mabs = Math.abs; const mmin = Math.min; const mmax = Math.max; const mPI = Math.PI; const mPIS2 = Math.PI / 2; const m2PI = Math.PI * 2; const msin = Math.sin; const mcos = Math.cos; const matan2 = Math.atan2; const mhypot = Math.hypot; const msqrt = Math.sqrt; const rac3 = msqrt(3); const rac3s2 = rac3 / 2; const mPIS3 = Math.PI / 3; const sinPIS6 = 0.5; const cosPIS6 = rac3s2; const sinPIS3 = cosPIS6; const cosPIS3 = sinPIS6; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - function alea(mini, maxi) { // random number in given range if (typeof maxi == 'undefined') return mini * mrandom(); // range 0..mini return mini + mrandom() * (maxi - mini); // range mini..maxi } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - function intAlea(mini, maxi) { // random integer in given range (mini..maxi - 1 or 0..mini - 1) // if (typeof maxi == 'undefined') return mfloor(mini * mrandom()); // range 0..mini - 1 return mini + mfloor(mrandom() * (maxi - mini)); // range mini .. maxi - 1 } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - /* returns intermediate point between p0 and p1, alpha = 0 whill preturn p0, alpha = 1 will return p1 values of alpha outside [0,1] may be used to compute points outside the p0-p1 segment */ function intermediate(p0, p1, alpha) { return [(1 - alpha) * p0[0] + alpha * p1[0], (1 - alpha) * p0[1] + alpha * p1[1]]; } // function intermediate // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - function Noise1DOneShot(periodmin, periodmax, min = 0, max = 1, random) { /* returns a 1D single-shot noise generator. the (optional) random function must return a value between 0 and 1 the returned function has no parameter, and will return a new number every tiime it is called. If the random function provides reproductible values (and is not used elsewhere), this one will return reproductible values too. period should be > 1. The bigger period is, the smoother output noise is */ random = random || Math.random; let currx = random(); // start with random offset let y0 = min + (max - min) * random(); // 'previous' value let y1 = min + (max - min) * random(); // 'next' value let period = periodmin + (periodmax - periodmin) * random(); let dx = 1 / period; return function () { currx += dx; if (currx > 1) { currx -= 1; period = periodmin + (periodmax - periodmin) * random(); dx = 1 / period; y0 = y1; y1 = min + (max - min) * random(); } let z = (3 - 2 * currx) * currx * currx; return z * y1 + (1 - z) * y0; }; } // Noise1DOneShot //------------------------------------------------------------------------ // User Interface (controls) //------------------------------------------------------------------------ function toggleMenu() { if (menu.classList.contains("hidden")) { menu.classList.remove("hidden"); this.innerHTML = "close controls"; } else { menu.classList.add("hidden"); this.innerHTML = "controls"; } } // toggleMenu //------------------------------------------------------------------------ function prepareUI() { // toggle menu handler document.querySelector("#controls").addEventListener("click", toggleMenu); ui = {}; // User Interface HTML elements uiv = {}; // User Interface values of controls ["wavelength", "amplitude", "hue", "diam", "randomdiam", "ftl", "fbr", "colorspan", "pattern", "patternstatus"].forEach(ctrlName => ui[ctrlName] = document.getElementById(ctrlName)); registerControl("wavelength", readUIFloat, setUIValue, "change", changeWaveLength); registerControl("amplitude", readUIFloat, setUIValue, "input", createField); registerControl("hue", readUIFloat, setUIValue, "input", displayHue); registerControl("diam", readUIFloat, setUIValue, "input"); registerControl("randomdiam", readUICheck, setUIChecked, "input"); registerControl("ftl", readUICheck, setUIChecked, "input"); registerControl("fbr", readUICheck, setUIChecked, "input"); ui.pattern.addEventListener("click", () => {messages.push({ message: "pattern" });}); readUI(); toggleProgress(); } // prepareUI //------------------------------------------------------------------------ function readUI() { if (ui.registered) { for (const ctrl in ui.registered) ui.registered[ctrl].readF(); } displayHue(); } // readUI // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - function registerControl(controlName, readFunction, setFunction, changeEvent, changedFunction) { /* provides simple way to associate controls with their read / update / changeEvent / changed functions since many (but not all) controls work almost the same way */ /* changeEvent and changedFunction are optional */ const ctrl = ui[controlName]; ui.registered = ui.registered || []; ui.registered.push(ctrl); // NEVER register a control twice !!! ctrl.readF = readFunction; ctrl.setF = setFunction; ctrl.changedF = changedFunction; if (changeEvent) { ctrl.addEventListener(changeEvent, event => { readFunction.call(ctrl); if (changedFunction) changedFunction.call(ctrl, event); }); } } // registerControl // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - function readUIFloat() { uiv[this.id] = parseFloat(this.value); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - function readUIInt() { uiv[this.id] = parseInt(this.value); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - function readUICheck() { uiv[this.id] = this.checked; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - function setUIValue(value) { this.value = value; if (this.readF) this.readF(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - function setUIChecked(checked) { if (checked) this.setAttribute("checked", "");else this.removeAttribute("checked"); if (this.readF) this.readF(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - function setUIControls(params) { /* caution ! changing wavelength deletes the picture */ for (let ctrl in params) { if (ui[ctrl].setF) ui[ctrl].setF(params[ctrl]); if (ui[ctrl].changedF) ui[ctrl].changedF(params[ctrl]); } } // setUIControls //------------------------------------------------------------------------ function displayHue() { if (uiv.hue < 360) { ui.colorspan.style.backgroundColor = `hsl(${uiv.hue}, 100%, 50%)`; ui.colorspan.classList.remove("colorful"); } else { ui.colorspan.classList.add("colorful"); } } //------------------------------------------------------------------------ function changeWaveLength() { triWidth = uiv.wavelength; triHeight = triWidth * rac3s2; // number of rows / columns nbx = 2 * mfloor(maxx / triWidth) + 5; nby = mfloor((mfloor(maxy / triHeight) + 1) / 2) * 2 + 4; triangles = []; for (let ky = 0; ky < nby; ++ky) { triangles[ky] = []; for (let kx = 0; kx < nbx; ++kx) { triangles[ky][kx] = new Triangle(kx, ky); } // for kx } // for ky createFieldDir(); createField(); } //------------------------------------------------------------------------ // class Triangle function Triangle(kx, ky) { nbx2 = nbx >>> 1; nby2 = nby >>> 1; this.kx = kx; this.ky = ky; this.upsideDown = !!(kx + ky + nbx2 + nby2 & 1); // points up(false) or down(true) this.vertices = [[], [], []]; // center of triangle (in fact, middle of height) let ya = midy + (ky - nby2) * triHeight; let xa = midx + (kx - nbx2) * triWidth / 2; // vertex 0 this.vertices[0][0] = xa; this.vertices[0][1] = ya + triHeight / 2 * (this.upsideDown ? 1 : -1); // vertex 1 this.vertices[1][0] = xa + triWidth / 2; this.vertices[1][1] = ya + triHeight / 2 * (this.upsideDown ? -1 : 1); // vertex 2 this.vertices[2][0] = xa - triWidth / 2; this.vertices[2][1] = ya + triHeight / 2 * (this.upsideDown ? -1 : 1); } // function Triangle // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Triangle.prototype.projections = function (x, y) { /* the given point is supposed to be inside the triangle computes the coordinates of the projection of this point on 3 sides */ let proj = [[], [], []]; proj[0] = [x, this.vertices[1][1]]; if (this.upsideDown) { proj[2][0] = (3 * triWidth / 2 + x + 3 * this.vertices[0][0] + (this.vertices[1][1] - y) * rac3) / 4; proj[2][1] = ((this.vertices[0][0] - x) * rac3 + 3 * y + this.vertices[1][1] + rac3s2 * triWidth) / 4; proj[1][0] = (x + 3 * this.vertices[0][0] + rac3 * (y - this.vertices[1][1]) - 1.5 * triWidth) / 4; proj[1][1] = ((x - this.vertices[0][0]) * rac3 + 3 * y + this.vertices[1][1] + rac3s2 * triWidth) / 4; } else { proj[2][1] = (y * rac3 + this.vertices[0][1] / rac3 + x - this.vertices[0][0]) / (rac3 + 1 / rac3); proj[2][0] = rac3 * (y - proj[2][1]) + x; proj[1][1] = (y * rac3 + this.vertices[0][1] / rac3 - x + this.vertices[0][0]) / (rac3 + 1 / rac3); proj[1][0] = x - rac3 * (y - proj[1][1]); } return proj; }; // // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Triangle.prototype.draw =.........完整代码请登录后点击上方下载按钮下载查看
网友评论0