1cb93a386Sopenharmony_ci// Returns an [x, y] point on a circle, with given origin and radius, at a given angle 2cb93a386Sopenharmony_ci// counter-clockwise from the positive horizontal axis. 3cb93a386Sopenharmony_cifunction circleCoordinates(origin, radius, radians) { 4cb93a386Sopenharmony_ci return [ 5cb93a386Sopenharmony_ci origin[0] + Math.cos(radians) * radius, 6cb93a386Sopenharmony_ci origin[1] + Math.sin(radians) * radius 7cb93a386Sopenharmony_ci ]; 8cb93a386Sopenharmony_ci} 9cb93a386Sopenharmony_ci 10cb93a386Sopenharmony_ci// Animator handles calling and stopping requestAnimationFrame and keeping track of framerate. 11cb93a386Sopenharmony_ciclass Animator { 12cb93a386Sopenharmony_ci framesCount = 0; 13cb93a386Sopenharmony_ci totalFramesMs = 0; 14cb93a386Sopenharmony_ci animating = false; 15cb93a386Sopenharmony_ci renderer = null; 16cb93a386Sopenharmony_ci 17cb93a386Sopenharmony_ci start() { 18cb93a386Sopenharmony_ci if (this.animating === false) { 19cb93a386Sopenharmony_ci this.animating = true; 20cb93a386Sopenharmony_ci this.framesCount = 0; 21cb93a386Sopenharmony_ci const frameStartMs = performance.now(); 22cb93a386Sopenharmony_ci 23cb93a386Sopenharmony_ci const drawFrame = () => { 24cb93a386Sopenharmony_ci if (this.animating && this.renderer) { 25cb93a386Sopenharmony_ci requestAnimationFrame(drawFrame); 26cb93a386Sopenharmony_ci this.framesCount++; 27cb93a386Sopenharmony_ci 28cb93a386Sopenharmony_ci const [x, y] = circleCoordinates([-70, -70], 50, this.framesCount/100); 29cb93a386Sopenharmony_ci this.renderer.render(x, y); 30cb93a386Sopenharmony_ci 31cb93a386Sopenharmony_ci const frameTimeMs = performance.now() - frameStartMs; 32cb93a386Sopenharmony_ci this.totalFramesMs = frameTimeMs; 33cb93a386Sopenharmony_ci } 34cb93a386Sopenharmony_ci }; 35cb93a386Sopenharmony_ci requestAnimationFrame(drawFrame); 36cb93a386Sopenharmony_ci } 37cb93a386Sopenharmony_ci } 38cb93a386Sopenharmony_ci 39cb93a386Sopenharmony_ci stop() { 40cb93a386Sopenharmony_ci this.animating = false; 41cb93a386Sopenharmony_ci } 42cb93a386Sopenharmony_ci} 43cb93a386Sopenharmony_ci 44cb93a386Sopenharmony_ci// The following three renderers draw a repeating pattern of paths. 45cb93a386Sopenharmony_ci// The approximate height and width of this repeated pattern is given by PATTERN_BOUNDS: 46cb93a386Sopenharmony_ciconst PATTERN_BOUNDS = 600; 47cb93a386Sopenharmony_ci// And the spacing of the pattern (distance between repeated paths) is given by PATTERN_SPACING: 48cb93a386Sopenharmony_ciconst PATTERN_SPACING = 70; 49cb93a386Sopenharmony_ci 50cb93a386Sopenharmony_ciclass SVGRenderer { 51cb93a386Sopenharmony_ci constructor(svgObjectElement) { 52cb93a386Sopenharmony_ci this.svgObjectElement = svgObjectElement; 53cb93a386Sopenharmony_ci this.svgElArray = []; 54cb93a386Sopenharmony_ci // Create an SVG element for every position in the pattern 55cb93a386Sopenharmony_ci for (let xo = 0; xo < PATTERN_BOUNDS; xo += PATTERN_SPACING) { 56cb93a386Sopenharmony_ci for (let yo = 0; yo < PATTERN_BOUNDS; yo += PATTERN_SPACING) { 57cb93a386Sopenharmony_ci const clonedSVG = svgObjectElement.cloneNode(true); 58cb93a386Sopenharmony_ci this.svgElArray.push(clonedSVG); 59cb93a386Sopenharmony_ci svgObjectElement.parentElement.appendChild(clonedSVG); 60cb93a386Sopenharmony_ci } 61cb93a386Sopenharmony_ci } 62cb93a386Sopenharmony_ci } 63cb93a386Sopenharmony_ci 64cb93a386Sopenharmony_ci render(x, y) { 65cb93a386Sopenharmony_ci let i = 0; 66cb93a386Sopenharmony_ci for (let xo = 0; xo < PATTERN_BOUNDS; xo += PATTERN_SPACING) { 67cb93a386Sopenharmony_ci for (let yo = 0; yo < PATTERN_BOUNDS; yo += PATTERN_SPACING) { 68cb93a386Sopenharmony_ci this.svgElArray[i].style.transform = `translate(${x + xo}px, ${y + yo}px)`; 69cb93a386Sopenharmony_ci i++; 70cb93a386Sopenharmony_ci } 71cb93a386Sopenharmony_ci } 72cb93a386Sopenharmony_ci } 73cb93a386Sopenharmony_ci} 74cb93a386Sopenharmony_ci 75cb93a386Sopenharmony_ciclass Path2dRenderer { 76cb93a386Sopenharmony_ci constructor(svgData, offscreenCanvas) { 77cb93a386Sopenharmony_ci this.data = svgData.map(([pathString, fillColor]) => [new Path2D(pathString), fillColor]); 78cb93a386Sopenharmony_ci 79cb93a386Sopenharmony_ci this.ctx = offscreenCanvas.getContext('2d'); 80cb93a386Sopenharmony_ci } 81cb93a386Sopenharmony_ci 82cb93a386Sopenharmony_ci render(x, y) { 83cb93a386Sopenharmony_ci const ctx = this.ctx; 84cb93a386Sopenharmony_ci 85cb93a386Sopenharmony_ci ctx.clearRect(0, 0, 500, 500); 86cb93a386Sopenharmony_ci 87cb93a386Sopenharmony_ci for (let xo = 0; xo < PATTERN_BOUNDS; xo += PATTERN_SPACING) { 88cb93a386Sopenharmony_ci for (let yo = 0; yo < PATTERN_BOUNDS; yo += PATTERN_SPACING) { 89cb93a386Sopenharmony_ci ctx.save(); 90cb93a386Sopenharmony_ci ctx.translate(x + xo, y + yo); 91cb93a386Sopenharmony_ci 92cb93a386Sopenharmony_ci for (const [path, fillColor] of this.data) { 93cb93a386Sopenharmony_ci ctx.fillStyle = fillColor; 94cb93a386Sopenharmony_ci ctx.fill(path); 95cb93a386Sopenharmony_ci } 96cb93a386Sopenharmony_ci ctx.restore(); 97cb93a386Sopenharmony_ci } 98cb93a386Sopenharmony_ci } 99cb93a386Sopenharmony_ci } 100cb93a386Sopenharmony_ci} 101cb93a386Sopenharmony_ci 102cb93a386Sopenharmony_ciclass CanvasKitRenderer { 103cb93a386Sopenharmony_ci constructor(svgData, offscreenCanvas, CanvasKit) { 104cb93a386Sopenharmony_ci this.CanvasKit = CanvasKit; 105cb93a386Sopenharmony_ci this.data = svgData.map(([pathString, fillColor]) => [ 106cb93a386Sopenharmony_ci CanvasKit.Path.MakeFromSVGString(pathString), 107cb93a386Sopenharmony_ci CanvasKit.parseColorString(fillColor) 108cb93a386Sopenharmony_ci ]); 109cb93a386Sopenharmony_ci 110cb93a386Sopenharmony_ci this.surface = CanvasKit.MakeWebGLCanvasSurface(offscreenCanvas, null); 111cb93a386Sopenharmony_ci if (!this.surface) { 112cb93a386Sopenharmony_ci throw 'Could not make canvas surface'; 113cb93a386Sopenharmony_ci } 114cb93a386Sopenharmony_ci this.canvas = this.surface.getCanvas(); 115cb93a386Sopenharmony_ci 116cb93a386Sopenharmony_ci this.paint = new CanvasKit.Paint(); 117cb93a386Sopenharmony_ci this.paint.setAntiAlias(true); 118cb93a386Sopenharmony_ci this.paint.setStyle(CanvasKit.PaintStyle.Fill); 119cb93a386Sopenharmony_ci } 120cb93a386Sopenharmony_ci 121cb93a386Sopenharmony_ci render(x, y) { 122cb93a386Sopenharmony_ci const canvas = this.canvas; 123cb93a386Sopenharmony_ci 124cb93a386Sopenharmony_ci canvas.clear(this.CanvasKit.WHITE); 125cb93a386Sopenharmony_ci 126cb93a386Sopenharmony_ci for (let xo = 0; xo < PATTERN_BOUNDS; xo += PATTERN_SPACING) { 127cb93a386Sopenharmony_ci for (let yo = 0; yo < PATTERN_BOUNDS; yo += PATTERN_SPACING) { 128cb93a386Sopenharmony_ci canvas.save(); 129cb93a386Sopenharmony_ci canvas.translate(x + xo, y + yo); 130cb93a386Sopenharmony_ci 131cb93a386Sopenharmony_ci for (const [path, color] of this.data) { 132cb93a386Sopenharmony_ci this.paint.setColor(color); 133cb93a386Sopenharmony_ci canvas.drawPath(path, this.paint); 134cb93a386Sopenharmony_ci } 135cb93a386Sopenharmony_ci canvas.restore(); 136cb93a386Sopenharmony_ci } 137cb93a386Sopenharmony_ci } 138cb93a386Sopenharmony_ci this.surface.flush(); 139cb93a386Sopenharmony_ci } 140cb93a386Sopenharmony_ci} 141