@sutton-signwriting/font-ttf
Version:
a javascript package for node that generates SVG and PNG images for individual symbols, complete signs, and structured text. The package covers the entire set of the International SignWritnig Alphabet 2010 (ISWA 2010).
301 lines (289 loc) • 8.72 kB
JavaScript
/**
* Sutton SignWriting TrueType Font Module v1.6.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;
let context;
/**
* Function that returns the size of a symbol using an id
* @function font.symbolSize
* @param {number} id - a 16-bit number of a symbol
* @returns {number[]} width and height of symbol
* @example
* font.symbolSize(1)
*
* return [15,30]
*/
const symbolSize = function (id) {
if (id in sizes) {
return [...sizes[id]];
}
if (!context) {
const canvaser = document.createElement("canvas");
canvaser.width = bound;
canvaser.height = bound;
context = canvaser.getContext("2d", {
willReadFrequently: true
});
}
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
* @returns {string} character for symbol line
* @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
* @returns {string} character for symbol fill
* @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
* @returns {string} SVG segment for line and fill
* @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 */