UNPKG

@sutton-signwriting/font-ttf

Version:

a javascript package for the web components and browser that generates SVG and PNG images for individual symbols and complete signs

323 lines (278 loc) 8.47 kB
/** * Sutton SignWriting TrueType Font Module v1.2.0 (https://github.com/sutton-signwriting/font-ttf) * Author: Steve Slevinski (https://SteveSlevinski.me) * font.mjs is released under the MIT License. */ /** * Function that appends font-face CSS for the Sutton SignWriting fonts for system installed fonts, relative directory fonts, or content delivery network * @function font.cssAppend * @param {string} dir - an optional relative directory for font location * @example * font.cssAppend('./font/') */ const cssAppend = function (dir = '') { const id = "SgnwFontCss"; if (!document.getElementById(id)) { const style = document.createElement('style'); style.setAttribute("id", "SgnwFontCss"); style.appendChild(document.createTextNode(` @font-face { font-family: "SuttonSignWritingLine"; src: local('SuttonSignWritingLine'), ${dir ? `url('${dir}SuttonSignWritingLine.ttf') format('truetype'),` : ""} url('https://cdn.jsdelivr.net/npm/@sutton-signwriting/font-ttf@1.0.0/font/SuttonSignWritingLine.ttf') format('truetype'); } @font-face { font-family: "SuttonSignWritingFill"; src: local('SuttonSignWritingFill'), ${dir ? `url('${dir}SuttonSignWritingFill.ttf') format('truetype'),` : ""} url('https://cdn.jsdelivr.net/npm/@sutton-signwriting/font-ttf@1.0.0/font/SuttonSignWritingFill.ttf') format('truetype'); } @font-face { font-family: "SuttonSignWritingOneD"; src: local('SuttonSignWritingOneD'), ${dir ? `url('${dir}SuttonSignWritingOneD.ttf') format('truetype'),` : ""} url('https://cdn.jsdelivr.net/npm/@sutton-signwriting/font-ttf@1.0.0/font/SuttonSignWritingOneD.ttf') format('truetype'); } `)); document.head.appendChild(style); } }; let sizes = {}; const zoom = 2; const bound = 76 * zoom; const canvaser = document.createElement("canvas"); canvaser.width = bound; canvaser.height = bound; const context = canvaser.getContext("2d"); /** * Function that returns the size of a symbol using an id * @function font.symbolSize * @param {number} id - a 16-bit number of a symbol * @example * font.symbolSize(1) * * return [15,30] */ const symbolSize = function (id) { if (id in sizes) { return [...sizes[id]]; } context.clearRect(0, 0, bound, bound); context.font = 30 * zoom + "px 'SuttonSignWritingLine'"; context.fillText(String.fromCodePoint(id + 0xF0000), 0, 0); const imgData = context.getImageData(0, 0, bound, bound).data; let w, h, i, s; wloop: for (w = bound - 1; w >= 0; w--) { for (h = 0; h < bound; h += 1) { for (s = 0; s < 4; s += 1) { i = w * 4 + h * 4 * bound + s; if (imgData[i]) { break wloop; } } } } var width = w; hloop: for (h = bound - 1; h >= 0; h--) { for (w = 0; w < width; w += 1) { for (s = 0; s < 4; s += 1) { i = w * 4 + h * 4 * bound + s; if (imgData[i]) { break hloop; } } } } var height = h + 1; width = Math.ceil(width / zoom); height = Math.ceil(height / zoom); // Rounding error in chrome. Manual fixes. if (14394 == id) { width = 19; } if ([10468, 10480, 10496, 10512, 10500, 10532, 10548, 10862, 10878, 10894, 11058, 11074, 11476, 11488, 11492, 11504, 11508, 11520, 10516, 10910, 10926, 11042, 11082, 10942].includes(id)) { width = 20; } if (31921 == id) { width = 22; } if (38460 == id) { width = 23; } if ([20164, 20212].includes(id)) { width = 25; } if (31894 == id) { width = 28; } if (46698 == id) { width = 29; } if (29606 == id) { width = 30; } if (44855 == id) { width = 40; } if (32667 == id) { width = 50; } if ([11088, 11474, 11490, 11506].includes(id)) { height = 20; } if (6285 == id) { height = 21; } if (40804 == id) { height = 31; } if (41475 == id) { height = 36; } // Error in chrome. Manual fix. // if (width==0 && height==0) { if (width == 0 && height == 0) { const sizefix = { 9: [15, 30], 10: [21, 30], 11: [30, 15], 12: [30, 21], 13: [15, 30], 14: [21, 30] }; if (id in sizefix) { width = sizefix[id][0]; height = sizefix[id][1]; } } if (width == 0 && height == 0) { return undefined; } sizes[id] = [width, height]; return [width, height]; }; /** * Function that returns a plane 15 character for a symbol line using an id * @function font.symbolLine * @param {number} id - a 16-bit number of a symbol * @example * font.symbolLine(1) * * return '󰀁' */ const symbolLine = function (id) { return String.fromCodePoint(id + 0xF0000); }; /** * Function that returns a plane 16 character for a symbol fill using an id * @function font.symbolFill * @param {number} id - a 16-bit number of a symbol * @example * font.symbolFill(1) * * return '􀀁' */ const symbolFill = function (id) { return String.fromCodePoint(id + 0x100000); }; /** * Function that creates two text elements for a symbol using an id * @function font.symbolText * @param {number} id - a 16-bit number of a symbol * @example * font.symbolText(1) * * return ` <text class="sym-fill" fill="white" style="pointer-events:none;font-family:'SuttonSignWritingFill';font-size:30px;">􀀁</text> * <text class="sym-line" fill="black" style="pointer-events:none;font-family:'SuttonSignWritingLine';font-size:30px;">󰀁</text>` */ const symbolText = function (id) { return ` <text class="sym-fill" fill="white" style="pointer-events:none;font-family:'SuttonSignWritingFill';font-size:30px;">${symbolFill(id)}</text> <text class="sym-line" fill="black" style="pointer-events:none;font-family:'SuttonSignWritingLine';font-size:30px;">${symbolLine(id)}</text>`; }; /** * Function that executes a callback function once the Sutton SignWriiting Line and Fill fonts are ready to use * @function font.cssLoaded * @param {function} callback - a callback function to execute when fonts are ready * @example * const callback = () => { * console.log("Sutton SignWriting Line and Fill fonts are ready to use") * } * * font.cssLoaded( callback ) */ const cssLoaded = function (callback) { let lineReady = false; let fillReady = false; cssLoadedLine(() => { lineReady = true; }); cssLoadedFill(() => { fillReady = true; }); const cssCheck = setInterval(function () { if (lineReady && fillReady) { clearInterval(cssCheck); callback(); } }, 100); }; /** * Function that executes a callback function once the Sutton SignWriiting Line font is ready to use * @function font.cssLoadedLine * @param {function} callback - a callback function to execute when line font is ready * @example * const callback = () => { * console.log("Sutton SignWriting Line font is ready to use") * } * * font.cssLoadedLine( callback ) */ const cssLoadedLine = function (callback) { if (!symbolSize(1)) { const cssCheck = setInterval(function () { if (symbolSize(1)) { clearInterval(cssCheck); callback(); } }, 100); } else { callback(); } }; /** * Function that executes a callback function once the Sutton SignWriiting Fill font is ready to use * @function font.cssLoadedFill * @param {function} callback - a callback function to execute when fill font is ready * @example * const callback = () => { * console.log("Sutton SignWriting Fill font is ready to use") * } * * font.cssLoadedFill( callback ) */ const cssLoadedFill = function (callback) { const fillReady = function () { const canvaser = document.createElement("canvas"); canvaser.width = 15; canvaser.height = 30; const context = canvaser.getContext("2d"); context.font = "30px 'SuttonSignWritingFill'"; context.fillText(symbolFill(1), 0, 0); const imgData = context.getImageData(0, 0, 15, 30).data; return !imgData.every(item => item === 0); }; if (!fillReady()) { const cssCheck = setInterval(function () { if (fillReady()) { clearInterval(cssCheck); callback(); } }, 100); } else { callback(); } }; export { cssAppend, cssLoaded, cssLoadedFill, cssLoadedLine, symbolFill, symbolLine, symbolSize, symbolText }; /* support ongoing development on https://patreon.com/signwriting */