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