canvas-txt 5 interactive
by Geon George
HTML
<canvas id="c" width="800" height="500"></canvas>
CSS
body {
background: #fafaf7;
margin: 20px;
}
canvas {
background: #fff;
border: 1px solid #ddd;
}
JavaScript
import { layoutText, drawTextLayout } from 'https://unpkg.com/[email protected]/dist/index.js'
const canvas = document.getElementById('c')
const ctx = canvas.getContext('2d')
const box = { x: 240, y: 140, w: 320, h: 220 }
const MIN = 60 // minimum box size while resizing
const GRAB = 8 // hit radius around a handle, in px
const text =
'Drag me around, or grab a handle to resize — canvas-txt re-lays the text out on every change.'
function handles() {
const { x, y, w, h } = box
return [
{ id: 'nw', x, y },
{ id: 'n', x: x + w / 2, y },
{ id: 'ne', x: x + w, y },
{ id: 'w', x, y: y + h / 2 },
{ id: 'e', x: x + w, y: y + h / 2 },
{ id: 'sw', x, y: y + h },
{ id: 's', x: x + w / 2, y: y + h },
{ id: 'se', x: x + w, y: y + h },
]
}
function render() {
ctx.clearRect(0, 0, canvas.width, canvas.height)
// the library's job: turn the rectangle into laid-out text
ctx.fillStyle = '#17191c'
const layout = layoutText(ctx, text, {
width: box.w,
height: box.h,
fontSize: 22,
overflow: 'ellipsis',
})
drawTextLayout(ctx, layout, { x: box.x, y: box.y })
// your app's job: the selection chrome
ctx.strokeStyle = '#0c8ce9'
ctx.lineWidth = 1
ctx.strokeRect(box.x + 0.5, box.y + 0.5, box.w, box.h)
ctx.fillStyle = '#fff'
for (const p of handles()) {
ctx.fillRect(p.x - 3, p.y - 3, 6, 6)
ctx.strokeRect(p.x - 2.5, p.y - 2.5, 5, 5)
}
}
// ------- pointer handling: hit-test, drag, resize -------
function pick(mx, my) {
for (const p of handles()) {
if (Math.abs(mx - p.x) <= GRAB && Math.abs(my - p.y) <= GRAB) return p.id
}
const { x, y, w, h } = box
if (mx >= x && mx <= x + w && my >= y && my <= y + h) return 'move'
return null
}
const CURSORS = {
nw: 'nwse-resize', se: 'nwse-resize',
ne: 'nesw-resize', sw: 'nesw-resize',
n: 'ns-resize', s: 'ns-resize',
w: 'ew-resize', e: 'ew-resize',
move:...