From a5b2f23ceef59a07cb2572c6262be6beb7ea09e5 Mon Sep 17 00:00:00 2001 From: Azgaar Date: Tue, 9 Feb 2021 00:02:21 +0300 Subject: [PATCH] v1.5.12 - emblems adding, save/load --- index.css | 7 +- index.html | 605 ++-------------------- modules/coa-generator.js | 5 +- modules/coa-renderer-old.js | 887 +++++++++++++++++++++++++++++++++ modules/coa-renderer.js | 447 +++++++++++------ modules/cultures-generator.js | 1 - modules/save-and-load.js | 16 +- modules/ui/burg-editor.js | 27 +- modules/ui/editors.js | 7 +- modules/ui/emblems-editor.js | 82 ++- modules/ui/provinces-editor.js | 26 +- modules/ui/states-editor.js | 12 +- 12 files changed, 1379 insertions(+), 743 deletions(-) create mode 100644 modules/coa-renderer-old.js diff --git a/index.css b/index.css index 386e2ba5..0adc7ba2 100644 --- a/index.css +++ b/index.css @@ -1451,9 +1451,13 @@ div.states > .coaIcon > use { line-height: 1.4em; } +#burgBody div.label { + display: inline-block; + width: 6em; +} + #stateNameEditor div.label, #provinceNameEditor div.label, -#burgBody div.label, #regimentBody div.label { display: inline-block; width: 5.5em; @@ -1588,6 +1592,7 @@ rect.fillRect { text-align: center; } +#emblemUploadControl, #emblemDownloadControl { margin-top: .3em; text-align: center; diff --git a/index.html b/index.html index ea9000cf..8d495fde 100644 --- a/index.html +++ b/index.html @@ -142,6 +142,7 @@ + @@ -203,6 +204,7 @@ + @@ -213,16 +215,16 @@ + + Port - - - + @@ -875,11 +877,6 @@ - - - - - @@ -1929,9 +1926,6 @@ - - -
@@ -1941,7 +1935,7 @@ - + @@ -2433,8 +2427,10 @@ + - + + - - - - + + + - - - - - + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + diff --git a/modules/coa-generator.js b/modules/coa-generator.js index d8bab364..a0702e34 100644 --- a/modules/coa-generator.js +++ b/modules/coa-generator.js @@ -191,20 +191,17 @@ }; const generate = function(parent, kinship, dominion) { + if (parent === "custom") parent = null; let usedPattern = null, usedTinctures = []; // TODO // seafaring - // stringify coa on save and load - // generate on new item creation // old versions auto migration: coa generation for cultures and states etc. // emblems layer for old maps // define emblems layer style for all styles // style settings for emblems layer - // fix map download svg/png // test in FF // layout preset - // burg editor - add emblem // other editors const t1 = P(kinship) ? parent.t1 : getTincture("field"); diff --git a/modules/coa-renderer-old.js b/modules/coa-renderer-old.js new file mode 100644 index 00000000..be34ed01 --- /dev/null +++ b/modules/coa-renderer-old.js @@ -0,0 +1,887 @@ +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : + typeof define === 'function' && define.amd ? define(factory) : + (global.COArenderer = factory()); +}(this, (function () {'use strict'; + const colors = { + argent: "#fafafa", + or: "#ffe066", + gules: "#d7374a", + sable: "#333333", + azure: "#377cd7", + vert: "#26c061", + purpure: "#522d5b", + murrey: "#85185b", + sanguine: "#b63a3a", + tenné: "#cc7f19" + } + + const shieldPositions = { + // shield-specific position: [x, y] (relative to center) + heater: { + a: [-43.75, -50], b: [0, -50], c: [43.75, -50], + d: [-43.75, 0], e: [0, 0], f: [43.75, 0], + g: [-32.25, 37.5], h: [0, 50], i: [32.25, 37.5], + y: [-50, -50], z: [0, 62.5], + j: [-37.5, -37.5], k: [0, -37.5], l: [37.5, -37.5], + m: [-30, 30], n: [0, 42.5], o: [30, 30], + p: [-37.5, 0], q: [37.5, 0], + A: [-66.2, -66.6], B: [-22, -66.6], C: [22, -66.6], D: [66.2, -66.6], + K: [-66.2, -20], E: [66.2, -20], + J: [-55.5, 26], F: [55.5, 26], + I: [-33, 62], G: [33, 62], + H: [0, 89.5] + }, + spanish: { + a: [-43.75, -50], b: [0, -50], c: [43.75, -50], + d: [-43.75, 0], e: [0, 0], f: [43.75, 0], + g: [-43.75, 50], h: [0, 50], i: [43.75, 50], + y: [-50, -50], z: [0, 50], + j: [-37.5, -37.5], k: [0, -37.5], l: [37.5, -37.5], + m: [-37.5, 37.5], n: [0, 37.5], o: [37.5, 37.5], + p: [-37.5, 0], q: [37.5, 0], + A: [-66.2, -66.6], B: [-22, -66.6], C: [22, -66.6], D: [66.2, -66.6], + K: [-66.4, -20], E: [66.4, -20], + J: [-66.4, 26], F: [66.4, 26], + I: [-49, 70], G: [49, 70], + H: [0, 92] + }, + french: { + a: [-43.75, -50], b: [0, -50], c: [43.75, -50], + d: [-43.75, 0], e: [0, 0], f: [43.75, 0], + g: [-43.75, 50], h: [0, 50], i: [43.75, 50], + y: [-50, -50], z: [0, 65], + j: [-37.5, -37.5], k: [0, -37.5], l: [37.5, -37.5], + m: [-37.5, 37.5], n: [0, 37.5], o: [37.5, 37.5], + p: [-37.5, 0], q: [37.5, 0], + A: [-66.2, -66.6], B: [-22, -66.6], C: [22, -66.6], D: [66.2, -66.6], + K: [-66.4, -20], E: [66.4, -20], + J: [-66.4, 26], F: [66.4, 26], + I: [-65.4, 70], G: [65.4, 70], + H: [0, 89] + }, + horsehead: { + a: [-43.75, -47.5], b: [0, -50], c: [43.75, -47.5], + d: [-35, 0], e: [0, 0], f: [35, 0], + h: [0, 50], + y: [-50, -50], z: [0, 55], + j: [-35, -35], k: [0, -40], l: [35, -35], + m: [-30, 30], n: [0, 40], o: [30, 30], + p: [-27.5, 0], q: [27.5, 0], + A: [-71, -52], B: [-24, -73], C: [24, -73], D: [71, -52], + K: [-62, -16], E: [62, -16], + J: [-39, 20], F: [39, 20], + I: [-33.5, 60], G: [33.5, 60], + H: [0, 91.5] + }, + horsehead2: { + a: [-37.5, -47.5], b: [0, -50], c: [37.5, -47.5], + d: [-35, 0], e: [0, 0], f: [35, 0], + g: [-35, -47.5], h: [0, 50], i: [35, -47.5], + y: [-50, -50], z: [0, 55], + j: [-30, -30], k: [0, -40], l: [30, -30], + m: [-30, 30], n: [0, 40], o: [30, 30], + p: [-27.5, 0], q: [27.5, 0], + A: [-49, -39], B: [-22, -70], C: [22, -70], D: [49, -39], + K: [-51, -2], E: [51, -2], + J: [-38.5, 31], F: [38.5, 31], + I: [-35, 67], G: [35, 67], + H: [0, 85] + }, + polish: { + a: [-35, -50], b: [0, -50], c: [35, -50], + d: [-40, 0], e: [0, 0], f: [40, 0], + g: [-37.5, 50], h: [0, 50], i: [37.5, 50], + y: [-50, -50], z: [0, 65], + j: [-27.5, -27.5], k: [0, -45], l: [27.5, -27.5], + m: [-27.5, 27.5], n: [0, 45], o: [27.5, 27.5], + p: [-32.5, 0], q: [32.5, 0], + A: [-48, -52], B: [-23, -80], C: [23, -80], D: [48, -52], + K: [-47, -10], E: [47, -10], + J: [-62, 32], F: [62, 32], + I: [-37, 68], G: [37, 68], + H: [0, 86] + }, + hessen: { + a: [-43.75, -50], b: [0, -50], c: [43.75, -50], + d: [-43.75, 0], e: [0, 0], f: [43.75, 0], + g: [-43.75, 50], h: [0, 50], i: [43.75, 50], + y: [-50, -50], z: [0, 52.5], + j: [-40, -40], k: [0, -40], l: [40, -40], + m: [-40, 40], n: [0, 40], o: [40, 40], + p: [-40, 0], q: [40, 0], + A: [-69, -64], B: [-22, -76], C: [22, -76], D: [69, -64], + K: [-66.4, -20], E: [66.4, -20], + J: [-62, 26], F: [62, 26], + I: [-46, 70], G: [46, 70], + H: [0, 91.5] + }, + swiss: { + a: [-43.75, -50], b: [0, -50], c: [43.75, -50], + d: [-43.75, 0], e: [0, 0], f: [43.75, 0], + g: [-32, 37.5], h: [0, 50], i: [32, 37.5], + y: [-50, -50], z: [0, 62.5], + j: [-37.5, -37.5], k: [0, -37.5], l: [37.5, -37.5], + m: [-32, 32.5], n: [0, 42.5], o: [32, 32.5], + p: [-37.5, 0], q: [37.5, 0], + A: [-66.2, -66.6], B: [-22, -66], C: [22, -66], D: [66.2, -66.6], + K: [-63, -20], E: [63, -20], + J: [-50, 26], F: [50, 26], + I: [-29, 62], G: [29, 62], + H: [0, 89.5] + }, + boeotian: { + a: [-37.5, -47.5], b: [0, -47.5], c: [37.5, -47.5], + d: [-25, 0], e: [0, 0], f: [25, 0], + g: [-37.5, 47.5], h: [0, 47.5], i: [37.5, 47.5], + y: [-48, -48], z: [0, 60], + j: [-32.5, -37.5], k: [0, -45], l: [32.5, -37.5], + m: [-32.5, 37.5], n: [0, 45], o: [32.5, 37.5], + p: [-20, 0], q: [20, 0], + A: [-45, -55], B: [-20, -77], C: [20, -77], D: [45, -55], + K: [-59, -25], E: [59, -25], + J: [-58, 27], F: [58, 27], + I: [-39, 63], G: [39, 63], + H: [0, 81] + }, + roman: { + a: [-40, -52.5], b: [0, -52.5], c: [40, -52.5], + d: [-40, 0], e: [0, 0], f: [40, 0], + g: [-40, 52.5], h: [0, 52.5], i: [40, 52.5], + y: [-42.5, -52.5], z: [0, 65], + j: [-30, -37.5], k: [0, -37.5], l: [30, -37.5], + m: [-30, 37.5], n: [0, 37.5], o: [30, 37.5], + p: [-30, 0], q: [30, 0], + A: [-51.5, -65], B: [-17, -75], C: [17, -75], D: [51.5, -65], + K: [-51.5, -21], E: [51.5, -21], + J: [-51.5, 21], F: [51.5, 21], + I: [-51.5, 65], G: [51.5, 65], + H: [-17, 75], L: [17, 75] + }, + kite: { + b: [0, -65], e: [0, -15], h: [0, 35], + z: [0, 35], k: [0, -50], n: [0, 20], + p: [-20, -15], q: [20, -15], + A: [-38, -52], B: [-29, -78], C: [29, -78], D: [38, -52], + K: [-33, -20], E: [33, -20], + J: [-25, 11], F: [25, 11], + I: [-15, 42], G: [15, 42], + H: [0, 73], L: [0, -91] + }, + oldFrench: { + a: [-43.75, -50], b: [0, -50], c: [43.75, -50], + d: [-43.75, 0], e: [0, 0], f: [43.75, 0], + g: [-37.5, 50], h: [0, 50], i: [37.5, 50], + y: [-50, -50], z: [0, 62.5], + j: [-37.5, -37.5], k: [0, -37.5], l: [37.5, -37.5], + m: [-37.5, 37.5], n: [0, 45], o: [37.5, 37.5], + p: [-37.5, 0], q: [37.5, 0], + A: [-66.2, -66.6], B: [-22, -66.6], C: [22, -66.6], D: [66.2, -66.6], + K: [-66.2, -20], E: [66.2, -20], + J: [-64, 26], F: [64, 26], + I: [-45, 62], G: [45, 62], + H: [0, 91], + }, + renaissance: { + a: [-43.75, -50], b: [0, -50], c: [43.75, -50], + d: [-41.5, 0], e: [0, 0], f: [41.5, 0], + g: [-43.75, 50], h: [0, 50], i: [43.75, 50], + y: [-50, -50], z: [0, 62.5], + j: [-37.5, -37.5], k: [0, -37.5], l: [37.5, -37.5], + m: [-37.5, 37.5], n: [0, 37.5], o: [37.5, 37.5], + p: [-37.5, 0], q: [37.5, 0], + A: [-61, -55], B: [-23, -67], C: [23, -67], D: [61, -55], + K: [-55, -11], E: [55, -11], + J: [-65, 31], F: [65, 31], + I: [-45, 76], G: [45, 76], + H: [0, 87] + }, + baroque: { + a: [-43.75, -45], b: [0, -45], c: [43.75, -45], + d: [-43.75, 0], e: [0, 0], f: [43.75, 0], + g: [-43.75, 50], h: [0, 50], i: [43.75, 50], + y: [-50, -50], z: [0, 60], + j: [-37.5, -37.5], k: [0, -37.5], l: [37.5, -37.5], + m: [-37.5, 37.5], n: [0, 37.5], o: [37.5, 37.5], + p: [-37.5, 0], q: [37.5, 0], + A: [-65, -54.5], B: [-22, -65], C: [22, -65], D: [65, -54.5], + K: [-58.5, -15], E: [58.5, -15], + J: [-65, 31], F: [66, 31], + I: [-35, 73], G: [35, 73], + H: [0, 89] + }, + targe: { + a: [-43.75, -50], b: [0, -50], c: [43.75, -50], + d: [-43.75, 0], e: [0, 0], f: [43.75, 0], + g: [-43.75, 50], h: [0, 50], i: [43.75, 50], + y: [-50, -50], z: [0, 50], + j: [-40, -40], k: [0, -40], l: [40, -40], + m: [-40, 40], n: [0, 40], o: [40, 40], + p: [-32.5, 0], q: [32.5, 0], + A: [-66.2, -60], B: [-22, -77], C: [22, -86], D: [60, -66.6], + K: [-28, -20], E: [57, -20], + J: [-61, 26], F: [61, 26], + I: [-49, 63], G: [49, 59], + H: [0, 80] + }, + targe2: { + a: [-43.75, -50], b: [0, -50], c: [43.75, -50], + d: [-40, 0], e: [0, 0], f: [40, 0], + g: [-43.75, 50], h: [0, 50], i: [43.75, 50], + y: [-50, -50], z: [0, 60], + j: [-37.5, -37.5], k: [0, -37.5], l: [37.5, -37.5], + m: [-37.5, 37.5], n: [0, 37.5], o: [37.5, 37.5], + p: [-32.5, 0], q: [32.5, 0], + A: [-55, -59], B: [-15, -59], C: [24, -79], D: [51, -58], + K: [-40, -14], E: [51, -14], + J: [-64, 26], F: [62, 26], + I: [-46, 66], G: [48, 67], + H: [0, 83] + }, + pavise: { + a: [-40, -52.5], b: [0, -52.5], c: [40, -52.5], + d: [-40, 0], e: [0, 0], f: [40, 0], + g: [-40, 52.5], h: [0, 52.5], i: [40, 52.5], + y: [-42.5, -52.5], z: [0, 60], + j: [-30, -35], k: [0, -37.5], l: [30, -35], + m: [-30, 35], n: [0, 37.5], o: [30, 35], + p: [-30, 0], q: [30, 0], + A: [-57, -55], B: [-22, -74], C: [22, -74], D: [57, -55], + K: [-54, -11], E: [54, -11], + J: [-50, 36], F: [50, 36], + I: [-46, 81], G: [46, 81], + H: [0, 81] + }, + wedged: { + a: [-43.75, -50], b: [0, -50], c: [43.75, -50], + d: [-43.75, 0], e: [0, 0], f: [43.75, 0], + g: [-32.25, 37.5], h: [0, 50], i: [32.25, 37.5], + y: [-50, -50], z: [0, 62.5], + j: [-37.5, -37.5], k: [0, -37.5], l: [37.5, -37.5], + m: [-32.5, 32.5], n: [0, 42.5], o: [32.5, 32.5], + p: [-37.5, 0], q: [37.5, 0], + A: [-66, -53], B: [-22, -72.5], C: [22, -72.5], D: [66, -53], + K: [-62.6, -13], E: [62.6, -13], + J: [-50, 26], F: [50, 26], + I: [-27, 62], G: [27, 62], + H: [0, 87] + }, + flag: { + a: [-60, -40], b: [0, -40], c: [60, -40], + d: [-60, 0], e: [0, 0], f: [60, 0], + g: [-60, 40], h: [0, 40], i: [60, 40], + y: [-60, -42.5], z: [0, 40], + j: [-45, -30], k: [0, -30], l: [45, -30], + m: [-45, 30], n: [0, 30], o: [45, 30], + p: [-45, 0], q: [45, 0], + A: [-81, -51], B: [-27, -51], C: [27, -51], D: [81, -51], + K: [-81, -17], E: [81, -17], + J: [-81, 17], F: [81, 17], + I: [-81, 51], G: [81, 51], + H: [-27, 51], L: [27, 51] + }, + pennon: { + a: [-75, -40], + d: [-75, 0], e: [-25, 0], f: [25, 0], + g: [-75, 40], + y: [-70, -42.5], + j: [-60, -30], + m: [-60, 30], + p: [-60, 0], q: [5, 0], + A: [-81, -48], B: [-43, -36], C: [-4.5, -24], D: [33, -12], + E: [72, 0], + F: [33, 12], G: [-4.5, 24], H: [-43, 36], I: [-81, 48], + J: [-81, 17], K: [-81, -17] + }, + guidon: { + a: [-60, -40], b: [0, -40], c: [60, -40], + d: [-60, 0], e: [0, 0], + g: [-60, 40], h: [0, 40], i: [60, 40], + y: [-60, -42.5], z: [0, 40], + j: [-45, -30], k: [0, -30], l: [45, -30], + m: [-45, 30], n: [0, 30], o: [45, 30], + p: [-45, 0], + A: [-81, -51], B: [-27, -51], C: [27, -51], D: [78, -51], + K: [-81, -17], E: [40.5, -17], + J: [-81, 17], F: [40.5, 17], + I: [-81, 51], G: [78, 51], + H: [-27, 51], L: [27, 51] + }, + banner: { + a: [-50, -50], b: [0, -50], c: [50, -50], + d: [-50, 0], e: [0, 0], f: [50, 0], + g: [-50, 40], h: [0, 40], i: [50, 40], + y: [-50, -50], z: [0, 40], + j: [-37.5, -37.5], k: [0, -37.5], l: [37.5, -37.5], + m: [-37.5, 27.5], n: [0, 27.5], o: [37.5, 27.5], + p: [-37.5, 0], q: [37.5, 0], + A: [-66.5, -66.5], B: [-22, -66.5], C: [22, -66.5], D: [66.5, -66.5], + K: [-66.5, -20], E: [66.5, -20], + J: [-66.5, 26], F: [66.5, 26], + I: [-66.5, 66.5], G: [66.5, 66.5], + H: [-25, 75], L: [25, 75] + }, + dovetail: { + a: [-49.75, -50], b: [0, -50], c: [49.75, -50], + d: [-49.75, 0], e: [0, 0], f: [49.75, 0], + g: [-49.75, 50], i: [49.75, 50], + y: [-50, -50], z: [0, 40], + j: [-37.5, -37.5], k: [0, -37.5], l: [37.5, -37.5], + m: [-37.5, 37.5], n: [0, 32.5], o: [37.5, 37.5], + p: [-37.5, 0], q: [37.5, 0], + A: [-66.5, -66.5], B: [-22, -66.5], C: [22, -66.5], D: [66.5, -66.5], + K: [-66.5, -16.5], E: [66.5, -16.5], + J: [-66.5, 34.5], F: [66.5, 34.5], + I: [-66.5, 84.5], G: [66.5, 84.5], + H: [-25, 64], L: [25, 64] + }, + gonfalon: { + a: [-49.75, -50], b: [0, -50], c: [49.75, -50], + d: [-49.75, 0], e: [0, 0], f: [49.75, 0], + g: [-49.75, 50], h: [0, 50], i: [49.75, 50], + y: [-50, -50], z: [0, 50], + j: [-37.5, -37.5], k: [0, -37.5], l: [37.5, -37.5], + m: [-37.5, 37.5], n: [0, 37.5], o: [37.5, 37.5], + p: [-37.5, 0], q: [37.5, 0], + A: [-66.5, -66.5], B: [-22, -66.5], C: [22, -66.5], D: [66.5, -66.5], + K: [-66.5, -20], E: [66.5, -20], + J: [-66.5, 26], F: [66.5, 26], + I: [-40, 63], G: [40, 63], + H: [0, 88] + }, + pennant: { + a: [-45, -50], b: [0, -50], c: [45, -50], + e: [0, 0], h: [0, 50], + y: [-50, -50], z: [0, 50], + j: [-32.5, -37.5], k: [0, -37.5], l: [32.5, -37.5], + n: [0, 37.5], + A: [-60, -76], B: [-22, -76], C: [22, -76], D: [60, -76], + K: [-46, -38], E: [46, -38], + J: [-31, 0], F: [31, 0], + I: [-16, 38], G: [16, 38], + H: [0, 76] + }, + round: { + a: [-40, -40], b: [0, -40], c: [40, -40], + d: [-40, 0], e: [0, 0], f: [40, 0], + g: [-40, 40], h: [0, 40], i: [40, 40], + y: [-48, -48], z: [0, 57.5], + j: [-35.5, -35.5], k: [0, -37.5], l: [35.5, -35.5], + m: [-35.5, 35.5], n: [0, 37.5], o: [35.5, 35.5], + p: [-36.5, 0], q: [36.5, 0], + A: [-59, -48], B: [-23, -73], C: [23, -73], D: [59, -48], + K: [-76, -10], E: [76, -10], + J: [-70, 31], F: [70, 31], + I: [-42, 64], G: [42, 64], + H: [0, 77] + }, + oval: { + a: [-37.5, -50], b: [0, -50], c: [37.5, -50], + d: [-43, 0], e: [0, 0], f: [43, 0], + g: [-37.5, 50], h: [0, 50], i: [37.5, 50], + y: [-48, -48], z: [0, 60], + j: [-35.5, -37.5], k: [0, -37.5], l: [35.5, -37.5], + m: [-35.5, 37.5], n: [0, 50], o: [35.5, 37.5], + p: [-36.5, 0], q: [36.5, 0], + A: [-48, -48], B: [-23, -78], C: [23, -78], D: [48, -48], + K: [-59, -10], E: [59, -10], + J: [-55, 31], F: [55, 31], + I: [-36, 68], G: [36, 68], + H: [0, 85] + }, + vesicaPiscis: { + a: [-32, -37], b: [0, -50], c: [32, -37], + d: [-32, 0], e: [0, 0], f: [32, 0], + g: [-32, 37], h: [0, 50], i: [32, 37], + y: [-50, -50], z: [0, 62], + j: [-27.5, -27.5], k: [0, -37], l: [27.5, -27.5], + m: [-27.5, 27.5], n: [0, 42], o: [27.5, 27.5], + p: [-27.5, 0], q: [27.5, 0], + A: [-45, -32], B: [-29, -63], C: [29, -63], D: [45, -32], + K: [-50, 0], E: [50, 0], + J: [-45, 32], F: [45, 32], + I: [-29, 63], G: [29, 63], + H: [0, 89], L: [0, -89] + }, + square: { + a: [-49.75, -50], b: [0, -50], c: [49.75, -50], + d: [-49.75, 0], e: [0, 0], f: [49.75, 0], + g: [-49.75, 50], h: [0, 50], i: [49.75, 50], + y: [-50, -50], z: [0, 50], + j: [-37.5, -37.5], k: [0, -37.5], l: [37.5, -37.5], + m: [-37.5, 37.5], n: [0, 37.5], o: [37.5, 37.5], + p: [-37.5, 0], q: [37.5, 0], + A: [-66.5, -66.5], B: [-22, -66.5], C: [22, -66.5], D: [66.5, -66.5], + K: [-66.5, -20], E: [66.5, -20], + J: [-66.5, 26], F: [66.5, 26], + I: [-66.5, 66.5], G: [66.5, 66.5], + H: [-22, 66.5], L: [22, 66.5] + }, + diamond: { + a: [-32, -37], b: [0, -50], c: [32, -37], + d: [-43, 0], e: [0, 0], f: [43, 0], + g: [-32, 37], h: [0, 50], i: [32, 37], + y: [-50, -50], z: [0, 62], + j: [-27.5, -27.5], k: [0, -37], l: [27.5, -27.5], + m: [-27.5, 27.5], n: [0, 42], o: [27.5, 27.5], + p: [-37, 0], q: [37, 0], + A: [-43, -28], B: [-22, -56], C: [22, -56], D: [43, -28], + K: [-63, 0], E: [63, 0], + J: [-42, 28], F: [42, 28], + I: [-22, 56], G: [22, 56], + H: [0, 83], L: [0, -82] + }, + no: { + a: [-66.5, -66.5], b: [0, -66.5], c: [66.5, -66.5], + d: [-66.5, 0], e: [0, 0], f: [66.5, 0], + g: [-66.5, 66.5], h: [0, 66.5], i: [66.5, 66.5], + y: [-50, -50], z: [0, 75], + j: [-50, -50], k: [0, -50], l: [50, -50], + m: [-50, 50], n: [0, 50], o: [50, 50], + p: [-50, 0], q: [50, 0], + A: [-91.5, -91.5], B: [-30.5, -91.5], C: [30.5, -91.5], D: [91.5, -91.5], + K: [-91.5, -30.5], E: [91.5, -30.5], + J: [-91.5, 30.5], F: [91.5, 30.5], + I: [-91.5, 91.5], G: [91.5, 91.5], + H: [-30.5, 91.5], L: [30.5, 91.5] + }, + fantasy1: { + a: [-45, -45], b: [0, -50], c: [45, -45], + d: [-40, 0], e: [0, 0], f: [40, 0], + g: [-36, 42.5], h: [0, 50], i: [36, 42.5], + y: [-50, -50], z: [0, 60], + j: [-37, -37], k: [0, -40], l: [37, -37], + m: [-32, 32], n: [0, 40], o: [32, 32], + p: [-28.5, 0], q: [28.5, 0], + A: [-66, -55], B: [-22, -67], C: [22, -67], D: [66, -55], + K: [-53, -20], E: [53, -20], + J: [-46, 26], F: [46, 26], + I: [-29, 62], G: [29, 62], + H: [0, 84] + }, + fantasy2: { + a: [-45, -45], b: [0, -45], c: [45, -45], + d: [-35, 0], e: [0, 0], f: [35, 0], + g: [-36, 42.5], h: [0, 45], i: [36, 42.5], + y: [-50, -50], z: [0, 55], + j: [-32.5, -32.5], k: [0, -40], l: [32.5, -32.5], + m: [-30, 30], n: [0, 40], o: [30, 30], + p: [-27.5, 0], q: [27.5, 0], + A: [-58, -35], B: [-44, -67], C: [44, -67], D: [58, -35], + K: [-39, -5], E: [39, -5], + J: [-57, 26], F: [57, 26], + I: [-32, 58], G: [32, 58], + H: [0, 83], L: [0, -72] + }, + fantasy3: { + a: [-40, -45], b: [0, -50], c: [40, -45], + d: [-35, 0], e: [0, 0], f: [35, 0], + g: [-36, 42.5], h: [0, 50], i: [36, 42.5], + y: [-50, -50], z: [0, 55], + j: [-32.5, -32.5], k: [0, -40], l: [32.5, -32.5], + m: [-30, 30], n: [0, 40], o: [30, 30], + p: [-27.5, 0], q: [27.5, 0], + A: [-56, -42], B: [-22, -72], C: [22, -72], D: [56, -42], + K: [-37, -11], E: [37, -11], + J: [-60, 20], F: [60, 20], + I: [-34, 56], G: [34, 56], + H: [0, 83] + }, + fantasy4: { + a: [-50, -45], b: [0, -50], c: [50, -45], + d: [-45, 0], e: [0, 0], f: [45, 0], + g: [-40, 45], h: [0, 50], i: [40, 45], + y: [-50, -50], z: [0, 62.5], + j: [-37.5, -37.5], k: [0, -45], l: [37.5, -37.5], + m: [-37.5, 37.5], n: [0, 45], o: [37.5, 37.5], + p: [-35, 0], q: [35, 0], + A: [-75, -56], B: [-36, -61], C: [36, -61], D: [75, -56], + K: [-67, -12], E: [67, -12], + J: [-63, 32], F: [63, 32], + I: [-42, 75], G: [42, 75], + H: [0, 91.5], L: [0, -79] + }, + fantasy5: { + a: [-45, -50], b: [0, -50], c: [45, -50], + d: [-40, 0], e: [0, 0], f: [40, 0], + g: [-30, 45], h: [0, 50], i: [30, 45], + y: [-50, -50], z: [0, 60], + j: [-37, -37], k: [0, -40], l: [37, -37], + m: [-32, 32], n: [0, 40], o: [32, 32], + p: [-28.5, 0], q: [28.5, 0], + A: [-61, -67], B: [-22, -76], C: [22, -76], D: [61, -67], + K: [-58, -25], E: [58, -25], + J: [-48, 20], F: [48, 20], + I: [-28.5, 60], G: [28.5, 60], + H: [0, 89] + }, + noldor: { + b: [0, -65], e: [0, -15], h: [0, 35], + z: [0, 35], k: [0, -50], n: [0, 30], + p: [-20, -15], q: [20, -15], + A: [-34, -47], B: [-20, -68], C: [20, -68], D: [34, -47], + K: [-18, -20], E: [18, -20], + J: [-26, 11], F: [26, 11], + I: [-14, 43], G: [14, 43], + H: [0, 74], L: [0, -85] + }, + gondor: { + a: [-32.5, -50], b: [0, -50], c: [32.5, -50], + d: [-32.5, 0], e: [0, 0], f: [32.5, 0], + g: [-32.5, 50], h: [0, 50], i: [32.5, 50], + y: [-42.5, -52.5], z: [0, 65], + j: [-25, -37.5], k: [0, -37.5], l: [25, -37.5], + m: [-25, 30], n: [0, 37.5], o: [25, 30], + p: [-25, 0], q: [25, 0], + A: [-42, -52], B: [-17, -75], C: [17, -75], D: [42, -52], + K: [-42, -15], E: [42, -15], + J: [-42, 22], F: [42, 22], + I: [-26, 60], G: [26, 60], + H: [0, 87] + }, + easterling: { + a: [-40, -47.5], b: [0, -47.5], c: [40, -47.5], + d: [-40, 0], e: [0, 0], f: [40, 0], + g: [-40, 47.5], h: [0, 47.5], i: [40, 47.5], + y: [-42.5, -52.5], z: [0, 65], + j: [-30, -37.5], k: [0, -37.5], l: [30, -37.5], + m: [-30, 37.5], n: [0, 37.5], o: [30, 37.5], + p: [-30, 0], q: [30, 0], + A: [-52, -72], B: [0, -65], D: [52, -72], + K: [-52, -24], E: [52, -24], + J: [-52, 24], F: [52, 24], + I: [-52, 72], G: [52, 72], + H: [0, 65] + }, + erebor: { + a: [-40, -40], b: [0, -55], c: [40, -40], + d: [-40, 0], e: [0, 0], f: [40, 0], + g: [-40, 40], h: [0, 55], i: [40, 40], + y: [-50, -50], z: [0, 50], + j: [-35, -35], k: [0, -45], l: [35, -35], + m: [-35, 35], n: [0, 45], o: [35, 35], + p: [-37.5, 0], q: [37.5, 0], + A: [-47, -46], B: [-22, -81], C: [22, -81], D: [47, -46], + K: [-66.5, 0], E: [66.5, 0], + J: [-47, 46], F: [47, 46], + I: [-22, 81], G: [22, 81] + }, + ironHills: { + a: [-43.75, -50], b: [0, -50], c: [43.75, -50], + d: [-43.25, 0], e: [0, 0], f: [43.25, 0], + g: [-42.5, 42.5], h: [0, 50], i: [42.5, 42.5], + y: [-50, -50], z: [0, 62.5], + j: [-32.5, -32.5], k: [0, -40], l: [32.5, -32.5], + m: [-32.5, 32.5], n: [0, 40], o: [32.5, 32.5], + p: [-37.5, 0], q: [37.5, 0], + A: [-61, -67], B: [-22, -74], C: [22, -74], D: [61, -67], + K: [-59, -20], E: [59, -20], + J: [-57, 26], F: [57, 26], + I: [-33, 64], G: [33, 64], + H: [0, 88] + }, + urukHai: { + a: [-40, -45], b: [0, -45], c: [40, -45], + d: [-36, 0], e: [0, 0], f: [36, 0], + g: [-32.25, 40], h: [0, 40], i: [32.25, 40], + y: [-50, -50], z: [0, 40], + j: [-32.5, -32.5], k: [0, -37.5], l: [32.5, -32.5], + m: [-27.5, 27.5], n: [0, 32.5], o: [27.5, 27.5], + p: [-37.5, 0], q: [37.5, 0], + A: [-31, -79], B: [-1, -90], C: [31, -74], D: [61, -57], + K: [-55, -19], E: [53, -19], + J: [-45, 19], F: [45, 19], + I: [-33, 57], G: [35, 57], + H: [0, 57], L: [-39, -50] + }, + moriaOrc: { + a: [-37.5, -37.5], b: [0, -37.5], c: [37.5, -37.5], + d: [-37.5, 0], e: [0, 0], f: [37.5, 0], + g: [-37.5, 37.5], h: [0, 37.5], i: [37.5, 37.5], + y: [-50, -50], z: [0, 40], + j: [-30, -30], k: [0, -30], l: [30, -30], + m: [-30, 30], n: [0, 30], o: [30, 30], + p: [-30, 0], q: [30, 0], + A: [-48, -48], B: [-16, -50], C: [16, -46], D: [39, -61], + K: [-52, -19], E: [52, -26], + J: [-42, 9], F: [52, 9], + I: [-31, 40], G: [40, 43], + H: [4, 47] + } + }; + + const shieldSize = { + horsehead: .9, horsehead2: .9, polish: .85, swiss: .95, + boeotian: .75, roman: .95, kite: .65, targe2: .9, pavise: .9, wedged: .95, + flag: .7, pennon: .5, guidon: .65, banner: .8, dovetail: .8, pennant: .6, + oval: .95, vesicaPiscis: .8, diamond: .8, no: 1.2, + fantasy1: .8, fantasy2: .7, fantasy3: .7, fantasy5: .9, + noldor: .5, gondor: .75, easterling: .8, erebor: .9, urukHai: .8, moriaOrc: .7 + } + + const shieldBox = { + heater: "0 10 200 200", + spanish: "0 10 200 200", + french: "0 10 200 200", + + horsehead: "0 10 200 200", + horsehead2: "0 10 200 200", + polish: "0 0 200 200", + hessen: "0 5 200 200", + swiss: "0 10 200 200", + + boeotian: "0 0 200 200", + roman: "0 0 200 200", + kite: "0 0 200 200", + oldFrench: "0 10 200 200", + renaissance: "0 5 200 200", + baroque: "0 10 200 200", + + targe: "0 0 200 200", + targe2: "0 0 200 200", + pavise: "0 0 200 200", + wedged: "0 10 200 200", + + flag: "0 0 200 200", + pennon: "2.5 0 200 200", + guidon: "2.5 0 200 200", + banner: "0 10 200 200", + dovetail: "0 10 200 200", + gonfalon: "0 10 200 200", + pennant: "0 0 200 200", + + round: "0 0 200 200", + oval: "0 0 200 200", + vesicaPiscis: "0 0 200 200", + square: "0 0 200 200", + diamond: "0 0 200 200", + no: "0 0 200 200", + + fantasy1: "0 0 200 200", + fantasy2: "0 5 200 200", + fantasy3: "0 5 200 200", + fantasy4: "0 5 200 200", + fantasy5: "0 0 200 200", + + noldor: "0 0 200 200", + gondor: "0 5 200 200", + easterling: "0 0 200 200", + erebor: "0 0 200 200", + ironHills: "0 5 200 200", + urukHai: "0 0 200 200", + moriaOrc: "0 0 200 200" + } + + function draw(id, coa) { + const {division, ordinaries = [], charges = []} = coa; + const ordinariesRegular = ordinaries.filter(o => !o.above); + const ordinariesAboveCharges = ordinaries.filter(o => o.above); + const shieldPath = document.getElementById(coa.shield).querySelector("path").getAttribute("d"); + const tDiv = division ? division.t.includes("-") ? division.t.split("-")[1] : division.t : null; + const positions = shieldPositions[coa.shield]; + const sizeModifier = shieldSize[coa.shield] || 1; + const viewBox = shieldBox[coa.shield] || "0 0 200 200"; + + let svg = ` + + + ${division ? `${getTemplate(division.division, division.line)}` : ''} + + + + ${templateDivision()} + ${templateAboveAll()} + + + `; + + // insert coa svg to defs + document.getElementById("coas").insertAdjacentHTML("beforeend", svg); + + // fetch charges + if (charges.length) { + const defs = document.getElementById(id).querySelector("defs"); + const uniqueCharges = [...new Set(charges.map(charge => charge.charge))]; + uniqueCharges.forEach(charge => fetchCharge(charge, defs)); + } + + function templateDivision() { + if (!division) return ""; + let svg = ""; + + // In field part + for (const ordinary of ordinariesRegular) { + if (ordinary.divided === "field") svg += templateOrdinary(ordinary, ordinary.t); else + if (ordinary.divided === "counter") svg += templateOrdinary(ordinary, tDiv); + } + + for (const charge of charges) { + if (charge.divided === "field") svg += templateCharge(charge, charge.t); else + if (charge.divided === "counter") svg += templateCharge(charge, tDiv); + } + + for (const ordinary of ordinariesAboveCharges) { + if (ordinary.divided === "field") svg += templateOrdinary(ordinary, ordinary.t); else + if (ordinary.divided === "counter") svg += templateOrdinary(ordinary, tDiv); + } + + // In division part + svg += ` + + + `; + + for (const ordinary of ordinariesRegular) { + if (ordinary.divided === "division") svg += templateOrdinary(ordinary, ordinary.t); else + if (ordinary.divided === "counter") svg += templateOrdinary(ordinary, coa.t1); + } + + for (const charge of charges) { + if (charge.divided === "division") svg += templateCharge(charge, charge.t); else + if (charge.divided === "counter") svg += templateCharge(charge, coa.t1); + } + + for (const ordinary of ordinariesAboveCharges) { + if (ordinary.divided === "division") svg += templateOrdinary(ordinary, ordinary.t); else + if (ordinary.divided === "counter") svg += templateOrdinary(ordinary, coa.t1); + } + + return svg += `` + } + + function templateAboveAll() { + let svg = ""; + + ordinariesRegular.filter(o => !o.divided).forEach(ordinary => { + svg += templateOrdinary(ordinary, ordinary.t); + }); + + charges.filter(o => !o.divided || !division).forEach(charge => { + svg += templateCharge(charge, charge.t); + }); + + ordinariesAboveCharges.filter(o => !o.divided).forEach(ordinary => { + svg += templateOrdinary(ordinary, ordinary.t); + }) + + return svg; + } + + function templateOrdinary(ordinary, tincture) { + const fill = clr(tincture); + let svg = ``; + if (ordinary.ordinary === "bordure") svg += ``; + else if (ordinary.ordinary === "orle") svg += ``; + else svg += getTemplate(ordinary.ordinary, ordinary.line); + return svg + ``; + } + + function templateCharge(charge, tincture) { + const fill = clr(tincture); + const chargePositions = [...new Set(charge.p)].filter(position => positions[position]); + + let svg = ""; + svg += ``; + for (const p of chargePositions) { + const transform = getElTransform(charge, p); + svg += ``; + } + return svg + ``; + + function getElTransform(c, p) { + const [x, y] = positions[p]; + const s = (c.size || 1) * sizeModifier; + const scale = c.sinister || c.reversed ? `${c.sinister ? "-" : ""}${s}, ${c.reversed ? "-" : ""}${s}` : s; + return `translate(${x} ${y}) scale(${scale})`; + } + } + + // get color or link to pattern + function clr(tincture) { + if (colors[tincture]) return colors[tincture]; + const pattern = document.getElementById(tincture); + if (!pattern) renderPattern(tincture); + return "url(#"+tincture+")"; + } + + function renderPattern(tincture) { + const [pattern, t1, t2, size] = tincture.split("-"); + const semy = pattern.slice(0, 4) === "semy"; + + const template = document.getElementById(semy ? "semy" : pattern); + let html = template.innerHTML.replace(/{id}/, tincture); + + const width = template.querySelector("pattern").getAttribute("width"); + const height = template.querySelector("pattern").getAttribute("height"); + + if (t1) html = html.replace(/{c1}/g, clr(t1)); + if (t2) html = html.replace(/{c2}/g, clr(t2)); + + document.getElementById("patterns").insertAdjacentHTML("beforeend", html); + + if (semy) { + const charge = pattern.split("_of_")[1]; + const el = document.getElementById(tincture); + + fetch("https://azgaar.github.io/Armoria/charges/"+charge+".svg").then(res => { + if (res.ok) return res.text(); + else throw new Error('Cannot fetch charge'); + }).then(text => { + const html = document.createElement("html"); + html.innerHTML = text; + el.innerHTML = el.innerHTML.replace(//g, html.querySelector("g").outerHTML); + }); + } + + if (size) { + let mod = 1; + if (size === "small") mod = .5; + if (size === "smaller") mod = .25; + if (size === "smallest") mod = .125; + if (size === "big") mod = 2; + + const el = document.getElementById(tincture); + el.setAttribute("width", width * mod); + el.setAttribute("height", height * mod); + } + } + + function getTemplate(templateId, lineId) { + if (!lineId) return document.getElementById(templateId)?.innerHTML; + const template = document.getElementById(templateId); + const line = document.getElementById(lineId) ? document.getElementById(lineId) : document.getElementById("straight"); + return template.innerHTML.replace(/{line}/g, line.getAttribute("d")).replace(/dpath/g, "d"); + } + + function fetchCharge(charge, defs) { + if (charge === "inescutcheon") { + const g = ``; + defs.insertAdjacentHTML("beforeend", g); + return; + } + + fetch("https://azgaar.github.io/Armoria/charges/"+charge+".svg").then(res => { + if (res.ok) return res.text(); + else throw new Error('Cannot fetch charge'); + }).then(text => { + const el = document.createElement("html"); + el.innerHTML = text; + const g = el.querySelector("g"); + g.id = charge + "_" + id; + defs.insertAdjacentHTML("beforeend", g.outerHTML); + }); + } + } + + // async render coa if it does not exist + const trigger = function(id, coa) { + if (!coa) { + console.warn(`Emblem ${id} is undefined`); + return; + } + if (!document.getElementById(id)) draw(id, coa); + } + + return {trigger}; + +}))); \ No newline at end of file diff --git a/modules/coa-renderer.js b/modules/coa-renderer.js index 1dd3cb81..1c473d03 100644 --- a/modules/coa-renderer.js +++ b/modules/coa-renderer.js @@ -3,6 +3,7 @@ typeof define === 'function' && define.amd ? define(factory) : (global.COArenderer = factory()); }(this, (function () {'use strict'; + const colors = { argent: "#fafafa", or: "#ffe066", @@ -608,7 +609,7 @@ I: [-31, 40], G: [40, 43], H: [4, 47] } - }; + } const shieldSize = { horsehead: .9, horsehead2: .9, polish: .85, swiss: .95, @@ -672,100 +673,246 @@ moriaOrc: "0 0 200 200" } - function draw(id, coa) { - const {division, ordinaries = [], charges = []} = coa; + const shieldPaths = { + heater: "m25,25 h150 v50 a150,150,0,0,1,-75,125 a150,150,0,0,1,-75,-125 z", + spanish: "m25,25 h150 v100 a75,75,0,0,1,-150,0 z", + french: "m 25,25 h 150 v 139.15 c 0,41.745 -66,18.15 -75,36.3 -9,-18.15 -75,5.445 -75,-36.3 v 0 z", + horsehead: "m 20,40 c 0,60 40,80 40,100 0,10 -4,15 -0.35,30 C 65,185.7 81,200 100,200 c 19.1,0 35.3,-14.6 40.5,-30.4 C 144.2,155 140,150 140,140 140,120 180,100 180,40 142.72,40 150,15 100,15 55,15 55,40 20,40 Z", + horsehead2: "M60 20c-5 20-10 35-35 55 25 35 35 65 30 100 20 0 35 10 45 26 10-16 30-26 45-26-5-35 5-65 30-100a87 87 0 01-35-55c-25 3-55 3-80 0z", + polish: "m 90.3,6.3 c -12.7,0 -20.7,10.9 -40.5,14 0,11.8 -4.9,23.5 -11.4,31.1 0,0 12.7,6 12.7,19.3 C 51.1,90.8 30,90.8 30,90.8 c 0,0 -3.6,7.4 -3.6,22.4 0,34.3 23.1,60.2 40.7,68.2 17.6,8 27.7,11.4 32.9,18.6 5.2,-7.3 15.3,-10.7 32.8,-18.6 17.6,-8 40.7,-33.9 40.7,-68.2 0,-15 -3.6,-22.4 -3.6,-22.4 0,0 -21.1,0 -21.1,-20.1 0,-13.3 12.7,-19.3 12.7,-19.3 C 155.1,43.7 150.2,32.1 150.2,20.3 130.4,17.2 122.5,6.3 109.7,6.3 102.5,6.3 100,10 100,10 c 0,0 -2.5,-3.7 -9.7,-3.7 z", + hessen: "M170 20c4 5 8 13 15 20 0 0-10 0-10 15 0 100-15 140-75 145-65-5-75-45-75-145 0-15-10-15-10-15l15-20c0 15 10-5 70-5s70 20 70 5z", + swiss: "m 25,20 c -0.1,0 25.2,8.5 37.6,8.5 C 75.1,28.5 99.1,20 100,20 c 0.6,0 24.9,8.5 37.3,8.5 C 149.8,28.5 174.4,20 175,20 l -0.3,22.6 C 173.2,160.3 100,200 100,200 100,200 26.5,160.9 25.2,42.6 Z", + boeotian: "M150 115c-5 0-10-5-10-15s5-15 10-15c10 0 7 10 15 10 10 0 0-30 0-30-10-25-30-55-65-55S45 40 35 65c0 0-10 30 0 30 8 0 5-10 15-10 5 0 10 5 10 15s-5 15-10 15c-10 0-7-10-15-10-10 0 0 30 0 30 10 25 30 55 65 55s55-30 65-55c0 0 10-30 0-30-8 0-5 10-15 10z", + roman: "m 160,170 c -40,20 -80,20 -120,0 V 30 C 80,10 120,10 160,30 Z", + kite: "m 53.3,46.4 c 0,4.1 1,12.3 1,12.3 7.1,55.7 45.7,141.3 45.7,141.3 0,0 38.6,-85.6 45.7,-141.2 0,0 1,-8.1 1,-12.3 C 146.7,20.9 125.8,0.1 100,0.1 74.2,0.1 53.3,20.9 53.3,46.4 Z", + oldFrench: "m25,25 h150 v75 a100,100,0,0,1,-75,100 a100,100,0,0,1,-75,-100 z", + renaissance: "M 25,33.9 C 33.4,50.3 36.2,72.9 36.2,81.7 36.2,109.9 25,122.6 25,141 c 0,29.4 24.9,44.1 40.2,47.7 15.3,3.7 29.3,0 34.8,11.3 5.5,-11.3 19.6,-7.6 34.8,-11.3 C 150.1,185 175,170.3 175,141 c 0,-18.4 -11.2,-31.1 -11.2,-59.3 0,-8.8 2.8,-31.3 11.2,-47.7 L 155.7,14.4 C 138.2,21.8 119.3,25.7 100,25.7 c -19.3,0 -38.2,-3.9 -55.7,-11.3 z", + baroque: "m 100,25 c 18,0 50,2 75,14 v 37 l -2.7,3.2 c -4.9,5.4 -6.6,9.6 -6.7,16.2 0,6.5 2,11.6 6.9,17.2 l 2.8,3.1 v 10.2 c 0,17.7 -2.2,27.7 -7.8,35.9 -5,7.3 -11.7,11.3 -32.3,19.4 -12.6,5 -20.2,8.8 -28.6,14.5 C 103.3,198 100,200 100,200 c 0,0 -2.8,-2.3 -6.4,-4.7 C 85.6,189.8 78,186 65,180.9 32.4,168.1 26.9,160.9 25.8,129.3 L 25,116 l 3.3,-3.3 c 4.8,-5.2 7,-10.7 7,-17.3 0,-6.8 -1.8,-11.1 -6.5,-16.1 L 25,76 V 39 C 50,27 82,25 100,25 Z", + targe: "m 20,35 c 15,0 115,-60 155,-10 -5,10 -15,15 -10,50 5,45 10,70 -10,90 C 125,195 75,195 50,175 25,150 30,130 35,85 50,95 65,85 65,70 65,50 50,45 40,50 30,55 27,65 30,70 23,73 20,70 14,70 11,60 20,45 20,35 Z", + targe2: "m 84,32.2 c 6.2,-1 19.5,-31.4 94.1,-20.2 -30.57,33.64 -21.66,67.37 -11.2,95 20.2,69.5 -41.17549,84.7 -66.88,84.7 C 74.32,191.7071 8.38,168.95 32,105.9 36.88,92.88 31,89 31,82.6 35.15,82.262199 56.79,86.17 56.5,69.8 56.20,52.74 42.2,47.9 25.9,55.2 25.9,51.4 39.8,6.7 84,32.2 Z", + pavise: "M95 7L39.9 37.3a10 10 0 00-5.1 9.5L46 180c.4 5.2 3.7 10 9 10h90c5.3 0 9.6-4.8 10-10l10.6-133.2a10 10 0 00-5-9.5L105 7c-4.2-2.3-6.2-2.3-10 0z", + wedged: "m 51.2,19 h 96.4 c 3.1,12.7 10.7,20.9 26.5,20.8 C 175.7,94.5 165.3,144.3 100,200 43.5,154.2 22.8,102.8 25.1,39.7 37,38.9 47.1,34.7 51.2,19 Z", + round: "m 185,100 a 85,85 0 0 1 -85,85 85,85 0 0 1 -85,-85 85,85 0 0 1 85,-85 85,85 0 0 1 85,85", + oval: "m 32.3,99.5 a 67.7,93.7 0 1 1 0,1.3 z", + vesicaPiscis: "M 100,0 C 63.9,20.4 41,58.5 41,100 c 0,41.5 22.9,79.6 59,100 36.1,-20.4 59,-58.5 59,-100 C 159,58.5 136.1,20.4 100,0 Z", + square: "M 25,25 H 175 V 175 H 25 Z", + diamond: "M 25,100 100,200 175,100 100,0 Z", + no: "m0,0 h200 v200 h-200 z", + flag: "M 10,40 h180 v120 h-180 Z", + pennon: "M 10,40 l190,60 -190,60 Z", + guidon: "M 10,40 h190 l-65,60 65,60 h-190 Z", + banner: "m 25,25 v 170 l 25,-40 25,40 25,-40 25,40 25,-40 25,40 V 25 Z", + dovetail: "m 25,25 v 175 l 75,-40 75,40 V 25 Z", + gonfalon: "m 25,25 v 125 l 75,50 75,-50 V 25 Z", + pennant: "M 25,15 100,200 175,15 Z", + fantasy1: "M 100,5 C 85,30 40,35 15,40 c 40,35 20,90 40,115 15,25 40,30 45,45 5,-15 30,-20 45,-45 20,-25 0,-80 40,-115 C 160,35 115,30 100,5 Z", + fantasy2: "m 152,21 c 0,0 -27,14 -52,-4 C 75,35 48,21 48,21 50,45 30,55 30,75 60,75 60,115 32,120 c 3,40 53,50 68,80 15,-30 65,-40 68,-80 -28,-5 -28,-45 2,-45 C 170,55 150,45 152,21 Z", + fantasy3: "M 167,67 C 165,0 35,0 33,67 c 32,-7 27,53 -3,43 -5,45 60,65 70,90 10,-25 75,-47.51058 70,-90 -30,10 -35,-50 -3,-43 z", + fantasy4: "M100 9C55 48 27 27 13 39c23 50 3 119 49 150 14 9 28 11 38 11s27-4 38-11c55-39 24-108 49-150-14-12-45 7-87-30z", + fantasy5: "M 100,0 C 75,25 30,25 30,25 c 0,69 20,145 70,175 50,-30 71,-106 70,-175 0,0 -45,0 -70,-25 z", + noldor: "m 55,75 h 2 c 3,-25 38,-10 3,20 15,50 30,75 40,105 10,-30 25,-55 40,-105 -35,-30 0,-45 3,-20 h 2 C 150,30 110,20 100,0 90,20 50,30 55,75 Z", + gondor: "m 100,200 c 15,-15 38,-35 45,-60 h 5 V 30 h -5 C 133,10 67,10 55,30 h -5 v 110 h 5 c 7,25 30,45 45,60 z", + easterling: "M 160,185 C 120,170 80,170 40,185 V 15 c 40,15 80,15 120,0 z", + erebor: "M25 135 V60 l22-13 16-37 h75 l15 37 22 13 v75l-22 18-16 37 H63l-16-37z", + ironHills: "m 30,25 60,-10 10,10 10,-10 60,10 -5,125 -65,50 -65,-50 z", + urukHai: "M 30,60 C 40,60 60,50 60,20 l -5,-3 45,-17 75,40 -5,5 -35,155 -5,-35 H 70 v 35 z", + moriaOrc: "M45 35c5 3 7 10 13 9h19c4-2 7-4 9-9 6 1 9 9 16 11 7-2 14 0 21 0 6-3 6-10 10-15 2-5 1-10-2-15-2-4-5-14-4-16 3 6 7 11 12 14 7 3 3 12 7 16 3 6 4 12 9 18 2 4 6 8 5 14 0 6-1 12 3 18-3 6-2 13-1 20 1 6-2 12-1 18 0 6-3 13 0 18 8 4 0 8-5 7-4 3-9 3-13 9-5 5-5 13-8 19 0 6 0 15-7 16-1 6-7 6-10 12-1-6 0-6-2-9l2-19c2-4 5-12-3-12-4-5-11-5-15 1l-13-18c-3-4-2 9-3 12 2 2-4-6-7-5-8-2-8 7-11 11-2 4-5 10-8 9 3-10 3-16 1-23-1-4 2-9-4-11 0-6 1-13-2-19-4-2-9-6-13-7V91c4-7-5-13 0-19-3-7 2-11 2-18-1-6 1-12 3-17v-1z" + } + + const lines = { + straight: "m 0,100 v15 h 200 v -15 z", + engrailed: "m 0,95 a 6.25,6.25 0 0 0 12.5,0 6.25,6.25 0 0 0 12.5,0 6.25,6.25 0 0 0 12.5,0 6.25,6.25 0 0 0 12.5,0 6.25,6.25 0 0 0 12.5,0 6.25,6.25 0 0 0 12.5,0 6.25,6.25 0 0 0 12.5,0 6.25,6.25 0 0 0 12.5,0 6.25,6.25 0 0 0 12.5,0 6.25,6.25 0 0 0 12.5,0 6.25,6.25 0 0 0 12.5,0 6.25,6.25 0 0 0 12.5,0 6.25,6.25 0 0 0 12.5,0 6.25,6.25 0 0 0 12.5,0 6.25,6.25 0 0 0 12.5,0 6.25,6.25 0 0 0 12.5,0 v 20 H 0 Z", + invecked: "M0,102.5 a6.25,6.25,0,0,1,12.5,0 a6.25,6.25,0,0,1,12.5,0 a6.25,6.25,0,0,1,12.5,0 a6.25,6.25,0,0,1,12.5,0 a6.25,6.25,0,0,1,12.5,0 a6.25,6.25,0,0,1,12.5,0 a6.25,6.25,0,0,1,12.5,0 a6.25,6.25,0,0,1,12.5,0 a6.25,6.25,0,0,1,12.5,0 a6.25,6.25,0,0,1,12.5,0 a6.25,6.25,0,0,1,12.5,0 a6.25,6.25,0,0,1,12.5,0 a6.25,6.25,0,0,1,12.5,0 a6.25,6.25,0,0,1,12.5,0 a6.25,6.25,0,0,1,12.5,0 a6.25,6.25,0,0,1,12.5,0 v12.5 H0 z", + embattled: "M 0,105 H 2.5 V 95 h 15 v 10 h 15 V 95 h 15 v 10 h 15 V 95 h 15 v 10 h 15 V 95 h 15 v 10 h 15 V 95 h 15 v 10 h 15 V 95 h 15 v 10 h 15 V 95 h 15 v 10 h 2.5 v 10 H 0 Z", + wavy: "m 200,115 v -15 c -8.9,3.5 -16,3.1 -25,0 -8.9,-3.5 -16,-3.1 -25,0 -8.9,3.5 -16,3.2 -25,0 -8.9,-3.5 -16,-3.2 -25,0 -8.9,3.5 -16,3.1 -25,0 -8.9,-3.5 -16,-3.1 -25,0 -8.9,3.5 -16,3.2 -25,0 -8.9,-3.5 -16,-3.2 -25,0 v 15 z", + raguly: "m 200,95 h -3 l -5,10 h -10 l 5,-10 h -10 l -5,10 h -10 l 5,-10 h -10 l -5,10 h -10 l 5,-10 h -10 l -5,10 h -10 l 5,-10 h -10 l -5,10 h -10 l 5,-10 H 97 l -5,10 H 82 L 87,95 H 77 l -5,10 H 62 L 67,95 H 57 l -5,10 H 42 L 47,95 H 37 l -5,10 H 22 L 27,95 H 17 l -5,10 H 2 L 7,95 H 0 v 20 h 200 z", + dancetty: "m 0,105 10,-15 15,20 15,-20 15,20 15,-20 15,20 15,-20 15,20 15,-20 15,20 15,-20 15,20 15,-20 10,15 v 10 H 0 Z", + dentilly: "M 180,105 170,95 v 10 L 160,95 v 10 L 150,95 v 10 L 140,95 v 10 L 130,95 v 10 L 120,95 v 10 L 110,95 v 10 L 100,95 v 10 L 90,95 v 10 L 80,95 v 10 L 70,95 v 10 L 60,95 v 10 L 50,95 v 10 L 40,95 v 10 L 30,95 v 10 L 20,95 v 10 L 10,95 v 10 L 0,95 v 20 H 200 V 105 L 190,95 v 10 L 180,95 Z", + angled: "m 0,95 h 100 v 10 h 100 v 10 H 0 Z", + urdy: "m 200,90 -5,5 v 10 l -5,5 -5,-5 V 95 l -5,-5 -5,5 v 10 l -5,5 -5,-5 V 95 l -5,-5 -5,5 v 10 l -5,5 -5,-5 V 95 l -5,-5 -5,5 v 10 l -5,6 -5,-6 V 95 l -5,-5 -5,5 v 10 l -5,5 -5,-5 V 95 l -5,-5 -5,5 v 10 l -5,5 -5,-5 V 95 l -5,-5 -5,5 v 10 l -5,6 -5,-6 V 95 l -5,-5 -5,5 v 10 l -5,5 -5,-5 V 95 l -5,-5 -5,5 v 10 l -5,5 -5,-5 V 95 l -5,-5 -5,5 v 10 l -5,5 -5,-5 V 95 L 0,90 v 25 h 200", + indented: "m 100,95 5,10 5,-10 5,10 5,-10 5,10 5,-10 5,10 5,-10 5,10 5,-10 5,10 5,-10 5,10 5,-10 5,10 5,-10 5,10 5,-10 5,10 5,-10 v 20 H 0 V 95 l 5,10 5,-10 5,10 5,-10 5,10 5,-10 5,10 5,-10 5,10 5,-10 5,10 5,-10 5,10 5,-10 5,10 5,-10 5,10 5,-10 5,10 z", + bevilled: "m 0,92.5 h 110 l -20,15 H 200 V 115 H 0 Z", + nowy: "m 0,95 h 80 c 0,0 0.1,20.1 20,20 19.9,-0.1 20,-20 20,-20 h 80 v 20 H 0 Z", + nowyReversed: "m 200,105 h -80 c 0,0 -0.1,-20.1 -20,-20 -19.9,0.1 -20,20 -20,20 H 0 v 10 h 200 z", + potenty: "m 3,95 v 5 h 5 v 5 H 0 v 10 h 200 l 0.5,-10 H 193 v -5 h 5 v -5 h -15 v 5 h 5 v 5 h -15 v -5 h 5 v -5 h -15 v 5 h 5 v 5 h -15 v -5 h 5 v -5 h -15 v 5 h 5 v 5 h -15 v -5 h 5 v -5 h -15 v 5 h 5 v 5 h -15 v -5 h 5 v -5 h -15 v 5 h 5 v 5 H 100.5 93 v -5 h 5 V 95 H 83 v 5 h 5 v 5 H 73 v -5 h 5 V 95 H 63 v 5 h 5 v 5 H 53 v -5 h 5 V 95 H 43 v 5 h 5 v 5 H 33 v -5 h 5 V 95 H 23 v 5 h 5 v 5 H 13 v -5 h 5 v -5 z", + potentyDexter: "m 200,105 h -2 v -10 0 0 h -10 v 5 h 5 v 5 H 183 V 95 h -10 v 5 h 5 v 5 H 168 V 95 h -10 v 5 h 5 v 5 H 153 V 95 h -10 v 5 h 5 v 5 H 138 V 95 h -10 v 5 h 5 v 5 H 123 V 95 h -10 v 5 h 5 v 5 h -10 v 0 0 -10 H 98 v 5 h 5 v 5 H 93 V 95 H 83 v 5 h 5 v 5 H 78 V 95 H 68 v 5 h 5 v 5 H 63 V 95 H 53 v 5 h 5 v 5 H 48 V 95 H 38 v 5 h 5 v 5 H 33 V 95 H 23 v 5 h 5 v 5 H 18 V 95 H 8 v 5 h 5 v 5 H 3 V 95 H 0 v 20 h 200 z", + potentySinister: "m 2.5,95 v 10 H 0 v 10 h 202.5 v -15 h 5 v -5 h -10 v 10 h -10 v -5 h 5 v -5 h -10 v 10 h -10 v -5 h 5 v -5 h -10 v 10 h -10 v -5 h 5 v -5 h -10 v 10 h -10 v -5 h 5 v -5 h -10 v 10 h -10 v -5 h 5 v -5 h -10 v 10 h -10 v -5 h 5 v -5 h -10 v 10 h -10 v -5 h 5 v -5 h -10 v 10 h -10 v -5 h 5 v -5 h -10 v 10 h -10 v -5 h 5 v -5 h -10 v 10 h -10 v -5 h 5 v -5 h -10 v 10 h -10 v -5 h 5 v -5 h -10 v 10 h -10 v -5 h 5 v -5 h -10 v 10 h -10 v -5 h 5 v -5 z", + embattledGhibellin: "M 200,200 V 100 l -5,-5 v 10 l -5,-5 -5,5 V 95 l -5,5 -5,-5 v 10 l -5,-5 -5,5 V 95 l -5,5 -5,-5 v 10 l -5,-5 -5,5 V 95 l -5,5 -5,-5 v 10 l -5,-5 -5,5 V 95 l -5,5 -5,-5 v 10 l -5,-5 -5,5 V 95 l -5,5 -5,-5 v 10 l -5,-5 -5,5 V 95 l -5,5 -5,-5 v 10 l -5,-5 -5,5 V 95 l -5,5 -5,-5 v 10 l -5,-5 -5,5 V 95 l -5,5 -5,-5 v 10 l -5,-5 -5,5 V 95 l -5,5 -5,-5 v 10 l -5,-5 -5,5 V 95 l -5,5 v 15 h 200", + embattledNotched: "m 200,105 h -5 V 95 l -5,5 -5,-5 v 10 h -5 V 95 l -5,5 -5,-5 v 10 h -5 V 95 l -5,5 -5,-5 v 10 h -5 V 95 l -5,5 -5,-5 v 10 h -5 V 95 l -5,5 -5,-5 v 10 h -5 V 95 l -5,5 -5,-5 v 10 h -5 V 95 l -5,5 -5,-5 v 10 H 90 V 95 l -5,5 -5,-5 v 10 H 75 V 95 l -5,5 -5,-5 v 10 H 60 V 95 l -5,5 -5,-5 v 10 H 45 V 95 l -5,5 -5,-5 v 10 H 30 V 95 l -5,5 -5,-5 v 10 H 15 V 95 l -5,5 -5,-5 v 10 H 0 v 10 h 200", + embattledGrady: "m 0,95 v 20 H 200 V 95 h -2.5 v 5 h -5 v 5 h -5 v -5 h -5 v -5 h -5 v 5 h -5 v 5 h -5 v -5 h -5 v -5 h -5 v 5 h -5 v 5 h -5 v -5 h -5 v -5 h -5 v 5 h -5 v 5 h -5 v -5 h -5 v -5 h -5 v 5 h -5 v 5 h -5 v -5 h -5 v -5 h -5 v 5 h -5 v 5 h -5 v -5 h -5 v -5 h -5 v 5 h -5 v 5 h -5 v -5 h -5 v -5 h -5 v 5 h -5 v 5 h -5 v -5 h -5 v -5 h -5 v 5 h -5 v 5 h -5 v -5 h -5 v -5 h -5 v 5 h -5 v 5 h -5 v -5 h -5 v -5 z", + dovetailed: "m 200,95 h -7 l 4,10 h -14 l 4,-10 h -14 l 4,10 h -14 l 4,-10 h -14 l 4,10 h -14 l 4,-10 h -14 l 4,10 h -14 l 4,-10 h -14 l 4,10 h -14 l 4,-10 H 93 l 4,10 H 83 L 87,95 H 73 l 4,10 H 63 L 67,95 H 53 l 4,10 H 43 L 47,95 H 33 l 4,10 H 23 L 27,95 H 13 l 4,10 H 3 L 7,95 H 0 v 20 h 200", + dovetailedIndented: "m 200,100 -7,-5 4,10 -7,-5 -7,5 4,-10 -7,5 -7,-5 4,10 -7,-5 -7,5 4,-10 -7,5 -7,-5 4,10 -7,-5 -7,5 4,-10 -7,5 -7,-5 4,10 -7,-5 -7,5 4,-10 -7,5 -7,-5 4,10 -7,-5 -7,5 4,-10 -7,5 -7,-5 4,10 -7,-5 -7,5 4,-10 -7,5 -7,-5 4,10 -7,-5 -7,5 4,-10 -7,5 -7,-5 4,10 -7,-5 -7,5 4,-10 -7,5 -7,-5 4,10 -7,-5 -7,5 4,-10 -7,5 -7,-5 4,10 -7,-5 -7,5 4,-10 -7,5 v 15 h 200", + nebuly: "m 13.1,89.8 c -4.1,0 -7.3,2 -7.3,4.5 0,1.2 0.7,2.3 1.8,3.1 1.2,0.7 1.9,1.8 1.9,3 0,2.5 -3.2,4.5 -7.3,4.5 -0.5,0 -2.2,-0.2 -2.2,-0.2 V 115 h 200 v -10.1 c -3.7,-0.2 -6.7,-2.2 -6.7,-4.5 0,-1.2 0.7,-2.3 1.9,-3 1.2,-0.8 1.8,-1.9 1.8,-3.1 0,-2.5 -3.2,-4.5 -7.2,-4.5 -4.1,0 -7.3,2 -7.3,4.5 0,1.2 0.7,2.3 1.8,3.1 1.2,0.7 1.9,1.8 1.9,3 0,2.5 -3.3,4.5 -7.3,4.5 -4,0 -7.3,-2 -7.3,-4.5 0,-1.2 0.7,-2.3 1.9,-3 1.2,-0.8 1.8,-1.9 1.8,-3.1 0,-2.5 -3.2,-4.5 -7.2,-4.5 -4.1,0 -7.3,2 -7.3,4.5 0,1.2 0.7,2.3 1.8,3.1 1.2,0.7 1.9,1.8 1.9,3 -1.5,4.1 -4.2,4.4 -8.8,4.5 -4.7,-0.1 -8.7,-1.5 -8.9,-4.5 0,-1.2 0.7,-2.3 1.9,-3 1.2,-0.8 1.9,-1.9 1.9,-3.1 0,-2.5 -3.3,-4.5 -7.3,-4.5 -4.1,0 -7.3,2 -7.3,4.5 0,1.2 0.7,2.3 1.8,3.1 1.2,0.7 1.9,1.8 1.9,3 0,2.5 -3.3,4.5 -7.3,4.5 -4,0 -7.3,-2 -7.3,-4.5 0,-1.2 0.7,-2.3 1.9,-3 1.2,-0.8 1.9,-1.9 1.9,-3.1 0,-2.5 -3.3,-4.5 -7.3,-4.5 -4.1,0 -7.3,2 -7.3,4.5 0,1.2 0.7,2.3 1.8,3.1 1.2,0.7 1.9,1.8 1.9,3 0,2.5 -3.3,4.5 -7.3,4.5 -4,0 -7.3,-2 -7.3,-4.5 0,-1.2 0.7,-2.3 1.9,-3 1.2,-0.8 1.9,-1.9 1.9,-3.1 0,-2.5 -3.3,-4.5 -7.3,-4.5 -4.1,0 -7.3,2 -7.3,4.5 0,1.2 0.7,2.3 1.8,3.1 1.2,0.7 1.9,1.8 1.9,3 0,2.5 -3.3,4.5 -7.3,4.5 -4,0 -7.3,-2 -7.3,-4.5 0,-1.2 0.7,-2.3 1.9,-3 1.2,-0.8 1.9,-1.9 1.9,-3.1 0,-2.5 -3.3,-4.5 -7.3,-4.5 -4.1,0 -7.3,2 -7.3,4.5 0,1.2 0.7,2.3 1.8,3.1 1.2,0.7 1.9,1.8 1.9,3 0,2.5 -3.3,4.5 -7.3,4.5 -4,0 -7.3,-2 -7.3,-4.5 0,-1.2 0.7,-2.3 1.9,-3 1.2,-0.8 1.9,-1.9 1.9,-3.1 0,-2.5 -3.3,-4.5 -7.3,-4.5 -4.1,0 -7.3,2 -7.3,4.5 0,1.2 0.7,2.3 1.8,3.1 1.2,0.7 1.9,1.8 1.9,3 0,2.5 -3.3,4.5 -7.3,4.5 -4,0 -7.3,-2 -7.3,-4.5 0,-1.2 0.7,-2.3 1.9,-3 1.2,-0.8 1.9,-1.9 1.9,-3.1 0,-2.5 -3.3,-4.5 -7.3,-4.5 -4.1,0 -7.3,2 -7.3,4.5 0,1.2 0.7,2.3 1.8,3.1 1.2,0.7 1.9,1.8 1.9,3 0,2.5 -3.3,4.5 -7.3,4.5 -4,0 -7.3,-2 -7.3,-4.5 0,-1.2 0.7,-2.3 1.9,-3 1.2,-0.8 1.9,-1.9 1.9,-3.1 0,-2.5 -3.3,-4.5 -7.3,-4.5 z", + rayonne: "M0 115l-.1-6 .2.8c1.3-1 2.3-2.5 2.9-4.4.5-2 .4-3.9-.3-5.4-.7-1.5-.8-3.4-.3-5.4A9 9 0 015.5 90c-.7 1.5-.8 3.4-.3 5.4.5 2 1.7 3.6 3.1 4.6a9 9 0 013.1 4.6c.5 2 .4 3.9-.3 5.4a9 9 0 003.1-4.6c.5-2 .4-3.9-.3-5.4-.7-1.5-.8-3.4-.3-5.4.5-2 1.7-3.6 3.1-4.6-.7 1.5-.8 3.4-.3 5.4.5 2 1.7 3.6 3.1 4.6a9 9 0 013.1 4.6c.5 2 .4 3.9-.3 5.4a9 9 0 003.1-4.6c.5-2 .4-3.9-.3-5.4-.7-1.5-.8-3.4-.3-5.4.5-2 1.7-3.6 3.1-4.6-.7 1.5-.8 3.4-.3 5.4.5 2 1.7 3.6 3.1 4.6a9 9 0 013.1 4.6c.5 2 .4 3.9-.3 5.4a9 9 0 003.1-4.6c.5-2 .4-3.9-.3-5.4-.7-1.5-.8-3.4-.3-5.4.5-2 1.7-3.6 3.1-4.6-.7 1.5-.8 3.4-.3 5.4.5 2 1.7 3.6 3.1 4.6a9 9 0 013.1 4.6c.5 2 .4 3.9-.3 5.4a9 9 0 003.1-4.6c.5-2 .4-3.9-.3-5.4-.7-1.5-.8-3.4-.3-5.4.5-2 1.7-3.6 3.1-4.6-.7 1.5-.8 3.4-.3 5.4.5 2 1.7 3.6 3.1 4.6a9 9 0 013.1 4.6c.5 2 .4 3.9-.3 5.4a9 9 0 003.1-4.6c.5-2 .4-3.9-.3-5.4-.7-1.5-.8-3.4-.3-5.4.5-2 1.7-3.6 3.1-4.6-.7 1.5-.8 3.4-.3 5.4.5 2 1.7 3.6 3.1 4.6a9 9 0 013.1 4.6c.5 2 .4 3.9-.3 5.4a9 9 0 003.1-4.6c.5-2 .4-3.9-.3-5.4-.7-1.5-.8-3.4-.3-5.4.5-2 1.7-3.6 3.1-4.6-.7 1.5-.8 3.4-.3 5.4.5 2 1.7 3.6 3.1 4.6a9 9 0 013.1 4.6c.5 2 .4 3.9-.3 5.4a9 9 0 003.1-4.6c.5-2 .4-3.9-.3-5.4-.7-1.5-.8-3.4-.3-5.4.5-2 1.7-3.6 3.1-4.6-.7 1.5-.8 3.4-.3 5.4.5 2 1.7 3.6 3.1 4.6a9 9 0 013.1 4.6c.5 2 .4 3.9-.3 5.4a9 9 0 003.1-4.6c.5-2 .4-3.9-.3-5.4-.7-1.5-.8-3.4-.3-5.4.5-2 1.7-3.6 3.1-4.6-.7 1.5-.8 3.4-.3 5.4.5 2 2.1 3.1 3.1 4.6 1 1.6 2.4 3.1 2.7 4.8.3 1.7.3 3.3 0 5.2 1.3-1 2.6-2.7 3.2-4.6.5-2 .4-3.9-.3-5.4-.7-1.5-.8-3.4-.3-5.4.5-2 1.7-3.6 3.1-4.6-.7 1.5-.8 3.4-.3 5.4.5 2 1.7 3.6 3.1 4.6a9 9 0 013.1 4.6c.5 2 .4 3.9-.3 5.4a9 9 0 003.1-4.6c.5-2 .4-3.9-.3-5.4-.7-1.5-.8-3.4-.3-5.4.5-2 1.7-3.6 3.1-4.6-.7 1.5-.8 3.4-.3 5.4.5 2 1.7 3.6 3.1 4.6a9 9 0 013.1 4.6c.5 2 .4 3.9-.3 5.4a9 9 0 003.1-4.6c.5-2 .4-3.9-.3-5.4-.7-1.5-.8-3.4-.3-5.4.5-2 1.7-3.6 3.1-4.6-.7 1.5-.8 3.4-.3 5.4.5 2 1.7 3.6 3.1 4.6a9 9 0 013.1 4.6c.5 2 .4 3.9-.3 5.4a9 9 0 003.1-4.6c.5-2 .4-3.9-.3-5.4-.7-1.5-.8-3.4-.3-5.4.5-2 1.7-3.6 3.1-4.6-.7 1.5-.8 3.4-.3 5.4.5 2 1.7 3.6 3.1 4.6a9 9 0 013.1 4.6c.5 2 .4 3.9-.3 5.4a9 9 0 003.1-4.6c.5-2 .4-3.9-.3-5.4-.7-1.5-.8-3.4-.3-5.4.5-2 1.7-3.6 3.1-4.6-.7 1.5-.8 3.4-.3 5.4.5 2 1.7 3.6 3.1 4.6a9 9 0 013.1 4.6c.5 2 .4 3.9-.3 5.4a9 9 0 003.1-4.6c.5-2 .4-3.9-.3-5.4-.7-1.5-.8-3.4-.3-5.4.5-2 1.7-3.6 3.1-4.6-.7 1.5-.8 3.4-.3 5.4.5 2 1.7 3.6 3.1 4.6a9 9 0 013.1 4.6c.5 2 .4 3.9-.3 5.4a9 9 0 003.1-4.6c.5-2 .4-3.9-.3-5.4-.7-1.5-.8-3.4-.3-5.4.5-2 1.7-3.6 3.1-4.6-.7 1.5-.8 3.4-.3 5.4.5 2 1.7 3.6 3.1 4.6a9 9 0 013.1 4.6c.5 2 .4 3.9-.3 5.4a9 9 0 003.1-4.6c.5-2 .4-3.9-.3-5.4-.7-1.5-.8-3.4-.3-5.4.5-2 1.7-3.6 3.1-4.6-.7 1.5-.8 3.4-.3 5.4.5 2 1.7 3.6 3.1 4.6a9 9 0 013.1 4.6c.5 2 .4 3.9-.3 5.4a9 9 0 003.1-4.6c.5-2 .4-3.9-.3-5.4-.7-1.5-.8-3.4-.3-5.4.5-2 1.7-3.6 3.1-4.6-.7 1.5-.8 3.4-.3 5.4.75 2.79 2.72 4.08 4.45 5.82L200 115z", + seaWaves: "m 28.83,94.9 c -4.25,0 -7.16,3.17 -8.75,5.18 -1.59,2.01 -4.5,5.18 -8.75,5.18 -2.16,0 -3.91,-1.63 -3.91,-3.64 0,-2.01 1.44,-3.6 3.6,-3.6 0.7,0 1.36,0.17 1.93,0.48 -0.33,-2.03 -2.19,-3.56 -4.45,-3.56 -4.24,0 -6.91,3.13 -8.5,5.13 V 115 h 200 v -14.89 c -1.59,2.01 -4.5,5.18 -8.75,5.18 -2.16,0 -3.91,-1.63 -3.91,-3.64 0,-2.01 1.75,-3.64 3.91,-3.64 0.7,0 1.36,0.17 1.93,0.48 -0.34,-2.01 -2.2,-3.55 -4.46,-3.55 -4.25,0 -7.16,3.17 -8.75,5.18 -1.59,2.01 -4.5,5.18 -8.75,5.18 -2.16,0 -3.91,-1.63 -3.91,-3.64 0,-2.01 1.75,-3.64 3.91,-3.64 0.7,0 1.36,0.17 1.93,0.48 -0.34,-2.01 -2.21,-3.55 -4.46,-3.55 -4.25,0 -7.16,3.17 -8.75,5.18 -1.59,2.01 -4.5,5.18 -8.75,5.18 -2.16,0 -3.91,-1.63 -3.91,-3.64 0,-2.01 1.75,-3.64 3.91,-3.64 0.7,0 1.36,0.17 1.93,0.48 -0.34,-2.01 -2.21,-3.55 -4.46,-3.55 -4.25,0 -7.16,3.17 -8.75,5.18 -1.59,2.01 -4.5,5.18 -8.75,5.18 -2.16,0 -3.91,-1.63 -3.91,-3.64 0,-2.01 1.75,-3.64 3.91,-3.64 0.7,0 1.36,0.17 1.93,0.48 -0.34,-2.01 -2.2,-3.55 -4.46,-3.55 -4.25,0 -7.16,3.17 -8.75,5.18 -1.59,2.01 -4.5,5.18 -8.75,5.18 -2.16,0 -3.91,-1.63 -3.91,-3.64 0,-2.01 1.44,-3.6 3.6,-3.6 0.7,0 1.36,0.17 1.93,0.48 -0.34,-2.01 -2.21,-3.55 -4.46,-3.55 -4.25,0 -6.6,3.09 -8.19,5.09 -1.59,2.01 -4.5,5.18 -8.75,5.18 -2.16,0 -3.91,-1.63 -3.91,-3.64 0,-2.01 1.75,-3.64 3.91,-3.64 0.7,0 1.36,0.17 1.93,0.48 -0.34,-2.01 -2.21,-3.55 -4.46,-3.55 -4.25,0 -7.16,3.17 -8.75,5.18 -1.59,2.01 -4.5,5.18 -8.75,5.18 -2.16,0 -3.91,-1.63 -3.91,-3.64 0,-2.01 1.75,-3.64 3.91,-3.64 0.7,0 1.36,0.17 1.93,0.48 -0.34,-2.01 -2.2,-3.55 -4.46,-3.55 -4.25,0 -7.16,3.17 -8.75,5.18 -1.59,2.01 -4.5,5.18 -8.75,5.18 -2.16,0 -3.91,-1.63 -3.91,-3.64 0,-2.01 1.75,-3.64 3.91,-3.64 0.7,0 1.36,0.17 1.93,0.48 -0.34,-2.01 -2.2,-3.55 -4.46,-3.55 -4.25,0 -7.16,3.17 -8.75,5.18 -1.59,2.01 -4.5,5.18 -8.75,5.18 -2.16,0 -3.91,-1.63 -3.91,-3.64 0,-2.01 1.75,-3.64 3.91,-3.64 0.7,0 1.36,0.17 1.93,0.48 -0.34,-2.01 -2.21,-3.55 -4.46,-3.55 z", + dragonTeeth: "M 9.4,85 C 6.5,88.1 4.1,92.9 3,98.8 1.9,104.6 2.3,110.4 3.8,115 2.4,113.5 0,106.6 0,109.3 v 5.7 h 200 v -5.7 c -1.1,-2.4 -2,-5.1 -2.6,-8 -1.1,-5.9 -0.7,-11.6 0.8,-16.2 -2.9,3.1 -5.3,7.9 -6.4,13.8 -1.1,5.9 -0.7,11.6 0.8,16.2 -2.9,-3.1 -5.3,-7.9 -6.4,-13.8 -1.1,-5.9 -0.7,-11.6 0.8,-16.2 -2.9,3.1 -5.3,7.9 -6.4,13.8 -1.1,5.9 -0.7,11.6 0.8,16.2 -2.9,-3.1 -5.3,-7.9 -6.4,-13.8 -1.1,-5.9 -0.7,-11.6 0.8,-16.2 -2.9,3.1 -5.3,7.9 -6.4,13.8 -1.1,5.9 -0.7,11.6 0.8,16.2 -2.9,-3.1 -5.3,-7.9 -6.4,-13.8 -1.1,-5.9 -0.7,-11.6 0.8,-16.2 -2.9,3.1 -5.3,7.9 -6.4,13.8 -1.1,5.9 -0.7,11.6 0.8,16.2 -2.9,-3.1 -5.3,-7.9 -6.4,-13.8 -1.1,-5.9 -0.7,-11.6 0.8,-16.2 -2.9,3.1 -5.3,7.9 -6.4,13.8 -1.1,5.9 -0.7,11.6 0.8,16.2 -2.9,-3.1 -5.3,-7.9 -6.4,-13.8 -1.1,-5.9 -0.7,-11.6 0.8,-16.2 -2.9,3.1 -5.3,7.9 -6.4,13.8 -1.1,5.9 -0.7,11.6 0.8,16.2 -2.9,-3.1 -5.3,-7.9 -6.4,-13.8 -1.1,-5.9 -0.7,-11.6 0.8,-16.2 -2.9,3.1 -5.3,7.9 -6.4,13.8 -1.1,5.9 -0.7,11.6 0.8,16.2 -2.9,-3.1 -5.3,-7.9 -6.4,-13.8 -1.1,-5.9 -0.7,-11.6 0.8,-16.2 -2.9,3.1 -5.3,7.9 -6.4,13.8 -1.1,5.9 -0.7,11.6 0.8,16.2 -2.9,-3.1 -5.3,-7.9 -6.4,-13.8 -1.1,-5.9 -0.7,-11.6 0.8,-16.2 -2.9,3.1 -5.3,7.9 -6.4,13.8 -1.1,5.9 -0.7,11.6 0.8,16.2 -1.4,-1.5 -2.8,-3.9 -3.8,-6.1 -1.1,-2.4 -2.3,-6.1 -2.6,-7.7 -0.2,-5.9 0.2,-11.7 1.7,-16.3 -3,3.1 -5.3,7.9 -6.4,13.8 -1.1,5.8 -0.7,11.6 0.8,16.2 -2.9,-3.1 -5.3,-7.9 -6.4,-13.8 -1,-5.8 -0.7,-11.6 0.9,-16.2 -3,3.1 -5.3,7.9 -6.4,13.8 -1.1,5.8 -0.7,11.6 0.8,16.2 -2.9,-3.1 -5.3,-7.9 -6.4,-13.8 -1.1,-5.8 -0.7,-11.6 0.9,-16.2 -3,3.1 -5.3,7.9 -6.4,13.8 -1.1,5.8 -0.7,11.6 0.8,16.2 -2.9,-3.1 -5.3,-7.9 -6.4,-13.8 C 63,95.4 63.4,89.6 64.9,85 c -2.9,3.1 -5.3,7.9 -6.3,13.8 -1.1,5.8 -0.7,11.6 0.8,16.2 -3,-3.1 -5.3,-7.9 -6.4,-13.8 -1.1,-5.8 -0.7,-11.6 0.8,-16.2 -2.9,3.1 -5.3,7.9 -6.4,13.8 -1,5.8 -0.6,11.6 0.9,16.2 -3,-3.1 -5.3,-7.9 -6.4,-13.8 -1.1,-5.8 -0.7,-11.6 0.8,-16.2 -2.9,3.1 -5.3,7.9 -6.4,13.8 -1,5.8 -0.7,11.6 0.9,16.2 -3,-3.1 -5.3,-7.9 -6.4,-13.8 -1.1,-5.8 -0.7,-11.6 0.8,-16.2 -2.9,3.1 -5.3,7.9 -6.4,13.8 -1.1,5.8 -0.7,11.6 0.9,16.2 -3,-3.1 -5.3,-7.9 -6.4,-13.8 C 18.6,95.4 19,89.6 20.5,85 17.6,88.1 15.2,92.9 14.1,98.8 13,104.6 13.4,110.4 14.9,115 12,111.9 9.6,107.1 8.6,101.2 7.5,95.4 7.9,89.6 9.4,85 Z", + firTrees: "m 3.9,90 -4,7 2,-0.5 L 0,100 v 15 h 200 v -15 l -1.9,-3.5 2,0.5 -4,-7 -4,7 2,-0.5 -4,7 2,-0.5 -4,7 -4,-7 2,0.5 -4,-7 2,0.5 -4,-7 -4,7 2,-0.5 -4,7 2,-0.5 -4,7 -4,-7 2,0.5 -4,-7 2,0.5 -4,-7 -4,7 2,-0.5 -4,7 2,-0.5 -4,7 -4,-7 2,0.5 -4,-7 2,0.5 -4.1,-7 -4,7 2,-0.5 -4,7 2,-0.5 -4,7 -4,-7 2,0.5 -4,-7 2,0.5 -4,-7 -4,7 2,-0.5 -4,7 2,-0.5 -4,7 -4,-7 2,0.5 -4,-7 2,0.5 -4,-7 -4,7 2,-0.5 -4,7 2,-0.5 -4,7 -4,-7 2,0.5 -4,-7 2,0.5 -4,-7 -4,7 2,-0.5 -4,7 2,-0.5 -4,7 -4,-7 2,0.5 -4,-7 2,0.5 -4,-7 -4,7 2,-0.5 -4,7 2,-0.5 -4,7 -4,-7 2,0.5 -4,-7 2,0.5 -4,-7 -4,7 2,-0.5 -4,7 2,-0.5 -4,7 -4,-7 2,0.5 -4,-7 2,0.5 -4.1,-7 -4,7 2,-0.5 -4,7 2,-0.5 -4,7 -4,-7 2,0.5 -4,-7 2,0.5 -4,-7 -4,7 2,-0.5 -4,7 2,-0.5 -4,7 -4,-7 2,0.5 -4,-7 2,0.5 -4,-7 -4,7 2,-0.5 -4,7 2,-0.5 -4,7 -4,-7 2,0.5 -4,-7 2,0.5 z", + flechy: "m 0,100 h 85 l 15,-15 15,15 h 85 v 15 H 0 Z", + barby: "m 0,100 h 85 l 15,15 15,-15 h 85 v 15 H 0 Z", + enclavy: "M 0,100 H 85 V 85 h 30 v 15 h 85 v 15 H 0 Z", + escartely: "m 0,100 h 85 v 15 h 30 v -15 h 85 v 15 H 0 Z", + arched: "m 100,95 c 40,-0.2 100,20 100,20 H 0 c 0,0 60,-19.8 100,-20 z", + archedReversed: "m 0,85 c 0,0 60,20.2 100,20 40,-0.2 100,-20 100,-20 v 30 H 0 Z" + } + + const templates = { + // divisions + perFess: line => ``, + perPale: line => ``, + perBend: line => ``, + perBendSinister: line => ``, + perChevron: line => ``, + perChevronReversed: line => ``, + perCross: line => ``, + perPile: line => ``, + perSaltire: () => ``, + gyronny: () => ``, + chevronny: () => ``, + // oprinaries + fess: line => ``, + pale: line => ``, + bend: line => ``, + bendSinister: line => ``, + chief: line => ``, + bar: line => ``, + gemelle: line => ``, + fessCotissed: line => ``, + fessDoubleCotissed: line => ``, + bendlet: line => ``, + bendletSinister: line => ``, + terrace: line => ``, + cross: line => ``, + crossParted: line => ``, + saltire: line => ``, + saltireParted: line => ``, + mount: () => ``, + point: () => ``, + flaunches: () => ``, + gore: () => ``, + pall: () => ``, + pallReversed: () => ``, + chevron: () => ``, + chevronReversed: () => ``, + gyron: () => ``, + quarter: () => ``, + canton: () => ``, + pile: () => ``, + pileInBend: () => ``, + pileInBendSinister: () => ``, + piles: () => ``, + pilesInPoint: () => ``, + label: () => `` + } + + const patterns = { + semy: (p, c1, c2, size, chargeId) => ``, + vair: (p, c1, c2, size) => ``, + vairInPale: (p, c1, c2, size) => ``, + vairEnPointe: (p, c1, c2, size) => ``, + ermine: (p, c1, c2, size) => ``, + chequy: (p, c1, c2, size) => ``, + lozengy: (p, c1, c2, size) => ``, + fusily: (p, c1, c2, size) => ``, + pally: (p, c1, c2, size) => ``, + barry: (p, c1, c2, size) => ``, + gemelles: (p, c1, c2, size) => ``, + bendy: (p, c1, c2, size) => ``, + bendySinister: (p, c1, c2, size) => ``, + palyBendy: (p, c1, c2, size) => ``, + pappellony: (p, c1, c2, size) => ``, + masoned: (p, c1, c2, size) => ``, + fretty: (p, c1, c2, size) => `` + } + + const draw = async function(id, coa) { + const {shield, division, ordinaries = [], charges = []} = coa; + const ordinariesRegular = ordinaries.filter(o => !o.above); const ordinariesAboveCharges = ordinaries.filter(o => o.above); - const shieldPath = document.getElementById(coa.shield).querySelector("path").getAttribute("d"); - const tDiv = division ? division.t.includes("-") ? division.t.split("-")[1] : division.t : null; - const positions = shieldPositions[coa.shield]; - const sizeModifier = shieldSize[coa.shield] || 1; - const viewBox = shieldBox[coa.shield] || "0 0 200 200"; + const shieldPath = shieldPaths[shield]; + const tDiv = division ? (division.t.includes("-") ? division.t.split("-")[1] : division.t) : null; + const positions = shieldPositions[shield]; + const sizeModifier = shieldSize[shield] || 1; + const viewBox = shieldBox[shield] || "0 0 200 200"; - const coaDefs = document.getElementById("coaDefs"); + const shieldClip = ``; + const divisionClip = division ? `${getTemplate(division.division, division.line)}` : ""; + const loadedCharges = await getCharges(coa, id, shieldPath); + const loadedPatterns = getPatterns(coa, id); + const blacklight = ` + + + + `; + const field = ``; + const divisionGroup = division ? templateDivision() : ""; + const overlay = ``; - let svg = ` - - - ${division ? `${getTemplate(division.division, division.line)}` : ''} - - - - ${templateDivision()} - ${templateAboveAll()} - - - - `; + const svg= ` + ${shieldClip}${divisionClip}${loadedCharges}${loadedPatterns}${blacklight} + ${field}${divisionGroup}${templateAboveAll()} + ${overlay}`; - // insert coa svg to coaDefs - coaDefs.querySelector("#coas").insertAdjacentHTML("beforeend", svg); - - // fetch charges - if (charges.length) { - const defs = document.getElementById(id).querySelector("defs"); - const uniqueCharges = [...new Set(charges.map(charge => charge.charge))]; - uniqueCharges.forEach(charge => fetchCharge(charge, defs)); - } + // insert coa svg to defs + document.getElementById("coas").insertAdjacentHTML("beforeend", svg); function templateDivision() { - if (!division) return ""; let svg = ""; // In field part for (const ordinary of ordinariesRegular) { - if (ordinary.divided === "field") svg += templateOrdinary(ordinary, ordinary.t); else - if (ordinary.divided === "counter") svg += templateOrdinary(ordinary, tDiv); + if (ordinary.divided === "field") svg += templateOrdinary(ordinary, ordinary.t); + else if (ordinary.divided === "counter") svg += templateOrdinary(ordinary, tDiv); } for (const charge of charges) { - if (charge.divided === "field") svg += templateCharge(charge, charge.t); else - if (charge.divided === "counter") svg += templateCharge(charge, tDiv); + if (charge.divided === "field") svg += templateCharge(charge, charge.t); + else if (charge.divided === "counter") svg += templateCharge(charge, tDiv); } for (const ordinary of ordinariesAboveCharges) { - if (ordinary.divided === "field") svg += templateOrdinary(ordinary, ordinary.t); else - if (ordinary.divided === "counter") svg += templateOrdinary(ordinary, tDiv); + if (ordinary.divided === "field") svg += templateOrdinary(ordinary, ordinary.t); + else if (ordinary.divided === "counter") svg += templateOrdinary(ordinary, tDiv); } // In division part - svg += ` - - - `; + svg += ``; for (const ordinary of ordinariesRegular) { - if (ordinary.divided === "division") svg += templateOrdinary(ordinary, ordinary.t); else - if (ordinary.divided === "counter") svg += templateOrdinary(ordinary, coa.t1); + if (ordinary.divided === "division") svg += templateOrdinary(ordinary, ordinary.t); + else if (ordinary.divided === "counter") svg += templateOrdinary(ordinary, coa.t1); } for (const charge of charges) { - if (charge.divided === "division") svg += templateCharge(charge, charge.t); else - if (charge.divided === "counter") svg += templateCharge(charge, coa.t1); + if (charge.divided === "division") svg += templateCharge(charge, charge.t); + else if (charge.divided === "counter") svg += templateCharge(charge, coa.t1); } for (const ordinary of ordinariesAboveCharges) { - if (ordinary.divided === "division") svg += templateOrdinary(ordinary, ordinary.t); else - if (ordinary.divided === "counter") svg += templateOrdinary(ordinary, coa.t1); + if (ordinary.divided === "division") svg += templateOrdinary(ordinary, ordinary.t); + else if (ordinary.divided === "counter") svg += templateOrdinary(ordinary, coa.t1); } - return svg += `` + return (svg += ``); } function templateAboveAll() { let svg = ""; - ordinariesRegular.filter(o => !o.divided).forEach(ordinary => { - svg += templateOrdinary(ordinary, ordinary.t); - }); + ordinariesRegular.filter(o => !o.divided) + .forEach(ordinary => { + svg += templateOrdinary(ordinary, ordinary.t); + }); - charges.filter(o => !o.divided || !division).forEach(charge => { - svg += templateCharge(charge, charge.t); - }); + charges.filter(o => !o.divided || !division) + .forEach(charge => { + svg += templateCharge(charge, charge.t); + }); - ordinariesAboveCharges.filter(o => !o.divided).forEach(ordinary => { - svg += templateOrdinary(ordinary, ordinary.t); - }) + ordinariesAboveCharges.filter(o => !o.divided) + .forEach(ordinary => { + svg += templateOrdinary(ordinary, ordinary.t); + }); return svg; } @@ -787,97 +934,105 @@ svg += ``; for (const p of chargePositions) { const transform = getElTransform(charge, p); - svg += ``; + svg += ``; } return svg + ``; function getElTransform(c, p) { - const [x, y] = positions[p]; const s = (c.size || 1) * sizeModifier; - const scale = c.sinister || c.reversed ? `${c.sinister ? "-" : ""}${s}, ${c.reversed ? "-" : ""}${s}` : s; + const sx = c.sinister ? -s : s; + const sy = c.reversed ? -s : s; + let [x, y] = positions[p]; + x = x - 100 * (sx - 1); + y = y - 100 * (sy - 1); + const scale = c.sinister || c.reversed ? `${sx} ${sy}` : s; return `translate(${x} ${y}) scale(${scale})`; } } - - // get color or link to pattern - function clr(tincture) { - if (colors[tincture]) return colors[tincture]; - const pattern = document.getElementById(tincture); - if (!pattern) renderPattern(tincture); - return "url(#"+tincture+")"; - } - - function renderPattern(tincture) { - const [pattern, t1, t2, size] = tincture.split("-"); - const semy = pattern.slice(0, 4) === "semy"; - - const template = document.getElementById(semy ? "semy" : pattern); - let html = template.innerHTML.replace(/{id}/, tincture); - - const width = template.querySelector("pattern").getAttribute("width"); - const height = template.querySelector("pattern").getAttribute("height"); - - if (t1) html = html.replace(/{c1}/g, clr(t1)); - if (t2) html = html.replace(/{c2}/g, clr(t2)); - - document.getElementById("patterns").insertAdjacentHTML("beforeend", html); - - if (semy) { - const charge = pattern.split("_of_")[1]; - const el = document.getElementById(tincture); - - fetch("https://azgaar.github.io/Armoria/charges/"+charge+".svg").then(res => { - if (res.ok) return res.text(); - else throw new Error('Cannot fetch charge'); - }).then(text => { - const html = document.createElement("html"); - html.innerHTML = text; - el.innerHTML = el.innerHTML.replace(//g, html.querySelector("g").outerHTML); - }); - } - - if (size) { - let mod = 1; - if (size === "small") mod = .5; - if (size === "smaller") mod = .25; - if (size === "smallest") mod = .125; - if (size === "big") mod = 2; - - const el = document.getElementById(tincture); - el.setAttribute("width", width * mod); - el.setAttribute("height", height * mod); - } - } - - function getTemplate(templateId, lineId) { - if (!lineId) return document.getElementById(templateId)?.innerHTML; - const template = document.getElementById(templateId); - const line = document.getElementById(lineId) ? document.getElementById(lineId) : document.getElementById("straight"); - return template.innerHTML.replace(/{line}/g, line.getAttribute("d")).replace(/dpath/g, "d"); - } - - function fetchCharge(charge, defs) { - if (charge === "inescutcheon") { - const g = ``; - defs.insertAdjacentHTML("beforeend", g); - return; - } - - fetch("https://azgaar.github.io/Armoria/charges/"+charge+".svg").then(res => { - if (res.ok) return res.text(); - else throw new Error('Cannot fetch charge'); - }).then(text => { - const el = document.createElement("html"); - el.innerHTML = text; - const g = el.querySelector("g"); - g.id = charge + "_" + id; - defs.insertAdjacentHTML("beforeend", g.outerHTML); - }); - } } - // async render coa if it does not exist + async function getCharges(coa, id, shieldPath) { + let charges = coa.charges ? coa.charges.map(charge => charge.charge) : []; // add charges + if (semy(coa.t1)) charges.push(semy(coa.t1)); // add field semy charge + if (semy(coa.division?.t)) charges.push(semy(coa.division.t)); // add division semy charge + + const uniqueCharges = [...new Set(charges)]; + const fetchedCharges = await Promise.all( + uniqueCharges.map(async charge => { + if (charge === "inescutcheon") return ``; + const fetched = await fetchCharge(charge, id); + return fetched; + }) + ); + return fetchedCharges.join(""); + } + + async function fetchCharge(charge, id) { + const fetched = fetch("https://azgaar.github.io/Armoria/charges/" + charge + ".svg") + .then(res => { + if (res.ok) return res.text(); + else throw new Error("Cannot fetch charge"); + }) + .then(text => { + const html = document.createElement("html"); + html.innerHTML = text; + const g = html.querySelector("g"); + g.setAttribute("id", charge + "_" + id); + return g.outerHTML; + }); + return fetched; + } + + function getPatterns(coa, id) { + const isPattern = string => string.includes("-"); + let patternsToAdd = []; + if (coa.t1.includes("-")) patternsToAdd.push(coa.t1); // add field pattern + if (coa.division && isPattern(coa.division.t)) patternsToAdd.push(coa.division.t); // add division pattern + if (coa.ordinaries) coa.ordinaries.filter(ordinary => isPattern(ordinary.t)).forEach(ordinary => patternsToAdd.push(ordinary.t)); // add ordinaries pattern + if (coa.charges) coa.charges.filter(charge => isPattern(charge.t)).forEach(charge => patternsToAdd.push(charge.t)); // add charges pattern + if (!patternsToAdd.length) return ""; + + return [...new Set(patternsToAdd)].map(patternString => { + const [pattern, t1, t2, size] = patternString.split("-"); + const charge = semy(patternString); + if (charge) return patterns.semy(patternString, clr(t1), clr(t2), getSizeMod(size), charge + "_" + id); + return patterns[pattern](patternString, clr(t1), clr(t2), getSizeMod(size), charge); + }).join(""); + } + + function getSizeMod(size) { + if (size === "small") return .5; + if (size === "smaller") return .25; + if (size === "smallest") return .125; + if (size === "big") return 2; + return 1; + } + + function getTemplate(templateId, lineId) { + if (!lineId) return templates[templateId](); + const line = lines[lineId] || lines.straight; + return templates[templateId](line); + } + + // get color or link to pattern + function clr(tincture) { + if (colors[tincture]) return colors[tincture]; + return `url(#${tincture})`; + } + + // get charge is string starts with "semy" + function semy(string) { + const isSemy = /^semy/.test(string); + if (!isSemy) return false; + return string.match(/semy_of_(.*?)-/)[1]; + } + + // render coa if does not exist const trigger = function(id, coa) { + if (coa === "custom") { + console.warn("Cannot render custom emblem", coa); + return; + } if (!coa) { console.warn(`Emblem ${id} is undefined`); return; @@ -885,6 +1040,18 @@ if (!document.getElementById(id)) draw(id, coa); } - return {trigger}; + const add = function(type, i, coa, x, y) { + const id = type + "COA" + i; + const g = document.getElementById(type+"Emblems"); -}))); \ No newline at end of file + if (emblems.selectAll("use").size()) { + const size = +g.getAttribute("font-size") || 50; + const use = ``; + g.insertAdjacentHTML("beforeend", use); + } + if (layerIsOn("toggleEmblems")) trigger(id, coa); + } + + return {trigger, add}; + +}))); diff --git a/modules/cultures-generator.js b/modules/cultures-generator.js index 01ed06a8..c54ce994 100644 --- a/modules/cultures-generator.js +++ b/modules/cultures-generator.js @@ -171,7 +171,6 @@ const td = (cell, goal) => {const d = Math.abs(temp[cells.g[cell]] - goal); return d ? d+1 : 1;} // temperature difference fee const bd = (cell, biomes, fee = 4) => biomes.includes(cells.biome[cell]) ? 1 : fee; // biome difference fee const sf = (cell, fee = 4) => cells.haven[cell] && pack.features[cells.f[cells.haven[cell]]].type !== "lake" ? 1 : fee; // not on sea coast fee - // https://en.wikipedia.org/wiki/List_of_cities_by_average_temperature if (culturesSet.value === "european") { return [ diff --git a/modules/save-and-load.js b/modules/save-and-load.js index e682002e..7baa57c0 100644 --- a/modules/save-and-load.js +++ b/modules/save-and-load.js @@ -94,6 +94,17 @@ async function getMapURL(type, subtype) { if (customization && type === "mesh") updateMeshCells(clone); inlineStyle(clone); + // add displayed emblems + if (layerIsOn("toggleEmblems")) { + const defsEmblems = cloneEl.getElementById("defs-emblems"); + clone.selectAll("#emblems use").each(function() { + const href = this.getAttribute("href"); + if (!href) return; + const emblem = document.getElementById(href.slice(1)).cloneNode(true); // clone emblem + defsEmblems.append(emblem); + }); + } + const fontStyle = await GFontToDataURI(getFontsToLoad()); // load non-standard fonts if (fontStyle) clone.select("defs").append("style").text(fontStyle.join('\n')); // add font to style @@ -115,7 +126,7 @@ function removeUnusedElements(clone) { for (let empty = 1; empty;) { empty = 0; clone.selectAll("g").each(function() { - if (!this.hasChildNodes() || this.style.display === "none") {empty++; this.remove();} + if (!this.hasChildNodes() || this.style.display === "none" || this.classList.contains("hidden")) {empty++; this.remove();} if (this.hasAttribute("display") && this.style.display === "inline") this.removeAttribute("display"); }); } @@ -246,7 +257,8 @@ function getMapData() { const biomes = [biomesData.color, biomesData.habitability, biomesData.name].join("|"); const notesData = JSON.stringify(notes); - const cloneEl = document.getElementById("map").cloneNode(true); // clone svg + // clone svg + const cloneEl = document.getElementById("map").cloneNode(true); // set transform values to default cloneEl.setAttribute("width", graphWidth); diff --git a/modules/ui/burg-editor.js b/modules/ui/burg-editor.js index 38c2d886..4113db4f 100644 --- a/modules/ui/burg-editor.js +++ b/modules/ui/burg-editor.js @@ -52,6 +52,11 @@ function editBurg(id) { function updateBurgValues() { const id = +elSelected.attr("data-id"); const b = pack.burgs[id]; + const province = pack.cells.province[b.cell]; + const provinceName = province ? pack.provinces[province].fullName + ", " : ""; + const stateName = pack.states[b.state].fullName || pack.states[b.state].name; + document.getElementById("burgProvinceAndState").innerHTML = provinceName + stateName; + document.getElementById("burgName").value = b.name; document.getElementById("burgPopulation").value = rn(b.population * populationRate.value * urbanization.value); document.getElementById("burgEditAnchorStyle").style.display = +b.port ? "inline-block" : "none"; @@ -62,6 +67,11 @@ function editBurg(id) { const cultures = pack.cultures.filter(c => !c.removed); cultures.forEach(c => cultureSelect.options.add(new Option(c.name, c.i, false, c.i === b.culture))); + const temperature = grid.cells.temp[pack.cells.g[b.cell]]; + document.getElementById("burgTemperature").innerHTML = convertTemperature(temperature); + document.getElementById("burgTemperatureLikeIn").innerHTML = getTemperatureLikeness(temperature); + document.getElementById("burgElevation").innerHTML = getHeight(pack.cells.h[b.cell]); + // toggle features if (b.capital) document.getElementById("burgCapital").classList.remove("inactive"); else document.getElementById("burgCapital").classList.add("inactive"); @@ -93,6 +103,18 @@ function editBurg(id) { document.getElementById("burgEmblem").setAttribute("href", "#" + coaID); } + // in °C, array from -1 °C; source: https://en.wikipedia.org/wiki/List_of_cities_by_average_temperature + function getTemperatureLikeness(temperature) { + if (temperature < -5) return "Yakutsk"; + const cities = [ + "Snag (Yukon)", "Yellowknife (Canada)", "Okhotsk (Russia)", "Fairbanks (Alaska)", "Nuuk (Greenland)", "Murmansk", // -5 - 0 + "Arkhangelsk", "Anchorage", "Tromsø", "Reykjavik", "Riga", "Stockholm", "Halifax", "Prague", "Copenhagen9", "London", // 1 - 10 + "Antwerp", "Paris", "Milan", "Batumi", "Rome", "Dubrovnik", "Lisbon", "Barcelona", "Marrakesh", "Alexandria", // 11 - 20 + "Tegucigalpa", "Guangzhou", "Rio de Janeiro", "Dakar", "Miami", "Jakarta", "Mogadishu", "Bangkok", "Aden", "Khartoum"]; // 21 - 30 + if (temperature > 30) return "Mecca"; + return cities[temperature+5] || null; + } + function dragBurgLabel() { const tr = parseTransform(this.getAttribute("transform")); const dx = +tr[0] - d3.event.x, dy = +tr[1] - d3.event.y; @@ -313,7 +335,8 @@ function editBurg(id) { if (!seed && burg.MFCGlink) {openURL(burg.MFCGlink); return;} const cells = pack.cells; const name = elSelected.text(); - const size = Math.max(Math.min(rn(burg.population), 65), 6); + const size = Math.max(Math.min(rn(burg.population), 100), 6); // to be removed once change on MFDC is done + const population = rn(burg.population * populationRate.value * urbanization.value); const s = burg.MFCG || defSeed; const cell = burg.cell; @@ -338,7 +361,7 @@ function editBurg(id) { } const site = "http://fantasycities.watabou.ru/?random=0&continuous=0"; - const url = `${site}&name=${name}&size=${size}&seed=${s}&hub=${hub}&river=${river}&coast=${coast}&citadel=${citadel}&plaza=${plaza}&temple=${temple}&walls=${walls}&shantytown=${shanty}${sea}`; + const url = `${site}&name=${name}&population=${population}&size=${size}&seed=${s}&hub=${hub}&river=${river}&coast=${coast}&citadel=${citadel}&plaza=${plaza}&temple=${temple}&walls=${walls}&shantytown=${shanty}${sea}`; openURL(url); } } diff --git a/modules/ui/editors.js b/modules/ui/editors.js index 3544a8ef..74168294 100644 --- a/modules/ui/editors.js +++ b/modules/ui/editors.js @@ -125,7 +125,12 @@ function addBurg(point) { const temple = pack.states[state].form === "Theocracy"; const population = Math.max((cells.s[cell] + cells.road[cell]) / 3 + i / 1000 + cell % 100 / 1000, .1); - pack.burgs.push({name, cell, x, y, state, i, culture, feature, capital: 0, port: 0, temple, population}); + // generate emblem + const coa = COA.generate(pack.states[state].coa, .25); + coa.shield = COA.getShield(culture, state); + COArenderer.add("burg", i, coa, x, y); + + pack.burgs.push({name, cell, x, y, state, i, culture, feature, capital: 0, port: 0, temple, population, coa}); cells.burg[cell] = i; const townSize = burgIcons.select("#towns").attr("size") || 0.5; diff --git a/modules/ui/emblems-editor.js b/modules/ui/emblems-editor.js index d46908bd..c1b5431c 100644 --- a/modules/ui/emblems-editor.js +++ b/modules/ui/emblems-editor.js @@ -8,6 +8,7 @@ function editEmblem(type, id, el) { const emblemStates = document.getElementById("emblemStates"); const emblemProvinces = document.getElementById("emblemProvinces"); const emblemBurgs = document.getElementById("emblemBurgs"); + const emblemShapeSelector = document.getElementById("emblemShapeSelector"); updateElementSelectors(type, id, el); @@ -21,9 +22,14 @@ function editEmblem(type, id, el) { emblemStates.oninput = selectState; emblemProvinces.oninput = selectProvince; emblemBurgs.oninput = selectBurg; - document.getElementById("emblemShapeSelector").oninput = changeShape; + emblemShapeSelector.oninput = changeShape; document.getElementById("emblemsRegenerate").onclick = regenerate; document.getElementById("emblemsArmoria").onclick = openInArmoria; + document.getElementById("emblemsUpload").onclick = toggleUpload; + document.getElementById("emblemsUploadImage").onclick = () => emblemImageToLoad.click(); + document.getElementById("emblemsUploadSVG").onclick = () => emblemSVGToLoad.click(); + document.getElementById("emblemImageToLoad").onchange = () => upload("image"); + document.getElementById("emblemSVGToLoad").onchange = () => upload("svg"); document.getElementById("emblemsDownload").onclick = toggleDownload; document.getElementById("emblemsDownloadSVG").onclick = () => download("svg"); document.getElementById("emblemsDownloadPNG").onclick = () => download("png"); @@ -88,10 +94,15 @@ function editEmblem(type, id, el) { function updateEmblemData(type, id, el) { if (!el.coa) return; document.getElementById("emblemImage").setAttribute("href", "#" + id); - document.getElementById("emblemShapeSelector").value = el.coa.shield; let name = el.fullName || el.name; if (type === "burg") name = "Burg of " + name; document.getElementById("emblemArmiger").innerText = name; + + if (el.coa === "custom") emblemShapeSelector.disabled = true; + else { + emblemShapeSelector.disabled = false; + emblemShapeSelector.value = el.coa.shield; + } } function selectState() { @@ -149,27 +160,75 @@ function editEmblem(type, id, el) { function regenerate() { let parent = null; - if (type === "province") parent = pack.states[el.state].coa; + if (type === "province") parent = pack.states[el.state]; else if (type === "burg") { const province = pack.cells.province[el.cell]; - parent = province ? pack.provinces[province].coa : pack.states[el.state].coa; + parent = province ? pack.provinces[province] : pack.states[el.state]; } - const shield = el.coa.shield; - el.coa = COA.generate(parent); + const shield = el.coa.shield || COA.getShield(el.culture || parent?.culture || 0, el.state); + el.coa = COA.generate(parent ? parent.coa : null); el.coa.shield = shield; + emblemShapeSelector.disabled = false; + emblemShapeSelector.value = el.coa.shield; - document.getElementById(id).remove(); + const coaEl = document.getElementById(id); + if (coaEl) coaEl.remove(); COArenderer.trigger(id, el.coa); } function openInArmoria() { - const json = JSON.stringify(el.coa).replaceAll("#", "%23"); + const coa = el.coa && el.coa !== "custom" ? el.coa : {t1: "sable"}; + const json = JSON.stringify(coa).replaceAll("#", "%23"); const url = `http://azgaar.github.io/Armoria/?coa=${json}`; openURL(url); } + function toggleUpload() { + document.getElementById("emblemDownloadControl").classList.add("hidden"); + const buttons = document.getElementById("emblemUploadControl"); + buttons.classList.toggle("hidden"); + } + + function upload(type) { + const input = type === "image" ? document.getElementById("emblemImageToLoad") : document.getElementById("emblemSVGToLoad"); + const file = input.files[0]; + input.value = ""; + + if (file.size > 500000) { + tip(`File is too big, please optimize file size up to 500kB and re-upload. Recommended size is 200x200 px and up to 100kB`, true, "error", 5000); + return; + } + + const reader = new FileReader(); + + reader.onload = function(readerEvent) { + const result = readerEvent.target.result; + const defs = document.getElementById("defs-emblems"); + + if (type === "image") { + const svg = ``; + defs.insertAdjacentHTML("beforeend", svg); + } else { + defs.insertAdjacentHTML("beforeend", result); + const newEmblem = defs.lastChild; // new coa + newEmblem.id = id; + newEmblem.setAttribute("width", 200); + newEmblem.setAttribute("height", 200); + } + + const coa = document.getElementById(id); + if (coa) coa.remove(); // remove old emblem + + el.coa = "custom"; + emblemShapeSelector.disabled = true; + }; + + if (type === "image") reader.readAsDataURL(file); else reader.readAsText(file); + } + function toggleDownload() { + document.getElementById("emblemUploadControl").classList.add("hidden"); const buttons = document.getElementById("emblemDownloadControl"); buttons.classList.toggle("hidden"); } @@ -225,16 +284,9 @@ function editEmblem(type, id, el) { const clone = svg.cloneNode(true); // clone svg const d = clone.getElementsByTagName("defs")[0]; - clone.removeAttribute("id"); clone.setAttribute("width", size); clone.setAttribute("height", size); - d.insertAdjacentHTML("beforeend", document.getElementById(coa.shield).outerHTML); // copy shield to defs - clone.querySelectorAll("[fill^=url]").forEach(el => { - const id = el.getAttribute("fill").match(/\#([^)]+)\)/)[1]; - d.insertAdjacentHTML("beforeend", document.getElementById(id).outerHTML); - }); - return (new XMLSerializer()).serializeToString(clone); } diff --git a/modules/ui/provinces-editor.js b/modules/ui/provinces-editor.js index 54893fa2..90966494 100644 --- a/modules/ui/provinces-editor.js +++ b/modules/ui/provinces-editor.js @@ -239,10 +239,15 @@ function editProvinces() { const name = provinces[p].name; const color = getRandomColor(); + const coa = provinces[p].coa; + const coaEl = document.getElementById("provinceCOA"+p); + if (coaEl) coaEl.id = "stateCOA"+newState; + emblems.select(`#provinceEmblems > use[data-i='${p}']`).remove(); + // update cells cells.i.filter(i => cells.province[i] === p).forEach(i => { - cells.province[i] = 0; - cells.state[i] = newState; + cells.province[i] = 0; + cells.state[i] = newState; }); // update diplomacy and reverse relations @@ -264,7 +269,7 @@ function editProvinces() { states[0].diplomacy.push([`Independance declaration`, `${name} declared its independance from ${states[oldState].name}`]); // create new state - states.push({i:newState, name, diplomacy, provinces:[], color, expansionism:.5, capital:burg, type:"Generic", center, culture, military:[], alert:1}); + states.push({i:newState, name, diplomacy, provinces:[], color, expansionism:.5, capital:burg, type:"Generic", center, culture, military:[], alert:1, coa}); BurgsAndStates.collectStatistics(); BurgsAndStates.defineStateForms([newState]); @@ -276,7 +281,10 @@ function editProvinces() { // remove old province unfog("focusProvince"+p); if (states[oldState].provinces.includes(p)) states[oldState].provinces.splice(states[oldState].provinces.indexOf(p), 1); - provinces[p].removed = true; + provinces[p] = {i:p, removed: true}; + + // draw emblem + COArenderer.add("state", newState, coa, pack.states[newState].pole[0], pack.states[newState].pole[1]); closeDialogs(); editStates(); @@ -767,7 +775,15 @@ function editProvinces() { const fullName = name + " " + formName; const stateColor = pack.states[state].color, rndColor = getRandomColor(); const color = stateColor[0] === "#" ? d3.color(d3.interpolate(stateColor, rndColor)(.2)).hex() : rndColor; - provinces.push({i:province, state, center, burg, name, formName, fullName, color}); + + // generate emblem + const kinship = burg ? .8 : .4; + const parent = burg ? pack.burgs[burg].coa : pack.states[state].coa; + const coa = COA.generate(parent, kinship); + coa.shield = COA.getShield(c, state); + COArenderer.add("province", province, coa, point[0], point[1]); + + provinces.push({i:province, state, center, burg, name, formName, fullName, color, coa}); cells.province[center] = province; cells.c[center].forEach(c => { diff --git a/modules/ui/states-editor.js b/modules/ui/states-editor.js index 7e87b7cc..103bd7ca 100644 --- a/modules/ui/states-editor.js +++ b/modules/ui/states-editor.js @@ -842,6 +842,10 @@ function editStates() { const name = Names.getState(basename, culture); const color = getRandomColor(); + // generate emblem + const coa = COA.generate(burgs[burg].coa, .4); + coa.shield = COA.getShield(culture, null); + // update diplomacy and reverse relations const diplomacy = states.map(s => { if (!s.i) return "x"; @@ -869,7 +873,9 @@ function editStates() { const affectedProvinces = [cells.province[center]]; cells.state[center] = newState; cells.province[center] = 0; - cells.c[center].forEach(c => { + + const cellsToCheck = [...new Set(cells.c[center].map(c => cells.c[c].map(c => cells.c[c])).flat(2))]; + cellsToCheck.forEach(c => { if (cells.h[c] < 20) return; if (cells.burg[c]) return; affectedStates.push(cells.state[c]); @@ -877,7 +883,8 @@ function editStates() { cells.state[c] = newState; cells.province[c] = 0; }); - states.push({i:newState, name, diplomacy, provinces:[], color, expansionism:.5, capital:burg, type:"Generic", center, culture, military:[], alert:1}); + + states.push({i:newState, name, diplomacy, provinces:[], color, expansionism:.5, capital:burg, type:"Generic", center, culture, military:[], alert:1, coa}); BurgsAndStates.collectStatistics(); BurgsAndStates.defineStateForms([newState]); adjustProvinces([...new Set(affectedProvinces)]); @@ -886,6 +893,7 @@ function editStates() { if (!layerIsOn("toggleStates")) toggleStates(); else drawStates(); if (!layerIsOn("toggleBorders")) toggleBorders(); else drawBorders(); BurgsAndStates.drawStateLabels([...new Set(affectedStates)]); + COArenderer.add("state", newState, coa, states[newState].pole[0], states[newState].pole[1]); statesEditorAddLines(); }