xref: /aosp_15_r20/external/skia/modules/pathkit/npm-asmjs/example.html (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker<!DOCTYPE html>
2*c8dee2aaSAndroid Build Coastguard Worker<title>PathKit (Skia's Geometry + asm.js)</title>
3*c8dee2aaSAndroid Build Coastguard Worker<meta charset="utf-8" />
4*c8dee2aaSAndroid Build Coastguard Worker<meta http-equiv="X-UA-Compatible" content="IE=edge">
5*c8dee2aaSAndroid Build Coastguard Worker<meta name="viewport" content="width=device-width, initial-scale=1.0">
6*c8dee2aaSAndroid Build Coastguard Worker
7*c8dee2aaSAndroid Build Coastguard Worker<style>
8*c8dee2aaSAndroid Build Coastguard Worker  svg, canvas {
9*c8dee2aaSAndroid Build Coastguard Worker    border: 1px dashed #AAA;
10*c8dee2aaSAndroid Build Coastguard Worker  }
11*c8dee2aaSAndroid Build Coastguard Worker
12*c8dee2aaSAndroid Build Coastguard Worker  canvas {
13*c8dee2aaSAndroid Build Coastguard Worker    width: 200px;
14*c8dee2aaSAndroid Build Coastguard Worker    height: 200px;
15*c8dee2aaSAndroid Build Coastguard Worker  }
16*c8dee2aaSAndroid Build Coastguard Worker
17*c8dee2aaSAndroid Build Coastguard Worker  canvas.big {
18*c8dee2aaSAndroid Build Coastguard Worker    width: 300px;
19*c8dee2aaSAndroid Build Coastguard Worker    height: 300px;
20*c8dee2aaSAndroid Build Coastguard Worker  }
21*c8dee2aaSAndroid Build Coastguard Worker
22*c8dee2aaSAndroid Build Coastguard Worker</style>
23*c8dee2aaSAndroid Build Coastguard Worker
24*c8dee2aaSAndroid Build Coastguard Worker<h2> Can output to an SVG Path, a Canvas, or a Path2D object </h2>
25*c8dee2aaSAndroid Build Coastguard Worker<svg id=svg1 xmlns='http://www.w3.org/2000/svg' width=200 height=200></svg>
26*c8dee2aaSAndroid Build Coastguard Worker<canvas id=canvas1></canvas>
27*c8dee2aaSAndroid Build Coastguard Worker<canvas id=canvas2></canvas>
28*c8dee2aaSAndroid Build Coastguard Worker
29*c8dee2aaSAndroid Build Coastguard Worker<h2> Interact with NewPath() just like a Path2D Object </h2>
30*c8dee2aaSAndroid Build Coastguard Worker<canvas class=big id=canvas3></canvas>
31*c8dee2aaSAndroid Build Coastguard Worker<canvas class=big id=canvas4></canvas>
32*c8dee2aaSAndroid Build Coastguard Worker
33*c8dee2aaSAndroid Build Coastguard Worker<h2> Has various Path Effects </h2>
34*c8dee2aaSAndroid Build Coastguard Worker<canvas class=big id=canvas5></canvas>
35*c8dee2aaSAndroid Build Coastguard Worker<canvas class=big id=canvas6></canvas>
36*c8dee2aaSAndroid Build Coastguard Worker<canvas class=big id=canvas7></canvas>
37*c8dee2aaSAndroid Build Coastguard Worker<canvas class=big id=canvas8></canvas>
38*c8dee2aaSAndroid Build Coastguard Worker<canvas class=big id=canvas9></canvas>
39*c8dee2aaSAndroid Build Coastguard Worker<canvas class=big id=canvas10></canvas>
40*c8dee2aaSAndroid Build Coastguard Worker<canvas class=big id=canvas11></canvas>
41*c8dee2aaSAndroid Build Coastguard Worker<canvas class=big id=canvasTransform></canvas>
42*c8dee2aaSAndroid Build Coastguard Worker
43*c8dee2aaSAndroid Build Coastguard Worker<h2> Supports fill-rules of nonzero and evenodd </h2>
44*c8dee2aaSAndroid Build Coastguard Worker<svg id=svg2 xmlns='http://www.w3.org/2000/svg' width=200 height=200></svg>
45*c8dee2aaSAndroid Build Coastguard Worker<svg id=svg3 xmlns='http://www.w3.org/2000/svg' width=200 height=200></svg>
46*c8dee2aaSAndroid Build Coastguard Worker
47*c8dee2aaSAndroid Build Coastguard Worker<h2> Solves Cubics for Y given X </h2>
48*c8dee2aaSAndroid Build Coastguard Worker<canvas class=big id=cubics></canvas>
49*c8dee2aaSAndroid Build Coastguard Worker
50*c8dee2aaSAndroid Build Coastguard Worker<script type="text/javascript" src="/build/asmjs/pathkit.js"></script>
51*c8dee2aaSAndroid Build Coastguard Worker
52*c8dee2aaSAndroid Build Coastguard Worker<script type="text/javascript" charset="utf-8">
53*c8dee2aaSAndroid Build Coastguard Worker
54*c8dee2aaSAndroid Build Coastguard Worker  PathKitInit({
55*c8dee2aaSAndroid Build Coastguard Worker    locateFile: (file) => '/build/asmjs/'+file,
56*c8dee2aaSAndroid Build Coastguard Worker  }).then((PathKit) => {
57*c8dee2aaSAndroid Build Coastguard Worker    window.PathKit = PathKit;
58*c8dee2aaSAndroid Build Coastguard Worker    OutputsExample(PathKit);
59*c8dee2aaSAndroid Build Coastguard Worker    Path2DExample(PathKit);
60*c8dee2aaSAndroid Build Coastguard Worker    PathEffectsExample(PathKit);
61*c8dee2aaSAndroid Build Coastguard Worker    MatrixTransformExample(PathKit);
62*c8dee2aaSAndroid Build Coastguard Worker    FilledSVGExample(PathKit);
63*c8dee2aaSAndroid Build Coastguard Worker    CubicSolverExample(PathKit);
64*c8dee2aaSAndroid Build Coastguard Worker  });
65*c8dee2aaSAndroid Build Coastguard Worker
66*c8dee2aaSAndroid Build Coastguard Worker  function setCanvasSize(ctx, width, height) {
67*c8dee2aaSAndroid Build Coastguard Worker    ctx.canvas.width = width;
68*c8dee2aaSAndroid Build Coastguard Worker    ctx.canvas.height = height;
69*c8dee2aaSAndroid Build Coastguard Worker  }
70*c8dee2aaSAndroid Build Coastguard Worker
71*c8dee2aaSAndroid Build Coastguard Worker  function OutputsExample(PathKit) {
72*c8dee2aaSAndroid Build Coastguard Worker    let firstPath = PathKit.FromSVGString('M11.99 2C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zM12 20c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8zm.5-13H11v6l5.25 3.15.75-1.23-4.5-2.67z');
73*c8dee2aaSAndroid Build Coastguard Worker
74*c8dee2aaSAndroid Build Coastguard Worker    let secondPath = PathKit.NewPath();
75*c8dee2aaSAndroid Build Coastguard Worker    // Acts somewhat like the Canvas API, except can be chained
76*c8dee2aaSAndroid Build Coastguard Worker    secondPath.moveTo(1, 1)
77*c8dee2aaSAndroid Build Coastguard Worker              .lineTo(20, 1)
78*c8dee2aaSAndroid Build Coastguard Worker              .lineTo(10, 30)
79*c8dee2aaSAndroid Build Coastguard Worker              .closePath();
80*c8dee2aaSAndroid Build Coastguard Worker
81*c8dee2aaSAndroid Build Coastguard Worker    // Join the two paths together (mutating firstPath in the process)
82*c8dee2aaSAndroid Build Coastguard Worker    firstPath.op(secondPath, PathKit.PathOp.INTERSECT);
83*c8dee2aaSAndroid Build Coastguard Worker
84*c8dee2aaSAndroid Build Coastguard Worker    let simpleStr = firstPath.toSVGString();
85*c8dee2aaSAndroid Build Coastguard Worker
86*c8dee2aaSAndroid Build Coastguard Worker    let newSVG = document.createElementNS('http://www.w3.org/2000/svg', 'path');
87*c8dee2aaSAndroid Build Coastguard Worker    newSVG.setAttribute('stroke', 'rgb(0,0,200)');
88*c8dee2aaSAndroid Build Coastguard Worker    newSVG.setAttribute('fill', 'white');
89*c8dee2aaSAndroid Build Coastguard Worker    newSVG.setAttribute('transform', 'scale(8,8)');
90*c8dee2aaSAndroid Build Coastguard Worker    newSVG.setAttribute('d', simpleStr);
91*c8dee2aaSAndroid Build Coastguard Worker    document.getElementById('svg1').appendChild(newSVG);
92*c8dee2aaSAndroid Build Coastguard Worker
93*c8dee2aaSAndroid Build Coastguard Worker    // Draw directly to Canvas
94*c8dee2aaSAndroid Build Coastguard Worker    let ctx = document.getElementById('canvas1').getContext('2d');
95*c8dee2aaSAndroid Build Coastguard Worker    setCanvasSize(ctx, 200, 200);
96*c8dee2aaSAndroid Build Coastguard Worker    ctx.strokeStyle = 'green';
97*c8dee2aaSAndroid Build Coastguard Worker    ctx.fillStyle = 'white';
98*c8dee2aaSAndroid Build Coastguard Worker    ctx.scale(8, 8);
99*c8dee2aaSAndroid Build Coastguard Worker    ctx.beginPath();
100*c8dee2aaSAndroid Build Coastguard Worker    firstPath.toCanvas(ctx);
101*c8dee2aaSAndroid Build Coastguard Worker    ctx.stroke();
102*c8dee2aaSAndroid Build Coastguard Worker
103*c8dee2aaSAndroid Build Coastguard Worker    // create Path2D object and use it in a Canvas.
104*c8dee2aaSAndroid Build Coastguard Worker    let path2D = firstPath.toPath2D();
105*c8dee2aaSAndroid Build Coastguard Worker    ctx = document.getElementById('canvas2').getContext('2d');
106*c8dee2aaSAndroid Build Coastguard Worker    setCanvasSize(ctx, 200, 200);
107*c8dee2aaSAndroid Build Coastguard Worker    ctx.canvas.width = 200
108*c8dee2aaSAndroid Build Coastguard Worker    ctx.scale(8, 8);
109*c8dee2aaSAndroid Build Coastguard Worker    ctx.fillStyle = 'purple';
110*c8dee2aaSAndroid Build Coastguard Worker    ctx.strokeStyle = 'orange';
111*c8dee2aaSAndroid Build Coastguard Worker    ctx.fill(path2D);
112*c8dee2aaSAndroid Build Coastguard Worker    ctx.stroke(path2D);
113*c8dee2aaSAndroid Build Coastguard Worker
114*c8dee2aaSAndroid Build Coastguard Worker    // clean up memory and call destructors in the c++ code (if any).
115*c8dee2aaSAndroid Build Coastguard Worker    // See http://kripken.github.io/emscripten-site/docs/porting/connecting_cpp_and_javascript/embind.html?highlight=memory#memory-management
116*c8dee2aaSAndroid Build Coastguard Worker    firstPath.delete();
117*c8dee2aaSAndroid Build Coastguard Worker    secondPath.delete();
118*c8dee2aaSAndroid Build Coastguard Worker  }
119*c8dee2aaSAndroid Build Coastguard Worker
120*c8dee2aaSAndroid Build Coastguard Worker  function Path2DExample(PathKit) {
121*c8dee2aaSAndroid Build Coastguard Worker    let objs = [new Path2D(), PathKit.NewPath(), new Path2D(), PathKit.NewPath()];
122*c8dee2aaSAndroid Build Coastguard Worker    let canvases = [
123*c8dee2aaSAndroid Build Coastguard Worker      document.getElementById('canvas3').getContext('2d'),
124*c8dee2aaSAndroid Build Coastguard Worker      document.getElementById('canvas4').getContext('2d')
125*c8dee2aaSAndroid Build Coastguard Worker    ];
126*c8dee2aaSAndroid Build Coastguard Worker
127*c8dee2aaSAndroid Build Coastguard Worker    for (i = 0; i <= 1; i++) {
128*c8dee2aaSAndroid Build Coastguard Worker      let path = objs[i];
129*c8dee2aaSAndroid Build Coastguard Worker
130*c8dee2aaSAndroid Build Coastguard Worker      path.moveTo(20, 5);
131*c8dee2aaSAndroid Build Coastguard Worker      path.lineTo(30, 20);
132*c8dee2aaSAndroid Build Coastguard Worker      path.lineTo(40, 10);
133*c8dee2aaSAndroid Build Coastguard Worker      path.lineTo(50, 20);
134*c8dee2aaSAndroid Build Coastguard Worker      path.lineTo(60, 0);
135*c8dee2aaSAndroid Build Coastguard Worker      path.lineTo(20, 5);
136*c8dee2aaSAndroid Build Coastguard Worker
137*c8dee2aaSAndroid Build Coastguard Worker      path.moveTo(20, 80);
138*c8dee2aaSAndroid Build Coastguard Worker      path.bezierCurveTo(90, 10, 160, 150, 190, 10);
139*c8dee2aaSAndroid Build Coastguard Worker
140*c8dee2aaSAndroid Build Coastguard Worker      path.moveTo(36, 148);
141*c8dee2aaSAndroid Build Coastguard Worker      path.quadraticCurveTo(66, 188, 120, 136);
142*c8dee2aaSAndroid Build Coastguard Worker      path.lineTo(36, 148);
143*c8dee2aaSAndroid Build Coastguard Worker
144*c8dee2aaSAndroid Build Coastguard Worker      path.rect(5, 170, 20, 20);
145*c8dee2aaSAndroid Build Coastguard Worker
146*c8dee2aaSAndroid Build Coastguard Worker      path.moveTo(150, 180);
147*c8dee2aaSAndroid Build Coastguard Worker      path.arcTo(150, 100, 50, 200, 20);
148*c8dee2aaSAndroid Build Coastguard Worker      path.lineTo(160, 160);
149*c8dee2aaSAndroid Build Coastguard Worker
150*c8dee2aaSAndroid Build Coastguard Worker      path.moveTo(20, 120);
151*c8dee2aaSAndroid Build Coastguard Worker      path.arc(20, 120, 18, 0, 1.75 * Math.PI);
152*c8dee2aaSAndroid Build Coastguard Worker      path.lineTo(20, 120);
153*c8dee2aaSAndroid Build Coastguard Worker
154*c8dee2aaSAndroid Build Coastguard Worker      let secondPath = objs[i+2];
155*c8dee2aaSAndroid Build Coastguard Worker      secondPath.ellipse(130, 25, 30, 10, -1*Math.PI/8, Math.PI/6, 1.5*Math.PI, false);
156*c8dee2aaSAndroid Build Coastguard Worker
157*c8dee2aaSAndroid Build Coastguard Worker      path.addPath(secondPath);
158*c8dee2aaSAndroid Build Coastguard Worker
159*c8dee2aaSAndroid Build Coastguard Worker      let m = document.createElementNS('http://www.w3.org/2000/svg', 'svg').createSVGMatrix();
160*c8dee2aaSAndroid Build Coastguard Worker      m.a = 1; m.b = 0;
161*c8dee2aaSAndroid Build Coastguard Worker      m.c = 0; m.d = 1;
162*c8dee2aaSAndroid Build Coastguard Worker      m.e = 0; m.f = 20.5;
163*c8dee2aaSAndroid Build Coastguard Worker
164*c8dee2aaSAndroid Build Coastguard Worker      path.addPath(secondPath, m);
165*c8dee2aaSAndroid Build Coastguard Worker      // With PathKit, one can also just provide the 6 params as floats, to avoid
166*c8dee2aaSAndroid Build Coastguard Worker      // the overhead of making an SVGMatrix
167*c8dee2aaSAndroid Build Coastguard Worker      // path.addPath(secondPath, 1, 0, 0, 1, 0, 20.5);
168*c8dee2aaSAndroid Build Coastguard Worker
169*c8dee2aaSAndroid Build Coastguard Worker      canvasCtx = canvases[i];
170*c8dee2aaSAndroid Build Coastguard Worker      canvasCtx.fillStyle = 'blue';
171*c8dee2aaSAndroid Build Coastguard Worker      setCanvasSize(canvasCtx, 300, 300);
172*c8dee2aaSAndroid Build Coastguard Worker      canvasCtx.scale(1.5, 1.5);
173*c8dee2aaSAndroid Build Coastguard Worker      if (path.toPath2D) {
174*c8dee2aaSAndroid Build Coastguard Worker        canvasCtx.stroke(path.toPath2D());
175*c8dee2aaSAndroid Build Coastguard Worker      } else {
176*c8dee2aaSAndroid Build Coastguard Worker        canvasCtx.stroke(path);
177*c8dee2aaSAndroid Build Coastguard Worker      }
178*c8dee2aaSAndroid Build Coastguard Worker    }
179*c8dee2aaSAndroid Build Coastguard Worker
180*c8dee2aaSAndroid Build Coastguard Worker
181*c8dee2aaSAndroid Build Coastguard Worker    objs[1].delete();
182*c8dee2aaSAndroid Build Coastguard Worker  }
183*c8dee2aaSAndroid Build Coastguard Worker
184*c8dee2aaSAndroid Build Coastguard Worker  // see https://fiddle.skia.org/c/@discrete_path
185*c8dee2aaSAndroid Build Coastguard Worker  function drawStar(path) {
186*c8dee2aaSAndroid Build Coastguard Worker    let R = 115.2, C = 128.0;
187*c8dee2aaSAndroid Build Coastguard Worker    path.moveTo(C + R + 22, C);
188*c8dee2aaSAndroid Build Coastguard Worker    for (let i = 1; i < 8; i++) {
189*c8dee2aaSAndroid Build Coastguard Worker      let a = 2.6927937 * i;
190*c8dee2aaSAndroid Build Coastguard Worker      path.lineTo(C + R * Math.cos(a) + 22, C + R * Math.sin(a));
191*c8dee2aaSAndroid Build Coastguard Worker    }
192*c8dee2aaSAndroid Build Coastguard Worker    path.closePath();
193*c8dee2aaSAndroid Build Coastguard Worker    return path;
194*c8dee2aaSAndroid Build Coastguard Worker  }
195*c8dee2aaSAndroid Build Coastguard Worker
196*c8dee2aaSAndroid Build Coastguard Worker  function PathEffectsExample(PathKit) {
197*c8dee2aaSAndroid Build Coastguard Worker    let effects = [
198*c8dee2aaSAndroid Build Coastguard Worker      // no-op
199*c8dee2aaSAndroid Build Coastguard Worker      (path) => path,
200*c8dee2aaSAndroid Build Coastguard Worker      // dash
201*c8dee2aaSAndroid Build Coastguard Worker      (path, counter) => path.dash(10, 3, counter/5),
202*c8dee2aaSAndroid Build Coastguard Worker      // trim (takes optional 3rd param for returning the trimmed part
203*c8dee2aaSAndroid Build Coastguard Worker      // or the complement)
204*c8dee2aaSAndroid Build Coastguard Worker      (path, counter) => path.trim((counter/100) % 1, 0.8, false),
205*c8dee2aaSAndroid Build Coastguard Worker      // simplify
206*c8dee2aaSAndroid Build Coastguard Worker      (path) => path.simplify(),
207*c8dee2aaSAndroid Build Coastguard Worker      // stroke
208*c8dee2aaSAndroid Build Coastguard Worker      (path, counter) => path.stroke({
209*c8dee2aaSAndroid Build Coastguard Worker        width: 10 * (Math.sin(counter/30) + 1),
210*c8dee2aaSAndroid Build Coastguard Worker        join: PathKit.StrokeJoin.BEVEL,
211*c8dee2aaSAndroid Build Coastguard Worker        cap: PathKit.StrokeCap.BUTT,
212*c8dee2aaSAndroid Build Coastguard Worker        miter_limit: 1,
213*c8dee2aaSAndroid Build Coastguard Worker      }),
214*c8dee2aaSAndroid Build Coastguard Worker      // "offset effect", that is, making a border around the shape.
215*c8dee2aaSAndroid Build Coastguard Worker      (path, counter) => {
216*c8dee2aaSAndroid Build Coastguard Worker        let orig = path.copy();
217*c8dee2aaSAndroid Build Coastguard Worker        path.stroke({
218*c8dee2aaSAndroid Build Coastguard Worker          width: 10 + (counter / 4) % 50,
219*c8dee2aaSAndroid Build Coastguard Worker          join: PathKit.StrokeJoin.ROUND,
220*c8dee2aaSAndroid Build Coastguard Worker          cap: PathKit.StrokeCap.SQUARE,
221*c8dee2aaSAndroid Build Coastguard Worker        })
222*c8dee2aaSAndroid Build Coastguard Worker          .op(orig, PathKit.PathOp.DIFFERENCE);
223*c8dee2aaSAndroid Build Coastguard Worker        orig.delete();
224*c8dee2aaSAndroid Build Coastguard Worker      },
225*c8dee2aaSAndroid Build Coastguard Worker      (path, counter) => {
226*c8dee2aaSAndroid Build Coastguard Worker        let simplified = path.simplify().copy();
227*c8dee2aaSAndroid Build Coastguard Worker        path.stroke({
228*c8dee2aaSAndroid Build Coastguard Worker          width: 2 + (counter / 2) % 100,
229*c8dee2aaSAndroid Build Coastguard Worker          join: PathKit.StrokeJoin.BEVEL,
230*c8dee2aaSAndroid Build Coastguard Worker          cap: PathKit.StrokeCap.BUTT,
231*c8dee2aaSAndroid Build Coastguard Worker        })
232*c8dee2aaSAndroid Build Coastguard Worker          .op(simplified, PathKit.PathOp.REVERSE_DIFFERENCE);
233*c8dee2aaSAndroid Build Coastguard Worker        simplified.delete();
234*c8dee2aaSAndroid Build Coastguard Worker      }
235*c8dee2aaSAndroid Build Coastguard Worker    ];
236*c8dee2aaSAndroid Build Coastguard Worker
237*c8dee2aaSAndroid Build Coastguard Worker    let names = ["(plain)", "Dash", "Trim", "Simplify", "Stroke", "Grow", "Shrink"];
238*c8dee2aaSAndroid Build Coastguard Worker
239*c8dee2aaSAndroid Build Coastguard Worker    let counter = 0;
240*c8dee2aaSAndroid Build Coastguard Worker    function frame() {
241*c8dee2aaSAndroid Build Coastguard Worker      counter++;
242*c8dee2aaSAndroid Build Coastguard Worker      for (let i = 0; i < effects.length; i++) {
243*c8dee2aaSAndroid Build Coastguard Worker        let path = PathKit.NewPath();
244*c8dee2aaSAndroid Build Coastguard Worker        drawStar(path);
245*c8dee2aaSAndroid Build Coastguard Worker
246*c8dee2aaSAndroid Build Coastguard Worker        // The transforms apply directly to the path.
247*c8dee2aaSAndroid Build Coastguard Worker        effects[i](path, counter);
248*c8dee2aaSAndroid Build Coastguard Worker
249*c8dee2aaSAndroid Build Coastguard Worker        let ctx = document.getElementById(`canvas${i+5}`).getContext('2d');
250*c8dee2aaSAndroid Build Coastguard Worker        setCanvasSize(ctx, 300, 300);
251*c8dee2aaSAndroid Build Coastguard Worker        ctx.strokeStyle = '#3c597a';
252*c8dee2aaSAndroid Build Coastguard Worker        ctx.fillStyle = '#3c597a';
253*c8dee2aaSAndroid Build Coastguard Worker        if (i >=4 ) {
254*c8dee2aaSAndroid Build Coastguard Worker          ctx.fill(path.toPath2D(), path.getFillTypeString());
255*c8dee2aaSAndroid Build Coastguard Worker        } else {
256*c8dee2aaSAndroid Build Coastguard Worker          ctx.stroke(path.toPath2D());
257*c8dee2aaSAndroid Build Coastguard Worker        }
258*c8dee2aaSAndroid Build Coastguard Worker
259*c8dee2aaSAndroid Build Coastguard Worker        ctx.font = '42px monospace';
260*c8dee2aaSAndroid Build Coastguard Worker
261*c8dee2aaSAndroid Build Coastguard Worker        let x = 150-ctx.measureText(names[i]).width/2;
262*c8dee2aaSAndroid Build Coastguard Worker        ctx.strokeText(names[i], x, 290);
263*c8dee2aaSAndroid Build Coastguard Worker
264*c8dee2aaSAndroid Build Coastguard Worker        path.delete();
265*c8dee2aaSAndroid Build Coastguard Worker      }
266*c8dee2aaSAndroid Build Coastguard Worker      window.requestAnimationFrame(frame);
267*c8dee2aaSAndroid Build Coastguard Worker    }
268*c8dee2aaSAndroid Build Coastguard Worker    window.requestAnimationFrame(frame);
269*c8dee2aaSAndroid Build Coastguard Worker  }
270*c8dee2aaSAndroid Build Coastguard Worker
271*c8dee2aaSAndroid Build Coastguard Worker  function MatrixTransformExample(PathKit) {
272*c8dee2aaSAndroid Build Coastguard Worker    // Creates an animated star that twists and moves.
273*c8dee2aaSAndroid Build Coastguard Worker    let ctx = document.getElementById('canvasTransform').getContext('2d');
274*c8dee2aaSAndroid Build Coastguard Worker    setCanvasSize(ctx, 300, 300);
275*c8dee2aaSAndroid Build Coastguard Worker    ctx.strokeStyle = '#3c597a';
276*c8dee2aaSAndroid Build Coastguard Worker
277*c8dee2aaSAndroid Build Coastguard Worker    let path = drawStar(PathKit.NewPath());
278*c8dee2aaSAndroid Build Coastguard Worker    // TODO(kjlubick): Perhaps expose some matrix helper functions to allow
279*c8dee2aaSAndroid Build Coastguard Worker    // clients to build their own matrices like this?
280*c8dee2aaSAndroid Build Coastguard Worker    // These matrices represent a 2 degree rotation and a 1% scale factor.
281*c8dee2aaSAndroid Build Coastguard Worker    let scaleUp = [1.0094, -0.0352,  3.1041,
282*c8dee2aaSAndroid Build Coastguard Worker                   0.0352,  1.0094, -6.4885,
283*c8dee2aaSAndroid Build Coastguard Worker                   0     ,  0      , 1];
284*c8dee2aaSAndroid Build Coastguard Worker
285*c8dee2aaSAndroid Build Coastguard Worker    let scaleDown = [ 0.9895, 0.0346, -2.8473,
286*c8dee2aaSAndroid Build Coastguard Worker                     -0.0346, 0.9895,  6.5276,
287*c8dee2aaSAndroid Build Coastguard Worker                      0     , 0     ,  1];
288*c8dee2aaSAndroid Build Coastguard Worker
289*c8dee2aaSAndroid Build Coastguard Worker    let i = 0;
290*c8dee2aaSAndroid Build Coastguard Worker    function frame(){
291*c8dee2aaSAndroid Build Coastguard Worker      i++;
292*c8dee2aaSAndroid Build Coastguard Worker      if (Math.round(i/100) % 2) {
293*c8dee2aaSAndroid Build Coastguard Worker        path.transform(scaleDown);
294*c8dee2aaSAndroid Build Coastguard Worker      } else {
295*c8dee2aaSAndroid Build Coastguard Worker        path.transform(scaleUp);
296*c8dee2aaSAndroid Build Coastguard Worker      }
297*c8dee2aaSAndroid Build Coastguard Worker
298*c8dee2aaSAndroid Build Coastguard Worker      ctx.clearRect(0, 0, 300, 300);
299*c8dee2aaSAndroid Build Coastguard Worker      ctx.stroke(path.toPath2D());
300*c8dee2aaSAndroid Build Coastguard Worker
301*c8dee2aaSAndroid Build Coastguard Worker      ctx.font = '42px monospace';
302*c8dee2aaSAndroid Build Coastguard Worker      let x = 150-ctx.measureText('Transform').width/2;
303*c8dee2aaSAndroid Build Coastguard Worker      ctx.strokeText('Transform', x, 290);
304*c8dee2aaSAndroid Build Coastguard Worker
305*c8dee2aaSAndroid Build Coastguard Worker      window.requestAnimationFrame(frame);
306*c8dee2aaSAndroid Build Coastguard Worker    }
307*c8dee2aaSAndroid Build Coastguard Worker    window.requestAnimationFrame(frame);
308*c8dee2aaSAndroid Build Coastguard Worker  }
309*c8dee2aaSAndroid Build Coastguard Worker
310*c8dee2aaSAndroid Build Coastguard Worker  function FilledSVGExample(PathKit) {
311*c8dee2aaSAndroid Build Coastguard Worker    let innerRect = PathKit.NewPath();
312*c8dee2aaSAndroid Build Coastguard Worker    innerRect.rect(80, 100, 40, 40);
313*c8dee2aaSAndroid Build Coastguard Worker
314*c8dee2aaSAndroid Build Coastguard Worker    let outerRect = PathKit.NewPath();
315*c8dee2aaSAndroid Build Coastguard Worker    outerRect.rect(50, 10, 100, 100)
316*c8dee2aaSAndroid Build Coastguard Worker             .op(innerRect, PathKit.PathOp.XOR);
317*c8dee2aaSAndroid Build Coastguard Worker
318*c8dee2aaSAndroid Build Coastguard Worker    let str = outerRect.toSVGString();
319*c8dee2aaSAndroid Build Coastguard Worker
320*c8dee2aaSAndroid Build Coastguard Worker    let diffSVG = document.createElementNS('http://www.w3.org/2000/svg', 'path');
321*c8dee2aaSAndroid Build Coastguard Worker    diffSVG.setAttribute('stroke', 'red');
322*c8dee2aaSAndroid Build Coastguard Worker    diffSVG.setAttribute('fill', 'black');
323*c8dee2aaSAndroid Build Coastguard Worker    // force fill-rule to nonzero to demonstrate difference
324*c8dee2aaSAndroid Build Coastguard Worker    diffSVG.setAttribute('fill-rule', 'nonzero');
325*c8dee2aaSAndroid Build Coastguard Worker    diffSVG.setAttribute('d', str);
326*c8dee2aaSAndroid Build Coastguard Worker    document.getElementById('svg2').appendChild(diffSVG);
327*c8dee2aaSAndroid Build Coastguard Worker
328*c8dee2aaSAndroid Build Coastguard Worker    let unionSVG = document.createElementNS('http://www.w3.org/2000/svg', 'path');
329*c8dee2aaSAndroid Build Coastguard Worker    unionSVG.setAttribute('stroke', 'red');
330*c8dee2aaSAndroid Build Coastguard Worker    unionSVG.setAttribute('fill', 'black');
331*c8dee2aaSAndroid Build Coastguard Worker    // ask what the path thinks fill-rule should be ('evenodd')
332*c8dee2aaSAndroid Build Coastguard Worker    // SVG and Canvas both use the same keys ('nonzero' and 'evenodd') and both
333*c8dee2aaSAndroid Build Coastguard Worker    // default to 'nonzero', so one call supports both.
334*c8dee2aaSAndroid Build Coastguard Worker    unionSVG.setAttribute('fill-rule', outerRect.getFillTypeString());
335*c8dee2aaSAndroid Build Coastguard Worker    unionSVG.setAttribute('d', str);
336*c8dee2aaSAndroid Build Coastguard Worker    document.getElementById('svg3').appendChild(unionSVG);
337*c8dee2aaSAndroid Build Coastguard Worker
338*c8dee2aaSAndroid Build Coastguard Worker    outerRect.delete();
339*c8dee2aaSAndroid Build Coastguard Worker    innerRect.delete();
340*c8dee2aaSAndroid Build Coastguard Worker  }
341*c8dee2aaSAndroid Build Coastguard Worker
342*c8dee2aaSAndroid Build Coastguard Worker  function CubicSolverExample(PathKit) {
343*c8dee2aaSAndroid Build Coastguard Worker    let ctx = document.getElementById('cubics').getContext('2d');
344*c8dee2aaSAndroid Build Coastguard Worker    setCanvasSize(ctx, 300, 300);
345*c8dee2aaSAndroid Build Coastguard Worker    // Draw lines between cp0 (0, 0) and cp1 and then cp2 and cp3 (1, 1)
346*c8dee2aaSAndroid Build Coastguard Worker    // scaled up to be on a 300x300 grid instead of unit square
347*c8dee2aaSAndroid Build Coastguard Worker    ctx.strokeStyle = 'black';
348*c8dee2aaSAndroid Build Coastguard Worker    ctx.beginPath();
349*c8dee2aaSAndroid Build Coastguard Worker    ctx.moveTo(0, 0);
350*c8dee2aaSAndroid Build Coastguard Worker    ctx.lineTo(0.1 * 300, 0.5*300);
351*c8dee2aaSAndroid Build Coastguard Worker
352*c8dee2aaSAndroid Build Coastguard Worker    ctx.moveTo(0.5 * 300, 0.1*300);
353*c8dee2aaSAndroid Build Coastguard Worker    ctx.lineTo(300, 300);
354*c8dee2aaSAndroid Build Coastguard Worker    ctx.stroke();
355*c8dee2aaSAndroid Build Coastguard Worker
356*c8dee2aaSAndroid Build Coastguard Worker
357*c8dee2aaSAndroid Build Coastguard Worker    ctx.strokeStyle = 'green';
358*c8dee2aaSAndroid Build Coastguard Worker    ctx.beginPath();
359*c8dee2aaSAndroid Build Coastguard Worker
360*c8dee2aaSAndroid Build Coastguard Worker    for (let x = 0; x < 300; x++) {
361*c8dee2aaSAndroid Build Coastguard Worker      // scale X into unit square
362*c8dee2aaSAndroid Build Coastguard Worker      let y = PathKit.cubicYFromX(0.1, 0.5, 0.5, 0.1, x/300);
363*c8dee2aaSAndroid Build Coastguard Worker      ctx.arc(x, y*300, 2, 0, 2*Math.PI);
364*c8dee2aaSAndroid Build Coastguard Worker    }
365*c8dee2aaSAndroid Build Coastguard Worker    ctx.stroke();
366*c8dee2aaSAndroid Build Coastguard Worker  }
367*c8dee2aaSAndroid Build Coastguard Worker
368*c8dee2aaSAndroid Build Coastguard Worker</script>
369