blob: d6852c8bb9dd992cb73c33d1856a0d322118ee10 [file] [log] [blame]
Kaido Kertb1089432024-03-18 19:46:49 -07001<!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 case 'w': editor.applyStyleToSelection({wavy:'toggle'}); return;
142
143 case ']': editor.applyStyleToSelection({size_add:1}); return;
144 case '[': editor.applyStyleToSelection({size_add:-1}); return;
145 case '}': editor.applyStyleToSelection({size_add:10}); return;
146 case '{': editor.applyStyleToSelection({size_add:-10}); return;
147 }
148 }
149 if (!e.ctrlKey && !e.metaKey) {
150 if (e.key.length == 1) { // avoid keys like "Escape" for now
151 e.preventDefault();
152 e.stopImmediatePropagation();
153 editor.insert(e.key);
154 }
155 }
156 }
157
158 document.getElementById('para2').addEventListener('pointermove', interact);
159 document.getElementById('para2').addEventListener('pointerdown', interact);
160 document.getElementById('para2').addEventListener('pointerup', interact);
161 document.getElementById('para2').addEventListener('keydown', keyhandler);
162 return surface;
163 }
164
165</script>