UNPKG

string-to-svg

Version:

Convert text to SVG path without native dependence.

169 lines (165 loc) 5.25 kB
var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/node.ts var node_exports = {}; __export(node_exports, { Font: () => import_opentype.Font, getD: () => getD, getHeight: () => getHeight, getMetrics: () => getMetrics, getPath: () => getPath, getSVG: () => getSVG, getWidth: () => getWidth, loadFont: () => loadFont }); module.exports = __toCommonJS(node_exports); var import_path = require("path"); var import_opentype = require("opentype.js"); // src/index.ts function getD(text, options) { const fontSize = options.fontSize || 72; const kerning = options.kerning; const letterSpacing = options.letterSpacing; const tracking = options.tracking; const metrics = getMetrics(text, options); const path = options.font.getPath(text, metrics.x, metrics.baseline, fontSize, { kerning, letterSpacing, tracking }); return path.toPathData(2); } function getPath(text, options) { const attributes = options.attributes || {}; const attributesString = Object.keys(attributes).map((key) => `${key}="${attributes[key]}"`).join(" "); const d = getD(text, options); if (attributesString) { return `<path ${attributesString} d="${d}"/>`; } return `<path d="${d}"/>`; } function getHeight(fontSize, font) { const fontScale = 1 / font.unitsPerEm * fontSize; return (font.ascender - font.descender) * fontScale; } function getWidth(text, options) { const fontSize = options.fontSize || 72; const kerning = "kerning" in options ? options.kerning : true; const fontScale = 1 / options.font.unitsPerEm * fontSize; let width = 0; const glyphs = options.font.stringToGlyphs(text); for (let i = 0; i < glyphs.length; i++) { const glyph = glyphs[i]; if (glyph.advanceWidth) { width += glyph.advanceWidth * fontScale; } if (kerning && i < glyphs.length - 1) { const kerningValue = options.font.getKerningValue(glyph, glyphs[i + 1]); width += kerningValue * fontScale; } if (options.letterSpacing) { width += options.letterSpacing * fontSize; } else if (options.tracking) { width += options.tracking / 1e3 * fontSize; } } return width; } function parseAnchorOption(anchor) { let horizontalMatch = anchor.match(/left|center|right/gi) || []; let horizontal = horizontalMatch.length === 0 ? "left" : horizontalMatch[0]; let verticalMatch = anchor.match(/baseline|top|bottom|middle/gi) || []; let vertical = verticalMatch.length === 0 ? "baseline" : verticalMatch[0]; return { horizontal, vertical }; } function getMetrics(text, options) { const fontSize = options.fontSize || 72; const anchor = parseAnchorOption(options.anchor || "left baseline"); const width = getWidth(text, options); const height = getHeight(fontSize, options.font); const fontScale = 1 / options.font.unitsPerEm * fontSize; const ascender = options.font.ascender * fontScale; const descender = options.font.descender * fontScale; let x = options.x || 0; switch (anchor.horizontal) { case "left": x -= 0; break; case "center": x -= width / 2; break; case "right": x -= width; break; default: throw new Error(`Unknown anchor option: ${anchor.horizontal}`); } let y = options.y || 0; switch (anchor.vertical) { case "baseline": y -= ascender; break; case "top": y -= 0; break; case "middle": y -= height / 2; break; case "bottom": y -= height; break; default: throw new Error(`Unknown anchor option: ${anchor.vertical}`); } const baseline = y + ascender; return { x, y, baseline, width, height, ascender, descender }; } // src/node.ts function loadFont(fontPath) { const path = (0, import_path.join)(__dirname, fontPath); return (0, import_opentype.loadSync)(path); } function getSVG(text, options) { if (!options.font) { options.font = loadFont("../fonts/ipag.ttf"); } const metrics = getMetrics(text, options); let svg = `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="${metrics.width}" height="${metrics.height}">`; if (options.beforePath) svg += options.beforePath; svg += getPath(text, options); if (options.afterPath) svg += options.afterPath; svg += "</svg>"; return svg; } // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { Font, getD, getHeight, getMetrics, getPath, getSVG, getWidth, loadFont });