UNPKG

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