1*c8dee2aaSAndroid Build Coastguard Worker 2*c8dee2aaSAndroid Build Coastguard Worker--- 3*c8dee2aaSAndroid Build Coastguard Workertitle: "CanvasKit - Quickstart" 4*c8dee2aaSAndroid Build Coastguard WorkerlinkTitle: "CanvasKit - Quickstart" 5*c8dee2aaSAndroid Build Coastguard Worker 6*c8dee2aaSAndroid Build Coastguard Worker--- 7*c8dee2aaSAndroid Build Coastguard Worker 8*c8dee2aaSAndroid Build Coastguard Worker 9*c8dee2aaSAndroid Build Coastguard WorkerCanvasKit is a wasm module that uses Skia to draw to canvas elements a more advance feature set than the canvas API. 10*c8dee2aaSAndroid Build Coastguard Worker 11*c8dee2aaSAndroid Build Coastguard WorkerMinimal application 12*c8dee2aaSAndroid Build Coastguard Worker------------------- 13*c8dee2aaSAndroid Build Coastguard Worker 14*c8dee2aaSAndroid Build Coastguard WorkerThis example is a minimal Canvaskit application that draws a rounded rect for one frame. 15*c8dee2aaSAndroid Build Coastguard WorkerIt pulls the wasm binary from unpkg.com but you can also build and host it yourself. 16*c8dee2aaSAndroid Build Coastguard Worker 17*c8dee2aaSAndroid Build Coastguard Worker<!--?prettify?--> 18*c8dee2aaSAndroid Build Coastguard Worker``` js 19*c8dee2aaSAndroid Build Coastguard Worker<canvas id=foo width=300 height=300></canvas> 20*c8dee2aaSAndroid Build Coastguard Worker 21*c8dee2aaSAndroid Build Coastguard Worker<script type="text/javascript" 22*c8dee2aaSAndroid Build Coastguard Worker src="https://unpkg.com/[email protected]/bin/canvaskit.js"></script> 23*c8dee2aaSAndroid Build Coastguard Worker<script type="text/javascript"> 24*c8dee2aaSAndroid Build Coastguard Worker const ckLoaded = CanvasKitInit({ 25*c8dee2aaSAndroid Build Coastguard Worker locateFile: (file) => 'https://unpkg.com/[email protected]/bin/'+file}); 26*c8dee2aaSAndroid Build Coastguard Worker ckLoaded.then((CanvasKit) => { 27*c8dee2aaSAndroid Build Coastguard Worker const surface = CanvasKit.MakeCanvasSurface('foo'); 28*c8dee2aaSAndroid Build Coastguard Worker 29*c8dee2aaSAndroid Build Coastguard Worker const paint = new CanvasKit.Paint(); 30*c8dee2aaSAndroid Build Coastguard Worker paint.setColor(CanvasKit.Color4f(0.9, 0, 0, 1.0)); 31*c8dee2aaSAndroid Build Coastguard Worker paint.setStyle(CanvasKit.PaintStyle.Stroke); 32*c8dee2aaSAndroid Build Coastguard Worker paint.setAntiAlias(true); 33*c8dee2aaSAndroid Build Coastguard Worker const rr = CanvasKit.RRectXY(CanvasKit.LTRBRect(10, 60, 210, 260), 25, 15); 34*c8dee2aaSAndroid Build Coastguard Worker 35*c8dee2aaSAndroid Build Coastguard Worker function draw(canvas) { 36*c8dee2aaSAndroid Build Coastguard Worker canvas.clear(CanvasKit.WHITE); 37*c8dee2aaSAndroid Build Coastguard Worker canvas.drawRRect(rr, paint); 38*c8dee2aaSAndroid Build Coastguard Worker } 39*c8dee2aaSAndroid Build Coastguard Worker surface.drawOnce(draw); 40*c8dee2aaSAndroid Build Coastguard Worker }); 41*c8dee2aaSAndroid Build Coastguard Worker</script> 42*c8dee2aaSAndroid Build Coastguard Worker``` 43*c8dee2aaSAndroid Build Coastguard Worker 44*c8dee2aaSAndroid Build Coastguard Worker<canvas id=foo width=300 height=300></canvas> 45*c8dee2aaSAndroid Build Coastguard Worker 46*c8dee2aaSAndroid Build Coastguard Worker<script type="text/javascript" 47*c8dee2aaSAndroid Build Coastguard Worker src="https://unpkg.com/[email protected]/bin/canvaskit.js"></script> 48*c8dee2aaSAndroid Build Coastguard Worker<script type="text/javascript"> 49*c8dee2aaSAndroid Build Coastguard Worker const ckLoaded = CanvasKitInit({ 50*c8dee2aaSAndroid Build Coastguard Worker locateFile: (file) => 'https://unpkg.com/[email protected]/bin/'+file}); 51*c8dee2aaSAndroid Build Coastguard Worker ckLoaded.then((CanvasKit) => { 52*c8dee2aaSAndroid Build Coastguard Worker const surface = CanvasKit.MakeCanvasSurface('foo'); 53*c8dee2aaSAndroid Build Coastguard Worker 54*c8dee2aaSAndroid Build Coastguard Worker const paint = new CanvasKit.Paint(); 55*c8dee2aaSAndroid Build Coastguard Worker paint.setColor(CanvasKit.Color4f(0.9, 0, 0, 1.0)); 56*c8dee2aaSAndroid Build Coastguard Worker paint.setStyle(CanvasKit.PaintStyle.Stroke); 57*c8dee2aaSAndroid Build Coastguard Worker paint.setAntiAlias(true); 58*c8dee2aaSAndroid Build Coastguard Worker const rr = CanvasKit.RRectXY(CanvasKit.LTRBRect(10, 60, 210, 260), 25, 15); 59*c8dee2aaSAndroid Build Coastguard Worker 60*c8dee2aaSAndroid Build Coastguard Worker function draw(canvas) { 61*c8dee2aaSAndroid Build Coastguard Worker canvas.clear(CanvasKit.WHITE); 62*c8dee2aaSAndroid Build Coastguard Worker canvas.drawRRect(rr, paint); 63*c8dee2aaSAndroid Build Coastguard Worker } 64*c8dee2aaSAndroid Build Coastguard Worker surface.drawOnce(draw); 65*c8dee2aaSAndroid Build Coastguard Worker }); 66*c8dee2aaSAndroid Build Coastguard Worker</script> 67*c8dee2aaSAndroid Build Coastguard Worker 68*c8dee2aaSAndroid Build Coastguard WorkerLet's break it down into parts and explain what they are doing: 69*c8dee2aaSAndroid Build Coastguard Worker 70*c8dee2aaSAndroid Build Coastguard Worker`<canvas id=foo width=300 height=300></canvas>` Creates the canvas to which CanvasKit will draw. 71*c8dee2aaSAndroid Build Coastguard WorkerThis element is where we control the width and height of the drawing buffer, while it's css style 72*c8dee2aaSAndroid Build Coastguard Workerwould control any scaling applied after drawing to those pixels. Despite using a canvas element, 73*c8dee2aaSAndroid Build Coastguard WorkerCanvasKit isn't calling the HTML canvas's own draw methods. It is using this canvas element to 74*c8dee2aaSAndroid Build Coastguard Workerget a WebGL2 context and performing most of the drawing work in C++ code compiled to WebAssembly, 75*c8dee2aaSAndroid Build Coastguard Workerthen sending commands to the GPU at the end of each frame. 76*c8dee2aaSAndroid Build Coastguard Worker 77*c8dee2aaSAndroid Build Coastguard Worker<!--?prettify?--> 78*c8dee2aaSAndroid Build Coastguard Worker``` html 79*c8dee2aaSAndroid Build Coastguard Worker<script type="text/javascript" 80*c8dee2aaSAndroid Build Coastguard Worker src="https://unpkg.com/[email protected]/bin/canvaskit.js"></script> 81*c8dee2aaSAndroid Build Coastguard Worker``` 82*c8dee2aaSAndroid Build Coastguard Workerand 83*c8dee2aaSAndroid Build Coastguard Worker 84*c8dee2aaSAndroid Build Coastguard Worker<!--?prettify?--> 85*c8dee2aaSAndroid Build Coastguard Worker``` js 86*c8dee2aaSAndroid Build Coastguard Workerconst ckLoaded = CanvasKitInit({ 87*c8dee2aaSAndroid Build Coastguard Worker locateFile: (file) => 'https://unpkg.com/[email protected]/bin/'+file}); 88*c8dee2aaSAndroid Build Coastguard WorkerckLoaded.then((CanvasKit) => { 89*c8dee2aaSAndroid Build Coastguard Worker``` 90*c8dee2aaSAndroid Build Coastguard Workerare loading the canvaskit helper js and wasm binary respectively. CanvasKitInit accepts a function 91*c8dee2aaSAndroid Build Coastguard Workerfor allowing you to alter the path where it will try to find `canvaskit.wasm` and returns a promise 92*c8dee2aaSAndroid Build Coastguard Workerthat resolves with the loaded module, which we typically name `CanvasKit`. 93*c8dee2aaSAndroid Build Coastguard Worker 94*c8dee2aaSAndroid Build Coastguard Worker<!--?prettify?--> 95*c8dee2aaSAndroid Build Coastguard Worker``` js 96*c8dee2aaSAndroid Build Coastguard Workerconst surface = CanvasKit.MakeCanvasSurface('foo'); 97*c8dee2aaSAndroid Build Coastguard Worker``` 98*c8dee2aaSAndroid Build Coastguard WorkerCreates a Surface associated with the HTML canvas element above. 99*c8dee2aaSAndroid Build Coastguard WorkerHardware acceleration is the default behavior, but can be overridden by calling 100*c8dee2aaSAndroid Build Coastguard Worker`MakeSWCanvasSurface` instead. `MakeCanvasSurface` is also where alternative color spaces or gl 101*c8dee2aaSAndroid Build Coastguard Workerattrtributes can be specified. 102*c8dee2aaSAndroid Build Coastguard Worker 103*c8dee2aaSAndroid Build Coastguard Worker<!--?prettify?--> 104*c8dee2aaSAndroid Build Coastguard Worker``` js 105*c8dee2aaSAndroid Build Coastguard Workerconst paint = new CanvasKit.Paint(); 106*c8dee2aaSAndroid Build Coastguard Workerpaint.setColor(CanvasKit.Color4f(0.9, 0, 0, 1.0)); 107*c8dee2aaSAndroid Build Coastguard Workerpaint.setStyle(CanvasKit.PaintStyle.Stroke); 108*c8dee2aaSAndroid Build Coastguard Workerpaint.setAntiAlias(true); 109*c8dee2aaSAndroid Build Coastguard Workerconst rr = CanvasKit.RRectXY(CanvasKit.LTRBRect(10, 60, 210, 260), 25, 15); 110*c8dee2aaSAndroid Build Coastguard Worker``` 111*c8dee2aaSAndroid Build Coastguard WorkerCreates a paint, a description of how to fill or stroke rects, paths, text and other geometry in 112*c8dee2aaSAndroid Build Coastguard Workercanvaskit. `rr` is a rounded rect, with corners having a radius of 25 in the x axis, and 15 pixels 113*c8dee2aaSAndroid Build Coastguard Workerin the y axis. 114*c8dee2aaSAndroid Build Coastguard Worker 115*c8dee2aaSAndroid Build Coastguard Worker<!--?prettify?--> 116*c8dee2aaSAndroid Build Coastguard Worker``` js 117*c8dee2aaSAndroid Build Coastguard Workerfunction draw(canvas) { 118*c8dee2aaSAndroid Build Coastguard Worker canvas.clear(CanvasKit.WHITE); 119*c8dee2aaSAndroid Build Coastguard Worker canvas.drawRRect(rr, paint); 120*c8dee2aaSAndroid Build Coastguard Worker} 121*c8dee2aaSAndroid Build Coastguard Worker``` 122*c8dee2aaSAndroid Build Coastguard WorkerDefines a function that will draw our frame. The function is provided a Canvas object on which we 123*c8dee2aaSAndroid Build Coastguard Workermake draw calls. One to clear the entire canvas, and one to draw the rounded rect with the 124*c8dee2aaSAndroid Build Coastguard Workerpaint from above. 125*c8dee2aaSAndroid Build Coastguard Worker 126*c8dee2aaSAndroid Build Coastguard WorkerWe also delete the paint object. CanvasKit objects created with `new` or methods prefixed with 127*c8dee2aaSAndroid Build Coastguard Worker`make` must be deleted for the wasm memory to be released. Javascript's GC will not take care of 128*c8dee2aaSAndroid Build Coastguard Workerit automatically. `rr` is just an array, wasn't created with `new` and doesn't point to any WASM 129*c8dee2aaSAndroid Build Coastguard Workermemory, so we don't have to call delete on it. 130*c8dee2aaSAndroid Build Coastguard Worker 131*c8dee2aaSAndroid Build Coastguard Worker<!--?prettify?--> 132*c8dee2aaSAndroid Build Coastguard Worker``` js 133*c8dee2aaSAndroid Build Coastguard Workersurface.drawOnce(draw); 134*c8dee2aaSAndroid Build Coastguard Workerpaint.delete() 135*c8dee2aaSAndroid Build Coastguard Worker``` 136*c8dee2aaSAndroid Build Coastguard WorkerHand the drawing function to `surface.drawOnce` which makes the calls and flushes the surface. 137*c8dee2aaSAndroid Build Coastguard WorkerUpon flushing, Skia will batch and send WebGL commands, making visible changes appear onscreen. 138*c8dee2aaSAndroid Build Coastguard WorkerThis example draws once and disposes of the surface. As promised, it is is a minimal 139*c8dee2aaSAndroid Build Coastguard Workerapplication. 140*c8dee2aaSAndroid Build Coastguard Worker 141*c8dee2aaSAndroid Build Coastguard WorkerBasic Draw Loop 142*c8dee2aaSAndroid Build Coastguard Worker--------------- 143*c8dee2aaSAndroid Build Coastguard Worker 144*c8dee2aaSAndroid Build Coastguard WorkerWhat if we need to redraw to our canvas every frame? This example 145*c8dee2aaSAndroid Build Coastguard Workerbounces a rounded rect around like a 90s screensaver. 146*c8dee2aaSAndroid Build Coastguard Worker 147*c8dee2aaSAndroid Build Coastguard Worker<!--?prettify?--> 148*c8dee2aaSAndroid Build Coastguard Worker``` js 149*c8dee2aaSAndroid Build Coastguard WorkerckLoaded.then((CanvasKit) => { 150*c8dee2aaSAndroid Build Coastguard Worker const surface = CanvasKit.MakeCanvasSurface('foo2'); 151*c8dee2aaSAndroid Build Coastguard Worker 152*c8dee2aaSAndroid Build Coastguard Worker const paint = new CanvasKit.Paint(); 153*c8dee2aaSAndroid Build Coastguard Worker paint.setColor(CanvasKit.Color4f(0.9, 0, 0, 1.0)); 154*c8dee2aaSAndroid Build Coastguard Worker paint.setStyle(CanvasKit.PaintStyle.Stroke); 155*c8dee2aaSAndroid Build Coastguard Worker paint.setAntiAlias(true); 156*c8dee2aaSAndroid Build Coastguard Worker // const rr = CanvasKit.RRectXY(CanvasKit.LTRBRect(10, 60, 210, 260), 25, 15); 157*c8dee2aaSAndroid Build Coastguard Worker const w = 100; // size of rect 158*c8dee2aaSAndroid Build Coastguard Worker const h = 60; 159*c8dee2aaSAndroid Build Coastguard Worker let x = 10; // initial position of top left corner. 160*c8dee2aaSAndroid Build Coastguard Worker let y = 60; 161*c8dee2aaSAndroid Build Coastguard Worker let dirX = 1; // box is always moving at a constant speed in one of the four diagonal directions 162*c8dee2aaSAndroid Build Coastguard Worker let dirY = 1; 163*c8dee2aaSAndroid Build Coastguard Worker 164*c8dee2aaSAndroid Build Coastguard Worker function drawFrame(canvas) { 165*c8dee2aaSAndroid Build Coastguard Worker // boundary check 166*c8dee2aaSAndroid Build Coastguard Worker if (x < 0 || x+w > 300) { 167*c8dee2aaSAndroid Build Coastguard Worker dirX *= -1; // reverse x direction when hitting side walls 168*c8dee2aaSAndroid Build Coastguard Worker } 169*c8dee2aaSAndroid Build Coastguard Worker if (y < 0 || y+h > 300) { 170*c8dee2aaSAndroid Build Coastguard Worker dirY *= -1; // reverse y direction when hitting top and bottom walls 171*c8dee2aaSAndroid Build Coastguard Worker } 172*c8dee2aaSAndroid Build Coastguard Worker // move 173*c8dee2aaSAndroid Build Coastguard Worker x += dirX; 174*c8dee2aaSAndroid Build Coastguard Worker y += dirY; 175*c8dee2aaSAndroid Build Coastguard Worker 176*c8dee2aaSAndroid Build Coastguard Worker canvas.clear(CanvasKit.WHITE); 177*c8dee2aaSAndroid Build Coastguard Worker const rr = CanvasKit.RRectXY(CanvasKit.LTRBRect(x, y, x+w, y+h), 25, 15); 178*c8dee2aaSAndroid Build Coastguard Worker canvas.drawRRect(rr, paint); 179*c8dee2aaSAndroid Build Coastguard Worker surface.requestAnimationFrame(drawFrame); 180*c8dee2aaSAndroid Build Coastguard Worker } 181*c8dee2aaSAndroid Build Coastguard Worker surface.requestAnimationFrame(drawFrame); 182*c8dee2aaSAndroid Build Coastguard Worker}); 183*c8dee2aaSAndroid Build Coastguard Worker``` 184*c8dee2aaSAndroid Build Coastguard Worker 185*c8dee2aaSAndroid Build Coastguard Worker<canvas id=foo2 width=300 height=300></canvas> 186*c8dee2aaSAndroid Build Coastguard Worker 187*c8dee2aaSAndroid Build Coastguard Worker<script type="text/javascript"> 188*c8dee2aaSAndroid Build Coastguard Worker ckLoaded.then((CanvasKit) => { 189*c8dee2aaSAndroid Build Coastguard Worker const surface = CanvasKit.MakeCanvasSurface('foo2'); 190*c8dee2aaSAndroid Build Coastguard Worker 191*c8dee2aaSAndroid Build Coastguard Worker const paint = new CanvasKit.Paint(); 192*c8dee2aaSAndroid Build Coastguard Worker paint.setColor(CanvasKit.Color4f(0.9, 0, 0, 1.0)); 193*c8dee2aaSAndroid Build Coastguard Worker paint.setStyle(CanvasKit.PaintStyle.Stroke); 194*c8dee2aaSAndroid Build Coastguard Worker paint.setAntiAlias(true); 195*c8dee2aaSAndroid Build Coastguard Worker // const rr = CanvasKit.RRectXY(CanvasKit.LTRBRect(10, 60, 210, 260), 25, 15); 196*c8dee2aaSAndroid Build Coastguard Worker const w = 100; // size of rect 197*c8dee2aaSAndroid Build Coastguard Worker const h = 60; 198*c8dee2aaSAndroid Build Coastguard Worker let x = 10; // initial position of top left corner. 199*c8dee2aaSAndroid Build Coastguard Worker let y = 60; 200*c8dee2aaSAndroid Build Coastguard Worker // The box is always moving at a constant speed in one of the four diagonal directions 201*c8dee2aaSAndroid Build Coastguard Worker let dirX = 1; 202*c8dee2aaSAndroid Build Coastguard Worker let dirY = 1; 203*c8dee2aaSAndroid Build Coastguard Worker 204*c8dee2aaSAndroid Build Coastguard Worker function drawFrame(canvas) { 205*c8dee2aaSAndroid Build Coastguard Worker // boundary check 206*c8dee2aaSAndroid Build Coastguard Worker if (x < 0 || x+w > 300) { 207*c8dee2aaSAndroid Build Coastguard Worker dirX *= -1; // reverse x direction when hitting side walls 208*c8dee2aaSAndroid Build Coastguard Worker } 209*c8dee2aaSAndroid Build Coastguard Worker if (y < 0 || y+h > 300) { 210*c8dee2aaSAndroid Build Coastguard Worker dirY *= -1; // reverse y direction when hitting top and bottom walls 211*c8dee2aaSAndroid Build Coastguard Worker } 212*c8dee2aaSAndroid Build Coastguard Worker // move 213*c8dee2aaSAndroid Build Coastguard Worker x += dirX; 214*c8dee2aaSAndroid Build Coastguard Worker y += dirY; 215*c8dee2aaSAndroid Build Coastguard Worker 216*c8dee2aaSAndroid Build Coastguard Worker canvas.clear(CanvasKit.WHITE); 217*c8dee2aaSAndroid Build Coastguard Worker const rr = CanvasKit.RRectXY(CanvasKit.LTRBRect(x, y, x+w, y+h), 25, 15); 218*c8dee2aaSAndroid Build Coastguard Worker canvas.drawRRect(rr, paint); 219*c8dee2aaSAndroid Build Coastguard Worker surface.requestAnimationFrame(drawFrame); 220*c8dee2aaSAndroid Build Coastguard Worker } 221*c8dee2aaSAndroid Build Coastguard Worker surface.requestAnimationFrame(drawFrame); 222*c8dee2aaSAndroid Build Coastguard Worker }); 223*c8dee2aaSAndroid Build Coastguard Worker</script> 224*c8dee2aaSAndroid Build Coastguard Worker 225*c8dee2aaSAndroid Build Coastguard WorkerThe main difference here is that we define a function to be called before each frame is drawn and 226*c8dee2aaSAndroid Build Coastguard Workerpass it to `surface.requestAnimationFrame(drawFrame);` That callback is handed a `canvas` and 227*c8dee2aaSAndroid Build Coastguard Workerflushing is taken care of. 228*c8dee2aaSAndroid Build Coastguard Worker 229*c8dee2aaSAndroid Build Coastguard Worker<!--?prettify?--> 230*c8dee2aaSAndroid Build Coastguard Worker``` js 231*c8dee2aaSAndroid Build Coastguard Workerfunction drawFrame(canvas) { 232*c8dee2aaSAndroid Build Coastguard Worker canvas.clear(CanvasKit.WHITE); 233*c8dee2aaSAndroid Build Coastguard Worker // code to update and draw the frame goes here 234*c8dee2aaSAndroid Build Coastguard Worker surface.requestAnimationFrame(drawFrame); 235*c8dee2aaSAndroid Build Coastguard Worker} 236*c8dee2aaSAndroid Build Coastguard Workersurface.requestAnimationFrame(drawFrame); 237*c8dee2aaSAndroid Build Coastguard Worker``` 238*c8dee2aaSAndroid Build Coastguard Worker 239*c8dee2aaSAndroid Build Coastguard WorkerCreates a function to serve as our main drawing loop. Each time a frame is about to be rendered 240*c8dee2aaSAndroid Build Coastguard Worker(the browser will typically target 60fps), our function is called, we clear the canvas with white, 241*c8dee2aaSAndroid Build Coastguard Workerredraw the round rect, and call `surface.requestAnimationFrame(drawFrame)` registering the 242*c8dee2aaSAndroid Build Coastguard Workerfunction to be called again before the next frame. 243*c8dee2aaSAndroid Build Coastguard Worker 244*c8dee2aaSAndroid Build Coastguard Worker`surface.requestAnimationFrame(drawFrame)` combines window.requestAnimationFrame with 245*c8dee2aaSAndroid Build Coastguard Worker`surface.flush()` and should be used in all the same ways. If your application would only make 246*c8dee2aaSAndroid Build Coastguard Workervisible changes as a result of mouse events, 247*c8dee2aaSAndroid Build Coastguard Workerdon't call `surface.requestAnimationFrame` at the end of your drawFrame function. Call it only 248*c8dee2aaSAndroid Build Coastguard Workerafter handling mouse input. 249*c8dee2aaSAndroid Build Coastguard Worker 250*c8dee2aaSAndroid Build Coastguard WorkerText Shaping 251*c8dee2aaSAndroid Build Coastguard Worker------------ 252*c8dee2aaSAndroid Build Coastguard Worker 253*c8dee2aaSAndroid Build Coastguard WorkerOne of the biggest features that CanvasKit offers over the HTML Canvas API is paragraph shaping. 254*c8dee2aaSAndroid Build Coastguard WorkerTo use text your applicatoin, supply a font file and use Promise.all to run your code when both 255*c8dee2aaSAndroid Build Coastguard WorkerCanvasKit and the font file are ready. 256*c8dee2aaSAndroid Build Coastguard Worker 257*c8dee2aaSAndroid Build Coastguard Worker<!--?prettify?--> 258*c8dee2aaSAndroid Build Coastguard Worker``` js 259*c8dee2aaSAndroid Build Coastguard Workerconst loadFont = fetch('https://storage.googleapis.com/skia-cdn/misc/Roboto-Regular.ttf') 260*c8dee2aaSAndroid Build Coastguard Worker .then((response) => response.arrayBuffer()); 261*c8dee2aaSAndroid Build Coastguard Worker 262*c8dee2aaSAndroid Build Coastguard WorkerPromise.all([ckLoaded, loadFont]).then(([CanvasKit, robotoData]) => { 263*c8dee2aaSAndroid Build Coastguard Worker const surface = CanvasKit.MakeCanvasSurface('foo3'); 264*c8dee2aaSAndroid Build Coastguard Worker const canvas = surface.getCanvas(); 265*c8dee2aaSAndroid Build Coastguard Worker canvas.clear(CanvasKit.Color4f(0.9, 0.9, 0.9, 1.0)); 266*c8dee2aaSAndroid Build Coastguard Worker 267*c8dee2aaSAndroid Build Coastguard Worker const fontMgr = CanvasKit.FontMgr.FromData([robotoData]); 268*c8dee2aaSAndroid Build Coastguard Worker const paraStyle = new CanvasKit.ParagraphStyle({ 269*c8dee2aaSAndroid Build Coastguard Worker textStyle: { 270*c8dee2aaSAndroid Build Coastguard Worker color: CanvasKit.BLACK, 271*c8dee2aaSAndroid Build Coastguard Worker fontFamilies: ['Roboto'], 272*c8dee2aaSAndroid Build Coastguard Worker fontSize: 28, 273*c8dee2aaSAndroid Build Coastguard Worker }, 274*c8dee2aaSAndroid Build Coastguard Worker textAlign: CanvasKit.TextAlign.Left, 275*c8dee2aaSAndroid Build Coastguard Worker }); 276*c8dee2aaSAndroid Build Coastguard Worker const text = 'Any sufficiently entrenched technology is indistinguishable from Javascript'; 277*c8dee2aaSAndroid Build Coastguard Worker const builder = CanvasKit.ParagraphBuilder.Make(paraStyle, fontMgr); 278*c8dee2aaSAndroid Build Coastguard Worker builder.addText(text); 279*c8dee2aaSAndroid Build Coastguard Worker const paragraph = builder.build(); 280*c8dee2aaSAndroid Build Coastguard Worker paragraph.layout(290); // width in pixels to use when wrapping text 281*c8dee2aaSAndroid Build Coastguard Worker canvas.drawParagraph(paragraph, 10, 10); 282*c8dee2aaSAndroid Build Coastguard Worker surface.flush(); 283*c8dee2aaSAndroid Build Coastguard Worker}); 284*c8dee2aaSAndroid Build Coastguard Worker``` 285*c8dee2aaSAndroid Build Coastguard Worker 286*c8dee2aaSAndroid Build Coastguard Worker<canvas id=foo3 width=300 height=300></canvas> 287*c8dee2aaSAndroid Build Coastguard Worker 288*c8dee2aaSAndroid Build Coastguard Worker<script type="text/javascript"> 289*c8dee2aaSAndroid Build Coastguard Workerconst loadFont = fetch('https://storage.googleapis.com/skia-cdn/misc/Roboto-Regular.ttf') 290*c8dee2aaSAndroid Build Coastguard Worker .then((response) => response.arrayBuffer()); 291*c8dee2aaSAndroid Build Coastguard Worker 292*c8dee2aaSAndroid Build Coastguard WorkerPromise.all([ckLoaded, loadFont]).then(([CanvasKit, robotoData]) => { 293*c8dee2aaSAndroid Build Coastguard Worker const surface = CanvasKit.MakeCanvasSurface('foo3'); 294*c8dee2aaSAndroid Build Coastguard Worker const canvas = surface.getCanvas(); 295*c8dee2aaSAndroid Build Coastguard Worker canvas.clear(CanvasKit.Color4f(0.9, 0.9, 0.9, 1.0)); 296*c8dee2aaSAndroid Build Coastguard Worker 297*c8dee2aaSAndroid Build Coastguard Worker const fontMgr = CanvasKit.FontMgr.FromData([robotoData]); 298*c8dee2aaSAndroid Build Coastguard Worker const paraStyle = new CanvasKit.ParagraphStyle({ 299*c8dee2aaSAndroid Build Coastguard Worker textStyle: { 300*c8dee2aaSAndroid Build Coastguard Worker color: CanvasKit.BLACK, 301*c8dee2aaSAndroid Build Coastguard Worker fontFamilies: ['Roboto'], 302*c8dee2aaSAndroid Build Coastguard Worker fontSize: 28, 303*c8dee2aaSAndroid Build Coastguard Worker }, 304*c8dee2aaSAndroid Build Coastguard Worker textAlign: CanvasKit.TextAlign.Left, 305*c8dee2aaSAndroid Build Coastguard Worker }); 306*c8dee2aaSAndroid Build Coastguard Worker const text = 'Any sufficiently entrenched technology is indistinguishable from Javascript'; 307*c8dee2aaSAndroid Build Coastguard Worker const builder = CanvasKit.ParagraphBuilder.Make(paraStyle, fontMgr); 308*c8dee2aaSAndroid Build Coastguard Worker builder.addText(text); 309*c8dee2aaSAndroid Build Coastguard Worker const paragraph = builder.build(); 310*c8dee2aaSAndroid Build Coastguard Worker paragraph.layout(290); // width in pixels to use when wrapping text 311*c8dee2aaSAndroid Build Coastguard Worker canvas.drawParagraph(paragraph, 10, 10); 312*c8dee2aaSAndroid Build Coastguard Worker surface.flush(); 313*c8dee2aaSAndroid Build Coastguard Worker}); 314*c8dee2aaSAndroid Build Coastguard Worker</script> 315*c8dee2aaSAndroid Build Coastguard Worker 316*c8dee2aaSAndroid Build Coastguard Worker<!--?prettify?--> 317*c8dee2aaSAndroid Build Coastguard Worker``` js 318*c8dee2aaSAndroid Build Coastguard Workerconst fontMgr = CanvasKit.FontMgr.FromData([robotoData]); 319*c8dee2aaSAndroid Build Coastguard Worker``` 320*c8dee2aaSAndroid Build Coastguard WorkerCreates an object that provides fonts by name to various text facilities in CanvasKit. You could 321*c8dee2aaSAndroid Build Coastguard Workerload more than one font in this statement if needed. 322*c8dee2aaSAndroid Build Coastguard Worker 323*c8dee2aaSAndroid Build Coastguard Worker<!--?prettify?--> 324*c8dee2aaSAndroid Build Coastguard Worker``` js 325*c8dee2aaSAndroid Build Coastguard Workerconst paraStyle = new CanvasKit.ParagraphStyle({ 326*c8dee2aaSAndroid Build Coastguard Worker textStyle: { 327*c8dee2aaSAndroid Build Coastguard Worker color: CanvasKit.BLACK, 328*c8dee2aaSAndroid Build Coastguard Worker fontFamilies: ['Roboto'], 329*c8dee2aaSAndroid Build Coastguard Worker fontSize: 28, 330*c8dee2aaSAndroid Build Coastguard Worker }, 331*c8dee2aaSAndroid Build Coastguard Worker textAlign: CanvasKit.TextAlign.Left, 332*c8dee2aaSAndroid Build Coastguard Worker}); 333*c8dee2aaSAndroid Build Coastguard Worker``` 334*c8dee2aaSAndroid Build Coastguard WorkerSpecifies the style of the text. The font's name, Roboto, will be used to fetch it from the font 335*c8dee2aaSAndroid Build Coastguard Workermanager. You can specify either (color) or (foregroundColor and backgroundColor) in order to have 336*c8dee2aaSAndroid Build Coastguard Workera highlight. For the full documentation of the API, check out the Typescript definitions in the 337*c8dee2aaSAndroid Build Coastguard Worker`types/` subfolder of the npm package or in the 338*c8dee2aaSAndroid Build Coastguard Worker[Skia repo](https://github.com/google/skia/tree/main/modules/canvaskit/npm_build/types). 339*c8dee2aaSAndroid Build Coastguard Worker 340*c8dee2aaSAndroid Build Coastguard Worker<!--?prettify?--> 341*c8dee2aaSAndroid Build Coastguard Worker``` js 342*c8dee2aaSAndroid Build Coastguard Workerconst builder = CanvasKit.ParagraphBuilder.Make(paraStyle, fontMgr); 343*c8dee2aaSAndroid Build Coastguard Workerbuilder.addText(text); 344*c8dee2aaSAndroid Build Coastguard Workerconst paragraph = builder.build(); 345*c8dee2aaSAndroid Build Coastguard Worker``` 346*c8dee2aaSAndroid Build Coastguard WorkerNext, we create a `ParagraphBuilder` with a style, add some text, and finalize it with `build()`. 347*c8dee2aaSAndroid Build Coastguard WorkerAlternatively, we could use multiple `TextStyle`s in one paragraph with 348*c8dee2aaSAndroid Build Coastguard Worker 349*c8dee2aaSAndroid Build Coastguard Worker<!--?prettify?--> 350*c8dee2aaSAndroid Build Coastguard Worker``` js 351*c8dee2aaSAndroid Build Coastguard Workerconst builder = CanvasKit.ParagraphBuilder.Make(paraStyle, fontMgr); 352*c8dee2aaSAndroid Build Coastguard Workerbuilder.addText(text1); 353*c8dee2aaSAndroid Build Coastguard Workerconst boldTextStyle = CanvasKit.TextStyle({ 354*c8dee2aaSAndroid Build Coastguard Worker color: CanvasKit.BLACK, 355*c8dee2aaSAndroid Build Coastguard Worker fontFamilies: ['Roboto'], 356*c8dee2aaSAndroid Build Coastguard Worker fontSize: 28, 357*c8dee2aaSAndroid Build Coastguard Worker fontStyle: {'weight': CanvasKit.FontWeight.Bold}, 358*c8dee2aaSAndroid Build Coastguard Worker}) 359*c8dee2aaSAndroid Build Coastguard Workerbuilder.pushStyle(boldTextStyle); 360*c8dee2aaSAndroid Build Coastguard Workerbuilder.addText(text2); 361*c8dee2aaSAndroid Build Coastguard Workerbuilder.pop(); 362*c8dee2aaSAndroid Build Coastguard Workerbuilder.addText(text3); 363*c8dee2aaSAndroid Build Coastguard Workerconst paragraph = builder.build(); 364*c8dee2aaSAndroid Build Coastguard Worker``` 365*c8dee2aaSAndroid Build Coastguard WorkerFinally, we *layout* the paragraph, meaning wrap the text to a particular width, and draw it to 366*c8dee2aaSAndroid Build Coastguard Workerthe canvas with 367*c8dee2aaSAndroid Build Coastguard Worker 368*c8dee2aaSAndroid Build Coastguard Worker<!--?prettify?--> 369*c8dee2aaSAndroid Build Coastguard Worker``` js 370*c8dee2aaSAndroid Build Coastguard Workerparagraph.layout(290); // width in pixels to use when wrapping text 371*c8dee2aaSAndroid Build Coastguard Workercanvas.drawParagraph(paragraph, 10, 10); // (x, y) position of left top corner of paragraph. 372*c8dee2aaSAndroid Build Coastguard Worker``` 373*c8dee2aaSAndroid Build Coastguard Worker 374