js实现旋转波纹效果
代码语言:html
所属分类:粒子
下面为部分代码预览,完整代码请点击下载或在bfwstudio webide中打开
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Trochoid ribbons</title> <style> * { box-sizing:border-box; } body { font-family:sans-serif; font-size:0.8em; background:#000; } canvas { max-width:100%; border-radius:400px; } #pmenu { border:none; cursor:pointer; padding:none; font-weight:bold; background:none; line-height:1; font-size:26pt; } div.mb { position:relative; margin:0; padding:0; text-align:center; font-weight:bold; border-top:1px dotted #BBB; border-right:1px solid transparent; border-bottom:1px solid transparent; border-left:1px solid transparent; } div.pholder { width:188px; padding:4px; height:25px; } div.slider { position:absolute; top:0px; left:0px; height:26px; opacity:0; background:hsl(240, 30%, 86%); display:block; width:70px; padding:4px 0; border-right:4px solid hsl(240,30%,74%); } /* 70 of 132 */ div.rtext { position:absolute; top:0px; left:0px; } div.rlabel { display:inline-block; float:left; white-space:nowrap; padding:4px 0; width:120px; } div.rep { display:inline-block; float:left; width:32px;margin-right:2px; border-left:1px dotted #EEE; padding:4px 4px 4px 0; text-align:right; } div.inputdiv { position:absolute; top:0px; left:0px; height:26px; border:1px solid transparent; } input.range { height:24px; opacity:0.01; cursor:pointer; margin:0; width:152px; } input.cb { position:absolute; top:0; left:0; opacity:0.01; width:100%; height:24px; cursor:pointer; margin:0; } div.infoc { border:1px dotted #99F; } div.locksym { text-align:center; font-size:14px; padding:2px 0; color:black; } div.lockdiv { position:relative; padding:0; float:right; height:24px; height:26px; margin-top:-1px; } </style> </head> <body translate="no"> <div style="text-align:center;"><canvas id="cta" width="800" height="800"></canvas></div> <div class="bgfade" style="position:absolute; top:8px; right:8px;"> <div style="text-align:right;"> <button id="pmenu"> <span id="xmrep" style="opacity:0;">×</span> <span id="pmrep" style="position:absolute; top:3px; right:5px; color:white; opacity:.8;">≡</span> </button> </div> <div id="ctl" style="opacity:0;"> <div class="mb" style="width:100%; height:24px;"> <div class="pholder"> </div> <div class="rtext"> <div id="ss" class="rlabel" style="width:188px;">Stop</div> </div> <div class="inputdiv"> <button style="width:188px; height:24px; display:block; cursor:pointer; padding:0; border:none; opacity:.01;" onfocus="btnFocus(this)" onblur="btnBlur(this)" onmouseover="bmov(this)" onmouseout="bmou(this)" onclick="start()"> </button> </div> </div> </div> <script> var CSIZE = 400; var canvas = document.querySelector('#cta'); onresize = function () { canvas.style.maxHeight = window.innerHeight - 20 + 'px'; }; var ctx = canvas.getContext('2d'); ctx.translate(CSIZE, CSIZE); ctx.rotate(-Math.PI / 2); ctx.lineWidth = 4; ctx.strokeStyle = 'hsl(180,90%,80%)'; ctx.fillStyle = 'hsla(0,0%,0%,0.05)'; onresize(); function powerRandom(p) { function rec(p, r) { --p; if (p <= 0) { return r; } else { r *= Math.random(); return rec(p, r); } } p = Math.round(p); return rec(p, Math.random()); } function getRandomInt(min, max, low) { var p = low ? low : 1; min = Math.ceil(min); max = Math.floor(max); return Math.floor(powerRandom(p) * (max - min)) + min; } var primes = [2, 3, 5, 7, 11, 13, 17, 19]; var cycsets = { 2: [2, 4, 6, 8, 10, 12, 14, 16, 18], 3: [3, 6, 9, 12, 15, 18], 5: [5, 10, 15], 7: [7, 14], 11: [11], 13: [13], 17: [17], 19: [19] }; var cycsets2 = { 2: [2, 4, 8, 16], 3: [3, 9], 5: [5], 7: [7], 11: [11], 13: [13], 17: [17], 19: [19] }; function getFactors(n) { let a = []; for (let p of primes) { if (n % p == 0) { a.push(p); } } return a; } function getCycleArray(n) { let a = new Set(); for (let p of primes) { if (n % p == 0) { for (let f of cycsets2[p]) { a.add(f); } } } return Array.from(a); } var Roulette = function (ro) { if (ro instanceof Roulette) { Object.assign(this, ro); } else { this.dz = -1; this.type1 = -1; this.type2 = -1; this.type3 = -1; this.type4 = -1; this.c0 = 1; this.c1 = 8; this.c2 = 16; this.c3 = 4; this.c4 = 4; this.cycleSet = 8; this.r1 = 100; this.r2 = 80; this.r3 = 40; this.r4 = 40; this.r5 = 40; this.radiiCount = 2; } let rself = this; this.getMetrics = function (rotFrac, n) { t = rself.dz * (rotFrac + n / ribbons.rCount) * rself.c0 * 2 * Math.PI; let f1 = 1 + rself.type1 * rself.c1 / rself.c0; var x, y; if (rself.radiiCount == 2) { x = rself.r1 * Math.cos(t) + rself.r2 * Math.cos(f1 * t); y = rself.r1 * Math.sin(t) + rself.r2 * Math.sin(f1 * t); } else if (rself.radiiCount == 3) { let f2 = 1 + (rself.type1 * rself.c1 + rself.type2 * rself.c2) / rself.c0; x = rself.r1 * Math.cos(t) + rself.r2 * Math.cos(f1 * t) + rself.r3 * Math.cos(f2 * t); y = rself.r1 * Math.sin(t) + rself.r2 * Math.sin(f1 * t) + rself.r3 * Math.sin(f2 * t); } else if (rself.radiiCount == 4) { let f2 = 1 + (rself.type1 * rself.c1 + rself.type2 * rself.c2) / rself.c0; let f3 = 1 + (rself.type1 * rself.c1 + rself.type2 * rself.c2 + rself.type3 * rself.c3) / rself.c0; x = rself.r1 * Math.cos(t) + rself.r2 * Math.cos(f1 * t) + rself.r3 * Math.cos(f2 * t) + rself.r4 * Math.cos(f3 * t); y = rself.r1 * Math.sin(t) + rself.r2 * Math.sin(f1 * t) + rself.r3 * Math.sin(f2 * t) + rself.r4 * Math.sin(f3 * t); } else if (rself.radiiCount == 5) { let f2 = 1 + (rself.type1 * rself.c1 + rself.type2 * rself.c2) / rself.c0; let f3 = 1 + (rself.type1 * rself.c1 + rself.type2 * rself.c2 + rself.type3 * rself.c3) / rself.c0; let f4 = 1 + (rself.type1 * rself.c1 + rself.type2 * rself.c2 + rself.type3 * rself.c3 + rself.type4 * rself.c4) / rself.c0; x = rself.r1 * Math.cos(t) + rself.r2 * Math.cos(f1 * t) + rself.r3 * Math.cos(f2 * t) + rself.r4 * Math.cos(f3 * t) + rself.r5 * Math.cos(f4 * t); y = rself.r1 * Math.sin(t) + rself.r2 * Math.sin(f1 * t) + rself.r3 * Math.sin(f2 * t) + rself.r4 * Math.sin(f3 * t) + rself.r5 * Math.sin(f4 * t); } else { //debugger; } return { x: x, y: y }; }; this.softCycle = function () { rself.c1 = rself.setCycles(); rself.c2 = rself.setCycles(); rself.c3 = rself.setCycles(); rself.c4 = rself.setCycles(); }; this.setCycle0Match = function () { rself.c0 = getRandomInt(1, 19, 4); }; this.getCycle0Match = function () { return getRandomInt(1, 19, 4); }; this.setCycles = function () { //if (Math.random()<0.3) { // put symmetry control here //let ca=getFactors(this.cycleSet); let ca = getCycleArray(this.cycleSet); if (ca.length == 0) { return this.cycleSet; } return ca[getRandomInt(0, ca.length)]; /* } else if (Math.random()<0.3) { // put symmetry control here let ca=getFactors(ribbons.rCount); if (ca.length==0) { return this.cycleSet; } return ca[getRandomInt(0,ca.length)]; } else { let ca=getCycleArray(ribbons.rCount); if (ca.length==0) { return this.cycleSet; } return ca[getRandomInt(0,ca.length)]; } */ }; this.randomizeRadiiCount = function () { //rself.radiiCount=2+Math.round(2*Math.random()); rself.radiiCount = 2 + getRandomInt(0, 4); }; this.randomizeRadii = function () { if (rself.radiiCount == 5) { rself.r1 = 70 - 20 * Math.random(); rself.r2 = 20 + (160 - rself.r1) * Math.random(); rself.r3 = 20 + (200 - rself.r1 - rself.r2) * Math.random(); rself.r4 = 20 + (240 - rself.r1 - rself.r2 - rself.r3) * Math.random(); rself.r5 = 280 - rself.r1 - rself.r2 - rself.r3 - rself.r4; } else if (rself.radiiCount == 4) { rself.r1 = 70 - 20 * Math.random(); /* rself.r2=70-20*Math.random(); rself.r3=70-20*Math.random(); rself.r4=70-20*Math.random(); */ // rself.r1=20+160*Math.random(); rself.r2 = 20 + (200 - rself.r1) * Math.random(); rself.r3 = 20 + (240 - rself.r1 - rself.r2) * Math.random(); rself.r4 = 280 - rself.r1 - rself.r2 - rself.r3; rself.r5 = 0; } else if (rself.radiiCount == 3) { rself.r1 = 90 - 30 * Math.random(); /* rself.r2=90-30*Math.random(); rself.r3=90-30*Math.random(); */ // rself.r1=20+160*Math.random(); rself.r2 = 20 + (240 - rself.r1) * Math.random(); rself.r3 = 280 - rself.r1 - rself.r2; rself.r4 = 0; rself.r5 = 0; } else if (rself.radiiCount == 2) { let rr = 210 + 70 * Math.random(); // sum of radii from 210-280 let rd = 30 - 60 * Math.random(); rself.r1 = (rd + rr) / 2; rself.r2 = (rr - rd) / 2; /* rself.r1=20+160*Math.random(); rself.r2=280-rself.r1; */ rself.r3 = 0; rself.r4 = 0; rself.r5 = 0; } else { //debugger; } }; this.randomizeCycles = function () { rself.cycleSet = ribbons.goodCycleSet(); rself.c1 = rself.setCycles(); rself.c2 = rself.setCycles(); rself.c3 = rself.setCycles(); rself.c4 = rself.setCycles(); rself.c0 = getRandomInt(1, 19, 4); }; this.randomizeTypes = function () { rself.type1 = [-1, 1][getRandomInt(0, 2)]; rself.type2 = [-1, 1][getRandomInt(0, 2)]; rself.type3 = [-1, 1][getRandomInt(0, 2)]; rself.type4 = [-1, 1][getRandomInt(0, 2)]; }; this.getSP = function () { let sp = this.c0 + this.c1; switch (this.radiiCount) { case 2: return sp; case 3: return sp += this.c2; case 4: return sp += this.c2 + this.c3; case 5: return sp += this.c2 + this.c3 + this.c4; default: return 0;} }; this.controlledCycleChange = function (mod) { let count = 0; let sMax = 24; let sMin = 15; do { mod(); var sp = rself.getSP(); if (count++ > 10) { return; } //} while (sp<rself.spMin || sp>rself.spMax); } while (sp > sMax++ || sp < sMin--); }; }; function cbLoc(p1, p2, frac) { var f1 = .2; var f2 = .8; var e1 = Math.pow(1 - frac, 3) * p1; var e2 = 3 * frac * Math.pow(1 - frac, 2) * (p1 + (p2 - p1) * f1); var e3 = 3 * (1 - frac) * Math.pow(frac, 2) * (p1 + (p2 - p1) * f2); var e4 = Math.pow(frac, 3) * p2; return e1 + e2 + e3 + e4; } var path = { fromRo: new Roulette(), toRo: new Roulette(), fromRoX: new Roulette(), toRoX: new Roulette(), start: 0, frac: 0, //duration:20000, duration: 5000, //duration:2000, getMetrics: function (rotFrac, n) { let fromMet = this.fromRo.getMetrics(rotFrac, n); let toMet = this.toRo.getMetrics(rotFrac, n); let fromMetX = this.fromRoX.getMetrics(rotFrac, n); let toMetX = this.toRoX.getMetrics(rotFrac, n); return { //x:this.frac*toMet.x+(1-this.frac)*fromMet.x, //y:this.frac*toMet.y+(1-this.frac)*fromMet.y, x: cbLoc(fromMet.x, toMet.x, this.frac), y: cbLoc(fromMet.y, toMet.y, this.frac), xX: cbLoc(fromMetX.x, toMetX.x, this.frac), yX: cbLoc(fromMetX.y, toMetX.y, this.frac) }; }, mf: 0.3, transit: function () { Object.assign(this.fromRo, this.toRo); Object.assign(this.fromRoX, this.toRoX); this.toRo = new Roulette(this.fromRo); this.toRoX = new Roulette(this.fromRoX); if (Math.random() < this.mf) { //this.toRo.randomizeCycles(); } else { if (Math.random() < this.mf) { this.toRo.controlledCycleChange(this.toRo.setCycle0Match); //this.toRo.c0=this.toRo.getCycle0Match(); //this.toRoX.c0=this.toRoX.getCycle0Match(); this.toRoX.c0 = this.toRo.c0; } if (Math.random() < this.mf) { this.toRo.controlledCycleChange(this.toRo.softCycle); //this.toRo.softCycle(); this.toRoX.c1 = this.toRo.c1; this.toRoX.c2 = this.toRo.c2; this.toRoX.c3 = this.toRo.c3; this.toRoX.c4 = this.toRo.c4; } } if (Math.random() < this.mf) { this.toRo.controlledCycleChange(this.toRo.randomizeRadiiCount); //this.toRo.randomizeRadiiCount(); //this.toRoX.randomizeRadiiCount(); this.toRoX.radiiCount = this.toRo.radiiCount; } if (Math.random() < this.mf) { this.toRo.randomizeTypes(); this.toRoX.type1 = this.toRo.type1; this.toRoX.type2 = this.toRo.type2; this.toRoX.type3 = this.toRo.type3; this.toRoX.type4 = this.toRo.type4; //this.toRoX.randomizeTypes(); } if (Math.random() < this.mf / 4) { this.toRo.dz = [-1, 1][getRandomInt(0, 2)]; this.toRoX.dz = this.toRo.dz; } if (this.mf > 0) { this.toRo.randomizeRadii(); this.toRoX.randomizeRadii(); } }, animate: function (ts) { if (stopped) { return; } if (!path.start) { path.start = ts; } let progress = ts - path.start; if (progress < path.duration) { path.frac .........完整代码请登录后点击上方下载按钮下载查看
网友评论0