1<!DOCTYPE html>
2<title>TextEdit demo in CanvasKit</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<script type="text/javascript" src="https://particles.skia.org/dist/canvaskit.js"></script>
7<script type="text/javascript" src="textapi_utils.js"></script>
8<script type="text/javascript" src="spiralshader.js"></script>
9
10<style>
11canvas {
12  border: 1px dashed grey;
13}
14</style>
15
16<body>
17  <h1>TextEdit in CanvasKit</h1>
18
19  <canvas id=para2 width=600 height=600 tabindex='-1'></canvas>
20</body>
21
22<script type="text/javascript" charset="utf-8">
23    let CanvasKit;
24    onload = async () => {
25      CanvasKit = await CanvasKitInit({ locateFile: (file) => 'https://particles.skia.org/dist/'+file });
26      ParagraphAPI2();
27    };
28
29    function ParagraphAPI2() {
30      const surface = CanvasKit.MakeCanvasSurface('para2');
31      if (!surface) {
32        console.error('Could not make surface');
33        return;
34      }
35
36      const mouse = MakeMouse();
37      const cursor = MakeCursor(CanvasKit);
38      const canvas = surface.getCanvas();
39      const spiralEffect = MakeSpiralShaderEffect(CanvasKit);
40
41      const text0 = "In a hole in the ground there lived a hobbit. Not a nasty, dirty, " +
42                    "wet hole full of worms and oozy smells. This was a hobbit-hole and " +
43                    "that means good food, a warm hearth, and all the comforts of home.";
44      const LOC_X = 20,
45            LOC_Y = 20;
46
47      const bgPaint = new CanvasKit.Paint();
48      bgPaint.setColor([0.965, 0.965, 0.965, 1]);
49
50      const editor = MakeEditor(text0, {typeface:null, size:30}, cursor, 540);
51
52      editor.applyStyleToRange({size:130}, 0, 1);
53      editor.applyStyleToRange({italic:true}, 38, 38+6);
54      editor.applyStyleToRange({color:[1,0,0,1]}, 5, 5+4);
55
56      editor.setXY(LOC_X, LOC_Y);
57
58      function drawFrame(canvas) {
59        const lines = editor.getLines();
60
61        canvas.clear(CanvasKit.WHITE);
62
63        if (mouse.isActive()) {
64            const pos = mouse.getPos(-LOC_X, -LOC_Y);
65            const a = lines_pos_to_index(lines, pos[0], pos[1]);
66            const b = lines_pos_to_index(lines, pos[2], pos[3]);
67            if (a === b) {
68                editor.setIndex(a);
69            } else {
70                editor.setIndices(a, b);
71            }
72        }
73
74        canvas.drawRect(editor.bounds(), bgPaint);
75
76        {
77            // update our animated shaders
78            const rad_scale = Math.sin(Date.now() / 5000) / 2;
79            const shader0 = spiralEffect.makeShader([
80                rad_scale,
81                editor.width()/2, editor.width()/2,
82                1,0,0,1,                            // color0
83                0,0,1,1                             // color1
84             ]);
85            editor.draw(canvas, [shader0]);
86            shader0.delete();
87        }
88
89        surface.requestAnimationFrame(drawFrame);
90      }
91      surface.requestAnimationFrame(drawFrame);
92
93      function interact(e) {
94        const type = e.type;
95        if (type === 'pointerup') {
96            mouse.setUp(e.offsetX, e.offsetY);
97        } else if (type === 'pointermove') {
98            mouse.setMove(e.offsetX, e.offsetY);
99        } else if (type === 'pointerdown') {
100            mouse.setDown(e.offsetX, e.offsetY);
101        }
102      };
103
104      function keyhandler(e) {
105          switch (e.key) {
106              case 'ArrowLeft':  editor.moveDX(-1); return;
107              case 'ArrowRight': editor.moveDX(1); return;
108              case 'ArrowUp':
109                e.preventDefault();
110                editor.moveDY(-1);
111                return;
112              case 'ArrowDown':
113                e.preventDefault();
114                editor.moveDY(1);
115                return;
116            case 'Backspace':
117                editor.deleteSelection(-1);
118                return;
119            case 'Delete':
120                editor.deleteSelection(1);
121                return;
122              case 'Shift':
123                return;
124              case 'Tab':   // todo: figure out how to handle...
125                e.preventDefault();
126                return;
127            }
128            if (e.ctrlKey) {
129                e.preventDefault();
130                e.stopImmediatePropagation();
131                switch (e.key) {
132                    case 'r': editor.applyStyleToSelection({color:[1,0,0,1]}); return;
133                    case 'g': editor.applyStyleToSelection({color:[0,0.6,0,1]}); return;
134                    case 'u': editor.applyStyleToSelection({color:[0,0,1,1]}); return;
135                    case 'k': editor.applyStyleToSelection({color:[0,0,0,1]}); return;
136
137                    case 's': editor.applyStyleToSelection({shaderIndex:0}); return;
138
139                    case 'i': editor.applyStyleToSelection({italic:'toggle'}); return;
140                    case 'b': editor.applyStyleToSelection({bold:'toggle'}); return;
141
142                    case ']': editor.applyStyleToSelection({size_add:1});  return;
143                    case '[': editor.applyStyleToSelection({size_add:-1}); return;
144                    case '}': editor.applyStyleToSelection({size_add:10});  return;
145                    case '{': editor.applyStyleToSelection({size_add:-10}); return;
146                }
147            }
148            if (!e.ctrlKey && !e.metaKey) {
149                if (e.key.length == 1) {  // avoid keys like "Escape" for now
150                    e.preventDefault();
151                    e.stopImmediatePropagation();
152                    editor.insert(e.key);
153                }
154            }
155      }
156
157      document.getElementById('para2').addEventListener('pointermove', interact);
158      document.getElementById('para2').addEventListener('pointerdown', interact);
159      document.getElementById('para2').addEventListener('pointerup', interact);
160      document.getElementById('para2').addEventListener('keydown', keyhandler);
161      return surface;
162    }
163
164</script>
165