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