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