UNPKG

8.72 kBJavaScriptView Raw
1/**
2* Sutton SignWriting TrueType Font Module v1.5.2 (https://github.com/sutton-signwriting/font-ttf)
3* Author: Steve Slevinski (https://SteveSlevinski.me)
4* font.mjs is released under the MIT License.
5*/
6
7/**
8 * Function that appends font-face CSS for the Sutton SignWriting fonts for system installed fonts, relative directory fonts, or content delivery network
9 * @function font.cssAppend
10 * @param {string} dir - an optional relative directory for font location
11 * @example
12 * font.cssAppend('./font/')
13 */
14const cssAppend = function (dir = '') {
15 const id = "SgnwFontCss";
16 if (!document.getElementById(id)) {
17 const style = document.createElement('style');
18 style.setAttribute("id", "SgnwFontCss");
19 style.appendChild(document.createTextNode(`
20 @font-face {
21 font-family: "SuttonSignWritingLine";
22 src:
23 local('SuttonSignWritingLine'),
24 ${dir ? `url('${dir}SuttonSignWritingLine.ttf') format('truetype'),` : ""}
25 url('https://cdn.jsdelivr.net/npm/@sutton-signwriting/font-ttf@1.0.0/font/SuttonSignWritingLine.ttf') format('truetype');
26 }
27 @font-face {
28 font-family: "SuttonSignWritingFill";
29 src:
30 local('SuttonSignWritingFill'),
31 ${dir ? `url('${dir}SuttonSignWritingFill.ttf') format('truetype'),` : ""}
32 url('https://cdn.jsdelivr.net/npm/@sutton-signwriting/font-ttf@1.0.0/font/SuttonSignWritingFill.ttf') format('truetype');
33 }
34 @font-face {
35 font-family: "SuttonSignWritingOneD";
36 src:
37 local('SuttonSignWritingOneD'),
38 ${dir ? `url('${dir}SuttonSignWritingOneD.ttf') format('truetype'),` : ""}
39 url('https://cdn.jsdelivr.net/npm/@sutton-signwriting/font-ttf@1.0.0/font/SuttonSignWritingOneD.ttf') format('truetype');
40 }
41 `));
42 document.head.appendChild(style);
43 }
44};
45
46let sizes = {};
47const zoom = 2;
48const bound = 76 * zoom;
49let context;
50
51/**
52 * Function that returns the size of a symbol using an id
53 * @function font.symbolSize
54 * @param {number} id - a 16-bit number of a symbol
55 * @returns {number[]} width and height of symbol
56 * @example
57 * font.symbolSize(1)
58 *
59 * return [15,30]
60 */
61const symbolSize = function (id) {
62 if (id in sizes) {
63 return [...sizes[id]];
64 }
65 if (!context) {
66 const canvaser = document.createElement("canvas");
67 canvaser.width = bound;
68 canvaser.height = bound;
69 context = canvaser.getContext("2d", {
70 willReadFrequently: true
71 });
72 }
73 context.clearRect(0, 0, bound, bound);
74 context.font = 30 * zoom + "px 'SuttonSignWritingLine'";
75 context.fillText(String.fromCodePoint(id + 0xF0000), 0, 0);
76 const imgData = context.getImageData(0, 0, bound, bound).data;
77 let w, h, i, s;
78 wloop: for (w = bound - 1; w >= 0; w--) {
79 for (h = 0; h < bound; h += 1) {
80 for (s = 0; s < 4; s += 1) {
81 i = w * 4 + h * 4 * bound + s;
82 if (imgData[i]) {
83 break wloop;
84 }
85 }
86 }
87 }
88 var width = w;
89 hloop: for (h = bound - 1; h >= 0; h--) {
90 for (w = 0; w < width; w += 1) {
91 for (s = 0; s < 4; s += 1) {
92 i = w * 4 + h * 4 * bound + s;
93 if (imgData[i]) {
94 break hloop;
95 }
96 }
97 }
98 }
99 var height = h + 1;
100 width = Math.ceil(width / zoom);
101 height = Math.ceil(height / zoom);
102 // Rounding error in chrome. Manual fixes.
103 if (14394 == id) {
104 width = 19;
105 }
106 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)) {
107 width = 20;
108 }
109 if (31921 == id) {
110 width = 22;
111 }
112 if (38460 == id) {
113 width = 23;
114 }
115 if ([20164, 20212].includes(id)) {
116 width = 25;
117 }
118 if (31894 == id) {
119 width = 28;
120 }
121 if (46698 == id) {
122 width = 29;
123 }
124 if (29606 == id) {
125 width = 30;
126 }
127 if (44855 == id) {
128 width = 40;
129 }
130 if (32667 == id) {
131 width = 50;
132 }
133 if ([11088, 11474, 11490, 11506].includes(id)) {
134 height = 20;
135 }
136 if (6285 == id) {
137 height = 21;
138 }
139 if (40804 == id) {
140 height = 31;
141 }
142 if (41475 == id) {
143 height = 36;
144 }
145 // Error in chrome. Manual fix.
146 // if (width==0 && height==0) {
147 if (width == 0 && height == 0) {
148 const sizefix = {
149 9: [15, 30],
150 10: [21, 30],
151 11: [30, 15],
152 12: [30, 21],
153 13: [15, 30],
154 14: [21, 30]
155 };
156 if (id in sizefix) {
157 width = sizefix[id][0];
158 height = sizefix[id][1];
159 }
160 }
161 if (width == 0 && height == 0) {
162 return undefined;
163 }
164 sizes[id] = [width, height];
165 return [width, height];
166};
167
168/**
169 * Function that returns a plane 15 character for a symbol line using an id
170 * @function font.symbolLine
171 * @param {number} id - a 16-bit number of a symbol
172 * @returns {string} character for symbol line
173 * @example
174 * font.symbolLine(1)
175 *
176 * return '󰀁'
177 */
178const symbolLine = function (id) {
179 return String.fromCodePoint(id + 0xF0000);
180};
181
182/**
183 * Function that returns a plane 16 character for a symbol fill using an id
184 * @function font.symbolFill
185 * @param {number} id - a 16-bit number of a symbol
186 * @returns {string} character for symbol fill
187 * @example
188 * font.symbolFill(1)
189 *
190 * return '􀀁'
191 */
192const symbolFill = function (id) {
193 return String.fromCodePoint(id + 0x100000);
194};
195
196/**
197 * Function that creates two text elements for a symbol using an id
198 * @function font.symbolText
199 * @param {number} id - a 16-bit number of a symbol
200 * @returns {string} SVG segment for line and fill
201 * @example
202 * font.symbolText(1)
203 *
204 * return ` <text class="sym-fill" fill="white" style="pointer-events:none;font-family:'SuttonSignWritingFill';font-size:30px;">􀀁</text>
205 * <text class="sym-line" fill="black" style="pointer-events:none;font-family:'SuttonSignWritingLine';font-size:30px;">󰀁</text>`
206 */
207const symbolText = function (id) {
208 return ` <text class="sym-fill" fill="white" style="pointer-events:none;font-family:'SuttonSignWritingFill';font-size:30px;">${symbolFill(id)}</text>
209 <text class="sym-line" fill="black" style="pointer-events:none;font-family:'SuttonSignWritingLine';font-size:30px;">${symbolLine(id)}</text>`;
210};
211
212/**
213 * Function that executes a callback function once the Sutton SignWriiting Line and Fill fonts are ready to use
214 * @function font.cssLoaded
215 * @param {function} callback - a callback function to execute when fonts are ready
216 * @example
217 * const callback = () => {
218 * console.log("Sutton SignWriting Line and Fill fonts are ready to use")
219 * }
220 *
221 * font.cssLoaded( callback )
222 */
223const cssLoaded = function (callback) {
224 let lineReady = false;
225 let fillReady = false;
226 cssLoadedLine(() => {
227 lineReady = true;
228 });
229 cssLoadedFill(() => {
230 fillReady = true;
231 });
232 const cssCheck = setInterval(function () {
233 if (lineReady && fillReady) {
234 clearInterval(cssCheck);
235 callback();
236 }
237 }, 100);
238};
239
240/**
241 * Function that executes a callback function once the Sutton SignWriiting Line font is ready to use
242 * @function font.cssLoadedLine
243 * @param {function} callback - a callback function to execute when line font is ready
244 * @example
245 * const callback = () => {
246 * console.log("Sutton SignWriting Line font is ready to use")
247 * }
248 *
249 * font.cssLoadedLine( callback )
250 */
251const cssLoadedLine = function (callback) {
252 if (!symbolSize(1)) {
253 const cssCheck = setInterval(function () {
254 if (symbolSize(1)) {
255 clearInterval(cssCheck);
256 callback();
257 }
258 }, 100);
259 } else {
260 callback();
261 }
262};
263
264/**
265 * Function that executes a callback function once the Sutton SignWriiting Fill font is ready to use
266 * @function font.cssLoadedFill
267 * @param {function} callback - a callback function to execute when fill font is ready
268 * @example
269 * const callback = () => {
270 * console.log("Sutton SignWriting Fill font is ready to use")
271 * }
272 *
273 * font.cssLoadedFill( callback )
274 */
275const cssLoadedFill = function (callback) {
276 const fillReady = function () {
277 const canvaser = document.createElement("canvas");
278 canvaser.width = 15;
279 canvaser.height = 30;
280 const context = canvaser.getContext("2d");
281 context.font = "30px 'SuttonSignWritingFill'";
282 context.fillText(symbolFill(1), 0, 0);
283 const imgData = context.getImageData(0, 0, 15, 30).data;
284 return !imgData.every(item => item === 0);
285 };
286 if (!fillReady()) {
287 const cssCheck = setInterval(function () {
288 if (fillReady()) {
289 clearInterval(cssCheck);
290 callback();
291 }
292 }, 100);
293 } else {
294 callback();
295 }
296};
297
298export { cssAppend, cssLoaded, cssLoadedFill, cssLoadedLine, symbolFill, symbolLine, symbolSize, symbolText };
299
300/* support ongoing development on https://patreon.com/signwriting */