UNPKG

64.6 kBJavaScriptView Raw
1/**
2* Sutton SignWriting TrueType Font Module v1.1.0 (https://github.com/sutton-signwriting/font-ttf)
3* Author: Steve Slevinski (https://SteveSlevinski.me)
4* index.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
17 if (!document.getElementById(id)) {
18 const style = document.createElement('style');
19 style.setAttribute("id", "SgnwFontCss");
20 style.appendChild(document.createTextNode(`
21 @font-face {
22 font-family: "SuttonSignWritingLine";
23 src:
24 local('SuttonSignWritingLine'),
25 ${dir ? `url('${dir}SuttonSignWritingLine.ttf') format('truetype'),` : ""}
26 url('https://unpkg.com/@sutton-signwriting/font-ttf@1.0.0/font/SuttonSignWritingLine.ttf') format('truetype');
27 }
28 @font-face {
29 font-family: "SuttonSignWritingFill";
30 src:
31 local('SuttonSignWritingFill'),
32 ${dir ? `url('${dir}SuttonSignWritingFill.ttf') format('truetype'),` : ""}
33 url('https://unpkg.com/@sutton-signwriting/font-ttf@1.0.0/font/SuttonSignWritingFill.ttf') format('truetype');
34 }
35 @font-face {
36 font-family: "SuttonSignWritingOneD";
37 src:
38 local('SuttonSignWritingOneD'),
39 ${dir ? `url('${dir}SuttonSignWritingOneD.ttf') format('truetype'),` : ""}
40 url('https://unpkg.com/@sutton-signwriting/font-ttf@1.0.0/font/SuttonSignWritingOneD.ttf') format('truetype');
41 }
42 `));
43 document.head.appendChild(style);
44 }
45};
46
47let sizes = {};
48const zoom = 2;
49const bound = 76 * zoom;
50const canvaser = document.createElement("canvas");
51canvaser.width = bound;
52canvaser.height = bound;
53const context = canvaser.getContext("2d");
54/**
55 * Function that returns the size of a symbol using an id
56 * @function font.symbolSize
57 * @param {number} id - a 16-bit number of a symbol
58 * @example
59 * font.symbolSize(1)
60 *
61 * return [15,30]
62 */
63
64const symbolSize = function (id) {
65 if (id in sizes) {
66 return [...sizes[id]];
67 }
68
69 context.clearRect(0, 0, bound, bound);
70 context.font = 30 * zoom + "px 'SuttonSignWritingLine'";
71 context.fillText(String.fromCodePoint(id + 0xF0000), 0, 0);
72 const imgData = context.getImageData(0, 0, bound, bound).data;
73 let w, h, i, s;
74
75 wloop: for (w = bound - 1; w >= 0; w--) {
76 for (h = 0; h < bound; h += 1) {
77 for (s = 0; s < 4; s += 1) {
78 i = w * 4 + h * 4 * bound + s;
79
80 if (imgData[i]) {
81 break wloop;
82 }
83 }
84 }
85 }
86
87 var width = w;
88
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
94 if (imgData[i]) {
95 break hloop;
96 }
97 }
98 }
99 }
100
101 var height = h + 1;
102 width = Math.ceil(width / zoom);
103 height = Math.ceil(height / zoom); // Rounding error in chrome. Manual fixes.
104
105 if (14394 == id) {
106 width = 19;
107 }
108
109 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)) {
110 width = 20;
111 }
112
113 if (31921 == id) {
114 width = 22;
115 }
116
117 if (38460 == id) {
118 width = 23;
119 }
120
121 if ([20164, 20212].includes(id)) {
122 width = 25;
123 }
124
125 if (31894 == id) {
126 width = 28;
127 }
128
129 if (46698 == id) {
130 width = 29;
131 }
132
133 if (29606 == id) {
134 width = 30;
135 }
136
137 if (44855 == id) {
138 width = 40;
139 }
140
141 if (32667 == id) {
142 width = 50;
143 }
144
145 if ([11088, 11474, 11490, 11506].includes(id)) {
146 height = 20;
147 }
148
149 if (6285 == id) {
150 height = 21;
151 }
152
153 if (40804 == id) {
154 height = 31;
155 }
156
157 if (41475 == id) {
158 height = 36;
159 } // Error in chrome. Manual fix.
160 // if (width==0 && height==0) {
161
162
163 if (width == 0 && height == 0) {
164 const sizefix = {
165 9: [15, 30],
166 10: [21, 30],
167 11: [30, 15],
168 12: [30, 21],
169 13: [15, 30],
170 14: [21, 30]
171 };
172
173 if (id in sizefix) {
174 width = sizefix[id][0];
175 height = sizefix[id][1];
176 }
177 }
178
179 if (width == 0 && height == 0) {
180 return undefined;
181 }
182
183 sizes[id] = [width, height];
184 return [width, height];
185};
186
187/**
188 * Function that returns a plane 15 character for a symbol line using an id
189 * @function font.symbolLine
190 * @param {number} id - a 16-bit number of a symbol
191 * @example
192 * font.symbolLine(1)
193 *
194 * return '󰀁'
195 */
196const symbolLine = function (id) {
197 return String.fromCodePoint(id + 0xF0000);
198};
199/**
200 * Function that returns a plane 16 character for a symbol fill using an id
201 * @function font.symbolFill
202 * @param {number} id - a 16-bit number of a symbol
203 * @example
204 * font.symbolFill(1)
205 *
206 * return '􀀁'
207 */
208
209
210const symbolFill = function (id) {
211 return String.fromCodePoint(id + 0x100000);
212};
213/**
214 * Function that creates two text elements for a symbol using an id
215 * @function font.symbolText
216 * @param {number} id - a 16-bit number of a symbol
217 * @example
218 * font.symbolText(1)
219 *
220 * return ` <text class="sym-fill" fill="white" style="pointer-events:none;font-family:'SuttonSignWritingFill';font-size:30px;">􀀁</text>
221 * <text class="sym-line" fill="black" style="pointer-events:none;font-family:'SuttonSignWritingLine';font-size:30px;">󰀁</text>`
222 */
223
224
225const symbolText = function (id) {
226 return ` <text class="sym-fill" fill="white" style="pointer-events:none;font-family:'SuttonSignWritingFill';font-size:30px;">${symbolFill(id)}</text>
227 <text class="sym-line" fill="black" style="pointer-events:none;font-family:'SuttonSignWritingLine';font-size:30px;">${symbolLine(id)}</text>`;
228};
229
230/**
231 * Function that executes a callback function once the Sutton SignWriiting Line and Fill fonts are ready to use
232 * @function font.cssLoaded
233 * @param {function} callback - a callback function to execute when fonts are ready
234 * @example
235 * const callback = () => {
236 * console.log("Sutton SignWriting Line and Fill fonts are ready to use")
237 * }
238 *
239 * font.cssLoaded( callback )
240 */
241
242const cssLoaded = function (callback) {
243 let lineReady = false;
244 let fillReady = false;
245 cssLoadedLine(() => {
246 lineReady = true;
247 });
248 cssLoadedFill(() => {
249 fillReady = true;
250 });
251 const cssCheck = setInterval(function () {
252 if (lineReady && fillReady) {
253 clearInterval(cssCheck);
254 callback();
255 }
256 }, 100);
257};
258/**
259 * Function that executes a callback function once the Sutton SignWriiting Line font is ready to use
260 * @function font.cssLoadedLine
261 * @param {function} callback - a callback function to execute when line font is ready
262 * @example
263 * const callback = () => {
264 * console.log("Sutton SignWriting Line font is ready to use")
265 * }
266 *
267 * font.cssLoadedLine( callback )
268 */
269
270
271const cssLoadedLine = function (callback) {
272 if (!symbolSize(1)) {
273 const cssCheck = setInterval(function () {
274 if (symbolSize(1)) {
275 clearInterval(cssCheck);
276 callback();
277 }
278 }, 100);
279 } else {
280 callback();
281 }
282};
283/**
284 * Function that executes a callback function once the Sutton SignWriiting Fill font is ready to use
285 * @function font.cssLoadedFill
286 * @param {function} callback - a callback function to execute when fill font is ready
287 * @example
288 * const callback = () => {
289 * console.log("Sutton SignWriting Fill font is ready to use")
290 * }
291 *
292 * font.cssLoadedFill( callback )
293 */
294
295
296const cssLoadedFill = function (callback) {
297 const fillReady = function () {
298 const canvaser = document.createElement("canvas");
299 canvaser.width = 15;
300 canvaser.height = 30;
301 const context = canvaser.getContext("2d");
302 context.font = "30px 'SuttonSignWritingFill'";
303 context.fillText(symbolFill(1), 0, 0);
304 const imgData = context.getImageData(0, 0, 15, 30).data;
305 return !imgData.every(item => item === 0);
306 };
307
308 if (!fillReady()) {
309 const cssCheck = setInterval(function () {
310 if (fillReady()) {
311 clearInterval(cssCheck);
312 callback();
313 }
314 }, 100);
315 } else {
316 callback();
317 }
318};
319
320/** The font module contains functions for handing the TrueType fonts.
321 * @module font
322 */
323
324var index = /*#__PURE__*/Object.freeze({
325 __proto__: null,
326 cssAppend: cssAppend,
327 cssLoaded: cssLoaded,
328 cssLoadedLine: cssLoadedLine,
329 cssLoadedFill: cssLoadedFill,
330 symbolSize: symbolSize,
331 symbolLine: symbolLine,
332 symbolFill: symbolFill,
333 symbolText: symbolText
334});
335
336/**
337* Sutton SignWriting Core Module v1.1.0 (https://github.com/sutton-signwriting/core)
338* Author: Steve Slevinski (https://SteveSlevinski.me)
339* convert.mjs is released under the MIT License.
340*/
341/**
342 * Function to convert a number to an SWU number character
343 * @function convert.num2swu
344 * @param {number} num - Integer value for number
345 * @returns {string} SWU number character
346 * @example
347 * convert.num2swu(500)
348 *
349 * return 'ðĪ†'
350 */
351
352
353const num2swu = num => String.fromCodePoint(0x1D80C + parseInt(num) - 250);
354/**
355 * Function to convert an array of x,y integers to two SWU number characters
356 * @function convert.coord2swu
357 * @param {number[]} coord - Array of x,y integers
358 * @returns {string} Two SWU number character
359 * @example
360 * convert.coord2swu([500, 500])
361 *
362 * return 'ðĪ†ðĪ†'
363 */
364
365
366const coord2swu = coord => coord.map(num => num2swu(num)).join('');
367/**
368 * Function to convert an SWU symbol character to a code point on plane 4
369 * @function convert.swu2code
370 * @param {string} swuSym - SWU symbol character
371 * @returns {number} Code point on plane 4
372 * @example
373 * convert.swu2code('ņ€€')
374 *
375 * return 0x40001
376 */
377
378
379const swu2code = swuSym => parseInt(swuSym.codePointAt(0));
380/**
381 * Function to convert an SWU symbol character to a 16-bit ID
382 * @function convert.swu2id
383 * @param {string} swuSym - SWU symbol character
384 * @returns {number} 16-bit ID
385 * @example
386 * convert.swu2id('ņ€€')
387 *
388 * return 1
389 */
390
391
392const swu2id = swuSym => swu2code(swuSym) - 0x40000;
393/**
394 * Function to convert an FSW symbol key to a 16-bit ID
395 * @function convert.key2id
396 * @param {string} key - FSW symbol key
397 * @returns {number} 16-bit ID
398 * @example
399 * convert.key2id('S10000')
400 *
401 * return 1
402 */
403
404
405const key2id = key => 1 + (parseInt(key.slice(1, 4), 16) - 256) * 96 + parseInt(key.slice(4, 5), 16) * 16 + parseInt(key.slice(5, 6), 16);
406/* support ongoing development on https://patreon.com/signwriting */
407
408/**
409 * Function that returns the size of a symbol using an FSW symbol key
410 * @function fsw.symbolSize
411 * @param {string} fsw - an FSW symbol key
412 * @example
413 * fsw.symbolSize("S10000")
414 *
415 * return [15,30]
416 */
417
418const symbolSize$1 = function (fsw) {
419 return symbolSize(key2id(fsw));
420};
421
422/**
423 * Function that returns a plane 15 character for a symbol line using an FSW symbol key
424 * @function fsw.symbolLine
425 * @param {string} fsw - an FSW symbol key
426 * @example
427 * fsw.symbolLine('S10000')
428 *
429 * return '󰀁'
430 */
431
432const symbolLine$1 = function (fsw) {
433 return symbolLine(key2id(fsw));
434};
435/**
436 * Function that returns a plane 16 character for a symbol fill using an FSW symbol key
437 * @function fsw.symbolFill
438 * @param {string} fsw - an FSW symbol key
439 * @example
440 * font.symbolFill('S10000')
441 *
442 * return '􀀁'
443 */
444
445
446const symbolFill$1 = function (fsw) {
447 return symbolFill(key2id(fsw));
448};
449/**
450 * Function that creates two text elements for a symbol using an FSW symbol key
451 * @function fsw.symbolText
452 * @param {string} fsw - an FSW symbol key
453 * @example
454 * fsw.symbolText('S10000')
455 *
456 * return ` <text class="sym-fill" fill="white" style="pointer-events:none;font-family:'SuttonSignWritingFill';font-size:30px;">􀀁</text>
457 * <text class="sym-line" fill="black" style="pointer-events:none;font-family:'SuttonSignWritingLine';font-size:30px;">󰀁</text>`
458 */
459
460
461const symbolText$1 = function (fsw) {
462 return symbolText(key2id(fsw));
463};
464
465/**
466* Sutton SignWriting Core Module v1.1.0 (https://github.com/sutton-signwriting/core)
467* Author: Steve Slevinski (https://SteveSlevinski.me)
468* style.mjs is released under the MIT License.
469*/
470
471/**
472 * Object of regular expressions for style strings
473 *
474 * { colorize, colorhex, colorname, padding, zoom, zoomsym, classbase, id, colorbase, color, colors, background, detail, detailsym, classes, full }
475 * @alias style.re
476 * @type {object}
477 */
478let re = {
479 'colorize': 'C',
480 'colorhex': '(?:[0-9a-fA-F]{3}){1,2}',
481 'colorname': '[a-zA-Z]+',
482 'padding': 'P[0-9]{2}',
483 'zoom': 'Z(?:[0-9]+(?:\\.[0-9]+)?|x)',
484 'zoomsym': 'Z[0-9]{2},[0-9]+(?:\\.[0-9]+)?(?:,[0-9]{3}x[0-9]{3})?',
485 'classbase': '-?[_a-zA-Z][_a-zA-Z0-9-]{0,100}',
486 'id': '[a-zA-Z][_a-zA-Z0-9-]{0,100}'
487};
488re.colorbase = `(?:${re.colorhex}|${re.colorname})`;
489re.color = `_${re.colorbase}_`;
490re.colors = `_${re.colorbase}(?:,${re.colorbase})?_`;
491re.background = `G${re.color}`;
492re.detail = `D${re.colors}`;
493re.detailsym = `D[0-9]{2}${re.colors}`;
494re.classes = `${re.classbase}(?: ${re.classbase})*`;
495re.full = `-(${re.colorize})?(${re.padding})?(${re.background})?(${re.detail})?(${re.zoom})?(?:-((?:${re.detailsym})*)((?:${re.zoomsym})*))?(?:-(${re.classes})?!(?:(${re.id})!)?)?`;
496
497const prefixColor = color => {
498 const regex = new RegExp(`^${re.colorhex}$`);
499 return (regex.test(color) ? '#' : '') + color;
500};
501/**
502 * Function to parse style string to object
503 * @function style.parse
504 * @param {string} styleString - a style string
505 * @returns {object} elements of style string
506 * @example
507 * style.parse('-CP10G_blue_D_red,Cyan_')
508 *
509 * return {
510 * 'colorize': true,
511 * 'padding': 10,
512 * 'background': 'blue',
513 * 'detail': ['red', 'Cyan']
514 * }
515 */
516
517
518const parse = styleString => {
519 const regex = `^${re.full}`;
520 const m = typeof styleString === 'string' ? styleString.match(new RegExp(regex)) : [];
521 return {
522 'colorize': !m[1] ? undefined : !!m[1],
523 'padding': !m[2] ? undefined : parseInt(m[2].slice(1)),
524 'background': !m[3] ? undefined : prefixColor(m[3].slice(2, -1)),
525 'detail': !m[4] ? undefined : m[4].slice(2, -1).split(',').map(prefixColor),
526 'zoom': !m[5] ? undefined : m[5] === 'Zx' ? 'x' : parseFloat(m[5].slice(1)),
527 'detailsym': !m[6] ? undefined : m[6].match(new RegExp(re.detailsym, 'g')).map(val => {
528 const parts = val.split('_');
529 const detail = parts[1].split(',').map(prefixColor);
530 return {
531 'index': parseInt(parts[0].slice(1)),
532 'detail': detail
533 };
534 }),
535 'zoomsym': !m[7] ? undefined : m[7].match(new RegExp(re.zoomsym, 'g')).map(val => {
536 const parts = val.split(',');
537 return {
538 'index': parseInt(parts[0].slice(1)),
539 'zoom': parseFloat(parts[1]),
540 'offset': !parts[2] ? undefined : parts[2].split('x').map(val => parseInt(val) - 500)
541 };
542 }),
543 'classes': !m[8] ? undefined : m[8],
544 'id': !m[9] ? undefined : m[9]
545 };
546};
547/* support ongoing development on https://patreon.com/signwriting */
548
549/**
550* Sutton SignWriting Core Module v1.1.0 (https://github.com/sutton-signwriting/core)
551* Author: Steve Slevinski (https://SteveSlevinski.me)
552* fsw.mjs is released under the MIT License.
553*/
554
555/**
556 * Object of regular expressions for FSW strings
557 *
558 * { symbol, coord, sort, box, prefix, spatial, signbox, sign, term }
559 * @alias fsw.re
560 * @type {object}
561 */
562let re$1 = {
563 'symbol': 'S[123][0-9a-f]{2}[0-5][0-9a-f]',
564 'coord': '[0-9]{3}x[0-9]{3}',
565 'sort': 'A',
566 'box': '[BLMR]'
567};
568re$1.prefix = `(?:${re$1.sort}(?:${re$1.symbol})+)`;
569re$1.spatial = `${re$1.symbol}${re$1.coord}`;
570re$1.signbox = `${re$1.box}${re$1.coord}(?:${re$1.spatial})*`;
571re$1.sign = `${re$1.prefix}?${re$1.signbox}`;
572re$1.term = `${re$1.prefix}${re$1.signbox}`;
573/**
574 * Object of regular expressions for style strings
575 *
576 * { colorize, colorhex, colorname, padding, zoom, zoomsym, classbase, id, colorbase, color, colors, background, detail, detailsym, classes, full }
577 * @alias style.re
578 * @type {object}
579 */
580
581let re$1$1 = {
582 'colorize': 'C',
583 'colorhex': '(?:[0-9a-fA-F]{3}){1,2}',
584 'colorname': '[a-zA-Z]+',
585 'padding': 'P[0-9]{2}',
586 'zoom': 'Z(?:[0-9]+(?:\\.[0-9]+)?|x)',
587 'zoomsym': 'Z[0-9]{2},[0-9]+(?:\\.[0-9]+)?(?:,[0-9]{3}x[0-9]{3})?',
588 'classbase': '-?[_a-zA-Z][_a-zA-Z0-9-]{0,100}',
589 'id': '[a-zA-Z][_a-zA-Z0-9-]{0,100}'
590};
591re$1$1.colorbase = `(?:${re$1$1.colorhex}|${re$1$1.colorname})`;
592re$1$1.color = `_${re$1$1.colorbase}_`;
593re$1$1.colors = `_${re$1$1.colorbase}(?:,${re$1$1.colorbase})?_`;
594re$1$1.background = `G${re$1$1.color}`;
595re$1$1.detail = `D${re$1$1.colors}`;
596re$1$1.detailsym = `D[0-9]{2}${re$1$1.colors}`;
597re$1$1.classes = `${re$1$1.classbase}(?: ${re$1$1.classbase})*`;
598re$1$1.full = `-(${re$1$1.colorize})?(${re$1$1.padding})?(${re$1$1.background})?(${re$1$1.detail})?(${re$1$1.zoom})?(?:-((?:${re$1$1.detailsym})*)((?:${re$1$1.zoomsym})*))?(?:-(${re$1$1.classes})?!(?:(${re$1$1.id})!)?)?`;
599/** The convert module contains functions to convert between Formal SignWriitng in ASCII (FSW) and SignWriting in Unicode (SWU) characters, along with other types of data.
600 * [Characters set definitions](https://tools.ietf.org/id/draft-slevinski-formal-signwriting-07.html#rfc.section.2.2)
601 * @module convert
602 */
603
604/**
605 * Function to convert an FSW coordinate string to an array of x,y integers
606 * @function convert.fsw2coord
607 * @param {string} fswCoord - An FSW coordinate string
608 * @returns {number[]} Array of x,y integers
609 * @example
610 * convert.fsw2coord('500x500')
611 *
612 * return [500, 500]
613 */
614
615const fsw2coord = fswCoord => fswCoord.split('x').map(num => parseInt(num));
616
617const parse$1 = {
618 /**
619 * Function to parse an fsw symbol with optional coordinate and style string
620 * @function fsw.parse.symbol
621 * @param {string} fswSym - an fsw symbol
622 * @returns {object} elements of fsw symbol
623 * @example
624 * fsw.parse.symbol('S10000500x500-C')
625 *
626 * return {
627 * 'symbol': 'S10000',
628 * 'coord': [500, 500],
629 * 'style': '-C'
630 * }
631 */
632 symbol: fswSym => {
633 const regex = `^(${re$1.symbol})(${re$1.coord})?(${re$1$1.full})?`;
634 const symbol = typeof fswSym === 'string' ? fswSym.match(new RegExp(regex)) : undefined;
635 return {
636 'symbol': symbol ? symbol[1] : undefined,
637 'coord': symbol && symbol[2] ? fsw2coord(symbol[2]) : undefined,
638 'style': symbol ? symbol[3] : undefined
639 };
640 },
641
642 /**
643 * Function to parse an fsw sign with style string
644 * @function fsw.parse.sign
645 * @param {string} fswSign - an fsw sign
646 * @returns {object} elements of fsw sign
647 * @example
648 * fsw.parse.sign('AS10011S10019S2e704S2e748M525x535S2e748483x510S10011501x466S2e704510x500S10019476x475-C')
649 *
650 * return {
651 * sequence: ['S10011', 'S10019', 'S2e704', 'S2e748'],
652 * box: 'M',
653 * max: [525, 535],
654 * spatials: [
655 * {
656 * symbol: 'S2e748',
657 * coord: [483, 510]
658 * },
659 * {
660 * symbol: 'S10011',
661 * coord: [501, 466]
662 * },
663 * {
664 * symbol: 'S2e704',
665 * coord: [510, 500]
666 * },
667 * {
668 * symbol: 'S10019',
669 * coord: [476, 475]
670 * }
671 * ],
672 * style: '-C'
673 * }
674 */
675 sign: fswSign => {
676 const regex = `^(${re$1.prefix})?(${re$1.signbox})(${re$1$1.full})?`;
677 const sign = typeof fswSign === 'string' ? fswSign.match(new RegExp(regex)) : undefined;
678
679 if (sign) {
680 return {
681 'sequence': sign[1] ? sign[1].slice(1).match(/.{6}/g) : undefined,
682 'box': sign[2][0],
683 'max': fsw2coord(sign[2].slice(1, 8)),
684 'spatials': sign[2].length < 9 ? undefined : sign[2].slice(8).match(/(.{13})/g).map(m => {
685 return {
686 symbol: m.slice(0, 6),
687 coord: [parseInt(m.slice(6, 9)), parseInt(m.slice(10, 13))]
688 };
689 }),
690 'style': sign[3]
691 };
692 } else {
693 return {};
694 }
695 }
696};
697/**
698 * Array of numbers for categories of symbols: hand, movement, dynamics, head, trunk & limb, location, and punctuation.
699 * @alias fsw.category
700 * @type {array}
701 */
702
703const category = [0x100, 0x205, 0x2f7, 0x2ff, 0x36d, 0x37f, 0x387];
704/**
705 * Object of symbol ranges with starting and ending numbers.
706 *
707 * { all, writing, hand, movement, dynamic, head, hcenter, vcenter, trunk, limb, location, punctuation }
708 * @alias fsw.ranges
709 * @type {object}
710 */
711
712const ranges = {
713 'all': [0x100, 0x38b],
714 'writing': [0x100, 0x37e],
715 'hand': [0x100, 0x204],
716 'movement': [0x205, 0x2f6],
717 'dynamic': [0x2f7, 0x2fe],
718 'head': [0x2ff, 0x36c],
719 'hcenter': [0x2ff, 0x36c],
720 'vcenter': [0x2ff, 0x375],
721 'trunk': [0x36d, 0x375],
722 'limb': [0x376, 0x37e],
723 'location': [0x37f, 0x386],
724 'punctuation': [0x387, 0x38b]
725};
726/**
727 * Array of colors associated with the seven symbol categories.
728 * @alias fsw.colors
729 * @type {array}
730 */
731
732
733const colors = ['#0000CC', '#CC0000', '#FF0099', '#006600', '#000000', '#884411', '#FF9900'];
734/**
735 * Function that returns the standardized color for a symbol.
736 * @function fsw.colorize
737 * @param {string} key - an FSW symbol key
738 * @returns {string} name of standardized color for symbol
739 * @example
740 * fsw.colorize('S10000')
741 *
742 * return '#0000CC'
743 */
744
745const colorize = key => {
746 const parsed = parse$1.symbol(key);
747 let color = '#000000';
748
749 if (parsed.symbol) {
750 const dec = parseInt(parsed.symbol.slice(1, 4), 16);
751 const index = category.findIndex(val => val > dec);
752 color = colors[index < 0 ? 6 : index - 1];
753 }
754
755 return color;
756};
757/* support ongoing development on https://patreon.com/signwriting */
758
759/**
760 * Function that creates an SVG image from an FSW symbol key with an optional style string
761 * @function fsw.symbolSvg
762 * @param {string} fswSym - an FSW symbol key with optional style string
763 * @example
764 * fsw.symbolSvg('S10000')
765 *
766 * return `<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="15" height="30" viewBox="500 500 15 30">
767 * <text font-size="0">S10000</text>
768 * <g transform="translate(500,500)">
769 * <text class="sym-fill" fill="white" style="pointer-events:none;font-family:'SuttonSignWritingFill';font-size:30px;">􀀁</text>
770 * <text class="sym-line" fill="black" style="pointer-events:none;font-family:'SuttonSignWritingLine';font-size:30px;">󰀁</text>
771 * </g>
772 * </svg>`
773 */
774
775const symbolSvg = fswSym => {
776 const parsed = parse$1.symbol(fswSym);
777 const blank = '<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="1" height="1"></svg>';
778
779 if (parsed.symbol) {
780 let size = symbolSize$1(parsed.symbol);
781
782 if (size) {
783 let styling = parse(parsed.style);
784 let line;
785 let symSvg = symbolText$1(parsed.symbol);
786 symSvg = ` <g transform="translate(500,500)">
787${symSvg}
788 </g>`;
789
790 if (styling.colorize) {
791 line = colorize(parsed.symbol);
792 } else if (styling.detail) {
793 line = styling.detail[0];
794 }
795
796 if (line) {
797 symSvg = symSvg.replace(/class="sym-line" fill="black"/, `class="sym-line" fill="${line}"`);
798 }
799
800 let fill = styling.detail && styling.detail[1];
801
802 if (fill) {
803 symSvg = symSvg.replace(/class="sym-fill" fill="white"/, `class="sym-fill" fill="${fill}"`);
804 }
805
806 let x1 = 500;
807 let y1 = 500;
808 let background = '';
809
810 if (styling.padding) {
811 x1 -= styling.padding;
812 y1 -= styling.padding;
813 size[0] += styling.padding * 2;
814 size[1] += styling.padding * 2;
815 }
816
817 if (styling.background) {
818 background = `\n <rect x="${x1}" y="${y1}" width="${size[0]}" height="${size[1]}" style="fill:${styling.background};" />`;
819 }
820
821 let sizing = '';
822
823 if (styling.zoom != 'x') {
824 sizing = ` width="${size[0] * (styling.zoom ? styling.zoom : 1)}" height="${size[1] * (styling.zoom ? styling.zoom : 1)}"`;
825 }
826
827 let classes = '';
828
829 if (styling.classes) {
830 classes = ` class="${styling.classes}"`;
831 }
832
833 let id = '';
834
835 if (styling.id) {
836 id = ` id="${styling.id}"`;
837 }
838
839 return `<svg${classes}${id} version="1.1" xmlns="http://www.w3.org/2000/svg"${sizing} viewBox="${x1} ${y1} ${size[0]} ${size[1]}">
840 <text font-size="0">${fswSym}</text>${background}
841${symSvg}
842</svg>`;
843 }
844 }
845
846 return blank;
847};
848
849const symbolCanvas = function (fswSym) {
850 const parsed = parse$1.symbol(fswSym);
851
852 if (parsed.symbol) {
853 let size = symbolSize$1(parsed.symbol);
854
855 if (size) {
856 const canvas = document.createElement('canvas');
857 const context = canvas.getContext('2d');
858 let styling = parse(parsed.style);
859 let line = 'black';
860
861 if (styling.colorize) {
862 line = colorize(parsed.symbol);
863 } else if (styling.detail) {
864 line = styling.detail[0];
865 }
866
867 let fill = styling.detail && styling.detail[1] || 'white';
868 let x1 = 500;
869 let x2 = x1 + size[0];
870 let y1 = 500;
871 let y2 = y1 + size[1];
872
873 if (styling.padding) {
874 x1 -= styling.padding;
875 y1 -= styling.padding;
876 x2 += styling.padding;
877 y2 += styling.padding;
878 }
879
880 let sizing = 1;
881
882 if (styling.zoom != 'x') {
883 sizing = styling.zoom;
884 }
885
886 let w = (x2 - x1) * sizing;
887 let h = (y2 - y1) * sizing;
888 canvas.width = w ? w : 1;
889 canvas.height = h ? h : 1;
890
891 if (styling.background) {
892 context.rect(0, 0, w, h);
893 context.fillStyle = styling.background;
894 context.fill();
895 }
896
897 context.font = 30 * sizing + "px 'SuttonSignWritingFill'";
898 context.fillStyle = fill;
899 context.fillText(symbolFill$1(parsed.symbol), (500 - x1) * sizing, (500 - y1) * sizing);
900 context.font = 30 * sizing + "px 'SuttonSignWritingLine'";
901 context.fillStyle = line;
902 context.fillText(symbolLine$1(parsed.symbol), (500 - x1) * sizing, (500 - y1) * sizing);
903 return canvas;
904 }
905 }
906};
907/**
908 * Function that creates a binary PNG image from an FSW symbol key with an optional stle string
909 * @function fsw.symbolPng
910 * @param {string} fswSym - an FSW symbol key with optional style string
911 * @example
912 * fsw.symbolPng('S10000')
913 *
914 * return 'data:image/png;base64,iVBORw...'
915 */
916
917
918const symbolPng = fswSym => {
919 const canvas = symbolCanvas(fswSym);
920 const png = canvas.toDataURL("image/png");
921 canvas.remove();
922 return png;
923};
924
925const blank = null;
926/**
927 * Function that normalizes a symbol with a minimum coordinate for a center of 500,500
928 * @function fsw.symbolNormalize
929 * @param {string} fswSym - an FSW symbol key with optional coordinate and style string
930 * @example
931 * fsw.symbolNormalize('S10000-CP10G_green_Z2')
932 *
933 * return 'S10000493x485-CP10G_green_Z2'
934 */
935
936const symbolNormalize = fswSym => {
937 const parsed = parse$1.symbol(fswSym);
938
939 if (parsed.symbol) {
940 let size = symbolSize$1(parsed.symbol);
941
942 if (size) {
943 return `${parsed.symbol}${500 - parseInt(size[0] / 2)}x${500 - parseInt(size[1] / 2)}${parsed.style || ''}`;
944 }
945 } else {
946 return blank;
947 }
948};
949
950/**
951 * Function that creates an SVG image from an FSW sign with an optional style string
952 * @function fsw.signSvg
953 * @param {string} fswSign - an FSW sign with optional style string
954 * @example
955 * fsw.signSvg('M525x535S2e748483x510S10011501x466S2e704510x500S10019476x475')
956 *
957 * return `<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="49" height="69" viewBox="476 466 49 69">
958 * <text font-size="0">M525x535S2e748483x510S10011501x466S2e704510x500S10019476x475</text>
959 * <g transform="translate(483,510)">
960 * <text class="sym-fill" fill="white" style="pointer-events:none;font-family:'SuttonSignWritingFill';font-size:30px;">ô‹›Đ</text>
961 * <text class="sym-line" fill="black" style="pointer-events:none;font-family:'SuttonSignWritingLine';font-size:30px;">óŧ›Đ</text>
962 * </g>
963 * <g transform="translate(501,466)">
964 * <text class="sym-fill" fill="white" style="pointer-events:none;font-family:'SuttonSignWritingFill';font-size:30px;">􀀒</text>
965 * <text class="sym-line" fill="black" style="pointer-events:none;font-family:'SuttonSignWritingLine';font-size:30px;">󰀒</text>
966 * </g>
967 * <g transform="translate(510,500)">
968 * <text class="sym-fill" fill="white" style="pointer-events:none;font-family:'SuttonSignWritingFill';font-size:30px;">ô‹šĨ</text>
969 * <text class="sym-line" fill="black" style="pointer-events:none;font-family:'SuttonSignWritingLine';font-size:30px;">óŧšĨ</text>
970 * </g>
971 * <g transform="translate(476,475)">
972 * <text class="sym-fill" fill="white" style="pointer-events:none;font-family:'SuttonSignWritingFill';font-size:30px;">􀀚</text>
973 * <text class="sym-line" fill="black" style="pointer-events:none;font-family:'SuttonSignWritingLine';font-size:30px;">󰀚</text>
974 * </g>
975 * </svg>`
976 */
977
978const signSvg = fswSign => {
979 let parsed = parse$1.sign(fswSign);
980 const blank = '<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="1" height="1"></svg>';
981
982 if (parsed.spatials) {
983 let styling = parse(parsed.style);
984
985 if (styling.detailsym) {
986 styling.detailsym.forEach(sym => {
987 if (parsed.spatials[sym.index - 1]) {
988 parsed.spatials[sym.index - 1].detail = sym.detail;
989 }
990 });
991 }
992
993 let x1 = Math.min(...parsed.spatials.map(spatial => spatial.coord[0]));
994 let y1 = Math.min(...parsed.spatials.map(spatial => spatial.coord[1]));
995 let x2 = parsed.max[0];
996 let y2 = parsed.max[1];
997
998 if (styling.zoomsym) {
999 styling.zoomsym.forEach(sym => {
1000 if (parsed.spatials[sym.index - 1]) {
1001 parsed.spatials[sym.index - 1].zoom = sym.zoom;
1002
1003 if (sym.offset) {
1004 parsed.spatials[sym.index - 1].coord[0] += sym.offset[0];
1005 parsed.spatials[sym.index - 1].coord[1] += sym.offset[1];
1006 }
1007
1008 let size = symbolSize$1(parsed.spatials[sym.index - 1].symbol);
1009 x2 = Math.max(x2, parsed.spatials[sym.index - 1].coord[0] + size[0] * sym.zoom);
1010 y2 = Math.max(y2, parsed.spatials[sym.index - 1].coord[1] + size[1] * sym.zoom);
1011 }
1012 });
1013 }
1014
1015 let classes = '';
1016
1017 if (styling.classes) {
1018 classes = ` class="${styling.classes}"`;
1019 }
1020
1021 let id = '';
1022
1023 if (styling.id) {
1024 id = ` id="${styling.id}"`;
1025 }
1026
1027 let background = '';
1028
1029 if (styling.padding) {
1030 x1 -= styling.padding;
1031 y1 -= styling.padding;
1032 x2 += styling.padding;
1033 y2 += styling.padding;
1034 }
1035
1036 if (styling.background) {
1037 background = `\n <rect x="${x1}" y="${y1}" width="${x2 - x1}" height="${y2 - y1}" style="fill:${styling.background};" />`;
1038 }
1039
1040 let sizing = '';
1041
1042 if (styling.zoom != 'x') {
1043 sizing = ` width="${(x2 - x1) * (styling.zoom ? styling.zoom : 1)}" height="${(y2 - y1) * (styling.zoom ? styling.zoom : 1)}"`;
1044 }
1045
1046 let svg = `<svg${classes}${id} version="1.1" xmlns="http://www.w3.org/2000/svg"${sizing} viewBox="${x1} ${y1} ${x2 - x1} ${y2 - y1}">
1047 <text font-size="0">${fswSign}</text>${background}`;
1048 const line = styling.detail && styling.detail[0];
1049 const fill = styling.detail && styling.detail[1];
1050 svg += '\n' + parsed.spatials.map(spatial => {
1051 let svg = symbolText$1(spatial.symbol);
1052 let symLine = line;
1053
1054 if (spatial.detail) {
1055 symLine = spatial.detail[0];
1056 } else if (styling.colorize) {
1057 symLine = colorize(spatial.symbol);
1058 }
1059
1060 if (symLine) {
1061 svg = svg.replace(/class="sym-line" fill="black"/, `class="sym-line" fill="${symLine}"`);
1062 }
1063
1064 let symFill = fill;
1065
1066 if (spatial.detail && spatial.detail[1]) {
1067 symFill = spatial.detail[1];
1068 }
1069
1070 if (symFill) {
1071 svg = svg.replace(/class="sym-fill" fill="white"/, `class="sym-fill" fill="${symFill}"`);
1072 }
1073
1074 if (spatial.zoom) {
1075 svg = `<g transform="scale(${spatial.zoom})">${svg}</g>`;
1076 }
1077
1078 return ` <g transform="translate(${spatial.coord[0]},${spatial.coord[1]})">
1079${svg}
1080 </g>`;
1081 }).join('\n');
1082 svg += '\n</svg>';
1083 return svg;
1084 }
1085
1086 return blank;
1087};
1088
1089const signCanvas = function (fswSign) {
1090 const parsed = parse$1.sign(fswSign);
1091
1092 if (parsed.spatials) {
1093 const canvas = document.createElement('canvas');
1094 const context = canvas.getContext('2d');
1095 let styling = parse(parsed.style);
1096
1097 if (styling.detailsym) {
1098 styling.detailsym.forEach(sym => {
1099 if (parsed.spatials[sym.index - 1]) {
1100 parsed.spatials[sym.index - 1].detail = sym.detail;
1101 }
1102 });
1103 }
1104
1105 let x1 = Math.min(...parsed.spatials.map(spatial => spatial.coord[0]));
1106 let y1 = Math.min(...parsed.spatials.map(spatial => spatial.coord[1]));
1107 let x2 = parsed.max[0];
1108 let y2 = parsed.max[1];
1109
1110 if (styling.zoomsym) {
1111 styling.zoomsym.forEach(sym => {
1112 if (parsed.spatials[sym.index - 1]) {
1113 parsed.spatials[sym.index - 1].zoom = sym.zoom;
1114
1115 if (sym.offset) {
1116 parsed.spatials[sym.index - 1].coord[0] += sym.offset[0];
1117 parsed.spatials[sym.index - 1].coord[1] += sym.offset[1];
1118 }
1119
1120 let size = symbolSize$1(parsed.spatials[sym.index - 1].symbol);
1121 x2 = Math.max(x2, parsed.spatials[sym.index - 1].coord[0] + size[0] * sym.zoom);
1122 y2 = Math.max(y2, parsed.spatials[sym.index - 1].coord[1] + size[1] * sym.zoom);
1123 }
1124 });
1125 }
1126
1127 if (styling.padding) {
1128 x1 -= styling.padding;
1129 y1 -= styling.padding;
1130 x2 += styling.padding;
1131 y2 += styling.padding;
1132 }
1133
1134 let sizing = 1;
1135
1136 if (styling.zoom != 'x') {
1137 sizing = styling.zoom;
1138 }
1139
1140 let w = (x2 - x1) * sizing;
1141 let h = (y2 - y1) * sizing;
1142 canvas.width = w ? w : 1;
1143 canvas.height = h ? h : 1;
1144
1145 if (styling.background) {
1146 context.rect(0, 0, w, h);
1147 context.fillStyle = styling.background;
1148 context.fill();
1149 }
1150
1151 const line = styling.detail && styling.detail[0] || "black";
1152 const fill = styling.detail && styling.detail[1] || "white";
1153 parsed.spatials.forEach(spatial => {
1154 let symLine = line;
1155
1156 if (spatial.detail) {
1157 symLine = spatial.detail[0];
1158 } else if (styling.colorize) {
1159 symLine = colorize(spatial.symbol);
1160 }
1161
1162 let symFill = fill;
1163
1164 if (spatial.detail && spatial.detail[1]) {
1165 symFill = spatial.detail[1];
1166 }
1167
1168 let symZoom = spatial.zoom || 1;
1169 context.font = 30 * sizing * symZoom + "px 'SuttonSignWritingFill'";
1170 context.fillStyle = symFill;
1171 context.fillText(symbolFill$1(spatial.symbol), (spatial.coord[0] - x1) * sizing, (spatial.coord[1] - y1) * sizing);
1172 context.font = 30 * sizing * symZoom + "px 'SuttonSignWritingLine'";
1173 context.fillStyle = symLine;
1174 context.fillText(symbolLine$1(spatial.symbol), (spatial.coord[0] - x1) * sizing, (spatial.coord[1] - y1) * sizing);
1175 });
1176 return canvas;
1177 }
1178};
1179/**
1180 * Function that creates a binary PNG image from an FSW sign with an optional style string
1181 * @function fsw.signPng
1182 * @param {string} fswSign - an FSW sign with optional style string
1183 * @example
1184 * fsw.signPng('M525x535S2e748483x510S10011501x466S20544510x500S10019476x475')
1185 *
1186 * return 'data:image/png;base64,iVBORw...'
1187 */
1188
1189
1190const signPng = fswSign => {
1191 const canvas = signCanvas(fswSign);
1192 const png = canvas.toDataURL("image/png");
1193 canvas.remove();
1194 return png;
1195};
1196
1197/**
1198 * Function that normalizes an FSW sign for a center of 500,500
1199 * @function fsw.signNormalize
1200 * @param {string} fswSign - an FSW sign with optional style string
1201 * @example
1202 * fsw.signNormalize('M525x535S2e748483x510S10011501x466S2e704510x500S10019476x475')
1203 *
1204 * return 'M525x535S2e748483x510S10011501x466S2e704510x500S10019476x475'
1205 */
1206
1207const signNormalize = fswSign => {
1208 const parsed = parse$1.sign(fswSign);
1209
1210 if (parsed.spatials) {
1211 const symbolsizes = parsed.spatials.reduce((output, spatial) => {
1212 const size = symbolSize$1(spatial.symbol);
1213 output[spatial.symbol] = {
1214 width: size[0],
1215 height: size[1]
1216 };
1217 return output;
1218 }, {});
1219
1220 const bbox = symbols => {
1221 const x1 = Math.min(...symbols.map(spatial => spatial.coord[0]));
1222 const y1 = Math.min(...symbols.map(spatial => spatial.coord[1]));
1223 const x2 = Math.max(...symbols.map(spatial => spatial.coord[0] + parseInt(symbolsizes[spatial.symbol].width)));
1224 const y2 = Math.max(...symbols.map(spatial => spatial.coord[1] + parseInt(symbolsizes[spatial.symbol].height)));
1225 return {
1226 x1: x1,
1227 y1: y1,
1228 x2: x2,
1229 y2: y2
1230 };
1231 };
1232
1233 const hrange = ranges['hcenter'];
1234 const hsyms = parsed.spatials.filter(spatial => {
1235 const dec = parseInt(spatial.symbol.slice(1, 4), 16);
1236 return hrange[0] <= dec && hrange[1] >= dec;
1237 });
1238 const vrange = ranges['vcenter'];
1239 const vsyms = parsed.spatials.filter(spatial => {
1240 const dec = parseInt(spatial.symbol.slice(1, 4), 16);
1241 return vrange[0] <= dec && vrange[1] >= dec;
1242 });
1243 let abox = bbox(parsed.spatials);
1244 let max = [abox.x2, abox.y2];
1245
1246 if (hsyms.length) {
1247 const hbox = bbox(hsyms);
1248 abox.x1 = hbox.x1;
1249 abox.x2 = hbox.x2;
1250 }
1251
1252 if (vsyms.length) {
1253 const vbox = bbox(vsyms);
1254 abox.y1 = vbox.y1;
1255 abox.y2 = vbox.y2;
1256 }
1257
1258 const offset = [parseInt((abox.x2 + abox.x1) / 2) - 500, parseInt((abox.y2 + abox.y1) / 2) - 500];
1259 const fswout = (parsed.sequence ? 'A' + parsed.sequence.join('') : '') + parsed.box + (max[0] - offset[0]) + 'x' + (max[1] - offset[1]) + parsed.spatials.map(spatial => spatial.symbol + (spatial.coord[0] - offset[0]) + 'x' + (spatial.coord[1] - offset[1])).join('') + (parsed.style || '');
1260 return fswout;
1261 }
1262};
1263
1264/** The fsw module contains functions for handling Formal SignWriitng in ASCII (FSW) characters.
1265 * [FSW characters definition](https://tools.ietf.org/id/draft-slevinski-formal-signwriting-07.html#rfc.section.2.2.1)
1266 * @module fsw
1267 */
1268
1269var index$1 = /*#__PURE__*/Object.freeze({
1270 __proto__: null,
1271 symbolSize: symbolSize$1,
1272 symbolLine: symbolLine$1,
1273 symbolFill: symbolFill$1,
1274 symbolText: symbolText$1,
1275 symbolSvg: symbolSvg,
1276 symbolPng: symbolPng,
1277 symbolNormalize: symbolNormalize,
1278 signSvg: signSvg,
1279 signPng: signPng,
1280 signNormalize: signNormalize
1281});
1282
1283/**
1284 * Function that returns the size of a symbol using an SWU symbol character
1285 * @function swu.symbolSize
1286 * @param {string} swu - an SWU symbol character
1287 * @example
1288 * swu.symbolSize("ņ€€")
1289 *
1290 * return [15,30]
1291 */
1292
1293const symbolSize$2 = function (swu) {
1294 return symbolSize(swu2id(swu));
1295};
1296
1297/**
1298 * Function that returns a plane 15 character for a symbol line using an SWU symbol character
1299 * @function swu.symbolLine
1300 * @param {string} swu - an SWU symbol character
1301 * @example
1302 * swu.symbolLine('ņ€€')
1303 *
1304 * return '󰀁'
1305 */
1306
1307const symbolLine$2 = function (swu) {
1308 return symbolLine(swu2id(swu));
1309};
1310/**
1311 * Function that returns a plane 165 character for a symbol fill using an SWU symbol character
1312 * @function swu.symbolFill
1313 * @param {string} swu - an SWU symbol character
1314 * @example
1315 * swu.symbolFill('ņ€€')
1316 *
1317 * return '􀀁'
1318 */
1319
1320
1321const symbolFill$2 = function (swu) {
1322 return symbolFill(swu2id(swu));
1323};
1324/**
1325 * Function that creates two text elements for a symbol using an SWU symbol character
1326 * @function swu.symbolText
1327 * @param {string} swu - an SWU symbol character
1328 * @example
1329 * swu.symbolText('ņ€€')
1330 *
1331 * return ` <text class="sym-fill" fill="white" style="pointer-events:none;font-family:'SuttonSignWritingFill';font-size:30px;">􀀁</text>
1332 * <text class="sym-line" fill="black" style="pointer-events:none;font-family:'SuttonSignWritingLine';font-size:30px;">󰀁</text>`
1333 */
1334
1335
1336const symbolText$2 = function (swu) {
1337 return symbolText(swu2id(swu));
1338};
1339
1340/**
1341* Sutton SignWriting Core Module v1.1.0 (https://github.com/sutton-signwriting/core)
1342* Author: Steve Slevinski (https://SteveSlevinski.me)
1343* swu.mjs is released under the MIT License.
1344*/
1345
1346/**
1347 * Object of regular expressions for FSW strings
1348 *
1349 * { symbol, coord, sort, box, prefix, spatial, signbox, sign, term }
1350 * @alias swu.re
1351 * @type {object}
1352 */
1353let re$2 = {
1354 'symbol': '(?:(?:\uD8C0[\uDC01-\uDFFF])|(?:[\uD8C1-\uD8FC][\uDC00-\uDFFF])|(?:\uD8FD[\uDC00-\uDC80]))',
1355 'coord': '(?:\uD836[\uDC0C-\uDDFF]){2}',
1356 'sort': '\uD836\uDC00',
1357 'box': '\uD836[\uDC01-\uDC04]'
1358};
1359re$2.prefix = `(?:${re$2.sort}(?:${re$2.symbol})+)`;
1360re$2.spatial = `${re$2.symbol}${re$2.coord}`;
1361re$2.signbox = `${re$2.box}${re$2.coord}(?:${re$2.spatial})*`;
1362re$2.sign = `${re$2.prefix}?${re$2.signbox}`;
1363re$2.term = `${re$2.prefix}${re$2.signbox}`;
1364/**
1365 * Object of regular expressions for style strings
1366 *
1367 * { colorize, colorhex, colorname, padding, zoom, zoomsym, classbase, id, colorbase, color, colors, background, detail, detailsym, classes, full }
1368 * @alias style.re
1369 * @type {object}
1370 */
1371
1372let re$1$2 = {
1373 'colorize': 'C',
1374 'colorhex': '(?:[0-9a-fA-F]{3}){1,2}',
1375 'colorname': '[a-zA-Z]+',
1376 'padding': 'P[0-9]{2}',
1377 'zoom': 'Z(?:[0-9]+(?:\\.[0-9]+)?|x)',
1378 'zoomsym': 'Z[0-9]{2},[0-9]+(?:\\.[0-9]+)?(?:,[0-9]{3}x[0-9]{3})?',
1379 'classbase': '-?[_a-zA-Z][_a-zA-Z0-9-]{0,100}',
1380 'id': '[a-zA-Z][_a-zA-Z0-9-]{0,100}'
1381};
1382re$1$2.colorbase = `(?:${re$1$2.colorhex}|${re$1$2.colorname})`;
1383re$1$2.color = `_${re$1$2.colorbase}_`;
1384re$1$2.colors = `_${re$1$2.colorbase}(?:,${re$1$2.colorbase})?_`;
1385re$1$2.background = `G${re$1$2.color}`;
1386re$1$2.detail = `D${re$1$2.colors}`;
1387re$1$2.detailsym = `D[0-9]{2}${re$1$2.colors}`;
1388re$1$2.classes = `${re$1$2.classbase}(?: ${re$1$2.classbase})*`;
1389re$1$2.full = `-(${re$1$2.colorize})?(${re$1$2.padding})?(${re$1$2.background})?(${re$1$2.detail})?(${re$1$2.zoom})?(?:-((?:${re$1$2.detailsym})*)((?:${re$1$2.zoomsym})*))?(?:-(${re$1$2.classes})?!(?:(${re$1$2.id})!)?)?`;
1390/** The convert module contains functions to convert between Formal SignWriitng in ASCII (FSW) and SignWriting in Unicode (SWU) characters, along with other types of data.
1391 * [Characters set definitions](https://tools.ietf.org/id/draft-slevinski-formal-signwriting-07.html#rfc.section.2.2)
1392 * @module convert
1393 */
1394
1395/**
1396 * Function to convert an SWU number character to an integer
1397 * @function convert.swu2num
1398 * @param {string} swuNum - SWU number character
1399 * @returns {number} Integer value for number
1400 * @example
1401 * convert.swu2num('ðĪ†')
1402 *
1403 * return 500
1404 */
1405
1406const swu2num = swuNum => parseInt(swuNum.codePointAt(0)) - 0x1D80C + 250;
1407/**
1408 * Function to convert two SWU number characters to an array of x,y integers
1409 * @function convert.swu2coord
1410 * @param {string} swuCoord - Two SWU number character
1411 * @returns {number[]} Array of x,y integers
1412 * @example
1413 * convert.swu2coord('ðĪ†ðĪ†')
1414 *
1415 * return [500, 500]
1416 */
1417
1418
1419const swu2coord = swuCoord => [swu2num(swuCoord.slice(0, 2)), swu2num(swuCoord.slice(2, 4))];
1420/**
1421 * Function to convert an SWU symbol character to a code point on plane 4
1422 * @function convert.swu2code
1423 * @param {string} swuSym - SWU symbol character
1424 * @returns {number} Code point on plane 4
1425 * @example
1426 * convert.swu2code('ņ€€')
1427 *
1428 * return 0x40001
1429 */
1430
1431
1432const swu2code$1 = swuSym => parseInt(swuSym.codePointAt(0));
1433
1434const parse$2 = {
1435 /**
1436 * Function to parse an swu symbol with optional coordinate and style string
1437 * @function swu.parse.symbol
1438 * @param {string} swuSym - an swu symbol
1439 * @returns {object} elements of swu symbol
1440 * @example
1441 * swu.parse.symbol('ņ€€ðĪ†ðĪ†-C')
1442 *
1443 * return {
1444 * 'symbol': 'ņ€€',
1445 * 'coord': [500, 500],
1446 * 'style': '-C'
1447 * }
1448 */
1449 symbol: swuSym => {
1450 const regex = `^(${re$2.symbol})(${re$2.coord})?(${re$1$2.full})?`;
1451 const symbol = typeof swuSym === 'string' ? swuSym.match(new RegExp(regex)) : undefined;
1452 return {
1453 'symbol': symbol ? symbol[1] : undefined,
1454 'coord': symbol && symbol[2] ? swu2coord(symbol[2]) : undefined,
1455 'style': symbol ? symbol[3] : undefined
1456 };
1457 },
1458
1459 /**
1460 * Function to parse an swu sign with style string
1461 * @function swu.parse.sign
1462 * @param {string} swuSign - an swu sign
1463 * @returns {object} elements of swu sign
1464 * @example
1465 * swu.parse.sign('𝠀ņ€€’ņ€€šņ‹šĨņ‹›Đ𝠃ðĪŸðĪĐņ‹›ĐðĢĩðĪņ€€’ðĪ‡ðĢĪņ‹šĨðĪðĪ†ņ€€šðĢŪðĢ­-C')
1466 *
1467 * return {
1468 * sequence: ['ņ€€’','ņ€€š','ņ‹šĨ','ņ‹›Đ''],
1469 * box: '𝠃',
1470 * max: [525, 535],
1471 * spatials: [
1472 * {
1473 * symbol: 'ņ‹›Đ',
1474 * coord: [483, 510]
1475 * },
1476 * {
1477 * symbol: 'ņ€€’',
1478 * coord: [501, 466]
1479 * },
1480 * {
1481 * symbol: 'ņ‹šĨ',
1482 * coord: [510, 500]
1483 * },
1484 * {
1485 * symbol: 'ņ€€š',
1486 * coord: [476, 475]
1487 * }
1488 * ],
1489 * style: '-C'
1490 * }
1491 */
1492 sign: swuSign => {
1493 const regex = `^(${re$2.prefix})?(${re$2.signbox})(${re$1$2.full})?`;
1494 const sign = typeof swuSign === 'string' ? swuSign.match(new RegExp(regex)) : undefined;
1495
1496 if (sign) {
1497 return {
1498 'sequence': sign[1] ? sign[1].slice(2).match(/.{2}/g) : undefined,
1499 'box': sign[2].slice(0, 2),
1500 'max': swu2coord(sign[2].slice(2, 6)),
1501 'spatials': sign[2].length < 7 ? undefined : sign[2].slice(6).match(/(.{6})/g).map(m => {
1502 return {
1503 symbol: m.slice(0, 2),
1504 coord: swu2coord(m.slice(2))
1505 };
1506 }),
1507 'style': sign[3]
1508 };
1509 } else {
1510 return {};
1511 }
1512 }
1513};
1514/**
1515 * Array of plane 4 code points for categories of symbols: hand, movement, dynamics, head, trunk & limb, location, and punctuation.
1516 * @alias swu.category
1517 * @type {array}
1518 */
1519
1520const category$1 = [0x40001, 0x461e1, 0x4bca1, 0x4bfa1, 0x4e8e1, 0x4efa1, 0x4f2a1];
1521/**
1522 * Object of symbol ranges with starting and ending code points on plane 4.
1523 *
1524 * { all, writing, hand, movement, dynamic, head, hcenter, vcenter, trunk, limb, location, punctuation }
1525 * @alias swu.ranges
1526 * @type {object}
1527 */
1528
1529const ranges$1 = {
1530 'all': [0x40001, 0x4f480],
1531 'writing': [0x40001, 0x4efa0],
1532 'hand': [0x40001, 0x461e0],
1533 'movement': [0x461e1, 0x4bca0],
1534 'dynamic': [0x4bca1, 0x4bfa0],
1535 'head': [0x4bfa1, 0x4e8e0],
1536 'hcenter': [0x4bfa1, 0x4e8e0],
1537 'vcenter': [0x4bfa1, 0x4ec40],
1538 'trunk': [0x4e8e1, 0x4ec40],
1539 'limb': [0x4ec41, 0x4efa0],
1540 'location': [0x4efa1, 0x4f2a0],
1541 'punctuation': [0x4f2a1, 0x4f480]
1542};
1543/**
1544 * Array of colors associated with the seven symbol categories.
1545 * @alias swu.colors
1546 * @type {array}
1547 */
1548
1549
1550const colors$1 = ['#0000CC', '#CC0000', '#FF0099', '#006600', '#000000', '#884411', '#FF9900'];
1551/**
1552 * Function that returns the standardized color for a symbol.
1553 * @function swu.colorize
1554 * @param {string} swuSym - an SWU symbol character
1555 * @returns {string} name of standardized color for symbol
1556 * @example
1557 * swu.colorize('ņ€€')
1558 *
1559 * return '#0000CC'
1560 */
1561
1562const colorize$1 = swuSym => {
1563 const parsed = parse$2.symbol(swuSym);
1564 let color = '#000000';
1565
1566 if (parsed.symbol) {
1567 const code = swu2code$1(parsed.symbol);
1568 const index = category$1.findIndex(val => val > code);
1569 color = colors$1[index < 0 ? 6 : index - 1];
1570 }
1571
1572 return color;
1573};
1574/* support ongoing development on https://patreon.com/signwriting */
1575
1576/**
1577 * Function that creates an SVG image from an SWU symbol character with an optional style string
1578 * @function swu.symbolSvg
1579 * @param {string} swuSym - an SWU symbol character with optional style string
1580 * @example
1581 * swu.symbolSvg('ņ€€-CP10G_green_Z2')
1582 *
1583 * return `<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="70" height="100" viewBox="490 490 35 50">
1584 * <text font-size="0">ņ€€-CP10G_green_Z2</text>
1585 * <rect x="490" y="490" width="35" height="50" style="fill:green;" />
1586 * <g transform="translate(500,500)">
1587 * <text class="sym-fill" fill="white" style="pointer-events:none;font-family:'SuttonSignWritingFill';font-size:30px;">􀀁</text>
1588 * <text class="sym-line" fill="#0000CC" style="pointer-events:none;font-family:'SuttonSignWritingLine';font-size:30px;">󰀁</text>
1589 * </g>
1590 * </svg>`
1591 */
1592
1593const symbolSvg$1 = swuSym => {
1594 const parsed = parse$2.symbol(swuSym);
1595 const blank = '<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="1" height="1"></svg>';
1596
1597 if (parsed.symbol) {
1598 let size = symbolSize$2(parsed.symbol);
1599
1600 if (size) {
1601 let styling = parse(parsed.style);
1602 let line;
1603 let symSvg = symbolText$2(parsed.symbol);
1604 symSvg = ` <g transform="translate(500,500)">
1605${symSvg}
1606 </g>`;
1607
1608 if (styling.colorize) {
1609 line = colorize$1(parsed.symbol);
1610 } else if (styling.detail) {
1611 line = styling.detail[0];
1612 }
1613
1614 if (line) {
1615 symSvg = symSvg.replace(/class="sym-line" fill="black"/, `class="sym-line" fill="${line}"`);
1616 }
1617
1618 let fill = styling.detail && styling.detail[1];
1619
1620 if (fill) {
1621 symSvg = symSvg.replace(/class="sym-fill" fill="white"/, `class="sym-fill" fill="${fill}"`);
1622 }
1623
1624 let x1 = 500;
1625 let y1 = 500;
1626 let background = '';
1627
1628 if (styling.padding) {
1629 x1 -= styling.padding;
1630 y1 -= styling.padding;
1631 size[0] += styling.padding * 2;
1632 size[1] += styling.padding * 2;
1633 }
1634
1635 if (styling.background) {
1636 background = `\n <rect x="${x1}" y="${y1}" width="${size[0]}" height="${size[1]}" style="fill:${styling.background};" />`;
1637 }
1638
1639 let sizing = '';
1640
1641 if (styling.zoom != 'x') {
1642 sizing = ` width="${size[0] * (styling.zoom ? styling.zoom : 1)}" height="${size[1] * (styling.zoom ? styling.zoom : 1)}"`;
1643 }
1644
1645 let classes = '';
1646
1647 if (styling.classes) {
1648 classes = ` class="${styling.classes}"`;
1649 }
1650
1651 let id = '';
1652
1653 if (styling.id) {
1654 id = ` id="${styling.id}"`;
1655 }
1656
1657 return `<svg${classes}${id} version="1.1" xmlns="http://www.w3.org/2000/svg"${sizing} viewBox="${x1} ${y1} ${size[0]} ${size[1]}">
1658 <text font-size="0">${swuSym}</text>${background}
1659${symSvg}
1660</svg>`;
1661 }
1662 }
1663
1664 return blank;
1665};
1666
1667const symbolCanvas$1 = function (swuSym) {
1668 const parsed = parse$2.symbol(swuSym);
1669
1670 if (parsed.symbol) {
1671 let size = symbolSize$2(parsed.symbol);
1672
1673 if (size) {
1674 const canvas = document.createElement('canvas');
1675 const context = canvas.getContext('2d');
1676 let styling = parse(parsed.style);
1677 let line = 'black';
1678
1679 if (styling.colorize) {
1680 line = colorize$1(parsed.symbol);
1681 } else if (styling.detail) {
1682 line = styling.detail[0];
1683 }
1684
1685 let fill = styling.detail && styling.detail[1] || 'white';
1686 let x1 = 500;
1687 let x2 = x1 + size[0];
1688 let y1 = 500;
1689 let y2 = y1 + size[1];
1690
1691 if (styling.padding) {
1692 x1 -= styling.padding;
1693 y1 -= styling.padding;
1694 x2 += styling.padding;
1695 y2 += styling.padding;
1696 }
1697
1698 let sizing = 1;
1699
1700 if (styling.zoom != 'x') {
1701 sizing = styling.zoom;
1702 }
1703
1704 let w = (x2 - x1) * sizing;
1705 let h = (y2 - y1) * sizing;
1706 canvas.width = w ? w : 1;
1707 canvas.height = h ? h : 1;
1708
1709 if (styling.background) {
1710 context.rect(0, 0, w, h);
1711 context.fillStyle = styling.background;
1712 context.fill();
1713 }
1714
1715 context.font = 30 * sizing + "px 'SuttonSignWritingFill'";
1716 context.fillStyle = fill;
1717 context.fillText(symbolFill$2(parsed.symbol), (500 - x1) * sizing, (500 - y1) * sizing);
1718 context.font = 30 * sizing + "px 'SuttonSignWritingLine'";
1719 context.fillStyle = line;
1720 context.fillText(symbolLine$2(parsed.symbol), (500 - x1) * sizing, (500 - y1) * sizing);
1721 return canvas;
1722 }
1723 }
1724};
1725/**
1726 * Function that creates a binary PNG image from an SWU symbol character with an optional stle string
1727 * @function swu.symbolPng
1728 * @param {string} swuSym - an SWU symbol character with optional style string
1729 * @example
1730 * swu.symbolPng('ņ€€-CP10G_green_Z2')
1731 *
1732 * return 'data:image/png;base64,iVBORw...'
1733 */
1734
1735
1736const symbolPng$1 = swuSym => {
1737 const canvas = symbolCanvas$1(swuSym);
1738 const png = canvas.toDataURL("image/png");
1739 canvas.remove();
1740 return png;
1741};
1742
1743const blank$1 = null;
1744/**
1745 * Function that normalizes a symbol with a minimum coordinate for a center of 500,500
1746 * @function swu.symbolNormalize
1747 * @param {string} swuSym - an SWU symbol character with optional coordinate and style string
1748 * @example
1749 * swu.symbolNormalize('ņ€€')
1750 *
1751 * return 'ņ€€ðĢŋðĢ·'
1752 */
1753
1754const symbolNormalize$1 = swuSym => {
1755 const parsed = parse$2.symbol(swuSym);
1756
1757 if (parsed.symbol) {
1758 let size = symbolSize$2(parsed.symbol);
1759
1760 if (size) {
1761 return `${parsed.symbol}${coord2swu([500 - parseInt(size[0] / 2), 500 - parseInt(size[1] / 2)])}${parsed.style || ''}`;
1762 }
1763 } else {
1764 return blank$1;
1765 }
1766};
1767
1768/**
1769 * Function that creates an SVG image from an SWU sign with an optional style string
1770 * @function swu.signSvg
1771 * @param {string} swuSign - an SWU sign with optional style string
1772 * @example
1773 * swu.signSvg('𝠀ņ€€’ņ€€šņ‹šĨņ‹›Đ𝠃ðĪŸðĪĐņ‹›ĐðĢĩðĪņ€€’ðĪ‡ðĢĪņ‹šĨðĪðĪ†ņ€€šðĢŪðĢ­-P10G_green_D_yellow,ff0ff0_Z2')
1774 *
1775 * return `<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="138" height="178" viewBox="466 456 69 89">
1776 * <text font-size="0">𝠀ņ€€’ņ€€šņ‹šĨņ‹›Đ𝠃ðĪŸðĪĐņ‹›ĐðĢĩðĪņ€€’ðĪ‡ðĢĪņ‹šĨðĪðĪ†ņ€€šðĢŪðĢ­-P10G_green_D_yellow,ff0ff0_Z2</text>
1777 * <rect x="466" y="456" width="69" height="89" style="fill:green;" />
1778 * <g transform="translate(483,510)">
1779 * <text class="sym-fill" fill="#ff0ff0" style="pointer-events:none;font-family:\'SuttonSignWritingFill\';font-size:30px;">ô‹›Đ</text>
1780 * <text class="sym-line" fill="yellow" style="pointer-events:none;font-family:\'SuttonSignWritingLine\';font-size:30px;">óŧ›Đ</text>
1781 * </g>
1782 * <g transform="translate(501,466)">
1783 * <text class="sym-fill" fill="#ff0ff0" style="pointer-events:none;font-family:\'SuttonSignWritingFill\';font-size:30px;">􀀒</text>
1784 * <text class="sym-line" fill="yellow" style="pointer-events:none;font-family:\'SuttonSignWritingLine\';font-size:30px;">󰀒</text>
1785 * </g>
1786 * <g transform="translate(510,500)">
1787 * <text class="sym-fill" fill="#ff0ff0" style="pointer-events:none;font-family:\'SuttonSignWritingFill\';font-size:30px;">ô‹šĨ</text>
1788 * <text class="sym-line" fill="yellow" style="pointer-events:none;font-family:\'SuttonSignWritingLine\';font-size:30px;">óŧšĨ</text>
1789 * </g>
1790 * <g transform="translate(476,475)">
1791 * <text class="sym-fill" fill="#ff0ff0" style="pointer-events:none;font-family:\'SuttonSignWritingFill\';font-size:30px;">􀀚</text>
1792 * <text class="sym-line" fill="yellow" style="pointer-events:none;font-family:\'SuttonSignWritingLine\';font-size:30px;">󰀚</text>
1793 * </g>
1794 * </svg>`
1795 */
1796
1797const signSvg$1 = swuSign => {
1798 let parsed = parse$2.sign(swuSign);
1799 const blank = '<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="1" height="1"></svg>';
1800
1801 if (parsed.spatials) {
1802 let styling = parse(parsed.style);
1803
1804 if (styling.detailsym) {
1805 styling.detailsym.forEach(sym => {
1806 if (parsed.spatials[sym.index - 1]) {
1807 parsed.spatials[sym.index - 1].detail = sym.detail;
1808 }
1809 });
1810 }
1811
1812 let x1 = Math.min(...parsed.spatials.map(spatial => spatial.coord[0]));
1813 let y1 = Math.min(...parsed.spatials.map(spatial => spatial.coord[1]));
1814 let x2 = parsed.max[0];
1815 let y2 = parsed.max[1];
1816
1817 if (styling.zoomsym) {
1818 styling.zoomsym.forEach(sym => {
1819 if (parsed.spatials[sym.index - 1]) {
1820 parsed.spatials[sym.index - 1].zoom = sym.zoom;
1821
1822 if (sym.offset) {
1823 parsed.spatials[sym.index - 1].coord[0] += sym.offset[0];
1824 parsed.spatials[sym.index - 1].coord[1] += sym.offset[1];
1825 }
1826
1827 let size = symbolSize$2(parsed.spatials[sym.index - 1].symbol);
1828 x2 = Math.max(x2, parsed.spatials[sym.index - 1].coord[0] + size[0] * sym.zoom);
1829 y2 = Math.max(y2, parsed.spatials[sym.index - 1].coord[1] + size[1] * sym.zoom);
1830 }
1831 });
1832 }
1833
1834 let classes = '';
1835
1836 if (styling.classes) {
1837 classes = ` class="${styling.classes}"`;
1838 }
1839
1840 let id = '';
1841
1842 if (styling.id) {
1843 id = ` id="${styling.id}"`;
1844 }
1845
1846 let background = '';
1847
1848 if (styling.padding) {
1849 x1 -= styling.padding;
1850 y1 -= styling.padding;
1851 x2 += styling.padding;
1852 y2 += styling.padding;
1853 }
1854
1855 if (styling.background) {
1856 background = `\n <rect x="${x1}" y="${y1}" width="${x2 - x1}" height="${y2 - y1}" style="fill:${styling.background};" />`;
1857 }
1858
1859 let sizing = '';
1860
1861 if (styling.zoom != 'x') {
1862 sizing = ` width="${(x2 - x1) * (styling.zoom ? styling.zoom : 1)}" height="${(y2 - y1) * (styling.zoom ? styling.zoom : 1)}"`;
1863 }
1864
1865 let svg = `<svg${classes}${id} version="1.1" xmlns="http://www.w3.org/2000/svg"${sizing} viewBox="${x1} ${y1} ${x2 - x1} ${y2 - y1}">
1866 <text font-size="0">${swuSign}</text>${background}`;
1867 const line = styling.detail && styling.detail[0];
1868 const fill = styling.detail && styling.detail[1];
1869 svg += '\n' + parsed.spatials.map(spatial => {
1870 let svg = symbolText$2(spatial.symbol, spatial.coord);
1871 let symLine = line;
1872
1873 if (spatial.detail) {
1874 symLine = spatial.detail[0];
1875 } else if (styling.colorize) {
1876 symLine = colorize$1(spatial.symbol);
1877 }
1878
1879 if (symLine) {
1880 svg = svg.replace(/class="sym-line" fill="black"/, `class="sym-line" fill="${symLine}"`);
1881 }
1882
1883 let symFill = fill;
1884
1885 if (spatial.detail && spatial.detail[1]) {
1886 symFill = spatial.detail[1];
1887 }
1888
1889 if (symFill) {
1890 svg = svg.replace(/class="sym-fill" fill="white"/, `class="sym-fill" fill="${symFill}"`);
1891 }
1892
1893 if (spatial.zoom) {
1894 svg = `<g transform="scale(${spatial.zoom})">${svg}</g>`;
1895 }
1896
1897 return ` <g transform="translate(${spatial.coord[0]},${spatial.coord[1]})">
1898${svg}
1899 </g>`;
1900 }).join('\n');
1901 svg += '\n</svg>';
1902 return svg;
1903 }
1904
1905 return blank;
1906};
1907
1908const signCanvas$1 = function (swuSign) {
1909 const parsed = parse$2.sign(swuSign);
1910
1911 if (parsed.spatials) {
1912 const canvas = document.createElement('canvas');
1913 const context = canvas.getContext('2d');
1914 let styling = parse(parsed.style);
1915
1916 if (styling.detailsym) {
1917 styling.detailsym.forEach(sym => {
1918 if (parsed.spatials[sym.index - 1]) {
1919 parsed.spatials[sym.index - 1].detail = sym.detail;
1920 }
1921 });
1922 }
1923
1924 let x1 = Math.min(...parsed.spatials.map(spatial => spatial.coord[0]));
1925 let y1 = Math.min(...parsed.spatials.map(spatial => spatial.coord[1]));
1926 let x2 = parsed.max[0];
1927 let y2 = parsed.max[1];
1928
1929 if (styling.zoomsym) {
1930 styling.zoomsym.forEach(sym => {
1931 if (parsed.spatials[sym.index - 1]) {
1932 parsed.spatials[sym.index - 1].zoom = sym.zoom;
1933
1934 if (sym.offset) {
1935 parsed.spatials[sym.index - 1].coord[0] += sym.offset[0];
1936 parsed.spatials[sym.index - 1].coord[1] += sym.offset[1];
1937 }
1938
1939 let size = symbolSize$2(parsed.spatials[sym.index - 1].symbol);
1940 x2 = Math.max(x2, parsed.spatials[sym.index - 1].coord[0] + size[0] * sym.zoom);
1941 y2 = Math.max(y2, parsed.spatials[sym.index - 1].coord[1] + size[1] * sym.zoom);
1942 }
1943 });
1944 }
1945
1946 if (styling.padding) {
1947 x1 -= styling.padding;
1948 y1 -= styling.padding;
1949 x2 += styling.padding;
1950 y2 += styling.padding;
1951 }
1952
1953 let sizing = 1;
1954
1955 if (styling.zoom != 'x') {
1956 sizing = styling.zoom;
1957 }
1958
1959 let w = (x2 - x1) * sizing;
1960 let h = (y2 - y1) * sizing;
1961 canvas.width = w ? w : 1;
1962 canvas.height = h ? h : 1;
1963
1964 if (styling.background) {
1965 context.rect(0, 0, w, h);
1966 context.fillStyle = styling.background;
1967 context.fill();
1968 }
1969
1970 const line = styling.detail && styling.detail[0] || "black";
1971 const fill = styling.detail && styling.detail[1] || "white";
1972 parsed.spatials.forEach(spatial => {
1973 let symLine = line;
1974
1975 if (spatial.detail) {
1976 symLine = spatial.detail[0];
1977 } else if (styling.colorize) {
1978 symLine = colorize$1(spatial.symbol);
1979 }
1980
1981 let symFill = fill;
1982
1983 if (spatial.detail && spatial.detail[1]) {
1984 symFill = spatial.detail[1];
1985 }
1986
1987 let symZoom = spatial.zoom || 1;
1988 context.font = 30 * sizing * symZoom + "px 'SuttonSignWritingFill'";
1989 context.fillStyle = symFill;
1990 context.fillText(symbolFill$2(spatial.symbol), (spatial.coord[0] - x1) * sizing, (spatial.coord[1] - y1) * sizing);
1991 context.font = 30 * sizing * symZoom + "px 'SuttonSignWritingLine'";
1992 context.fillStyle = symLine;
1993 context.fillText(symbolLine$2(spatial.symbol), (spatial.coord[0] - x1) * sizing, (spatial.coord[1] - y1) * sizing);
1994 });
1995 return canvas;
1996 }
1997};
1998/**
1999 * Function that creates a binary PNG image from an SWU sign with an optional style string
2000 * @function swu.signPng
2001 * @param {string} swuSign - an SWU sign with optional style string
2002 * @example
2003 * swu.signPng('𝠀ņ€€’ņ€€šņ‹šĨņ‹›Đ𝠃ðĪŸðĪĐņ‹›ĐðĢĩðĪņ€€’ðĪ‡ðĢĪņ‹šĨðĪðĪ†ņ€€šðĢŪðĢ­')
2004 *
2005 * return 'data:image/png;base64,iVBORw...'
2006 */
2007
2008
2009const signPng$1 = swuSign => {
2010 const canvas = signCanvas$1(swuSign);
2011 const png = canvas.toDataURL("image/png");
2012 canvas.remove();
2013 return png;
2014};
2015
2016/**
2017 * Function that normalizes an SWU sign for a center of 500,500
2018 * @function swu.signNormalize
2019 * @param {string} swuSign - an SWU sign with optional style string
2020 * @example
2021 * swu.signNormalize('𝠀ņ€€’ņ€€šņ‹šĨņ‹›Đ𝠃ðĪŸðĪĐņ‹›ĐðĢĩðĪņ€€’ðĪ‡ðĢĪņ‹šĨðĪðĪ†ņ€€šðĢŪðĢ­')
2022 *
2023 * return '𝠀ņ€€’ņ€€šņ‹šĨņ‹›Đ𝠃ðĪŸðĪĐņ‹›ĐðĢĩðĪņ€€’ðĪ‡ðĢĪņ‹šĨðĪðĪ†ņ€€šðĢŪðĢ­'
2024 */
2025
2026const signNormalize$1 = swuSign => {
2027 const parsed = parse$2.sign(swuSign);
2028
2029 if (parsed.spatials) {
2030 const symbolsizes = parsed.spatials.reduce((output, spatial) => {
2031 const size = symbolSize$2(spatial.symbol);
2032 output[spatial.symbol] = {
2033 width: size[0],
2034 height: size[1]
2035 };
2036 return output;
2037 }, {});
2038
2039 const bbox = symbols => {
2040 const x1 = Math.min(...symbols.map(spatial => spatial.coord[0]));
2041 const y1 = Math.min(...symbols.map(spatial => spatial.coord[1]));
2042 const x2 = Math.max(...symbols.map(spatial => spatial.coord[0] + parseInt(symbolsizes[spatial.symbol].width)));
2043 const y2 = Math.max(...symbols.map(spatial => spatial.coord[1] + parseInt(symbolsizes[spatial.symbol].height)));
2044 return {
2045 x1: x1,
2046 y1: y1,
2047 x2: x2,
2048 y2: y2
2049 };
2050 };
2051
2052 const hrange = ranges$1['hcenter'];
2053 const hsyms = parsed.spatials.filter(spatial => {
2054 const dec = parseInt(spatial.symbol.slice(1, 4), 16);
2055 return hrange[0] <= dec && hrange[1] >= dec;
2056 });
2057 const vrange = ranges$1['vcenter'];
2058 const vsyms = parsed.spatials.filter(spatial => {
2059 const dec = parseInt(spatial.symbol.slice(1, 4), 16);
2060 return vrange[0] <= dec && vrange[1] >= dec;
2061 });
2062 let abox = bbox(parsed.spatials);
2063 let max = [abox.x2, abox.y2];
2064
2065 if (hsyms.length) {
2066 const hbox = bbox(hsyms);
2067 abox.x1 = hbox.x1;
2068 abox.x2 = hbox.x2;
2069 }
2070
2071 if (vsyms.length) {
2072 const vbox = bbox(vsyms);
2073 abox.y1 = vbox.y1;
2074 abox.y2 = vbox.y2;
2075 }
2076
2077 const offset = [parseInt((abox.x2 + abox.x1) / 2) - 500, parseInt((abox.y2 + abox.y1) / 2) - 500];
2078 const swuout = (parsed.sequence ? '𝠀' + parsed.sequence.join('') : '') + parsed.box + coord2swu([max[0] - offset[0], max[1] - offset[1]]) + parsed.spatials.map(spatial => spatial.symbol + coord2swu([spatial.coord[0] - offset[0], spatial.coord[1] - offset[1]])).join('') + (parsed.style || '');
2079 return swuout;
2080 }
2081};
2082
2083/** The swu module contains functions for handling Formal SignWriitng in ASCII (SWU) characters.
2084 * [SWU characters definition](https://tools.ietf.org/id/draft-slevinski-formal-signwriting-07.html#rfc.section.2.2.1)
2085 * @module swu
2086 */
2087
2088var index$2 = /*#__PURE__*/Object.freeze({
2089 __proto__: null,
2090 symbolSize: symbolSize$2,
2091 symbolLine: symbolLine$2,
2092 symbolFill: symbolFill$2,
2093 symbolText: symbolText$2,
2094 symbolSvg: symbolSvg$1,
2095 symbolPng: symbolPng$1,
2096 symbolNormalize: symbolNormalize$1,
2097 signSvg: signSvg$1,
2098 signPng: signPng$1,
2099 signNormalize: signNormalize$1
2100});
2101
2102export { index as font, index$1 as fsw, index$2 as swu };
2103
2104/* support ongoing development on https://patreon.com/signwriting */