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