UNPKG

37.2 kBJavaScriptView Raw
1/**
2* Sutton SignWriting TrueType Font Module v1.2.0 (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 = 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.2.0 (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 = 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(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 const canvaser = document.createElement("canvas");
77 canvaser.width = bound;
78 canvaser.height = bound;
79 const context = canvaser.getContext("2d");
80 /**
81 * Function that returns the size of a symbol using an id
82 * @function font.symbolSize
83 * @param {number} id - a 16-bit number of a symbol
84 * @example
85 * font.symbolSize(1)
86 *
87 * return [15,30]
88 */
89
90 const symbolSize = function (id) {
91 if (id in sizes) {
92 return [...sizes[id]];
93 }
94
95 context.clearRect(0, 0, bound, bound);
96 context.font = 30 * zoom + "px 'SuttonSignWritingLine'";
97 context.fillText(String.fromCodePoint(id + 0xF0000), 0, 0);
98 const imgData = context.getImageData(0, 0, bound, bound).data;
99 let w, h, i, s;
100
101 wloop: for (w = bound - 1; w >= 0; w--) {
102 for (h = 0; h < bound; h += 1) {
103 for (s = 0; s < 4; s += 1) {
104 i = w * 4 + h * 4 * bound + s;
105
106 if (imgData[i]) {
107 break wloop;
108 }
109 }
110 }
111 }
112
113 var width = w;
114
115 hloop: for (h = bound - 1; h >= 0; h--) {
116 for (w = 0; w < width; w += 1) {
117 for (s = 0; s < 4; s += 1) {
118 i = w * 4 + h * 4 * bound + s;
119
120 if (imgData[i]) {
121 break hloop;
122 }
123 }
124 }
125 }
126
127 var height = h + 1;
128 width = Math.ceil(width / zoom);
129 height = Math.ceil(height / zoom); // Rounding error in chrome. Manual fixes.
130
131 if (14394 == id) {
132 width = 19;
133 }
134
135 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)) {
136 width = 20;
137 }
138
139 if (31921 == id) {
140 width = 22;
141 }
142
143 if (38460 == id) {
144 width = 23;
145 }
146
147 if ([20164, 20212].includes(id)) {
148 width = 25;
149 }
150
151 if (31894 == id) {
152 width = 28;
153 }
154
155 if (46698 == id) {
156 width = 29;
157 }
158
159 if (29606 == id) {
160 width = 30;
161 }
162
163 if (44855 == id) {
164 width = 40;
165 }
166
167 if (32667 == id) {
168 width = 50;
169 }
170
171 if ([11088, 11474, 11490, 11506].includes(id)) {
172 height = 20;
173 }
174
175 if (6285 == id) {
176 height = 21;
177 }
178
179 if (40804 == id) {
180 height = 31;
181 }
182
183 if (41475 == id) {
184 height = 36;
185 } // Error in chrome. Manual fix.
186 // if (width==0 && height==0) {
187
188
189 if (width == 0 && height == 0) {
190 const sizefix = {
191 9: [15, 30],
192 10: [21, 30],
193 11: [30, 15],
194 12: [30, 21],
195 13: [15, 30],
196 14: [21, 30]
197 };
198
199 if (id in sizefix) {
200 width = sizefix[id][0];
201 height = sizefix[id][1];
202 }
203 }
204
205 if (width == 0 && height == 0) {
206 return undefined;
207 }
208
209 sizes[id] = [width, height];
210 return [width, height];
211 };
212
213 /**
214 * Function that returns the size of a symbol using an SWU symbol character
215 * @function swu.symbolSize
216 * @param {string} swu - an SWU symbol character
217 * @example
218 * swu.symbolSize("ņ€€")
219 *
220 * return [15,30]
221 */
222
223 const symbolSize$1 = function (swu) {
224 return symbolSize(swu2id(swu));
225 };
226
227 /**
228 * Function that returns a plane 15 character for a symbol line using an id
229 * @function font.symbolLine
230 * @param {number} id - a 16-bit number of a symbol
231 * @example
232 * font.symbolLine(1)
233 *
234 * return '󰀁'
235 */
236 const symbolLine = function (id) {
237 return String.fromCodePoint(id + 0xF0000);
238 };
239 /**
240 * Function that returns a plane 16 character for a symbol fill using an id
241 * @function font.symbolFill
242 * @param {number} id - a 16-bit number of a symbol
243 * @example
244 * font.symbolFill(1)
245 *
246 * return '􀀁'
247 */
248
249
250 const symbolFill = function (id) {
251 return String.fromCodePoint(id + 0x100000);
252 };
253 /**
254 * Function that creates two text elements for a symbol using an id
255 * @function font.symbolText
256 * @param {number} id - a 16-bit number of a symbol
257 * @example
258 * font.symbolText(1)
259 *
260 * return ` <text class="sym-fill" fill="white" style="pointer-events:none;font-family:'SuttonSignWritingFill';font-size:30px;">􀀁</text>
261 * <text class="sym-line" fill="black" style="pointer-events:none;font-family:'SuttonSignWritingLine';font-size:30px;">󰀁</text>`
262 */
263
264
265 const symbolText = function (id) {
266 return ` <text class="sym-fill" fill="white" style="pointer-events:none;font-family:'SuttonSignWritingFill';font-size:30px;">${symbolFill(id)}</text>
267 <text class="sym-line" fill="black" style="pointer-events:none;font-family:'SuttonSignWritingLine';font-size:30px;">${symbolLine(id)}</text>`;
268 };
269
270 /**
271 * Function that returns a plane 15 character for a symbol line using an SWU symbol character
272 * @function swu.symbolLine
273 * @param {string} swu - an SWU symbol character
274 * @example
275 * swu.symbolLine('ņ€€')
276 *
277 * return '󰀁'
278 */
279
280 const symbolLine$1 = function (swu) {
281 return symbolLine(swu2id(swu));
282 };
283 /**
284 * Function that returns a plane 165 character for a symbol fill using an SWU symbol character
285 * @function swu.symbolFill
286 * @param {string} swu - an SWU symbol character
287 * @example
288 * swu.symbolFill('ņ€€')
289 *
290 * return '􀀁'
291 */
292
293
294 const symbolFill$1 = function (swu) {
295 return symbolFill(swu2id(swu));
296 };
297 /**
298 * Function that creates two text elements for a symbol using an SWU symbol character
299 * @function swu.symbolText
300 * @param {string} swu - an SWU symbol character
301 * @example
302 * swu.symbolText('ņ€€')
303 *
304 * return ` <text class="sym-fill" fill="white" style="pointer-events:none;font-family:'SuttonSignWritingFill';font-size:30px;">􀀁</text>
305 * <text class="sym-line" fill="black" style="pointer-events:none;font-family:'SuttonSignWritingLine';font-size:30px;">󰀁</text>`
306 */
307
308
309 const symbolText$1 = function (swu) {
310 return symbolText(swu2id(swu));
311 };
312
313 /**
314 * Sutton SignWriting Core Module v1.2.0 (https://github.com/sutton-signwriting/core)
315 * Author: Steve Slevinski (https://SteveSlevinski.me)
316 * style.mjs is released under the MIT License.
317 */
318
319 /**
320 * Object of regular expressions for style strings
321 *
322 * { colorize, colorhex, colorname, padding, zoom, zoomsym, classbase, id, colorbase, color, colors, background, detail, detailsym, classes, full }
323 * @alias style.re
324 * @type {object}
325 */
326 let re = {
327 'colorize': 'C',
328 'colorhex': '(?:[0-9a-fA-F]{3}){1,2}',
329 'colorname': '[a-zA-Z]+',
330 'padding': 'P[0-9]{2}',
331 'zoom': 'Z(?:[0-9]+(?:\\.[0-9]+)?|x)',
332 'zoomsym': 'Z[0-9]{2},[0-9]+(?:\\.[0-9]+)?(?:,[0-9]{3}x[0-9]{3})?',
333 'classbase': '-?[_a-zA-Z][_a-zA-Z0-9-]{0,100}',
334 'id': '[a-zA-Z][_a-zA-Z0-9-]{0,100}'
335 };
336 re.colorbase = `(?:${re.colorhex}|${re.colorname})`;
337 re.color = `_${re.colorbase}_`;
338 re.colors = `_${re.colorbase}(?:,${re.colorbase})?_`;
339 re.background = `G${re.color}`;
340 re.detail = `D${re.colors}`;
341 re.detailsym = `D[0-9]{2}${re.colors}`;
342 re.classes = `${re.classbase}(?: ${re.classbase})*`;
343 re.full = `-(${re.colorize})?(${re.padding})?(${re.background})?(${re.detail})?(${re.zoom})?(?:-((?:${re.detailsym})*)((?:${re.zoomsym})*))?(?:-(${re.classes})?!(?:(${re.id})!)?)?`;
344
345 const prefixColor = color => {
346 const regex = new RegExp(`^${re.colorhex}$`);
347 return (regex.test(color) ? '#' : '') + color;
348 };
349 /**
350 * Function to parse style string to object
351 * @function style.parse
352 * @param {string} styleString - a style string
353 * @returns {object} elements of style string
354 * @example
355 * style.parse('-CP10G_blue_D_red,Cyan_')
356 *
357 * return {
358 * 'colorize': true,
359 * 'padding': 10,
360 * 'background': 'blue',
361 * 'detail': ['red', 'Cyan']
362 * }
363 */
364
365
366 const parse = styleString => {
367 const regex = `^${re.full}`;
368 const m = (typeof styleString === 'string' ? styleString.match(new RegExp(regex)) : []) || [];
369 return {
370 'colorize': !m[1] ? undefined : !!m[1],
371 'padding': !m[2] ? undefined : parseInt(m[2].slice(1)),
372 'background': !m[3] ? undefined : prefixColor(m[3].slice(2, -1)),
373 'detail': !m[4] ? undefined : m[4].slice(2, -1).split(',').map(prefixColor),
374 'zoom': !m[5] ? undefined : m[5] === 'Zx' ? 'x' : parseFloat(m[5].slice(1)),
375 'detailsym': !m[6] ? undefined : m[6].match(new RegExp(re.detailsym, 'g')).map(val => {
376 const parts = val.split('_');
377 const detail = parts[1].split(',').map(prefixColor);
378 return {
379 'index': parseInt(parts[0].slice(1)),
380 'detail': detail
381 };
382 }),
383 'zoomsym': !m[7] ? undefined : m[7].match(new RegExp(re.zoomsym, 'g')).map(val => {
384 const parts = val.split(',');
385 return {
386 'index': parseInt(parts[0].slice(1)),
387 'zoom': parseFloat(parts[1]),
388 'offset': !parts[2] ? undefined : parts[2].split('x').map(val => parseInt(val) - 500)
389 };
390 }),
391 'classes': !m[8] ? undefined : m[8],
392 'id': !m[9] ? undefined : m[9]
393 };
394 };
395
396 /* support ongoing development on https://patreon.com/signwriting */
397
398 /**
399 * Sutton SignWriting Core Module v1.2.0 (https://github.com/sutton-signwriting/core)
400 * Author: Steve Slevinski (https://SteveSlevinski.me)
401 * swu.mjs is released under the MIT License.
402 */
403
404 /**
405 * Object of regular expressions for SWU strings in UTF-16
406 *
407 * { symbol, coord, sort, box, prefix, spatial, signbox, sign, sortable }
408 * @alias swu.re
409 * @type {object}
410 */
411 let re$1 = {
412 'symbol': '(?:(?:\uD8C0[\uDC01-\uDFFF])|(?:[\uD8C1-\uD8FC][\uDC00-\uDFFF])|(?:\uD8FD[\uDC00-\uDC80]))',
413 'coord': '(?:\uD836[\uDC0C-\uDDFF]){2}',
414 'sort': '\uD836\uDC00',
415 'box': '\uD836[\uDC01-\uDC04]'
416 };
417 re$1.prefix = `(?:${re$1.sort}(?:${re$1.symbol})+)`;
418 re$1.spatial = `${re$1.symbol}${re$1.coord}`;
419 re$1.signbox = `${re$1.box}${re$1.coord}(?:${re$1.spatial})*`;
420 re$1.sign = `${re$1.prefix}?${re$1.signbox}`;
421 re$1.sortable = `${re$1.prefix}${re$1.signbox}`;
422
423 /**
424 * Object of regular expressions for style strings
425 *
426 * { colorize, colorhex, colorname, padding, zoom, zoomsym, classbase, id, colorbase, color, colors, background, detail, detailsym, classes, full }
427 * @alias style.re
428 * @type {object}
429 */
430 let re$1$1 = {
431 'colorize': 'C',
432 'colorhex': '(?:[0-9a-fA-F]{3}){1,2}',
433 'colorname': '[a-zA-Z]+',
434 'padding': 'P[0-9]{2}',
435 'zoom': 'Z(?:[0-9]+(?:\\.[0-9]+)?|x)',
436 'zoomsym': 'Z[0-9]{2},[0-9]+(?:\\.[0-9]+)?(?:,[0-9]{3}x[0-9]{3})?',
437 'classbase': '-?[_a-zA-Z][_a-zA-Z0-9-]{0,100}',
438 'id': '[a-zA-Z][_a-zA-Z0-9-]{0,100}'
439 };
440 re$1$1.colorbase = `(?:${re$1$1.colorhex}|${re$1$1.colorname})`;
441 re$1$1.color = `_${re$1$1.colorbase}_`;
442 re$1$1.colors = `_${re$1$1.colorbase}(?:,${re$1$1.colorbase})?_`;
443 re$1$1.background = `G${re$1$1.color}`;
444 re$1$1.detail = `D${re$1$1.colors}`;
445 re$1$1.detailsym = `D[0-9]{2}${re$1$1.colors}`;
446 re$1$1.classes = `${re$1$1.classbase}(?: ${re$1$1.classbase})*`;
447 re$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})!)?)?`;
448
449 /** 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.
450 * [Characters set definitions](https://tools.ietf.org/id/draft-slevinski-formal-signwriting-07.html#rfc.section.2.2)
451 * @module convert
452 */
453 /**
454 * Function to convert an SWU number character to an integer
455 * @function convert.swu2num
456 * @param {string} swuNum - SWU number character
457 * @returns {number} Integer value for number
458 * @example
459 * convert.swu2num('ðĪ†')
460 *
461 * return 500
462 */
463
464
465 const swu2num = swuNum => parseInt(swuNum.codePointAt(0)) - 0x1D80C + 250;
466 /**
467 * Function to convert two SWU number characters to an array of x,y integers
468 * @function convert.swu2coord
469 * @param {string} swuCoord - Two SWU number character
470 * @returns {number[]} Array of x,y integers
471 * @example
472 * convert.swu2coord('ðĪ†ðĪ†')
473 *
474 * return [500, 500]
475 */
476
477
478 const swu2coord = swuCoord => [swu2num(swuCoord.slice(0, 2)), swu2num(swuCoord.slice(2, 4))];
479 /**
480 * Function to convert an SWU symbol character to a code point on plane 4
481 * @function convert.swu2code
482 * @param {string} swuSym - SWU symbol character
483 * @returns {number} Code point on plane 4
484 * @example
485 * convert.swu2code('ņ€€')
486 *
487 * return 0x40001
488 */
489
490
491 const swu2code$1 = swuSym => parseInt(swuSym.codePointAt(0));
492
493 const parse$1 = {
494 /**
495 * Function to parse an swu symbol with optional coordinate and style string
496 * @function swu.parse.symbol
497 * @param {string} swuSym - an swu symbol
498 * @returns {object} elements of swu symbol
499 * @example
500 * swu.parse.symbol('ņ€€ðĪ†ðĪ†-C')
501 *
502 * return {
503 * 'symbol': 'ņ€€',
504 * 'coord': [500, 500],
505 * 'style': '-C'
506 * }
507 */
508 symbol: swuSym => {
509 const regex = `^(${re$1.symbol})(${re$1.coord})?(${re$1$1.full})?`;
510 const symbol = typeof swuSym === 'string' ? swuSym.match(new RegExp(regex)) : undefined;
511 return {
512 'symbol': symbol ? symbol[1] : undefined,
513 'coord': symbol && symbol[2] ? swu2coord(symbol[2]) : undefined,
514 'style': symbol ? symbol[3] : undefined
515 };
516 },
517
518 /**
519 * Function to parse an swu sign with style string
520 * @function swu.parse.sign
521 * @param {string} swuSign - an swu sign
522 * @returns {object} elements of swu sign
523 * @example
524 * swu.parse.sign('𝠀ņ€€’ņ€€šņ‹šĨņ‹›Đ𝠃ðĪŸðĪĐņ‹›ĐðĢĩðĪņ€€’ðĪ‡ðĢĪņ‹šĨðĪðĪ†ņ€€šðĢŪðĢ­-C')
525 *
526 * return {
527 * sequence: ['ņ€€’','ņ€€š','ņ‹šĨ','ņ‹›Đ''],
528 * box: '𝠃',
529 * max: [525, 535],
530 * spatials: [
531 * {
532 * symbol: 'ņ‹›Đ',
533 * coord: [483, 510]
534 * },
535 * {
536 * symbol: 'ņ€€’',
537 * coord: [501, 466]
538 * },
539 * {
540 * symbol: 'ņ‹šĨ',
541 * coord: [510, 500]
542 * },
543 * {
544 * symbol: 'ņ€€š',
545 * coord: [476, 475]
546 * }
547 * ],
548 * style: '-C'
549 * }
550 */
551 sign: swuSign => {
552 const regex = `^(${re$1.prefix})?(${re$1.signbox})(${re$1$1.full})?`;
553 const sign = typeof swuSign === 'string' ? swuSign.match(new RegExp(regex)) : undefined;
554
555 if (sign) {
556 return {
557 'sequence': sign[1] ? sign[1].slice(2).match(/.{2}/g) : undefined,
558 'box': sign[2].slice(0, 2),
559 'max': swu2coord(sign[2].slice(2, 6)),
560 'spatials': sign[2].length < 7 ? undefined : sign[2].slice(6).match(/(.{6})/g).map(m => {
561 return {
562 symbol: m.slice(0, 2),
563 coord: swu2coord(m.slice(2))
564 };
565 }),
566 'style': sign[3]
567 };
568 } else {
569 return {};
570 }
571 }
572 };
573 /**
574 * Array of plane 4 code points for categories of symbols: hand, movement, dynamics, head, trunk & limb, location, and punctuation.
575 * @alias swu.category
576 * @type {array}
577 */
578
579 const category = [0x40001, 0x461e1, 0x4bca1, 0x4bfa1, 0x4e8e1, 0x4efa1, 0x4f2a1];
580 /**
581 * Object of symbol ranges with starting and ending code points on plane 4.
582 *
583 * { all, writing, hand, movement, dynamic, head, hcenter, vcenter, trunk, limb, location, punctuation }
584 * @alias swu.ranges
585 * @type {object}
586 */
587
588 const ranges = {
589 'all': [0x40001, 0x4f480],
590 'writing': [0x40001, 0x4efa0],
591 'hand': [0x40001, 0x461e0],
592 'movement': [0x461e1, 0x4bca0],
593 'dynamic': [0x4bca1, 0x4bfa0],
594 'head': [0x4bfa1, 0x4e8e0],
595 'hcenter': [0x4bfa1, 0x4e8e0],
596 'vcenter': [0x4bfa1, 0x4ec40],
597 'trunk': [0x4e8e1, 0x4ec40],
598 'limb': [0x4ec41, 0x4efa0],
599 'location': [0x4efa1, 0x4f2a0],
600 'punctuation': [0x4f2a1, 0x4f480]
601 };
602
603 /**
604 * Array of colors associated with the seven symbol categories.
605 * @alias swu.colors
606 * @type {array}
607 */
608
609 const colors = ['#0000CC', '#CC0000', '#FF0099', '#006600', '#000000', '#884411', '#FF9900'];
610 /**
611 * Function that returns the standardized color for a symbol.
612 * @function swu.colorize
613 * @param {string} swuSym - an SWU symbol character
614 * @returns {string} name of standardized color for symbol
615 * @example
616 * swu.colorize('ņ€€')
617 *
618 * return '#0000CC'
619 */
620
621 const colorize = swuSym => {
622 const parsed = parse$1.symbol(swuSym);
623 let color = '#000000';
624
625 if (parsed.symbol) {
626 const code = swu2code$1(parsed.symbol);
627 const index = category.findIndex(val => val > code);
628 color = colors[index < 0 ? 6 : index - 1];
629 }
630
631 return color;
632 };
633
634 /* support ongoing development on https://patreon.com/signwriting */
635
636 /**
637 * Function that creates an SVG image from an SWU symbol character with an optional style string
638 * @function swu.symbolSvg
639 * @param {string} swuSym - an SWU symbol character with optional style string
640 * @example
641 * swu.symbolSvg('ņ€€-CP10G_green_Z2')
642 *
643 * return `<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="70" height="100" viewBox="490 490 35 50">
644 * <text font-size="0">ņ€€-CP10G_green_Z2</text>
645 * <rect x="490" y="490" width="35" height="50" style="fill:green;" />
646 * <g transform="translate(500,500)">
647 * <text class="sym-fill" fill="white" style="pointer-events:none;font-family:'SuttonSignWritingFill';font-size:30px;">􀀁</text>
648 * <text class="sym-line" fill="#0000CC" style="pointer-events:none;font-family:'SuttonSignWritingLine';font-size:30px;">󰀁</text>
649 * </g>
650 * </svg>`
651 */
652
653 const symbolSvg = swuSym => {
654 const parsed = parse$1.symbol(swuSym);
655 const blank = '<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="1" height="1"></svg>';
656
657 if (parsed.symbol) {
658 let size = symbolSize$1(parsed.symbol);
659
660 if (size) {
661 let styling = parse(parsed.style);
662 let line;
663 let symSvg = symbolText$1(parsed.symbol);
664 symSvg = ` <g transform="translate(500,500)">
665${symSvg}
666 </g>`;
667
668 if (styling.colorize) {
669 line = colorize(parsed.symbol);
670 } else if (styling.detail) {
671 line = styling.detail[0];
672 }
673
674 if (line) {
675 symSvg = symSvg.replace(/class="sym-line" fill="black"/, `class="sym-line" fill="${line}"`);
676 }
677
678 let fill = styling.detail && styling.detail[1];
679
680 if (fill) {
681 symSvg = symSvg.replace(/class="sym-fill" fill="white"/, `class="sym-fill" fill="${fill}"`);
682 }
683
684 let x1 = 500;
685 let y1 = 500;
686 let background = '';
687
688 if (styling.padding) {
689 x1 -= styling.padding;
690 y1 -= styling.padding;
691 size[0] += styling.padding * 2;
692 size[1] += styling.padding * 2;
693 }
694
695 if (styling.background) {
696 background = `\n <rect x="${x1}" y="${y1}" width="${size[0]}" height="${size[1]}" style="fill:${styling.background};" />`;
697 }
698
699 let sizing = '';
700
701 if (styling.zoom != 'x') {
702 sizing = ` width="${size[0] * (styling.zoom ? styling.zoom : 1)}" height="${size[1] * (styling.zoom ? styling.zoom : 1)}"`;
703 }
704
705 let classes = '';
706
707 if (styling.classes) {
708 classes = ` class="${styling.classes}"`;
709 }
710
711 let id = '';
712
713 if (styling.id) {
714 id = ` id="${styling.id}"`;
715 }
716
717 return `<svg${classes}${id} version="1.1" xmlns="http://www.w3.org/2000/svg"${sizing} viewBox="${x1} ${y1} ${size[0]} ${size[1]}">
718 <text font-size="0">${swuSym}</text>${background}
719${symSvg}
720</svg>`;
721 }
722 }
723
724 return blank;
725 };
726
727 const symbolCanvas = function (swuSym) {
728 const parsed = parse$1.symbol(swuSym);
729
730 if (parsed.symbol) {
731 let size = symbolSize$1(parsed.symbol);
732
733 if (size) {
734 const canvas = document.createElement('canvas');
735 const context = canvas.getContext('2d');
736 let styling = parse(parsed.style);
737 let line = 'black';
738
739 if (styling.colorize) {
740 line = colorize(parsed.symbol);
741 } else if (styling.detail) {
742 line = styling.detail[0];
743 }
744
745 let fill = styling.detail && styling.detail[1] || 'white';
746 let x1 = 500;
747 let x2 = x1 + size[0];
748 let y1 = 500;
749 let y2 = y1 + size[1];
750
751 if (styling.padding) {
752 x1 -= styling.padding;
753 y1 -= styling.padding;
754 x2 += styling.padding;
755 y2 += styling.padding;
756 }
757
758 let sizing = 1;
759
760 if (styling.zoom != 'x') {
761 sizing = styling.zoom;
762 }
763
764 let w = (x2 - x1) * sizing;
765 let h = (y2 - y1) * sizing;
766 canvas.width = w ? w : 1;
767 canvas.height = h ? h : 1;
768
769 if (styling.background) {
770 context.rect(0, 0, w, h);
771 context.fillStyle = styling.background;
772 context.fill();
773 }
774
775 context.font = 30 * sizing + "px 'SuttonSignWritingFill'";
776 context.fillStyle = fill;
777 context.fillText(symbolFill$1(parsed.symbol), (500 - x1) * sizing, (500 - y1) * sizing);
778 context.font = 30 * sizing + "px 'SuttonSignWritingLine'";
779 context.fillStyle = line;
780 context.fillText(symbolLine$1(parsed.symbol), (500 - x1) * sizing, (500 - y1) * sizing);
781 return canvas;
782 }
783 }
784 };
785 /**
786 * Function that creates a binary PNG image from an SWU symbol character with an optional stle string
787 * @function swu.symbolPng
788 * @param {string} swuSym - an SWU symbol character with optional style string
789 * @example
790 * swu.symbolPng('ņ€€-CP10G_green_Z2')
791 *
792 * return 'data:image/png;base64,iVBORw...'
793 */
794
795
796 const symbolPng = swuSym => {
797 const canvas = symbolCanvas(swuSym);
798 const png = canvas.toDataURL("image/png");
799 canvas.remove();
800 return png;
801 };
802
803 const blank = null;
804 /**
805 * Function that normalizes a symbol with a minimum coordinate for a center of 500,500
806 * @function swu.symbolNormalize
807 * @param {string} swuSym - an SWU symbol character with optional coordinate and style string
808 * @example
809 * swu.symbolNormalize('ņ€€')
810 *
811 * return 'ņ€€ðĢŋðĢ·'
812 */
813
814 const symbolNormalize = swuSym => {
815 const parsed = parse$1.symbol(swuSym);
816
817 if (parsed.symbol) {
818 let size = symbolSize$1(parsed.symbol);
819
820 if (size) {
821 return `${parsed.symbol}${coord2swu([500 - parseInt(size[0] / 2), 500 - parseInt(size[1] / 2)])}${parsed.style || ''}`;
822 }
823 } else {
824 return blank;
825 }
826 };
827
828 /**
829 * Function that creates an SVG image from an SWU sign with an optional style string
830 * @function swu.signSvg
831 * @param {string} swuSign - an SWU sign with optional style string
832 * @example
833 * swu.signSvg('𝠀ņ€€’ņ€€šņ‹šĨņ‹›Đ𝠃ðĪŸðĪĐņ‹›ĐðĢĩðĪņ€€’ðĪ‡ðĢĪņ‹šĨðĪðĪ†ņ€€šðĢŪðĢ­-P10G_green_D_yellow,ff0ff0_Z2')
834 *
835 * return `<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="138" height="178" viewBox="466 456 69 89">
836 * <text font-size="0">𝠀ņ€€’ņ€€šņ‹šĨņ‹›Đ𝠃ðĪŸðĪĐņ‹›ĐðĢĩðĪņ€€’ðĪ‡ðĢĪņ‹šĨðĪðĪ†ņ€€šðĢŪðĢ­-P10G_green_D_yellow,ff0ff0_Z2</text>
837 * <rect x="466" y="456" width="69" height="89" style="fill:green;" />
838 * <g transform="translate(483,510)">
839 * <text class="sym-fill" fill="#ff0ff0" style="pointer-events:none;font-family:\'SuttonSignWritingFill\';font-size:30px;">ô‹›Đ</text>
840 * <text class="sym-line" fill="yellow" style="pointer-events:none;font-family:\'SuttonSignWritingLine\';font-size:30px;">óŧ›Đ</text>
841 * </g>
842 * <g transform="translate(501,466)">
843 * <text class="sym-fill" fill="#ff0ff0" style="pointer-events:none;font-family:\'SuttonSignWritingFill\';font-size:30px;">􀀒</text>
844 * <text class="sym-line" fill="yellow" style="pointer-events:none;font-family:\'SuttonSignWritingLine\';font-size:30px;">󰀒</text>
845 * </g>
846 * <g transform="translate(510,500)">
847 * <text class="sym-fill" fill="#ff0ff0" style="pointer-events:none;font-family:\'SuttonSignWritingFill\';font-size:30px;">ô‹šĨ</text>
848 * <text class="sym-line" fill="yellow" style="pointer-events:none;font-family:\'SuttonSignWritingLine\';font-size:30px;">óŧšĨ</text>
849 * </g>
850 * <g transform="translate(476,475)">
851 * <text class="sym-fill" fill="#ff0ff0" style="pointer-events:none;font-family:\'SuttonSignWritingFill\';font-size:30px;">􀀚</text>
852 * <text class="sym-line" fill="yellow" style="pointer-events:none;font-family:\'SuttonSignWritingLine\';font-size:30px;">󰀚</text>
853 * </g>
854 * </svg>`
855 */
856
857 const signSvg = swuSign => {
858 let parsed = parse$1.sign(swuSign);
859 const blank = '<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="1" height="1"></svg>';
860
861 if (parsed.spatials) {
862 let styling = parse(parsed.style);
863
864 if (styling.detailsym) {
865 styling.detailsym.forEach(sym => {
866 if (parsed.spatials[sym.index - 1]) {
867 parsed.spatials[sym.index - 1].detail = sym.detail;
868 }
869 });
870 }
871
872 let x1 = Math.min(...parsed.spatials.map(spatial => spatial.coord[0]));
873 let y1 = Math.min(...parsed.spatials.map(spatial => spatial.coord[1]));
874 let x2 = parsed.max[0];
875 let y2 = parsed.max[1];
876
877 if (styling.zoomsym) {
878 styling.zoomsym.forEach(sym => {
879 if (parsed.spatials[sym.index - 1]) {
880 parsed.spatials[sym.index - 1].zoom = sym.zoom;
881
882 if (sym.offset) {
883 parsed.spatials[sym.index - 1].coord[0] += sym.offset[0];
884 parsed.spatials[sym.index - 1].coord[1] += sym.offset[1];
885 }
886
887 let size = symbolSize$1(parsed.spatials[sym.index - 1].symbol);
888 x2 = Math.max(x2, parsed.spatials[sym.index - 1].coord[0] + size[0] * sym.zoom);
889 y2 = Math.max(y2, parsed.spatials[sym.index - 1].coord[1] + size[1] * sym.zoom);
890 }
891 });
892 }
893
894 let classes = '';
895
896 if (styling.classes) {
897 classes = ` class="${styling.classes}"`;
898 }
899
900 let id = '';
901
902 if (styling.id) {
903 id = ` id="${styling.id}"`;
904 }
905
906 let background = '';
907
908 if (styling.padding) {
909 x1 -= styling.padding;
910 y1 -= styling.padding;
911 x2 += styling.padding;
912 y2 += styling.padding;
913 }
914
915 if (styling.background) {
916 background = `\n <rect x="${x1}" y="${y1}" width="${x2 - x1}" height="${y2 - y1}" style="fill:${styling.background};" />`;
917 }
918
919 let sizing = '';
920
921 if (styling.zoom != 'x') {
922 sizing = ` width="${(x2 - x1) * (styling.zoom ? styling.zoom : 1)}" height="${(y2 - y1) * (styling.zoom ? styling.zoom : 1)}"`;
923 }
924
925 let svg = `<svg${classes}${id} version="1.1" xmlns="http://www.w3.org/2000/svg"${sizing} viewBox="${x1} ${y1} ${x2 - x1} ${y2 - y1}">
926 <text font-size="0">${swuSign}</text>${background}`;
927 const line = styling.detail && styling.detail[0];
928 const fill = styling.detail && styling.detail[1];
929 svg += '\n' + parsed.spatials.map(spatial => {
930 let svg = symbolText$1(spatial.symbol, spatial.coord);
931 let symLine = line;
932
933 if (spatial.detail) {
934 symLine = spatial.detail[0];
935 } else if (styling.colorize) {
936 symLine = colorize(spatial.symbol);
937 }
938
939 if (symLine) {
940 svg = svg.replace(/class="sym-line" fill="black"/, `class="sym-line" fill="${symLine}"`);
941 }
942
943 let symFill = fill;
944
945 if (spatial.detail && spatial.detail[1]) {
946 symFill = spatial.detail[1];
947 }
948
949 if (symFill) {
950 svg = svg.replace(/class="sym-fill" fill="white"/, `class="sym-fill" fill="${symFill}"`);
951 }
952
953 if (spatial.zoom) {
954 svg = `<g transform="scale(${spatial.zoom})">${svg}</g>`;
955 }
956
957 return ` <g transform="translate(${spatial.coord[0]},${spatial.coord[1]})">
958${svg}
959 </g>`;
960 }).join('\n');
961 svg += '\n</svg>';
962 return svg;
963 }
964
965 return blank;
966 };
967
968 const signCanvas = function (swuSign) {
969 const parsed = parse$1.sign(swuSign);
970
971 if (parsed.spatials) {
972 const canvas = document.createElement('canvas');
973 const context = canvas.getContext('2d');
974 let styling = parse(parsed.style);
975
976 if (styling.detailsym) {
977 styling.detailsym.forEach(sym => {
978 if (parsed.spatials[sym.index - 1]) {
979 parsed.spatials[sym.index - 1].detail = sym.detail;
980 }
981 });
982 }
983
984 let x1 = Math.min(...parsed.spatials.map(spatial => spatial.coord[0]));
985 let y1 = Math.min(...parsed.spatials.map(spatial => spatial.coord[1]));
986 let x2 = parsed.max[0];
987 let y2 = parsed.max[1];
988
989 if (styling.zoomsym) {
990 styling.zoomsym.forEach(sym => {
991 if (parsed.spatials[sym.index - 1]) {
992 parsed.spatials[sym.index - 1].zoom = sym.zoom;
993
994 if (sym.offset) {
995 parsed.spatials[sym.index - 1].coord[0] += sym.offset[0];
996 parsed.spatials[sym.index - 1].coord[1] += sym.offset[1];
997 }
998
999 let size = symbolSize$1(parsed.spatials[sym.index - 1].symbol);
1000 x2 = Math.max(x2, parsed.spatials[sym.index - 1].coord[0] + size[0] * sym.zoom);
1001 y2 = Math.max(y2, parsed.spatials[sym.index - 1].coord[1] + size[1] * sym.zoom);
1002 }
1003 });
1004 }
1005
1006 if (styling.padding) {
1007 x1 -= styling.padding;
1008 y1 -= styling.padding;
1009 x2 += styling.padding;
1010 y2 += styling.padding;
1011 }
1012
1013 let sizing = 1;
1014
1015 if (styling.zoom != 'x') {
1016 sizing = styling.zoom;
1017 }
1018
1019 let w = (x2 - x1) * sizing;
1020 let h = (y2 - y1) * sizing;
1021 canvas.width = w ? w : 1;
1022 canvas.height = h ? h : 1;
1023
1024 if (styling.background) {
1025 context.rect(0, 0, w, h);
1026 context.fillStyle = styling.background;
1027 context.fill();
1028 }
1029
1030 const line = styling.detail && styling.detail[0] || "black";
1031 const fill = styling.detail && styling.detail[1] || "white";
1032 parsed.spatials.forEach(spatial => {
1033 let symLine = line;
1034
1035 if (spatial.detail) {
1036 symLine = spatial.detail[0];
1037 } else if (styling.colorize) {
1038 symLine = colorize(spatial.symbol);
1039 }
1040
1041 let symFill = fill;
1042
1043 if (spatial.detail && spatial.detail[1]) {
1044 symFill = spatial.detail[1];
1045 }
1046
1047 let symZoom = spatial.zoom || 1;
1048 context.font = 30 * sizing * symZoom + "px 'SuttonSignWritingFill'";
1049 context.fillStyle = symFill;
1050 context.fillText(symbolFill$1(spatial.symbol), (spatial.coord[0] - x1) * sizing, (spatial.coord[1] - y1) * sizing);
1051 context.font = 30 * sizing * symZoom + "px 'SuttonSignWritingLine'";
1052 context.fillStyle = symLine;
1053 context.fillText(symbolLine$1(spatial.symbol), (spatial.coord[0] - x1) * sizing, (spatial.coord[1] - y1) * sizing);
1054 });
1055 return canvas;
1056 }
1057 };
1058 /**
1059 * Function that creates a binary PNG image from an SWU sign with an optional style string
1060 * @function swu.signPng
1061 * @param {string} swuSign - an SWU sign with optional style string
1062 * @example
1063 * swu.signPng('𝠀ņ€€’ņ€€šņ‹šĨņ‹›Đ𝠃ðĪŸðĪĐņ‹›ĐðĢĩðĪņ€€’ðĪ‡ðĢĪņ‹šĨðĪðĪ†ņ€€šðĢŪðĢ­')
1064 *
1065 * return 'data:image/png;base64,iVBORw...'
1066 */
1067
1068
1069 const signPng = swuSign => {
1070 const canvas = signCanvas(swuSign);
1071 const png = canvas.toDataURL("image/png");
1072 canvas.remove();
1073 return png;
1074 };
1075
1076 /**
1077 * Function that normalizes an SWU sign for a center of 500,500
1078 * @function swu.signNormalize
1079 * @param {string} swuSign - an SWU sign with optional style string
1080 * @example
1081 * swu.signNormalize('𝠀ņ€€’ņ€€šņ‹šĨņ‹›Đ𝠃ðĪŸðĪĐņ‹›ĐðĢĩðĪņ€€’ðĪ‡ðĢĪņ‹šĨðĪðĪ†ņ€€šðĢŪðĢ­')
1082 *
1083 * return '𝠀ņ€€’ņ€€šņ‹šĨņ‹›Đ𝠃ðĪŸðĪĐņ‹›ĐðĢĩðĪņ€€’ðĪ‡ðĢĪņ‹šĨðĪðĪ†ņ€€šðĢŪðĢ­'
1084 */
1085
1086 const signNormalize = swuSign => {
1087 const parsed = parse$1.sign(swuSign);
1088
1089 if (parsed.spatials) {
1090 const symbolsizes = parsed.spatials.reduce((output, spatial) => {
1091 const size = symbolSize$1(spatial.symbol);
1092 output[spatial.symbol] = {
1093 width: size[0],
1094 height: size[1]
1095 };
1096 return output;
1097 }, {});
1098
1099 const bbox = symbols => {
1100 const x1 = Math.min(...symbols.map(spatial => spatial.coord[0]));
1101 const y1 = Math.min(...symbols.map(spatial => spatial.coord[1]));
1102 const x2 = Math.max(...symbols.map(spatial => spatial.coord[0] + parseInt(symbolsizes[spatial.symbol].width)));
1103 const y2 = Math.max(...symbols.map(spatial => spatial.coord[1] + parseInt(symbolsizes[spatial.symbol].height)));
1104 return {
1105 x1: x1,
1106 y1: y1,
1107 x2: x2,
1108 y2: y2
1109 };
1110 };
1111
1112 const hrange = ranges['hcenter'];
1113 const hsyms = parsed.spatials.filter(spatial => {
1114 const dec = parseInt(spatial.symbol.slice(1, 4), 16);
1115 return hrange[0] <= dec && hrange[1] >= dec;
1116 });
1117 const vrange = ranges['vcenter'];
1118 const vsyms = parsed.spatials.filter(spatial => {
1119 const dec = parseInt(spatial.symbol.slice(1, 4), 16);
1120 return vrange[0] <= dec && vrange[1] >= dec;
1121 });
1122 let abox = bbox(parsed.spatials);
1123 let max = [abox.x2, abox.y2];
1124
1125 if (hsyms.length) {
1126 const hbox = bbox(hsyms);
1127 abox.x1 = hbox.x1;
1128 abox.x2 = hbox.x2;
1129 }
1130
1131 if (vsyms.length) {
1132 const vbox = bbox(vsyms);
1133 abox.y1 = vbox.y1;
1134 abox.y2 = vbox.y2;
1135 }
1136
1137 const offset = [parseInt((abox.x2 + abox.x1) / 2) - 500, parseInt((abox.y2 + abox.y1) / 2) - 500];
1138 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 || '');
1139 return swuout;
1140 }
1141 };
1142
1143 exports.signNormalize = signNormalize;
1144 exports.signPng = signPng;
1145 exports.signSvg = signSvg;
1146 exports.symbolFill = symbolFill$1;
1147 exports.symbolLine = symbolLine$1;
1148 exports.symbolNormalize = symbolNormalize;
1149 exports.symbolPng = symbolPng;
1150 exports.symbolSize = symbolSize$1;
1151 exports.symbolSvg = symbolSvg;
1152 exports.symbolText = symbolText$1;
1153
1154 Object.defineProperty(exports, '__esModule', { value: true });
1155
1156})));
1157
1158/* support ongoing development on https://patreon.com/signwriting */