1PathKit - Geometry in the Browser
2=============================
3
4Skia has made its [SkPath](../api/SkPath_Reference) object and many related methods
5available to JS clients (e.g. Web Browsers) using WebAssembly and asm.js.
6
7Features
8--------
9
10PathKit is still under rapid development, so the exact API is subject to change.
11
12The primary features are:
13
14  - API compatibility (e.g. drop-in replacement) with [Path2D](https://developer.mozilla.org/en-US/docs/Web/API/Path2D)
15  - Can output to SVG / Canvas / Path2D
16  - Exposes a variety of path effects:
17
18<style>
19  canvas.patheffect {
20    border: 1px dashed #AAA;
21    width: 200px;
22    height: 200px;
23  }
24</style>
25
26<div id=effects>
27  <canvas class=patheffect id=canvas1 title="Plain: A drawn star with overlapping solid lines"></canvas>
28  <canvas class=patheffect id=canvas2 title="Dash: A drawn star with overlapping dashed lines"></canvas>
29  <canvas class=patheffect id=canvas3 title="Trim: A portion of a drawn star with overlapping solid lines"></canvas>
30  <canvas class=patheffect id=canvas4 title="Simplify: A drawn star with non-overlapping solid lines."></canvas>
31  <canvas class=patheffect id=canvas5 title="Stroke: A drawn star with non-overlapping solid lines stroked at various thicknesses and with square edges"></canvas>
32  <canvas class=patheffect id=canvas6 title="Grow: A drawn star's expanding outline"></canvas>
33  <canvas class=patheffect id=canvas7 title="Shrink: A solid drawn star shrunk down"></canvas>
34  <canvas class=patheffect id=canvasTransform title="Transform: A drawn star moved and rotated by an Affine Matrix"></canvas>
35</div>
36
37<script type="text/javascript">
38(function() {
39  // Tries to load the WASM version if supported, then falls back to asmjs
40  let s = document.createElement('script');
41  if (window.WebAssembly && typeof window.WebAssembly.compile === 'function') {
42    console.log('WebAssembly is supported! Using the wasm version of PathKit');
43    window.__pathkit_locate_file = 'https://unpkg.com/pathkit-wasm@0.5.0/bin/';
44  } else {
45    console.log('WebAssembly is not supported (yet) on this browser. Using the asmjs version of PathKit');
46    window.__pathkit_locate_file = 'https://unpkg.com/pathkit-asmjs@0.5.0/bin/';
47  }
48  s.src = window.__pathkit_locate_file+'pathkit.js';
49  s.onload = () => {
50    try {
51      PathKitInit({
52        locateFile: (file) => window.__pathkit_locate_file+file,
53      }).then((PathKit) => {
54        // Code goes here using PathKit
55        PathEffectsExample(PathKit);
56        MatrixTransformExample(PathKit);
57      });
58
59    }
60    catch(error) {
61      console.warn(error, 'falling back to image');
62      document.getElementById('effects').innerHTML = '<img width=800 src="./PathKit_effects.png"/>'
63    }
64  }
65
66  document.head.appendChild(s);
67
68  function setCanvasSize(ctx, width, height) {
69    ctx.canvas.width = width;
70    ctx.canvas.height = height;
71  }
72
73  function drawStar(path) {
74    let R = 115.2, C = 128.0;
75    path.moveTo(C + R + 22, C);
76    for (let i = 1; i < 8; i++) {
77      let a = 2.6927937 * i;
78      path.lineTo(C + R * Math.cos(a) + 22, C + R * Math.sin(a));
79    }
80    path.closePath();
81    return path;
82  }
83
84  function PathEffectsExample(PathKit) {
85    let effects = [
86      // no-op
87      (path) => path,
88      // dash
89      (path, counter) => path.dash(10, 3, counter/5),
90      // trim (takes optional 3rd param for returning the trimmed part
91      // or the complement)
92      (path, counter) => path.trim((counter/100) % 1, 0.8, false),
93      // simplify
94      (path) => path.simplify(),
95      // stroke
96      (path, counter) => path.stroke({
97        width: 10 * (Math.sin(counter/30) + 1),
98        join: PathKit.StrokeJoin.BEVEL,
99        cap: PathKit.StrokeCap.BUTT,
100        miter_limit: 1,
101      }),
102      // "offset effect", that is, making a border around the shape.
103      (path, counter) => {
104        let orig = path.copy();
105        path.stroke({
106          width: 10 + (counter / 4) % 50,
107          join: PathKit.StrokeJoin.ROUND,
108          cap: PathKit.StrokeCap.SQUARE,
109        })
110          .op(orig, PathKit.PathOp.DIFFERENCE);
111        orig.delete();
112      },
113      (path, counter) => {
114        let simplified = path.simplify().copy();
115        path.stroke({
116          width: 2 + (counter / 2) % 100,
117          join: PathKit.StrokeJoin.BEVEL,
118          cap: PathKit.StrokeCap.BUTT,
119        })
120          .op(simplified, PathKit.PathOp.REVERSE_DIFFERENCE);
121        simplified.delete();
122      }
123    ];
124
125    let names = ["(plain)", "Dash", "Trim", "Simplify", "Stroke", "Grow", "Shrink"];
126
127    let counter = 0;
128    function frame() {
129      counter++;
130      for (let i = 0; i < effects.length; i++) {
131        let path = PathKit.NewPath();
132        drawStar(path);
133
134        // The transforms apply directly to the path.
135        effects[i](path, counter);
136
137        let ctx = document.getElementById(`canvas${i+1}`);
138        if (!ctx) {
139          return;
140        } else {
141          ctx = ctx.getContext('2d');
142        }
143        setCanvasSize(ctx, 300, 300);
144        ctx.strokeStyle = '#3c597a';
145        ctx.fillStyle = '#3c597a';
146        if (i >=4 ) {
147          ctx.fill(path.toPath2D(), path.getFillTypeString());
148        } else {
149          ctx.stroke(path.toPath2D());
150        }
151
152        ctx.font = '42px monospace';
153
154        let x = 150-ctx.measureText(names[i]).width/2;
155        ctx.strokeText(names[i], x, 290);
156
157        path.delete();
158      }
159      window.requestAnimationFrame(frame);
160    }
161    window.requestAnimationFrame(frame);
162  }
163
164  function MatrixTransformExample(PathKit) {
165    // Creates an animated star that twists and moves.
166    let ctx = document.getElementById('canvasTransform').getContext('2d');
167    setCanvasSize(ctx, 300, 300);
168    ctx.strokeStyle = '#3c597a';
169
170    let path = drawStar(PathKit.NewPath());
171    // TODO(kjlubick): Perhaps expose some matrix helper functions to allow
172    // clients to build their own matrices like this?
173    // These matrices represent a 2 degree rotation and a 1% scale factor.
174    let scaleUp = [1.0094, -0.0352,  3.1041,
175                   0.0352,  1.0094, -6.4885,
176                   0     ,  0      , 1];
177
178    let scaleDown = [ 0.9895, 0.0346, -2.8473,
179                     -0.0346, 0.9895,  6.5276,
180                      0     , 0     ,  1];
181
182    let i = 0;
183    function frame(){
184      i++;
185      if (Math.round(i/100) % 2) {
186        path.transform(scaleDown);
187      } else {
188        path.transform(scaleUp);
189      }
190
191      ctx.clearRect(0, 0, 300, 300);
192      ctx.stroke(path.toPath2D());
193
194      ctx.font = '42px monospace';
195      let x = 150-ctx.measureText('Transform').width/2;
196      ctx.strokeText('Transform', x, 290);
197
198      window.requestAnimationFrame(frame);
199    }
200    window.requestAnimationFrame(frame);
201  }
202})();
203</script>
204
205
206Example Code
207------------
208The best place to look for examples on how to use PathKit would be in the
209[example.html](https://github.com/google/skia/blob/master/modules/pathkit/npm-wasm/example.html#L45),
210which comes in the npm package.
211
212
213Download the library
214--------------------
215
216See the the npm page for either the [WebAssembly](https://www.npmjs.com/package/pathkit-wasm) version
217or the [asm.js](https://www.npmjs.com/package/pathkit-asmjs) version
218for details on downloading and getting started.
219
220WebAssembly has faster load times and better overall performance but is
221currently supported by Chrome, Firefox, Edge, and Safari.
222The asm.js version should run anywhere JavaScript does.
223
224API
225----
226
227The primary feature of the library is the `SkPath` object. It can be created:
228
229 - From the SVG string of a path `PathKit.FromSVGString(str)`
230 - From a 2D array of verbs and arguments `PathKit.FromCmds(cmds)`
231 - From `PathKit.NewPath()` (It will be blank)
232 - As a copy of an existing `SkPath` with `path.copy()` or `PathKit.NewPath(path)`
233
234It can be exported as:
235
236 - An SVG string `path.toSVGString()`
237 - A [Path2D](https://developer.mozilla.org/en-US/docs/Web/API/Path2D) object `path.toPath2D()`
238 - Directly to a canvas 2D context `path.toCanvas(ctx)`
239 - A 2D array of verbs and arguments `path.toCmds()`
240
241Once an SkPath object has been made, it can be interacted with in the following ways:
242
243 - expanded by any of the Path2D operations (`moveTo`, `lineTo`, `rect`, `arc`, etc)
244 - combined with other paths using `op` or `PathKit.MakeFromOp(p1, p2, op)`.  For example, `path1.op(path2, PathKit.PathOp.INTERSECT)` will set path1 to be the area represented by where path1 and path2 overlap (intersect). `PathKit.MakeFromOp(path1, path2, PathKit.PathOp.INTERSECT)` will do the same but returned as a new `SkPath` object.
245 - adjusted with some of the effects (`trim`, `dash`, `stroke`, etc)
246
247
248**Important**: Any objects (`SkPath`, `SkOpBuilder`, etc) that are created must be cleaned up with `path.delete()` when they
249leave the scope to avoid leaking the memory in the WASM heap. This includes any of the constructors, `copy()`,
250or any function prefixed with "make".
251
252
253### PathKit ###
254
255#### `FromSVGString(str)` ####
256**str** - `String` representing an [SVGPath](https://www.w3schools.com/graphics/svg_path.asp)
257
258Returns an `SkPath` with the same verbs and arguments as the SVG string, or `null` on a failure.
259
260Example:
261
262    let path = PathKit.FromSVGString('M150 0 L75 200 L225 200 Z');
263    // path represents a triangle
264    // don't forget to do path.delete() when it goes out of scope.
265
266#### `FromCmds(cmds)` ####
267**cmds** - `Array<Array<Number>>`, a 2D array of commands, where a command is a verb
268           followed by its arguments.
269
270Returns an `SkPath` with the verbs and arguments from the list or `null` on a failure.
271
272This can be faster than calling `.moveTo()`, `.lineTo()`, etc many times.
273
274Example:
275
276    let cmds = [
277        [PathKit.MOVE_VERB, 0, 10],
278        [PathKit.LINE_VERB, 30, 40],
279        [PathKit.QUAD_VERB, 20, 50, 45, 60],
280    ];
281    let path = PathKit.FromCmds(cmds);
282    // path is the same as if a user had done
283    // let path = PathKit.NewPath().moveTo(0, 10).lineTo(30, 40).quadTo(20, 50, 45, 60);
284    // don't forget to do path.delete() when it goes out of scope.
285
286#### `NewPath()` ####
287
288Returns an empty `SkPath` object.
289
290Example:
291
292    let path = PathKit.NewPath();
293    path.moveTo(0, 10)
294        .lineTo(30, 40)
295        .quadTo(20, 50, 45, 60);
296    // don't forget to do path.delete() when it goes out of scope.
297    // Users can also do let path = new PathKit.SkPath();
298
299#### `NewPath(pathToCopy)` ####
300**pathToCopy** - SkPath, a path to make a copy of.
301
302Returns a `SkPath` that is a copy of the passed in `SkPath`.
303
304Example:
305
306    let otherPath = ...;
307    let clone = PathKit.NewPath(otherPath);
308    clone.simplify();
309    // don't forget to do clone.delete() when it goes out of scope.
310    // Users can also do let clone = new PathKit.SkPath(otherPath);
311    // or let clone = otherPath.copy();
312
313#### `MakeFromOp(pathOne, pathTwo, op)` ####
314**pathOne** - `SkPath`, a path. <br>
315**pathTwo** - `SkPath`, a path. <br>
316**op** - `PathOp`, an op to apply
317
318Returns a new `SkPath` that is the result of applying the given PathOp to the first and second
319path (order matters).
320
321Example:
322
323    let pathOne = PathKit.NewPath().moveTo(0, 20).lineTo(10, 10).lineTo(20, 20).close();
324    let pathTwo = PathKit.NewPath().moveTo(10, 20).lineTo(20, 10).lineTo(30, 20).close();
325    let mountains = PathKit.MakeFromOp(pathOne, pathTwo, PathKit.PathOp.UNION);
326    // don't forget to do mountains.delete() when it goes out of scope.
327    // Users can also do pathOne.op(pathTwo, PathKit.PathOp.UNION);
328    // to have the resulting path be stored to pathOne and avoid allocating another object.
329
330#### `cubicYFromX(cpx1, cpy1, cpx2, cpy2, X)` ####
331**cpx1, cpy1, cpx2, cpy2** - `Number`, coordinates for control points. <br>
332**X** - `Number`, The X coordinate for which to find the corresponding Y coordinate.
333
334Fast evaluation of a cubic ease-in / ease-out curve. This is defined as a parametric cubic
335curve inside the unit square. Makes the following assumptions:
336
337  - pt[0] is implicitly { 0, 0 }
338  - pt[3] is implicitly { 1, 1 }
339  - pts[1, 2] are inside the unit square
340
341This returns the Y coordinate for the given X coordinate.
342
343#### `cubicPtFromT(cpx1, cpy1, cpx2, cpy2, T)` ####
344**cpx1, cpy1, cpx2, cpy2** - `Number`, coordinates for control points. <br>
345**T** - `Number`, The T param for which to find the corresponding (X, Y) coordinates.
346
347Fast evaluation of a cubic ease-in / ease-out curve. This is defined as a parametric cubic
348curve inside the unit square. Makes the following assumptions:
349
350  - pt[0] is implicitly { 0, 0 }
351  - pt[3] is implicitly { 1, 1 }
352  - pts[1, 2] are inside the unit square
353
354This returns the (X, Y) coordinate for the given T value as a length 2 array.
355
356
357### SkPath (object) ###
358
359#### `addPath(otherPath)` ####
360**otherPath** - `SkPath`, a path to append to this path
361
362Adds the given path to `this` and then returns `this` for chaining purposes.
363
364#### `addPath(otherPath, transform)` ####
365**otherPath** - `SkPath`, a path to append to this path. <br>
366**transform** - [SVGMatrix](https://developer.mozilla.org/en-US/docs/Web/API/SVGMatrix),
367                a transform to apply to otherPath before appending it.
368
369Adds the given path to `this` after applying the transform and then returns `this` for
370chaining purposes. See [Path2D.addPath()](https://developer.mozilla.org/en-US/docs/Web/API/Path2D/addPath)
371for more details.
372
373#### `addPath(otherPath, a, b, c, d, e, f)` ####
374**otherPath** - `SkPath`, a path to append to this path. <br>
375**a, b, c, d, e, f** - `Number`, the six components of an
376                       [SVGMatrix](https://developer.mozilla.org/en-US/docs/Web/API/SVGMatrix),
377                       which define the transform to apply to otherPath before appending it.
378
379Adds the given path to `this` after applying the transform and then returns `this` for
380chaining purposes. See [Path2D.addPath()](https://developer.mozilla.org/en-US/docs/Web/API/Path2D/addPath)
381for more details.
382
383Example:
384
385    let box = PathKit.NewPath().rect(0, 0, 100, 100);
386    let moreBoxes = PathKit.NewPath();
387    // add box un-transformed (i.e. at 0, 0)
388    moreBoxes.addPath(box)
389    // the params fill out a 2d matrix like:
390    //     a c e
391    //     b d f
392    //     0 0 1
393    // add box 300 points to the right
394             .addPath(box, 1, 0, 0, 1, 300, 0)
395    // add a box shrunk by 50% in both directions
396             .addPath(box, 0.5, 0, 0, 0.5, 0, 0);
397    // moreBoxes now has 3 paths appended to it
398
399#### `addPath(otherPath, scaleX, skewX, transX, skewY, scaleY, transY, pers0, pers1, pers2)` ####
400**otherPath** - `SkPath`, a path to append to this path. <br>
401**scaleX, skewX, transX, skewY, scaleY, transY, pers0, pers1, pers2** -
402                       `Number`, the nine components of an
403                       [Affine Matrix](https://en.wikipedia.org/wiki/Transformation_matrix#Affine_transformations),
404                       which define the transform to apply to otherPath before appending it.
405
406Adds the given path to `this` after applying the transform and then returns `this` for
407chaining purposes.
408
409Example:
410
411    let box = PathKit.NewPath().rect(0, 0, 100, 100);
412    let moreBoxes = PathKit.NewPath();
413    // add box un-transformed (i.e. at 0, 0)
414    moreBoxes.addPath(box)
415    // add box 300 points to the right
416             .addPath(box, 1, 0, 0,
417                           0, 1, 300,
418                           0, 0 ,1)
419    // add a box shrunk by 50% in both directions
420             .addPath(box, 0.5, 0,   0,
421                           0,   0.5, 0,
422                           0,   0,   1)
423    // moreBoxes now has 3 paths appended to it
424
425#### `arc(x, y, radius, startAngle, endAngle, ccw=false)` ####
426**x, y** - `Number`, The coordinates of the arc's center. <br>
427**radius** - `Number`, The radius of the arc. <br>
428**startAngle, endAngle** - `Number`, the start and end of the angle, measured
429                           clockwise from the positive x axis and in radians. <br>
430**ccw** - `Boolean`, optional argument specifying if the arc should be drawn
431          counter-clockwise between **startAngle** and **endAngle** instead of
432          clockwise, the default.
433
434Adds the described arc to `this` then returns `this` for
435chaining purposes.  See [Path2D.arc()](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/arc)
436for more details.
437
438Example:
439
440    let path = PathKit.NewPath();
441    path.moveTo(20, 120);
442        .arc(20, 120, 18, 0, 1.75 * Math.PI);
443        .lineTo(20, 120);
444    // path looks like a pie with a 1/8th slice removed.
445
446#### `arcTo(x1, y1, x2, y2, radius)` ####
447**x1, y1, x2, y2** - `Number`, The coordinates defining the control points. <br>
448**radius** - `Number`, The radius of the arc.
449
450Adds the described arc to `this` (appending a line, if needed) then returns `this` for
451chaining purposes.  See [Path2D.arcTo()](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/arcTo)
452for more details.
453
454#### `close()` or `closePath()` ####
455Returns the pen to the start of the current sub-path, then returns `this` for
456chaining purposes.  See [Path2D.closePath()](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/closePath)
457for more details.
458
459#### `computeTightBounds()` ####
460
461Returns an `SkRect` that represents the minimum and maximum area of
462`this` path. See [SkPath reference](https://skia.org/user/api/SkPath_Reference#SkPath_computeTightBounds)
463for more details.
464
465#### `conicTo(x1, y1, x2, y2, w)` ####
466**x1, y1, x2, y2** - `Number`, The coordinates defining the control point and the end point. <br>
467**w** - `Number`, The weight of the conic.
468
469Adds the described conic line to `this` (appending a line, if needed) then returns `this` for
470chaining purposes. See [SkPath reference](https://skia.org/user/api/SkPath_Reference#SkPath_conicTo)
471for more details.
472
473#### `copy()` ####
474
475Return a copy of `this` path.
476
477#### `cubicTo(cp1x, cp1y, cp2x, cp2y, x, y)` or `bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)` ####
478**cp1x, cp1y, cp2x, cp2y** - `Number`, The coordinates defining the control points. <br>
479**x,y** - `Number`, The coordinates defining the end point
480
481Adds the described cubic line to `this` (appending a line, if needed) then returns `this` for
482chaining purposes. See [Path2D.bezierCurveTo](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/bezierCurveTo)
483for more details.
484
485#### `dash(on, off, phase)` ####
486**on, off** - `Number`, The number of pixels the dash should be on (drawn) and off (blank). <br>
487**phase** - `Number`, The number of pixels the on/off should be offset (mod **on** + **off**)
488
489Applies a dashed path effect to `this` then returns `this` for chaining purposes.
490See the "Dash" effect above for a visual example.
491
492Example:
493
494    let box = PathKit.NewPath().rect(0, 0, 100, 100);
495    box.dash(20, 10, 3);
496    // box is now a dashed rectangle that will draw for 20 pixels, then
497    // stop for 10 pixels.  Since phase is 3, the first line won't start
498    // at (0, 0), but 3 pixels around the path (3, 0)
499
500#### `ellipse(x, y, radiusX, radiusY, rotation, startAngle, endAngle, ccw=false)` ####
501**x, y** - `Number`, The coordinates of the center of the ellipse. <br>
502**radiusX, radiusY** - `Number`, The radii in the X and Y directions. <br>
503**rotation** - `Number`, The rotation in radians of this ellipse. <br>
504**startAngle, endAngle** - `Number`, the starting and ending angles of which to draw,
505                            measured in radians from the positive x axis. <br>
506**ccw** - `Boolean`, optional argument specifying if the ellipse should be drawn
507          counter-clockwise between **startAngle** and **endAngle** instead of
508          clockwise, the default.
509
510Adds the described ellipse to `this` then returns `this` for chaining purposes.
511See [Path2D.ellipse](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/ellipse)
512for more details.
513
514#### `equals(otherPath)` ####
515**otherPath** - `SkPath`, the path to compare to.
516
517Returns a `Boolean` value based on if `this` path is equal
518to **otherPath**.
519
520#### `getBounds()` ####
521
522Returns an `SkRect` that represents the minimum and maximum area of
523`this` path. See [SkPath reference](https://skia.org/user/api/SkPath_Reference#SkPath_getBounds)
524for more details.
525
526#### `getFillType()` ####
527
528Returns a `FillType` based on what this path is. This defaults to
529`PathKit.FillType.WINDING`, but may change with `op()` or `simplify()`.
530
531Clients will typically want `getFillTypeString()` because that value
532can be passed directly to an SVG or Canvas.
533
534#### `getFillTypeString()` ####
535
536Returns a `String` representing the fillType of `this` path.
537The values are either "nonzero" or "evenodd".
538
539Example:
540
541    let path = ...;
542    let ctx = document.getElementById('canvas1').getContext('2d');
543    ctx.strokeStyle = 'green';
544    ctx.fill(path.toPath2D(), path.getFillTypeString());
545
546#### `moveTo(x, y)` ####
547**x, y** - `Number`, The coordinates of where the pen should be moved to.
548
549Moves the pen (without drawing) to the given coordinates then returns `this` for chaining purposes.
550See [Path2D.moveTo](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/moveTo)
551for more details.
552
553#### `lineTo(x, y)` ####
554**x, y** - `Number`, The coordinates of where the pen should be moved to.
555
556Draws a straight line to the given coordinates then returns `this` for chaining purposes.
557See [Path2D.lineTo](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/lineTo)
558for more details.
559
560#### `op(otherPath, operation)` ####
561**otherPath** - `SkPath`, The other path to be combined with `this`. <br>
562**operation** - `PathOp`, The operation to apply to the two paths.
563
564Combines otherPath into `this` path with the given operation and returns `this`
565for chaining purposes.
566
567Example:
568
569    let pathOne = PathKit.NewPath().moveTo(0, 20).lineTo(10, 10).lineTo(20, 20).close();
570    let pathTwo = PathKit.NewPath().moveTo(10, 20).lineTo(20, 10).lineTo(30, 20).close();
571    // Combine the two triangles to look like two mountains
572    let mountains = pathOne.copy().op(pathOne, pathTwo, PathKit.PathOp.UNION);
573    // set pathOne to be the small triangle where pathOne and pathTwo overlap
574    pathOne.op(pathOne, pathTwo, PathKit.PathOp.INTERSECT);
575    // since copy() was called, don't forget to call delete() on mountains.
576
577#### `quadTo(cpx, cpy, x, y)` or `quadraticCurveTo(cpx, cpy, x, y)` ####
578**cpx, cpy** - `Number`, The coordinates for the control point. <br>
579**x, y** - `Number`, The coordinates for the end point.
580
581Draws a quadratic Bézier curve with the given coordinates then returns `this` for chaining purposes.
582See [Path2D.quadraticCurveTo](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/quadraticCurveTo)
583for more details.
584
585#### `rect(x, y, w, h)` ####
586**x, y** - `Number`, The coordinates of the upper-left corner of the rectangle. <br>
587**w, h** - `Number`, The width and height of the rectangle
588
589Draws a rectangle on `this`, then returns `this` for chaining purposes.
590See [Path2D.rect](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/rect)
591for more details.
592
593#### `setFillType(fillType)` ####
594**fillType** - `FillType`, the new fillType.
595
596Set the fillType of the path. See [SkPath reference](https://skia.org/user/api/SkPath_Reference#SkPath_FillType)
597for more details.
598
599#### `simplify()` ####
600Set `this` path to a set of *non-overlapping* contours that describe the same area
601as the original path. See the "Simplify" effect above for a visual example.
602
603#### `stroke(opts)` ####
604**opts** - `StrokeOpts`, contains the options for stroking.
605
606
607Strokes `this` path out with the given options. This can be used for a variety of
608effects.  See the "Stroke", "Grow", and "Shrink" effects above for visual examples.
609
610Example:
611
612    let box = PathKit.NewPath().rect(0, 0, 100, 100);
613    // Stroke the path with width 10 and rounded corners
614    let rounded = box.copy().stroke({width: 10, join: PathKit.StrokeJoin.ROUND});
615    // Grow effect, that is, a 20 pixel expansion around the box.
616    let grow = box.copy().stroke({width: 20}).op(box, PathKit.PathOp.DIFFERENCE);
617    // Shrink effect, in which we subtract away from the original
618    let simplified = box.copy().simplify(); // sometimes required for complicated paths
619    let shrink = box.copy().stroke({width: 15, cap: PathKit.StrokeCap.BUTT})
620                           .op(simplified, PathKit.PathOp.REVERSE_DIFFERENCE);
621    // Don't forget to call delete() on each of the copies!
622
623#### `toCanvas(ctx)` ####
624**ctx** - `Canvas2DContext`, Canvas on which to draw the path.
625
626Draws `this` path on the passed in
627[Canvas Context](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D).
628
629Example:
630
631    let box = PathKit.NewPath().rect(0, 0, 100, 100);
632    let ctx = document.getElementById('canvas1').getContext('2d');
633    ctx.strokeStyle = 'green';
634    ctx.beginPath();
635    box.toCanvas(ctx);
636    ctx.stroke();  // could also ctx.fill()
637
638#### `toCmds()` ####
639
640Returns a 2D Array of verbs and args. See `PathKit.FromCmds()` for
641more details.
642
643#### `toPath2D()` ####
644
645Returns a [Path2D](https://developer.mozilla.org/en-US/docs/Web/API/Path2D) object
646that has the same operations as `this` path.
647
648Example:
649
650    let box = PathKit.NewPath().rect(0, 0, 100, 100);
651    let ctx = document.getElementById('canvas1').getContext('2d');
652    ctx.strokeStyle = 'green';
653    ctx.stroke(box.toPath2D());
654
655#### `toSVGString()` ####
656
657Returns a `String` representing an [SVGPath](https://www.w3schools.com/graphics/svg_path.asp) based on `this` path.
658
659Example:
660
661    let box = PathKit.NewPath().rect(0, 0, 100, 100);
662    let svg = document.getElementById('svg1');
663    let newPath = document.createElementNS('http://www.w3.org/2000/svg', 'path');
664    newPath.setAttribute('stroke', 'green');
665    newPath.setAttribute('fill', 'white');
666    newPath.setAttribute('d', box.toSVGString());
667    svg.appendChild(newPath);
668
669#### `transform(matr)` ####
670**matr** - `SkMatrix`, i.e. an `Array<Number>` of the nine numbers of an Affine Transform Matrix.
671
672Applies the specified [transform](https://en.wikipedia.org/wiki/Transformation_matrix#Affine_transformations)
673to `this` and then returns `this` for chaining purposes.
674
675#### `transform(scaleX, skewX, transX, skewY, scaleY, transY, pers0, pers1, pers2)` ####
676**scaleX, skewX, transX, skewY, scaleY, transY, pers0, pers1, pers2** -
677        `Number`, the nine numbers of an Affine Transform Matrix.
678
679Applies the specified [transform](https://en.wikipedia.org/wiki/Transformation_matrix#Affine_transformations)
680to `this` and then returns `this` for chaining purposes.
681
682Example:
683
684    let path = PathKit.NewPath().rect(0, 0, 100, 100);
685    // scale up the path by 5x
686    path.transform([5, 0, 0,
687                    0, 5, 0,
688                    0, 0, 1]);
689    // move the path 75 px to the right.
690    path.transform(1, 0, 75,
691                   0, 1, 0,
692                   0, 0, 1);
693
694#### `trim(startT, stopT, isComplement=false)` ####
695**startT, stopT** - `Number`, values in [0, 1] that indicate the start and stop
696                    "percentages" of the path to draw <br>
697**isComplement** - `Boolean`, If the complement of the trimmed section should
698                    be drawn instead of the areas between **startT** and **stopT**.
699
700Sets `this` path to be a subset of the original path, then returns `this` for chaining purposes.
701See the "Trim" effect above for a visual example.
702
703Example:
704
705    let box = PathKit.NewPath().rect(0, 0, 100, 100);
706    box.trim(0.25, 1.0);
707    // box is now the 3 segments that look like a U
708    // (the top segment has been removed).
709
710
711### SkOpBuilder (object)  ###
712This object enables chaining multiple PathOps together.
713Create one with `let builder = new PathKit.SkOpBuilder();`
714When created, the internal state is "empty path".
715Don't forget to call `delete()` on both the builder and the result
716of `resolve()`
717
718#### `add(path, operation)` ####
719**path** - `SkPath`, The path to be combined with the given rule. <br>
720**operation** - `PathOp`, The operation to apply to the two paths.
721
722Adds a path and the operand to the builder.
723
724#### `make()` or `resolve()` ####
725
726Creates and returns a new `SkPath` based on all the given paths
727and operands.
728
729Don't forget to call `.delete()` on the returned path when it goes out of scope.
730
731
732### SkMatrix (struct) ###
733`SkMatrix` translates between a C++ struct and a JS Array.
734It basically takes a nine element 1D Array and turns it into a
7353x3 2D Affine Matrix.
736
737### SkRect (struct) ###
738
739`SkRect` translates between a C++ struct and a JS Object with
740the following keys (all values are `Number`:
741
742  - **fLeft**: x coordinate of top-left corner
743  - **fTop**: y coordinate of top-left corner
744  - **fRight**: x coordinate of bottom-right corner
745  - **fBottom**: y coordinate of bottom-rightcorner
746
747### StrokeOpts (struct) ###
748`StrokeOpts` translates between a C++ struct and a JS Object with
749the following keys:
750
751  - **width**, `Number` the width of the lines of the path. Default 1.
752  - **miter_limit**, `Number`, the miter limit. Defautl 4. See [SkPaint reference](https://skia.org/user/api/SkPaint_Reference#Miter_Limit) for more details.
753  - **join**, `StrokeJoin`, the join to use. Default `PathKit.StrokeJoin.MITER`.
754See [SkPaint reference](https://skia.org/user/api/SkPaint_Reference#SkPaint_Join) for more details.
755  - **cap**, `StrokeCap`, the cap to use. Default `PathKit.StrokeCap.BUTT`.
756See [SkPaint reference](https://skia.org/user/api/SkPaint_Reference#Stroke_Cap) for more details.
757
758### PathOp (enum) ###
759The following enum values are exposed. They are essentially constant
760objects, differentiated by thier `.value` property.
761
762  - `PathKit.PathOp.DIFFERENCE`
763  - `PathKit.PathOp.INTERSECT`
764  - `PathKit.PathOp.REVERSE_DIFFERENCE`
765  - `PathKit.PathOp.UNION`
766  - `PathKit.PathOp.XOR`
767
768These are used in `PathKit.MakeFromOp()` and `SkPath.op()`.
769
770### FillType (enum) ###
771The following enum values are exposed. They are essentially constant
772objects, differentiated by thier `.value` property.
773
774  - `PathKit.FillType.WINDING` (also known as nonzero)
775  - `PathKit.FillType.EVENODD`
776  - `PathKit.FillType.INVERSE_WINDING`
777  - `PathKit.FillType.INVERSE_EVENODD`
778
779These are used by `SkPath.getFillType()` and `SkPath.setFillType()`, but
780generally clients will want `SkPath.getFillTypeString()`.
781
782### StrokeJoin (enum) ###
783The following enum values are exposed. They are essentially constant
784objects, differentiated by thier `.value` property.
785
786  - `PathKit.StrokeJoin.MITER`
787  - `PathKit.StrokeJoin.ROUND`
788  - `PathKit.StrokeJoin.BEVEL`
789
790See [SkPaint reference](https://skia.org/user/api/SkPaint_Reference#SkPaint_Join) for more details.
791
792### StrokeCap (enum) ###
793The following enum values are exposed. They are essentially constant
794objects, differentiated by thier `.value` property.
795
796  - `PathKit.StrokeCap.BUTT`
797  - `PathKit.StrokeCap.ROUND`
798  - `PathKit.StrokeCap.SQUARE`
799
800See [SkPaint reference](https://skia.org/user/api/SkPaint_Reference#Stroke_Cap) for more details.
801
802### Constants ###
803The following constants are exposed:
804
805  - `PathKit.MOVE_VERB` = 0
806  - `PathKit.LINE_VERB` = 1
807  - `PathKit.QUAD_VERB` = 2
808  - `PathKit.CONIC_VERB` = 3
809  - `PathKit.CUBIC_VERB` = 4
810  - `PathKit.CLOSE_VERB` = 5
811
812These are only needed for `PathKit.FromCmds()`.
813
814### Functions for testing only ###
815
816#### `PathKit.LTRBRect(left, top, right, bottom)` ####
817**left** - `Number`, x coordinate of top-left corner of the `SkRect`. <br>
818**top** - `Number`, y coordinate of top-left corner of the `SkRect`. <br>
819**right** - `Number`, x coordinate of bottom-right corner of the `SkRect`. <br>
820**bottom** - `Number`, y coordinate of bottom-right corner of the `SkRect`.
821
822Returns an `SkRect` object with the given params.
823
824#### `SkPath.dump()` ####
825
826Prints all the verbs and arguments to the console.
827Only available on Debug and Test builds.
828