UNPKG

@chemicalluck/canvas-txt

Version:

Render multiline textboxes in HTML5 canvas with auto line breaks and better alignment system

128 lines (127 loc) 3.58 kB
function k({ ctx: e, line: c, spaceWidth: p, spaceChar: n, width: a }) { const i = c.trim(), s = i.split(/\s+/), o = s.length - 1; if (o === 0) return i; const m = e.measureText(s.join("")).width, d = (a - m) / p, b = Math.floor(d / o); if (d < 1) return i; const r = n.repeat(b); return s.join(r); } const W = " "; function H({ ctx: e, text: c, justify: p, width: n }) { const a = /* @__PURE__ */ new Map(), i = (r) => { let g = a.get(r); return g !== void 0 || (g = e.measureText(r).width, a.set(r, g)), g; }; let s = [], o = c.split(` `); const m = p ? i(W) : 0; let d = 0, b = 0; for (const r of o) { let g = i(r); const y = r.length; if (g <= n) { s.push(r); continue; } let h = r, t, f, l = ""; for (; g > n; ) { if (d++, t = b, f = t === 0 ? 0 : i(r.substring(0, t)), f < n) for (; f < n && t < y && (t++, f = i(h.substring(0, t)), t !== y); ) ; else if (f > n) for (; f > n && (t = Math.max(1, t - 1), f = i(h.substring(0, t)), t !== 1); ) ; if (b = Math.round( b + (t - b) / d ), t--, t > 0) { let u = t; if (h.substring(u, u + 1) != " ") { for (; u >= 0 && h.substring(u, u + 1) != " "; ) u--; u > 0 && (t = u); } } t === 0 && (t = 1), l = h.substring(0, t), l = p ? k({ ctx: e, line: l, spaceWidth: m, spaceChar: W, width: n }) : l, s.push(l), h = h.substring(t), g = i(h); } g > 0 && (l = p ? k({ ctx: e, line: h, spaceWidth: m, spaceChar: W, width: n }) : h, s.push(l)); } return s; } function w({ ctx: e, text: c, style: p }) { const n = e.textBaseline, a = e.font; e.textBaseline = "bottom", e.font = p; const { actualBoundingBoxAscent: i } = e.measureText(c); return e.textBaseline = n, e.font = a, i; } const C = { debug: !1, align: "center", vAlign: "middle", drawStyle: "fill", fontSize: 14, fontWeight: "", fontStyle: "", fontVariant: "", font: "Arial", lineHeight: null, justify: !1 }; function E(e, c, p) { const { width: n, height: a, x: i, y: s } = p, o = { ...C, ...p }; if (n <= 0 || a <= 0 || o.fontSize <= 0) return { height: 0 }; const m = i + n, d = s + a, { fontStyle: b, fontVariant: r, fontWeight: g, fontSize: y, font: h } = o, t = `${b} ${r} ${g} ${y}px ${h}`; e.font = t; let f = s + a / 2 + o.fontSize / 2, l; o.align === "right" ? (l = m, e.textAlign = "right") : o.align === "left" ? (l = i, e.textAlign = "left") : (l = i + n / 2, e.textAlign = "center"); const u = H({ ctx: e, text: c, justify: o.justify, width: n }), A = o.lineHeight ? o.lineHeight : w({ ctx: e, text: "M", style: t }), v = A * (u.length - 1), B = v / 2; let S = s; o.vAlign === "top" ? (e.textBaseline = "top", f = s) : o.vAlign === "bottom" ? (e.textBaseline = "bottom", f = d - v, S = d) : (e.textBaseline = "bottom", S = s + a / 2, f -= B); const P = o.drawStyle === "fill" ? e.fillText.bind(e) : e.strokeText.bind(e); if (u.forEach((T) => { T = T.trim(), P(T, l, f), f += A; }), o.debug) { const T = "#0C8CE9"; e.lineWidth = 1, e.strokeStyle = T, e.strokeRect(i, s, n, a), e.lineWidth = 1, e.strokeStyle = T, e.beginPath(), e.moveTo(l, s), e.lineTo(l, d), e.stroke(), e.strokeStyle = T, e.beginPath(), e.moveTo(i, S), e.lineTo(m, S), e.stroke(); } return { height: v + A }; } export { E as drawText, w as getTextHeight, H as splitText };