| <!DOCTYPE html> |
| <title>TextEdit demo in CanvasKit</title> |
| <meta charset="utf-8" /> |
| <meta http-equiv="X-UA-Compatible" content="IE=edge"> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| <script type="text/javascript" src="https://particles.skia.org/dist/canvaskit.js"></script> |
| <script type="text/javascript" src="textapi_utils.js"></script> |
| <script type="text/javascript" src="spiralshader.js"></script> |
| |
| <style> |
| canvas { |
| border: 1px dashed grey; |
| } |
| </style> |
| |
| <body> |
| <h1>TextEdit in CanvasKit</h1> |
| |
| <canvas id=para2 width=600 height=600 tabindex='-1'></canvas> |
| </body> |
| |
| <script type="text/javascript" charset="utf-8"> |
| let CanvasKit; |
| onload = async () => { |
| CanvasKit = await CanvasKitInit({ locateFile: (file) => 'https://particles.skia.org/dist/'+file }); |
| ParagraphAPI2(); |
| }; |
| |
| function ParagraphAPI2() { |
| const surface = CanvasKit.MakeCanvasSurface('para2'); |
| if (!surface) { |
| console.error('Could not make surface'); |
| return; |
| } |
| |
| const mouse = MakeMouse(); |
| const cursor = MakeCursor(CanvasKit); |
| const canvas = surface.getCanvas(); |
| const spiralEffect = MakeSpiralShaderEffect(CanvasKit); |
| |
| const text0 = "In a hole in the ground there lived a hobbit. Not a nasty, dirty, " + |
| "wet hole full of worms and oozy smells. This was a hobbit-hole and " + |
| "that means good food, a warm hearth, and all the comforts of home."; |
| const LOC_X = 20, |
| LOC_Y = 20; |
| |
| const bgPaint = new CanvasKit.Paint(); |
| bgPaint.setColor([0.965, 0.965, 0.965, 1]); |
| |
| const editor = MakeEditor(text0, {typeface:null, size:30}, cursor, 540); |
| |
| editor.applyStyleToRange({size:130}, 0, 1); |
| editor.applyStyleToRange({italic:true}, 38, 38+6); |
| editor.applyStyleToRange({color:[1,0,0,1]}, 5, 5+4); |
| |
| editor.setXY(LOC_X, LOC_Y); |
| |
| function drawFrame(canvas) { |
| const lines = editor.getLines(); |
| |
| canvas.clear(CanvasKit.WHITE); |
| |
| if (mouse.isActive()) { |
| const pos = mouse.getPos(-LOC_X, -LOC_Y); |
| const a = lines_pos_to_index(lines, pos[0], pos[1]); |
| const b = lines_pos_to_index(lines, pos[2], pos[3]); |
| if (a === b) { |
| editor.setIndex(a); |
| } else { |
| editor.setIndices(a, b); |
| } |
| } |
| |
| canvas.drawRect(editor.bounds(), bgPaint); |
| |
| { |
| // update our animated shaders |
| const rad_scale = Math.sin(Date.now() / 5000) / 2; |
| const shader0 = spiralEffect.makeShader([ |
| rad_scale, |
| editor.width()/2, editor.width()/2, |
| 1,0,0,1, // color0 |
| 0,0,1,1 // color1 |
| ]); |
| editor.draw(canvas, [shader0]); |
| shader0.delete(); |
| } |
| |
| surface.requestAnimationFrame(drawFrame); |
| } |
| surface.requestAnimationFrame(drawFrame); |
| |
| function interact(e) { |
| const type = e.type; |
| if (type === 'pointerup') { |
| mouse.setUp(e.offsetX, e.offsetY); |
| } else if (type === 'pointermove') { |
| mouse.setMove(e.offsetX, e.offsetY); |
| } else if (type === 'pointerdown') { |
| mouse.setDown(e.offsetX, e.offsetY); |
| } |
| }; |
| |
| function keyhandler(e) { |
| switch (e.key) { |
| case 'ArrowLeft': editor.moveDX(-1); return; |
| case 'ArrowRight': editor.moveDX(1); return; |
| case 'ArrowUp': |
| e.preventDefault(); |
| editor.moveDY(-1); |
| return; |
| case 'ArrowDown': |
| e.preventDefault(); |
| editor.moveDY(1); |
| return; |
| case 'Backspace': |
| editor.deleteSelection(-1); |
| return; |
| case 'Delete': |
| editor.deleteSelection(1); |
| return; |
| case 'Shift': |
| return; |
| case 'Tab': // todo: figure out how to handle... |
| e.preventDefault(); |
| return; |
| } |
| if (e.ctrlKey) { |
| e.preventDefault(); |
| e.stopImmediatePropagation(); |
| switch (e.key) { |
| case 'r': editor.applyStyleToSelection({color:[1,0,0,1]}); return; |
| case 'g': editor.applyStyleToSelection({color:[0,0.6,0,1]}); return; |
| case 'u': editor.applyStyleToSelection({color:[0,0,1,1]}); return; |
| case 'k': editor.applyStyleToSelection({color:[0,0,0,1]}); return; |
| |
| case 's': editor.applyStyleToSelection({shaderIndex:0}); return; |
| |
| case 'i': editor.applyStyleToSelection({italic:'toggle'}); return; |
| case 'b': editor.applyStyleToSelection({bold:'toggle'}); return; |
| case 'w': editor.applyStyleToSelection({wavy:'toggle'}); return; |
| |
| case ']': editor.applyStyleToSelection({size_add:1}); return; |
| case '[': editor.applyStyleToSelection({size_add:-1}); return; |
| case '}': editor.applyStyleToSelection({size_add:10}); return; |
| case '{': editor.applyStyleToSelection({size_add:-10}); return; |
| } |
| } |
| if (!e.ctrlKey && !e.metaKey) { |
| if (e.key.length == 1) { // avoid keys like "Escape" for now |
| e.preventDefault(); |
| e.stopImmediatePropagation(); |
| editor.insert(e.key); |
| } |
| } |
| } |
| |
| document.getElementById('para2').addEventListener('pointermove', interact); |
| document.getElementById('para2').addEventListener('pointerdown', interact); |
| document.getElementById('para2').addEventListener('pointerup', interact); |
| document.getElementById('para2').addEventListener('keydown', keyhandler); |
| return surface; |
| } |
| |
| </script> |