UNPKG

25.1 kBJavaScriptView Raw
1/**
2* Sutton SignWriting Core Module v1.4.2 (https://github.com/sutton-signwriting/core)
3* Author: Steve Slevinski (https://SteveSlevinski.me)
4* fsw.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.fsw = {})));
11})(this, (function (exports) { 'use strict';
12
13 /**
14 * Object of regular expressions for FSW strings
15 *
16 * @alias fsw.re
17 * @property {string} symbol - regular expressions for a symbol
18 * @property {string} coord - regular expressions for a coordinate
19 * @property {string} sort - regular expressions for the sorting marker
20 * @property {string} box - regular expression for a signbox marker
21 * @property {string} prefix - regular expression for a sorting marker followed by one or more symbols
22 * @property {string} spatial - regular expression for a symbol followed by a coordinate
23 * @property {string} signbox - regular expression for a signbox marker, max coordinate and zero or more spatial symbols
24 * @property {string} sign - regular expression for an optional prefix followed by a signbox
25 * @property {string} sortable - regular expression for a mandatory prefix followed by a signbox
26 */
27 let re$1 = {
28 'symbol': 'S[123][0-9a-f]{2}[0-5][0-9a-f]',
29 'coord': '[0-9]{3}x[0-9]{3}',
30 'sort': 'A',
31 'box': '[BLMR]'
32 };
33 re$1.prefix = `(?:${re$1.sort}(?:${re$1.symbol})+)`;
34 re$1.spatial = `${re$1.symbol}${re$1.coord}`;
35 re$1.signbox = `${re$1.box}${re$1.coord}(?:${re$1.spatial})*`;
36 re$1.sign = `${re$1.prefix}?${re$1.signbox}`;
37 re$1.sortable = `${re$1.prefix}${re$1.signbox}`;
38
39 /**
40 * Object of regular expressions for style strings
41 *
42 * @alias style.re
43 * @type {object}
44 * @property {string} colorize - regular expression for colorize section
45 * @property {string} colorhex - regular expression for color hex values with 3 or 6 characters
46 * @property {string} colorname - regular expression for css color name
47 * @property {string} padding - regular expression for padding section
48 * @property {string} zoom - regular expression for zoom section
49 * @property {string} classbase - regular expression for class name definition
50 * @property {string} id - regular expression for id definition
51 * @property {string} colorbase - regular expression for color hex or color name
52 * @property {string} color - regular expression for single color entry
53 * @property {string} colors - regular expression for double color entry
54 * @property {string} background - regular expression for background section
55 * @property {string} detail - regular expression for color details for line and optional fill
56 * @property {string} detailsym - regular expression for color details for individual symbols
57 * @property {string} classes - regular expression for one or more class names
58 * @property {string} full - full regular expression for style string
59 */
60 let re = {
61 'colorize': 'C',
62 'colorhex': '(?:[0-9a-fA-F]{3}){1,2}',
63 'colorname': '[a-zA-Z]+',
64 'padding': 'P[0-9]{2}',
65 'zoom': 'Z(?:[0-9]+(?:\\.[0-9]+)?|x)',
66 'classbase': '-?[_a-zA-Z][_a-zA-Z0-9-]{0,100}',
67 'id': '[a-zA-Z][_a-zA-Z0-9-]{0,100}'
68 };
69 re.colorbase = `(?:${re.colorhex}|${re.colorname})`;
70 re.color = `_${re.colorbase}_`;
71 re.colors = `_${re.colorbase}(?:,${re.colorbase})?_`;
72 re.background = `G${re.color}`;
73 re.detail = `D${re.colors}`;
74 re.detailsym = `D[0-9]{2}${re.colors}`;
75 re.classes = `${re.classbase}(?: ${re.classbase})*`;
76 re.full = `-(${re.colorize})?(${re.padding})?(${re.background})?(${re.detail})?(${re.zoom})?(?:-((?:${re.detailsym})*))?(?:-(${re.classes})?!(?:(${re.id})!)?)?`;
77
78 const prefixColor = color => {
79 const regex = new RegExp(`^${re.colorhex}$`);
80 return (regex.test(color) ? '#' : '') + color;
81 };
82
83 const definedProps = obj => Object.fromEntries(Object.entries(obj).filter(([k, v]) => v !== undefined));
84 /**
85 * Function to parse style string to object
86 * @function style.parse
87 * @param {string} styleString - a style string
88 * @returns {StyleObject} elements of style string
89 * @example
90 * style.parse('-CP10G_blue_D_red,Cyan_')
91 *
92 * return {
93 * 'colorize': true,
94 * 'padding': 10,
95 * 'background': 'blue',
96 * 'detail': ['red', 'Cyan']
97 * }
98 */
99
100
101 const parse$1 = styleString => {
102 const regex = `^${re.full}`;
103 const m = (typeof styleString === 'string' ? styleString.match(new RegExp(regex)) : []) || [];
104 return definedProps({
105 'colorize': !m[1] ? undefined : !!m[1],
106 'padding': !m[2] ? undefined : parseInt(m[2].slice(1)),
107 'background': !m[3] ? undefined : prefixColor(m[3].slice(2, -1)),
108 'detail': !m[4] ? undefined : m[4].slice(2, -1).split(',').map(prefixColor),
109 'zoom': !m[5] ? undefined : m[5] === 'Zx' ? 'x' : parseFloat(m[5].slice(1)),
110 'detailsym': !m[6] ? undefined : m[6].match(new RegExp(re.detailsym, 'g')).map(val => {
111 const parts = val.split('_');
112 const detail = parts[1].split(',').map(prefixColor);
113 return {
114 'index': parseInt(parts[0].slice(1)),
115 'detail': detail
116 };
117 }),
118 'classes': !m[7] ? undefined : m[7],
119 'id': !m[8] ? undefined : m[8]
120 });
121 };
122
123 /** 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.
124 * [Characters set definitions](https://tools.ietf.org/id/draft-slevinski-formal-signwriting-09.html#name-characters)
125 * @module convert
126 */
127 /**
128 * Function to convert an FSW coordinate string to an array of x,y integers
129 * @function convert.fsw2coord
130 * @param {string} fswCoord - An FSW coordinate string
131 * @returns {number[]} Array of x,y integers
132 * @example
133 * convert.fsw2coord('500x500')
134 *
135 * return [500, 500]
136 */
137
138
139 const fsw2coord = fswCoord => fswCoord.split('x').map(num => parseInt(num));
140
141 const parse = {
142 /**
143 * Function to parse an fsw symbol with optional coordinate and style string
144 * @function fsw.parse.symbol
145 * @param {string} fswSym - an fsw symbol
146 * @returns {object} elements of fsw symbol
147 * @example
148 * fsw.parse.symbol('S10000500x500-C')
149 *
150 * return {
151 * 'symbol': 'S10000',
152 * 'coord': [500, 500],
153 * 'style': '-C'
154 * }
155 */
156 symbol: fswSym => {
157 const regex = `^(${re$1.symbol})(${re$1.coord})?(${re.full})?`;
158 const symbol = typeof fswSym === 'string' ? fswSym.match(new RegExp(regex)) : undefined;
159 return {
160 'symbol': symbol ? symbol[1] : undefined,
161 'coord': symbol && symbol[2] ? fsw2coord(symbol[2]) : undefined,
162 'style': symbol ? symbol[3] : undefined
163 };
164 },
165
166 /**
167 * Function to parse an fsw sign with style string
168 * @function fsw.parse.sign
169 * @param {string} fswSign - an fsw sign
170 * @returns {object} elements of fsw sign
171 * @example
172 * fsw.parse.sign('AS10011S10019S2e704S2e748M525x535S2e748483x510S10011501x466S2e704510x500S10019476x475-C')
173 *
174 * return {
175 * sequence: ['S10011', 'S10019', 'S2e704', 'S2e748'],
176 * box: 'M',
177 * max: [525, 535],
178 * spatials: [
179 * {
180 * symbol: 'S2e748',
181 * coord: [483, 510]
182 * },
183 * {
184 * symbol: 'S10011',
185 * coord: [501, 466]
186 * },
187 * {
188 * symbol: 'S2e704',
189 * coord: [510, 500]
190 * },
191 * {
192 * symbol: 'S10019',
193 * coord: [476, 475]
194 * }
195 * ],
196 * style: '-C'
197 * }
198 */
199 sign: fswSign => {
200 const regex = `^(${re$1.prefix})?(${re$1.signbox})(${re.full})?`;
201 const sign = typeof fswSign === 'string' ? fswSign.match(new RegExp(regex)) : undefined;
202
203 if (sign) {
204 return {
205 'sequence': sign[1] ? sign[1].slice(1).match(/.{6}/g) : undefined,
206 'box': sign[2][0],
207 'max': fsw2coord(sign[2].slice(1, 8)),
208 'spatials': sign[2].length < 9 ? undefined : sign[2].slice(8).match(/(.{13})/g).map(m => {
209 return {
210 symbol: m.slice(0, 6),
211 coord: [parseInt(m.slice(6, 9)), parseInt(m.slice(10, 13))]
212 };
213 }),
214 'style': sign[3]
215 };
216 } else {
217 return {};
218 }
219 },
220
221 /**
222 * Function to parse an fsw text
223 * @function fsw.parse.text
224 * @param {string} fswText - an fsw text
225 * @returns {array} fsw signs and punctuations
226 * @example
227 * fsw.parse.text('AS14c20S27106M518x529S14c20481x471S27106503x489 AS18701S1870aS2e734S20500M518x533S1870a489x515S18701482x490S20500508x496S2e734500x468 S38800464x496')
228 *
229 * return [
230 * 'AS14c20S27106M518x529S14c20481x471S27106503x489',
231 * 'AS18701S1870aS2e734S20500M518x533S1870a489x515S18701482x490S20500508x496S2e734500x468',
232 * 'S38800464x496'
233 * ]
234 */
235 text: fswText => {
236 if (typeof fswText !== 'string') return [];
237 const regex = `(${re$1.sign}(${re.full})?|${re$1.spatial}(${re.full})?)`;
238 const matches = fswText.match(new RegExp(regex, 'g'));
239 return matches ? [...matches] : [];
240 }
241 };
242
243 const compose = {
244 /**
245 * Function to compose an fsw symbol with optional coordinate and style string
246 * @function fsw.compose.symbol
247 * @param {object} fswSymObject - an fsw symbol object
248 * @param {string} fswSymObject.symbol - an fsw symbol key
249 * @param {number[]} fswSymObject.coord - top-left coordinate of symbol
250 * @param {string} fswSymObject.style - a style string for custom appearance
251 * @returns {string} an fsw symbol string
252 * @example
253 * fsw.compose.symbol({
254 * 'symbol': 'S10000',
255 * 'coord': [480, 480],
256 * 'style': '-C'
257 * })
258 *
259 * return 'S10000480x480-C'
260 */
261 symbol: fswSymObject => {
262 if (typeof fswSymObject.symbol === 'string') {
263 const symbol = (fswSymObject.symbol.match(re$1.symbol) || [''])[0];
264
265 if (symbol) {
266 const x = (fswSymObject.coord && fswSymObject.coord[0] || '').toString();
267 const y = (fswSymObject.coord && fswSymObject.coord[1] || '').toString();
268 const coord = ((x + 'x' + y).match(re$1.coord) || [''])[0] || '';
269 const styleStr = typeof fswSymObject.style === 'string' && (fswSymObject.style.match(re.full) || [''])[0] || '';
270 return symbol + coord + styleStr;
271 }
272 }
273
274 return undefined;
275 },
276
277 /**
278 * Function to compose an fsw sign with style string
279 * @function fsw.compose.sign
280 * @param {object} fswSymObject - an fsw sign object
281 * @param {string[]} fswSignObject.sequence - an ordered array of symbols
282 * @param {string} fswSignObject.box - a choice BLMR: horizontal Box, Left, Middle, and Right lane
283 * @param {number[]} fswSignObject.max - max bottom-right coordinate of the signbox space
284 * @param {{symbol:string,coord:number[]}[]} fswSignObject.spatials - array of symbols with top-left coordinate placement
285 * @param {string} fswSignObject.style - a style string for custom appearance
286 * @returns {string} an fsw sign string
287 * @example
288 * fsw.compose.sign({
289 * sequence: ['S10011', 'S10019', 'S2e704', 'S2e748'],
290 * box: 'M',
291 * max: [525, 535],
292 * spatials: [
293 * {
294 * symbol: 'S2e748',
295 * coord: [483, 510]
296 * },
297 * {
298 * symbol: 'S10011',
299 * coord: [501, 466]
300 * },
301 * {
302 * symbol: 'S2e704',
303 * coord: [510, 500]
304 * },
305 * {
306 * symbol: 'S10019',
307 * coord: [476, 475]
308 * }
309 * ],
310 * style: '-C'
311 * })
312 *
313 * return 'AS10011S10019S2e704S2e748M525x535S2e748483x510S10011501x466S2e704510x500S10019476x475-C'
314 */
315 sign: fswSignObject => {
316 let box = typeof fswSignObject.box !== 'string' ? 'M' : (fswSignObject.box + 'M').match(re$1.box);
317 const x = (fswSignObject.max && fswSignObject.max[0] || '').toString();
318 const y = (fswSignObject.max && fswSignObject.max[1] || '').toString();
319 const max = ((x + 'x' + y).match(re$1.coord) || [''])[0] || '';
320 if (!max) return undefined;
321 let prefix = '';
322
323 if (fswSignObject.sequence && Array.isArray(fswSignObject.sequence)) {
324 prefix = fswSignObject.sequence.map(key => (key.match(re$1.symbol) || [''])[0]).join('');
325 prefix = prefix ? 'A' + prefix : '';
326 }
327
328 let signbox = '';
329
330 if (fswSignObject.spatials && Array.isArray(fswSignObject.spatials)) {
331 signbox = fswSignObject.spatials.map(spatial => {
332 if (typeof spatial.symbol === 'string') {
333 const symbol = (spatial.symbol.match(re$1.symbol) || [''])[0];
334
335 if (symbol) {
336 const x = (spatial.coord && spatial.coord[0] || '').toString();
337 const y = (spatial.coord && spatial.coord[1] || '').toString();
338 const coord = ((x + 'x' + y).match(re$1.coord) || [''])[0] || '';
339
340 if (coord) {
341 return symbol + coord;
342 }
343 }
344 }
345
346 return '';
347 }).join('');
348 }
349
350 const styleStr = typeof fswSignObject.style === 'string' && (fswSignObject.style.match(re.full) || [''])[0] || '';
351 return prefix + box + max + signbox + styleStr;
352 }
353 };
354
355 /**
356 * Function to gather sizing information about an fsw sign or symbol
357 * @function fsw.info
358 * @param {string} fsw - an fsw sign or symbol
359 * @returns {object} information about the fsw string
360 * @example
361 * fsw.info('AS14c20S27106L518x529S14c20481x471S27106503x489-P10Z2')
362 *
363 * return {
364 * minX: 481,
365 * minY: 471,
366 * width: 37,
367 * height: 58,
368 * zoom: 2,
369 * padding: 10,
370 * segment: 'sign',
371 * lane: -1
372 * }
373 */
374
375 const info = fsw => {
376 let lanes = {
377 "B": 0,
378 "L": -1,
379 "M": 0,
380 "R": 1
381 };
382 let parsed = parse.sign(fsw);
383 let width, height, segment, x1, x2, y1, y2, lane;
384
385 if (parsed.spatials) {
386 x1 = Math.min(...parsed.spatials.map(spatial => spatial.coord[0]));
387 x2 = parsed.max[0];
388 width = x2 - x1;
389 y1 = Math.min(...parsed.spatials.map(spatial => spatial.coord[1]));
390 y2 = parsed.max[1];
391 height = y2 - y1;
392 segment = 'sign';
393 lane = parsed.box;
394 } else {
395 parsed = parse.symbol(fsw);
396 lane = "M";
397
398 if (parsed.coord) {
399 x1 = parsed.coord[0];
400 width = (500 - x1) * 2;
401 y1 = parsed.coord[1];
402 height = (500 - y1) * 2;
403 segment = 'symbol';
404 } else {
405 x1 = 490;
406 width = 20;
407 y1 = 490;
408 height = 20;
409 segment = 'none';
410 }
411 }
412
413 let style = parse$1(parsed.style);
414 let zoom = style.zoom || 1;
415 let padding = style.padding || 0;
416 return {
417 minX: x1,
418 minY: y1,
419 width: width,
420 height: height,
421 segment: segment,
422 lane: lanes[lane],
423 padding: padding,
424 zoom: zoom
425 };
426 };
427
428 const columnDefaults = {
429 'height': 500,
430 'width': 150,
431 'offset': 50,
432 'pad': 20,
433 'margin': 5,
434 'dynamic': false,
435 'background': undefined,
436 'punctuation': {
437 'spacing': true,
438 'pad': 30,
439 'pull': true
440 },
441 'style': {
442 'detail': ['black', 'white'],
443 'zoom': 1
444 }
445 };
446 /**
447 * Function to an object of column options with default values
448 *
449 * @function fsw.columnDefaultsMerge
450 * @param {ColumnOptions} options - object of column options
451 * @returns {ColumnOptions} object of column options merged with column defaults
452 * @example
453 * fsw.columnDefaultsMerge({height: 500,width:150})
454 *
455 * return {
456 * "height": 500,
457 * "width": 150,
458 * "offset": 50,
459 * "pad": 20,
460 * "margin": 5,
461 * "dynamic": false,
462 * "punctuation": {
463 * "spacing": true,
464 * "pad": 30,
465 * "pull": true
466 * },
467 * "style": {
468 * "detail": [
469 * "black",
470 * "white"
471 * ],
472 * "zoom": 1
473 * }
474 * }
475 */
476
477 const columnDefaultsMerge = options => {
478 if (typeof options !== 'object') options = {};
479 return { ...columnDefaults,
480 ...options,
481 punctuation: { ...columnDefaults.punctuation,
482 ...options.punctuation
483 },
484 style: { ...columnDefaults.style,
485 ...options.style
486 }
487 };
488 };
489 /**
490 * Function to transform an FSW text to an array of columns
491 *
492 * @function fsw.columns
493 * @param {string} fswText - FSW text of signs and punctuation
494 * @param {ColumnOptions} options - object of column options
495 * @returns {{options:ColumnOptions,widths:number[],columns:ColumnData}} object of column options, widths array, and column data
496 * @example
497 * fsw.columns('AS14c20S27106M518x529S14c20481x471S27106503x489 AS18701S1870aS2e734S20500M518x533S1870a489x515S18701482x490S20500508x496S2e734500x468 S38800464x496', {height: 500,width:150})
498 *
499 * return {
500 * "options": {
501 * "height": 500,
502 * "width": 150,
503 * "offset": 50,
504 * "pad": 20,
505 * "margin": 5,
506 * "dynamic": false,
507 * "punctuation": {
508 * "spacing": true,
509 * "pad": 30,
510 * "pull": true
511 * },
512 * "style": {
513 * "detail": [
514 * "black",
515 * "white"
516 * ],
517 * "zoom": 1
518 * }
519 * },
520 * "widths": [
521 * 150
522 * ],
523 * "columns": [
524 * [
525 * {
526 * "x": 56,
527 * "y": 20,
528 * "minX": 481,
529 * "minY": 471,
530 * "width": 37,
531 * "height": 58,
532 * "lane": 0,
533 * "padding": 0,
534 * "segment": "sign",
535 * "text": "AS14c20S27106M518x529S14c20481x471S27106503x489",
536 * "zoom": 1
537 * },
538 * {
539 * "x": 57,
540 * "y": 118,
541 * "minX": 482,
542 * "minY": 468,
543 * "width": 36,
544 * "height": 65,
545 * "lane": 0,
546 * "padding": 0,
547 * "segment": "sign",
548 * "text": "AS18701S1870aS2e734S20500M518x533S1870a489x515S18701482x490S20500508x496S2e734500x468",
549 * "zoom": 1
550 * },
551 * {
552 * "x": 39,
553 * "y": 203,
554 * "minX": 464,
555 * "minY": 496,
556 * "width": 72,
557 * "height": 8,
558 * "lane": 0,
559 * "padding": 0,
560 * "segment": "symbol",
561 * "text": "S38800464x496",
562 * "zoom": 1
563 * }
564 * ]
565 * ]
566 * }
567 */
568
569
570 const columns = (fswText, options) => {
571 if (typeof fswText !== 'string') return {};
572 const values = columnDefaultsMerge(options);
573 let input = parse.text(fswText);
574 let cursor = 0;
575 let cols = [];
576 let col = [];
577 let plus = 0;
578 let center = parseInt(values.width / 2);
579 let maxHeight = values.height - values.margin;
580 let pullable = true;
581 let finalize = false;
582
583 for (let val of input) {
584 let informed = info(val);
585 cursor += plus;
586
587 if (values.punctuation.spacing) {
588 cursor += informed.segment == 'sign' ? values.pad : 0;
589 } else {
590 cursor += values.pad;
591 }
592
593 finalize = cursor + informed.height > maxHeight;
594
595 if (finalize && informed.segment == 'symbol' && values.punctuation.pull && pullable) {
596 finalize = false;
597 pullable = false;
598 }
599
600 if (col.length == 0) {
601 finalize = false;
602 }
603
604 if (finalize) {
605 cursor = values.pad;
606 cols.push(col);
607 col = [];
608 pullable = true;
609 }
610
611 col.push(Object.assign(informed, {
612 x: center + values.offset * informed.lane - (500 - informed.minX) * informed.zoom * values.style.zoom,
613 y: cursor,
614 text: val
615 }));
616 cursor += informed.height * informed.zoom * values.style.zoom;
617
618 if (values.punctuation.spacing) {
619 plus = informed.segment == 'sign' ? values.pad : values.punctuation.pad;
620 } else {
621 plus = values.pad;
622 }
623 }
624
625 if (col.length) {
626 cols.push(col);
627 } // over height issue when pulling punctuation
628
629
630 if (values.punctuation.pull) {
631 for (let col of cols) {
632 let last = col[col.length - 1];
633 let diff = last.y + last.height - (values.height - values.margin);
634
635 if (diff > 0) {
636 let adj = parseInt(diff / col.length) + 1;
637
638 for (let i in col) {
639 col[i].y -= adj * i + adj;
640 }
641 }
642 }
643 } // contract, expand, adjust
644
645
646 let widths = [];
647
648 for (let col of cols) {
649 let min = [center - values.offset - values.pad];
650 let max = [center + values.offset + values.pad];
651
652 for (let item of col) {
653 min.push(item.x - values.pad);
654 max.push(item.x + item.width + values.pad);
655 }
656
657 min = Math.min(...min);
658 max = Math.max(...max);
659 let width = values.width;
660 let adj = 0;
661
662 if (!values.dynamic) {
663 adj = center - parseInt((min + max) / 2);
664 } else {
665 width = max - min;
666 adj = -min;
667 }
668
669 for (let item of col) {
670 item.x += adj;
671 }
672
673 widths.push(width);
674 }
675
676 return {
677 'options': values,
678 'widths': widths,
679 'columns': cols
680 };
681 };
682
683 /**
684 * Array of numbers for kinds of symbols: writing, location, and punctuation.
685 * @alias fsw.kind
686 * @type {array}
687 */
688
689 const kind = [0x100, 0x37f, 0x387];
690 /**
691 * Array of numbers for categories of symbols: hand, movement, dynamics, head, trunk & limb, location, and punctuation.
692 * @alias fsw.category
693 * @type {array}
694 */
695
696 const category = [0x100, 0x205, 0x2f7, 0x2ff, 0x36d, 0x37f, 0x387];
697 /**
698 * Array of numbers for the 30 symbol groups.
699 * @alias fsw.group
700 * @type {array}
701 */
702
703 const group = [0x100, 0x10e, 0x11e, 0x144, 0x14c, 0x186, 0x1a4, 0x1ba, 0x1cd, 0x1f5, 0x205, 0x216, 0x22a, 0x255, 0x265, 0x288, 0x2a6, 0x2b7, 0x2d5, 0x2e3, 0x2f7, 0x2ff, 0x30a, 0x32a, 0x33b, 0x359, 0x36d, 0x376, 0x37f, 0x387];
704 /**
705 * Object of symbol ranges with starting and ending numbers.
706 *
707 * { all, writing, hand, movement, dynamic, head, hcenter, vcenter, trunk, limb, location, punctuation }
708 * @alias fsw.ranges
709 * @type {object}
710 */
711
712 const ranges = {
713 'all': [0x100, 0x38b],
714 'writing': [0x100, 0x37e],
715 'hand': [0x100, 0x204],
716 'movement': [0x205, 0x2f6],
717 'dynamic': [0x2f7, 0x2fe],
718 'head': [0x2ff, 0x36c],
719 'hcenter': [0x2ff, 0x36c],
720 'vcenter': [0x2ff, 0x375],
721 'trunk': [0x36d, 0x375],
722 'limb': [0x376, 0x37e],
723 'location': [0x37f, 0x386],
724 'punctuation': [0x387, 0x38b]
725 };
726 /**
727 * Function to test if symbol is of a certain type.
728 * @function fsw.isType
729 * @param {string} key - an FSW symbol key
730 * @param {string} type - the name of a symbol range
731 * @returns {boolean} is symbol of specified type
732 * @example
733 * fsw.isType('S10000', 'hand')
734 *
735 * return true
736 */
737
738 const isType = (key, type) => {
739 const parsed = parse.symbol(key);
740
741 if (parsed.symbol) {
742 const dec = parseInt(parsed.symbol.slice(1, 4), 16);
743 const range = ranges[type];
744
745 if (range) {
746 return range[0] <= dec && range[1] >= dec;
747 }
748 }
749
750 return false;
751 };
752
753 /**
754 * Array of colors associated with the seven symbol categories.
755 * @alias fsw.colors
756 * @type {array}
757 */
758
759 const colors = ['#0000CC', '#CC0000', '#FF0099', '#006600', '#000000', '#884411', '#FF9900'];
760 /**
761 * Function that returns the standardized color for a symbol.
762 * @function fsw.colorize
763 * @param {string} key - an FSW symbol key
764 * @returns {string} name of standardized color for symbol
765 * @example
766 * fsw.colorize('S10000')
767 *
768 * return '#0000CC'
769 */
770
771 const colorize = key => {
772 const parsed = parse.symbol(key);
773 let color = '#000000';
774
775 if (parsed.symbol) {
776 const dec = parseInt(parsed.symbol.slice(1, 4), 16);
777 const index = category.findIndex(val => val > dec);
778 color = colors[index < 0 ? 6 : index - 1];
779 }
780
781 return color;
782 };
783
784 exports.category = category;
785 exports.colorize = colorize;
786 exports.colors = colors;
787 exports.columnDefaults = columnDefaults;
788 exports.columnDefaultsMerge = columnDefaultsMerge;
789 exports.columns = columns;
790 exports.compose = compose;
791 exports.group = group;
792 exports.info = info;
793 exports.isType = isType;
794 exports.kind = kind;
795 exports.parse = parse;
796 exports.ranges = ranges;
797 exports.re = re$1;
798
799 Object.defineProperty(exports, '__esModule', { value: true });
800
801}));
802
803/* support ongoing development on https://patreon.com/signwriting */