blob: ec097b947e4d47303f4127f9726435cc67436c32 [file] [log] [blame]
Kevin Lubicke1b36fe2018-08-02 11:30:33 -04001<!DOCTYPE html>
2<title>PathKit (Skia + WASM)</title>
3<meta charset="utf-8" />
4<meta http-equiv="X-UA-Compatible" content="IE=edge">
5<meta name="viewport" content="width=device-width, initial-scale=1.0">
6
7<style>
8 svg, canvas {
9 border: 1px dashed #AAA;
10 }
11
12 canvas {
13 width: 200px;
14 height: 200px;
15 }
16
Kevin Lubick641bf872018-08-06 14:49:39 -040017 canvas.big {
18 width: 300px;
19 height: 300px;
20 }
21
Kevin Lubicke1b36fe2018-08-02 11:30:33 -040022</style>
23
Kevin Lubick641bf872018-08-06 14:49:39 -040024<h2> Can output to an SVG Path, a Canvas, or a Path2D object </h2>
Kevin Lubicke1b36fe2018-08-02 11:30:33 -040025<svg id=svg xmlns='http://www.w3.org/2000/svg' width=200 height=200></svg>
Kevin Lubick641bf872018-08-06 14:49:39 -040026<canvas id=canvas1></canvas>
27<canvas id=canvas2></canvas>
Kevin Lubicke1b36fe2018-08-02 11:30:33 -040028
Kevin Lubick641bf872018-08-06 14:49:39 -040029<h2> Interact with NewPath() just like a Path2D Object </h2>
30<canvas class=big id=canvas3></canvas>
31<canvas class=big id=canvas4></canvas>
Kevin Lubicke1b36fe2018-08-02 11:30:33 -040032
Kevin Lubick97d6d982018-08-10 15:53:16 -040033<h2> Has various Path Effects </h2>
34<canvas class=big id=canvas5></canvas>
35<canvas class=big id=canvas6></canvas>
36<canvas class=big id=canvas7></canvas>
37<canvas class=big id=canvas8></canvas>
38<canvas class=big id=canvas9></canvas>
39<canvas class=big id=canvas10></canvas>
40
Kevin Lubicke1b36fe2018-08-02 11:30:33 -040041<script type="text/javascript" src="/node_modules/experimental-pathkit-wasm/bin/pathkit.js"></script>
42
43<script type="text/javascript" charset="utf-8">
44
45 PathKitInit({
46 locateFile: (file) => '/node_modules/experimental-pathkit-wasm/bin/'+file,
47 }).then((PathKit) => {
Kevin Lubick641bf872018-08-06 14:49:39 -040048 OutputsExample(PathKit);
49 Path2DExample(PathKit);
Kevin Lubick97d6d982018-08-10 15:53:16 -040050 PathEffectsExample(PathKit);
Kevin Lubick641bf872018-08-06 14:49:39 -040051 });
Kevin Lubicke1b36fe2018-08-02 11:30:33 -040052
Kevin Lubick641bf872018-08-06 14:49:39 -040053 function setCanvasSize(ctx, width, height) {
54 ctx.canvas.width = width;
55 ctx.canvas.height = height;
56 }
57
58 function OutputsExample(PathKit) {
Kevin Lubicke1b36fe2018-08-02 11:30:33 -040059 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');
60
61 let secondPath = PathKit.NewPath();
62 // Acts somewhat like the Canvas API
63 secondPath.moveTo(1, 1);
64 secondPath.lineTo(20, 1);
65 secondPath.lineTo(10, 30);
Kevin Lubick641bf872018-08-06 14:49:39 -040066 secondPath.closePath();
Kevin Lubicke1b36fe2018-08-02 11:30:33 -040067
Kevin Lubick641bf872018-08-06 14:49:39 -040068 let combinedPath = firstPath.op(secondPath, PathKit.PathOp.INTERSECT);
69 let simpleStr = combinedPath.toSVGString();
Kevin Lubicke1b36fe2018-08-02 11:30:33 -040070
71 let newSVG = document.createElementNS('http://www.w3.org/2000/svg', 'path');
72 newSVG.setAttribute('stroke', 'rgb(0,0,200)');
73 newSVG.setAttribute('fill', 'white');
Kevin Lubick641bf872018-08-06 14:49:39 -040074 newSVG.setAttribute('transform', 'scale(8,8)');
Kevin Lubicke1b36fe2018-08-02 11:30:33 -040075 newSVG.setAttribute('d', simpleStr);
76 document.getElementById('svg').appendChild(newSVG);
77
78 // Draw directly to Canvas
79 let ctx = document.getElementById('canvas1').getContext('2d');
Kevin Lubick641bf872018-08-06 14:49:39 -040080 setCanvasSize(ctx, 200, 200);
Kevin Lubicke1b36fe2018-08-02 11:30:33 -040081 ctx.strokeStyle = 'green';
82 ctx.fillStyle = 'white';
Kevin Lubick641bf872018-08-06 14:49:39 -040083 ctx.scale(8, 8);
Kevin Lubicke1b36fe2018-08-02 11:30:33 -040084 ctx.beginPath();
Kevin Lubick641bf872018-08-06 14:49:39 -040085 combinedPath.toCanvas(ctx);
Kevin Lubicke1b36fe2018-08-02 11:30:33 -040086 ctx.stroke();
87
88 // create Path2D object and use it in a Canvas.
Kevin Lubick641bf872018-08-06 14:49:39 -040089 let path2D = combinedPath.toPath2D();
Kevin Lubicke1b36fe2018-08-02 11:30:33 -040090 ctx = document.getElementById('canvas2').getContext('2d');
Kevin Lubick641bf872018-08-06 14:49:39 -040091 setCanvasSize(ctx, 200, 200);
92 ctx.canvas.width = 200
93 ctx.scale(8, 8);
Kevin Lubicke1b36fe2018-08-02 11:30:33 -040094 ctx.fillStyle = 'purple';
95 ctx.strokeStyle = 'orange';
96 ctx.fill(path2D);
97 ctx.stroke(path2D);
98
99 // clean up WASM memory
100 // See http://kripken.github.io/emscripten-site/docs/porting/connecting_cpp_and_javascript/embind.html?highlight=memory#memory-management
101 firstPath.delete();
102 secondPath.delete();
103 combinedPath.delete();
Kevin Lubick641bf872018-08-06 14:49:39 -0400104 }
105
106 function Path2DExample(PathKit) {
107 let objs = [new Path2D(), PathKit.NewPath(), new Path2D(), PathKit.NewPath()];
108 let canvases = [
109 document.getElementById('canvas3').getContext('2d'),
110 document.getElementById('canvas4').getContext('2d')
111 ];
112
113 for (i = 0; i <= 1; i++) {
114 let path = objs[i];
115
116 path.moveTo(20, 5);
117 path.lineTo(30, 20);
118 path.lineTo(40, 10);
119 path.lineTo(50, 20);
120 path.lineTo(60, 0);
121 path.lineTo(20, 5);
122
123 path.moveTo(20, 80);
124 path.bezierCurveTo(90, 10, 160, 150, 190, 10);
125
126 path.moveTo(36, 148);
127 path.quadraticCurveTo(66, 188, 120, 136);
128 path.lineTo(36, 148);
129
130 path.rect(5, 170, 20, 20);
131
132 path.moveTo(150, 180);
133 path.arcTo(150, 100, 50, 200, 20);
134 path.lineTo(160, 160);
135
136 path.moveTo(20, 120);
137 path.arc(20, 120, 18, 0, 1.75 * Math.PI);
138 path.lineTo(20, 120);
139
140 let secondPath = objs[i+2];
141 secondPath.ellipse(130, 25, 30, 10, -1*Math.PI/8, Math.PI/6, 1.5*Math.PI, false);
142
143 path.addPath(secondPath);
144
145 let m = document.createElementNS('http://www.w3.org/2000/svg', 'svg').createSVGMatrix();
146 m.a = 1; m.b = 0;
147 m.c = 0; m.d = 1;
148 m.e = 0; m.f = 20.5;
149
150 path.addPath(secondPath, m);
151 // With PathKit, one can also just provide the 6 params as floats, to avoid
152 // the overhead of making an SVGMatrix
153 // path.addPath(secondPath, 1, 0, 0, 1, 0, 20.5);
154
155 canvasCtx = canvases[i];
156 canvasCtx.fillStyle = 'blue';
157 setCanvasSize(canvasCtx, 300, 300);
158 canvasCtx.scale(1.5, 1.5);
159 if (path.toPath2D) {
160 canvasCtx.stroke(path.toPath2D());
161 } else {
162 canvasCtx.stroke(path);
163 }
164 }
165
166
167 objs[1].delete();
168 }
Kevin Lubicke1b36fe2018-08-02 11:30:33 -0400169
Kevin Lubick97d6d982018-08-10 15:53:16 -0400170 // see https://fiddle.skia.org/c/@discrete_path
171 function drawStar(path) {
172 let R = 115.2, C = 128.0;
173 path.moveTo(C + R + 22, C);
174 for (let i = 1; i < 8; i++) {
175 let a = 2.6927937 * i;
176 path.lineTo(C + R * Math.cos(a) + 22, C + R * Math.sin(a));
177 }
178 path.closePath();
179 return path;
180 }
181
182 function PathEffectsExample(PathKit) {
183 let transforms = [
184 // no-op
185 (path) => path,
186 // dash
187 (path) => path.dash(10, 3, 0),
188 // trim (takes optional 3rd param for returning the trimmed part
189 // or the complement)
190 (path) => path.trim(0.25, 0.8, false),
191 // simplify
192 (path) => path.simplify(),
193 // stroke
194 (path) => path.stroke(15, PathKit.StrokeJoin.BEVEL, PathKit.StrokeCap.BUTT),
195 // "offset effect", that is, making a border around the shape.
196 (path) => {
197 let temp = path.stroke(10, PathKit.StrokeJoin.ROUND, PathKit.StrokeCap.SQUARE);
198 let ret = temp.op(path, PathKit.PathOp.DIFFERENCE);
199 temp.delete();
200 return ret;
201 }
202 ];
203
204 let names = ["(plain)", "Dash", "Trim", "Simplify", "Stroke", "Offset"];
205
206 for (let i = 0; i < transforms.length; i++) {
207 let path = PathKit.NewPath();
208 drawStar(path);
209
210 let transformedPath = transforms[i](path);
211
212 let ctx = document.getElementById(`canvas${i+5}`).getContext('2d');
213 setCanvasSize(ctx, 300, 300);
214 ctx.strokeStyle = '#3c597a';
215 ctx.fillStyle = '#3c597a';
216 if (i === 4 || i === 5) {
217 ctx.fill(transformedPath.toPath2D(), transformedPath.getCanvasFillType());
218 if (i === 5) {
219 ctx.fillStyle = "#51d9bb";
220 ctx.fill(path.toPath2D());
221 }
222 } else {
223 ctx.stroke(transformedPath.toPath2D());
224 }
225
226 ctx.font = '42px monospace';
227
228 let x = 150-ctx.measureText(names[i]).width/2;
229 ctx.strokeText(names[i], x, 290);
230
231 if (i) {
232 transformedPath.delete();
233 }
234 path.delete();
235 }
236
237 }
238
Kevin Lubicke1b36fe2018-08-02 11:30:33 -0400239</script>