svg实现线条绘制三角canvas动画效果代码
代码语言:html
所属分类:动画
代码描述:svg实现线条绘制三角canvas动画效果代码
下面为部分代码预览,完整代码请点击下载或在bfwstudio webide中打开
<!DOCTYPE html> <html lang="en" > <head> <meta charset="UTF-8"> <style> document, body { margin: 0; min-height: 100vh; } body { align-items: center; display: flex; justify-content: center; } #container { align-items: center; display: flex; flex-direction: column; } #container > :first-child { cursor: pointer; } button { max-width: 200px; margin-top: 10px; } canvas, svg { width: 100vw; height: 100vh; } </style> </head> <body > <div id="container"></div> <script type="text/javascript" src="//repo.bfw.wiki/bfwrepo/js/svg.min.js"></script> <script type="module"> import { Vec2 } from 'https://cdn.skypack.dev/wtc-math'; console.clear(); const config = { drawingType: 1, dimensions: (new Vec2(window.innerWidth, window.innerHeight)).scale(2), breakRun: 2000, maxDepth: 12, maxPerRun: 100, insertType: 1, randomType: 0 }; const vars = { drawing: null, i:0, running: true, triangles: [] } const setup = () => { vars.running = false; setTimeout(() => { vars.running = true; vars.triangles = []; config.insertType = Math.floor(Math.random() * 3); config.randomType = Math.floor(Math.random() * 3); vars.i=0; document.querySelector('#container').innerHTML = ''; vars.drawing = new Drawing(config.drawingType).addTo('#container').size(config.dimensions); document.body.querySelector('#container>:first-child').addEventListener('click', () => { setup(); }); draw(); }, 100); }; window.addEventListener('resize', () => { config.dimensions = ( new Vec2(window.innerWidth, window.innerHeight)).scale(2) setup(); }); let depth = 0; const ts = [ ['a', 'b'], ['b', 'c'], ['c', 'a'] ]; const drawStep = () => { if(!vars.running) return; if(vars.i > 2000) return; let newTriangles = []; vars.triangles.forEach((triangle,i) => { if(i>config.breakRun) { // newTriangles.splice(0,0,triangle); return; } vars.drawing.polygon(triangle.points); let c = triangle.randomCentroid; if(config.randomType == 0) { c = triangle.centroid; } // vars.drawing.circle(c, 5); if(triangle.depth < config.maxDepth) { ts.forEach(t => { const tr = new Triangle(triangle[t[0]], triangle[t[1]], c); tr.depth=triangle.depth+1; newTriangles.push(tr); }); } }); if(config.insertType === 0) { if(vars.triangles.length>config.breakRun) newTriangles = vars.triangles.splice(config.breakRun).concat(newTriangles); } else if(config.insertType === 1) { if(vars.triangles.length>config.breakRun) newTriangles = vars.triangles.splice(config.breakRun).reverse().concat(newTriangles); } else { newTriangles = newTriangles.concat(vars.triangles.splice(config.breakRun)); } vars.triangles = newTriangles; vars.i++; requestAnimationFrame(drawStep); } let interval; const draw = () => { vars.drawing.linewidth = 1; vars.drawing.fill = "#333"; vars.drawing.rect(new Vec2(0,0), config.dimensions); vars.drawing.linewidth = 1; vars.drawing.fill = null; vars.drawing.stroke = 'rgba(255,255,255,.02)' const r = Math.min(config.dimensions.x, config.dimensions.y) * .6; const offset = r * 0.2333; const points = []; for(let i = 0.; i < Math.PI * 2; i += Math.PI * 2. / 3.) { points.push( new Vec2(Math.cos(i+Math.PI*.5) * r + config.dimensions.x / 2, Math.sin(i+Math.PI*.5) * r + config.dimensions.y / 2 - offset) ); } const t = new Triangle(...points); t.depth=0; vars.triangles.push(t); drawStep(); } class Triangle { #points constructor(a, b, c) { this.points = [a, b, c]; } set points(p) { if(p.reduce((a, c) => c instanceof Vec2 ? a+1 : 0, 0) === 3) this.#points = p; } get points() { return this.#points || []; } get a() { return this.#points[0]; } get b() { return this.#points[1]; } get c() { return this.#points[2]; } get circumcenter() { const d = this.b.subtractNew(this.a); const e = this.c.subtractNew(this.a); const bl = d.x * d.x + d.y * d.y; const cl = e.x * e.x + e.y * e.y; const ds = 0.5 / (d.x * e.y - d.y * e.x); return new Vec2( this.a.x + (e.y * bl - d.y * cl) * ds, this.a.y + (d.x * cl - e.x * bl) * ds ); } get randomCentroid() { let a = floatRandomBetween(.2,1.8); let b = floatRandomBetween(.2,1.8); let c = floatRandomBetween(.2,1.8); let abc = a+b+c; const f = (3-abc)/3; a += f; b += f; c += f; return this.a.scaleNew(a).add(this.b.scaleNew(b)).add(this.c.scaleNew(c)).divideScalar(3); } get centroid() { const a = floatRandomBetween(.5,1.5); const b = floatRandomBetween(.5,1.5); const c = floatRandomBetween(.5,1.5); const abc = a+b+c; return this.a.addNew(this.b).add(this.c).divideScalar(3); } get isComplete() { return this.points.reduce((a, c) => c instanceof Vec2 ? a+1 : 0, 0) === 3; } get segments() { return [ { a: this.a, b: this.b, c: this.c, segment: this.a.subtractNew(this.b) }, { a: this.b, b: this.c, c: this.a, segment: this.b.subtractNew(this.c) }, { a: this.c, b: this.a, c: this.b, segment: this.c.subtractNew(this.a) } ]; } get angles() { let ab = this.b.subtractNew(this.a).normalise(); let ac = this.c.subtractNew(this.a).normalise(); let ba = this.a.subtractNew(this.b).normalise(); let bc = this.c.subtractNew(this.b).normalise(); const ta = (Math.acos(ab.dot(ac))); const tb = (Math.acos(ba.dot(bc))); const tc = (Math.acos(ac.dot(bc))); return [ta,tb,tc]; } get isEqualateral() { return this.numEqualSides === 3; } get isIsosceles() { return this.numEqualSides === 2; } get isScalene() { return this.numEqualSides === 1; } get isRightAngle() { return this.angles.reduce((n, s) => n || precisionRound(Math.abs(s * 180 / Math.PI), 3) === 90, false); } get isObtuse() { return this.angles.reduce((n, s) => n || precisionRound(Math.abs(s * 180 / Math.PI), 3) > 90, false); } get isAcute() { return !this.isObtuse; } get numEqualSides() { const ls = this.segments.map(seg => precisionRound(seg.segment.length, 3)); const n = ls.map(l => ls.reduce((n, l1) => n + (l1 === l), 0)); return n.reduce((a, b) => b > a ? b : a, 0); } get hypot() { const segs = this.segments; let longest = 0; let hypotenuse = {}; segs.forEach(seg => { if(seg.segment.length > longest) { longest = seg.segment.length; hypotenuse = seg; } }); return hypotenuse; } } setTimeout(() => { setup(); }, 500); class Drawing { static #defaults = { stroke: '#333', pxratio: 1 } static DT_CANVAS = 1; static DT_SVG = 2; #drawing; #ctx; #mode; #instructions = []; constructor(mode = Drawing.DT_CANVAS, settings) { settings = Object.assign({}, Drawing.#defaults, settings); this.mode = mode; if(this.mode & Drawing.DT_CANVAS) { this.#drawing = document.createElement('canvas'); } else if(this.mode & Drawing.DT_SVG) { this.#drawing = SVG(); } this.stroke = settings.stroke; this.pxratio = settings.pxratio; } clear() { if(this.mode & Drawing.DT_CANVAS) { this.c.clearRect(0,0,...this.dimensions.array); } else if(this.mode & Drawing.DT_SVG) { this.drawing.clear(); } } rect(position, dimensions) { if(this.saving) { this.#instructions.push({ f: 'rect', args: [position, dimensions] }); } position = position.scaleNew(this.pxratio); dimensions = dimensions.scaleNew.........完整代码请登录后点击上方下载按钮下载查看
网友评论0