UNPKG

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