54c1b3dd43
This is a massive breaking change for all existing users of CanvasKit. It will be (one of the only) changes in 0.19.0 to make the transition easier. Suggested reviewing order: - index.d.ts (to see type changes). Notice SkPicture still has Sk prefix, but no other types do (this felt "right" since Sk is part of the name of the type, but I can be swayed on this). - canvaskit-wasm-tests.ts - tests/*.spec.js - interface.js and helper.js - html examples - markdown files Change-Id: I3b3d3815df2078f986893df3c70101d6248c117d Docs-Preview: https://skia.org/?cl=322617 Bug: skia:10717 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/322617 Commit-Queue: Kevin Lubick <kjlubick@google.com> Reviewed-by: Nathaniel Nifong <nifong@google.com>
141 lines
4.4 KiB
JavaScript
141 lines
4.4 KiB
JavaScript
// Returns an [x, y] point on a circle, with given origin and radius, at a given angle
|
|
// counter-clockwise from the positive horizontal axis.
|
|
function circleCoordinates(origin, radius, radians) {
|
|
return [
|
|
origin[0] + Math.cos(radians) * radius,
|
|
origin[1] + Math.sin(radians) * radius
|
|
];
|
|
}
|
|
|
|
// Animator handles calling and stopping requestAnimationFrame and keeping track of framerate.
|
|
class Animator {
|
|
framesCount = 0;
|
|
totalFramesMs = 0;
|
|
animating = false;
|
|
renderer = null;
|
|
|
|
start() {
|
|
if (this.animating === false) {
|
|
this.animating = true;
|
|
this.framesCount = 0;
|
|
const frameStartMs = performance.now();
|
|
|
|
const drawFrame = () => {
|
|
if (this.animating && this.renderer) {
|
|
requestAnimationFrame(drawFrame);
|
|
this.framesCount++;
|
|
|
|
const [x, y] = circleCoordinates([-70, -70], 50, this.framesCount/100);
|
|
this.renderer.render(x, y);
|
|
|
|
const frameTimeMs = performance.now() - frameStartMs;
|
|
this.totalFramesMs = frameTimeMs;
|
|
}
|
|
};
|
|
requestAnimationFrame(drawFrame);
|
|
}
|
|
}
|
|
|
|
stop() {
|
|
this.animating = false;
|
|
}
|
|
}
|
|
|
|
// The following three renderers draw a repeating pattern of paths.
|
|
// The approximate height and width of this repeated pattern is given by PATTERN_BOUNDS:
|
|
const PATTERN_BOUNDS = 600;
|
|
// And the spacing of the pattern (distance between repeated paths) is given by PATTERN_SPACING:
|
|
const PATTERN_SPACING = 70;
|
|
|
|
class SVGRenderer {
|
|
constructor(svgObjectElement) {
|
|
this.svgObjectElement = svgObjectElement;
|
|
this.svgElArray = [];
|
|
// Create an SVG element for every position in the pattern
|
|
for (let xo = 0; xo < PATTERN_BOUNDS; xo += PATTERN_SPACING) {
|
|
for (let yo = 0; yo < PATTERN_BOUNDS; yo += PATTERN_SPACING) {
|
|
const clonedSVG = svgObjectElement.cloneNode(true);
|
|
this.svgElArray.push(clonedSVG);
|
|
svgObjectElement.parentElement.appendChild(clonedSVG);
|
|
}
|
|
}
|
|
}
|
|
|
|
render(x, y) {
|
|
let i = 0;
|
|
for (let xo = 0; xo < PATTERN_BOUNDS; xo += PATTERN_SPACING) {
|
|
for (let yo = 0; yo < PATTERN_BOUNDS; yo += PATTERN_SPACING) {
|
|
this.svgElArray[i].style.transform = `translate(${x + xo}px, ${y + yo}px)`;
|
|
i++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
class Path2dRenderer {
|
|
constructor(svgData, offscreenCanvas) {
|
|
this.data = svgData.map(([pathString, fillColor]) => [new Path2D(pathString), fillColor]);
|
|
|
|
this.ctx = offscreenCanvas.getContext('2d');
|
|
}
|
|
|
|
render(x, y) {
|
|
const ctx = this.ctx;
|
|
|
|
ctx.clearRect(0, 0, 500, 500);
|
|
|
|
for (let xo = 0; xo < PATTERN_BOUNDS; xo += PATTERN_SPACING) {
|
|
for (let yo = 0; yo < PATTERN_BOUNDS; yo += PATTERN_SPACING) {
|
|
ctx.save();
|
|
ctx.translate(x + xo, y + yo);
|
|
|
|
for (const [path, fillColor] of this.data) {
|
|
ctx.fillStyle = fillColor;
|
|
ctx.fill(path);
|
|
}
|
|
ctx.restore();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
class CanvasKitRenderer {
|
|
constructor(svgData, offscreenCanvas, CanvasKit) {
|
|
this.CanvasKit = CanvasKit;
|
|
this.data = svgData.map(([pathString, fillColor]) => [
|
|
CanvasKit.MakePathFromSVGString(pathString),
|
|
CanvasKit.parseColorString(fillColor)
|
|
]);
|
|
|
|
this.surface = CanvasKit.MakeWebGLCanvasSurface(offscreenCanvas, null);
|
|
if (!this.surface) {
|
|
throw 'Could not make canvas surface';
|
|
}
|
|
this.canvas = this.surface.getCanvas();
|
|
|
|
this.paint = new CanvasKit.Paint();
|
|
this.paint.setAntiAlias(true);
|
|
this.paint.setStyle(CanvasKit.PaintStyle.Fill);
|
|
}
|
|
|
|
render(x, y) {
|
|
const canvas = this.canvas;
|
|
|
|
canvas.clear(this.CanvasKit.WHITE);
|
|
|
|
for (let xo = 0; xo < PATTERN_BOUNDS; xo += PATTERN_SPACING) {
|
|
for (let yo = 0; yo < PATTERN_BOUNDS; yo += PATTERN_SPACING) {
|
|
canvas.save();
|
|
canvas.translate(x + xo, y + yo);
|
|
|
|
for (const [path, color] of this.data) {
|
|
this.paint.setColor(color);
|
|
canvas.drawPath(path, this.paint);
|
|
}
|
|
canvas.restore();
|
|
}
|
|
}
|
|
this.surface.flush();
|
|
}
|
|
}
|