@@ -1745,51 +1745,69 @@
| Emblem shape |
|
@@ -3337,8 +3355,77 @@
Burg:
+
+
+ Shape:
+
+
+
+
+
+
+
@@ -3956,7 +4043,7 @@
-
+
diff --git a/modules/burgs-and-states.js b/modules/burgs-and-states.js
index f44d3063..fc8ed72c 100644
--- a/modules/burgs-and-states.js
+++ b/modules/burgs-and-states.js
@@ -186,8 +186,14 @@
if (cells.r[i]%2) b.y = rn(b.y + shift, 2); else b.y = rn(b.y - shift, 2);
}
- const stateCOA = pack.states[b.state].coa;
- b.coa = COA.generate(stateCOA);
+ // define emblem
+ const state = pack.states[b.state];
+ const stateCOA = state.coa;
+ let kinship = .25;
+ if (b.capital) kinship += .1;
+ else if (b.port) kinship -= .1;
+ if (b.culture !== state.culture) kinship -= .25;
+ b.coa = COA.generate(stateCOA, kinship);
b.coa.shield = getShield(b.culture, b.state);
}
@@ -949,7 +955,8 @@
form[formName] += 5;
const fullName = name + " " + formName;
const color = getMixedColor(s.color);
- const coa = COA.generate(stateBurgs[i].coa);
+ const kinship = nameByBurg ? .8 : .4;
+ const coa = COA.generate(stateBurgs[i].coa, kinship);
coa.shield = getShield(c, s.i);
provinces.push({i:province, state:s.i, center, burg, name, formName, fullName, color, coa});
}
@@ -1045,7 +1052,9 @@
const formName = singleIsle ? "Island" : isleGroup ? "Islands" : colony ? "Colony" : rw(forms["Wild"]);
const fullName = name + " " + formName;
const color = getMixedColor(s.color);
- const coa = COA.generate(s.coa);
+ const dominion = colony ? P(.95) : singleIsle || isleGroup ? P(.7) : P(.3);
+ const kinship = dominion ? 0 : .4;
+ const coa = COA.generate(s.coa, kinship, dominion);
coa.shield = getShield(c, s.i);
provinces.push({i:province, state:s.i, center, burg, name, formName, fullName, color, coa});
s.provinces.push(province);
diff --git a/modules/coa-generator.js b/modules/coa-generator.js
index 4fff8f6a..d0b599f4 100644
--- a/modules/coa-generator.js
+++ b/modules/coa-generator.js
@@ -101,7 +101,7 @@
crossParted: { e: 5, ee: 1 },
saltire: { ee: 5, jlemo: 1 },
saltireParted: { e: 5, ee: 1 },
- pall: { ee: 1, acez: 5, jlhh: 3 },
+ pall: { ee: 1, jleh: 5, jlhh: 3 },
pallReversed: { ee: 1, bemo: 5 },
pile: { bbb: 1 },
pileInBend: { eeee: 1, eeoo: 1 },
@@ -190,7 +190,7 @@
}
};
- const generate = function(parent) {
+ const generate = function(parent, kinship, dominion) {
let usedPattern = null, usedTinctures = [];
// TODO
@@ -207,17 +207,19 @@
// style settings for emblems layer
// fix download svg/png
// test in FF
+ // generate all?
+ // layout preset
- const t1 = parent && P(.3) ? parent.t1 : getTincture("field");
+ const t1 = P(kinship) ? parent.t1 : getTincture("field");
const coa = {t1};
let charge = P(usedPattern ? .5 : .93) ? true : false; // 80% for charge
- const linedOrdinary = charge && P(.3) || P(.5) ? parent?.ordinaries && P(.3) ? parent.ordinaries[0].ordinary : rw(ordinaries.lined) : null;
+ const linedOrdinary = charge && P(.3) || P(.5) ? parent?.ordinaries && P(kinship) ? parent.ordinaries[0].ordinary : rw(ordinaries.lined) : null;
const ordinary = !charge && P(.65) || P(.3) ? linedOrdinary ? linedOrdinary : rw(ordinaries.straight) : null; // 36% for ordinary
const rareDivided = ["chief", "terrace", "chevron", "quarter", "flaunches"].includes(ordinary);
const divisioned = rareDivided ? P(.03) : charge && ordinary ? P(.03) : charge ? P(.3) : ordinary ? P(.7) : P(.995); // 33% for division
- const division = divisioned ? parent?.division && P(.2) ? parent.division.division : rw(divisions.variants) : null;
- if (charge) charge = parent?.charges && P(.2) ? parent.charges[0].charge : selectCharge();
+ const division = divisioned ? parent?.division && P(kinship - .1) ? parent.division.division : rw(divisions.variants) : null;
+ if (charge) charge = parent?.charges && P(kinship - .1) ? parent.charges[0].charge : selectCharge();
if (division) {
const t = getTincture("division", usedTinctures, P(.98) ? coa.t1 : null);
@@ -335,6 +337,32 @@
}
}
+ // dominions have canton with parent coa
+ if (P(dominion)) {
+ const t = getType(parent.t1) === getType(coa.t1) ? getTincture("division", usedTinctures, coa.t1) : parent.t1;
+ const canton = {ordinary: "canton", t};
+ if (coa.charges) {
+ coa.charges.forEach((charge, i) => {
+ if (charge.p.includes("a")) charge.p = charge.p.replaceAll("a", "");
+ if (charge.p.includes("j")) charge.p = charge.p.replaceAll("j", "");
+ if (charge.p.includes("y")) charge.p = charge.p.replaceAll("y", "");
+ if (!charge.p) coa.charges.splice(i, 1);
+ });
+ }
+
+ if (parent.charges) {
+ let charge = parent.charges[0].charge;
+ if (charge === "inescutcheon" && parent.charges[1]) charge = parent.charges[1].charge;
+
+ let t2 = parent.charges[0].t;
+ if (getType(t) === getType(t2)) t2 = getTincture("charge", usedTinctures, t);
+
+ if (!coa.charges) coa.charges = [];
+ coa.charges.push({charge, t: t2, p: "y", size: 0.5});
+ } else canton.above = 1;
+ coa.ordinaries ? coa.ordinaries.push(canton) : coa.ordinaries = [canton];
+ }
+
function selectCharge(set) {
const type = set ? rw(set) : ordinary || divisioned ? rw(charges.types): rw(charges.single);
return type === "inescutcheon" ? "inescutcheon" : rw(charges[type]);
@@ -366,7 +394,6 @@
if (Object.keys(tinctures.metals).includes(tincture)) return "metals";
if (Object.keys(tinctures.colours).includes(tincture)) return "colours";
if (Object.keys(tinctures.stains).includes(tincture)) return "stains";
- debugger; // exception
}
function definePattern(pattern, element, size = "") {
diff --git a/modules/ui/editors.js b/modules/ui/editors.js
index 4d2f1c94..ed70c203 100644
--- a/modules/ui/editors.js
+++ b/modules/ui/editors.js
@@ -545,9 +545,7 @@ function unfog(id) {
}
function getFileName(dataType) {
- const formatTime = (time) => {
- return (time < 10) ? "0" + time : time;
- };
+ const formatTime = time => time < 10 ? "0" + time : time;
const name = mapName.value;
const type = dataType ? dataType + " " : "";
const date = new Date();
diff --git a/modules/ui/emblems-editor.js b/modules/ui/emblems-editor.js
index cdd40ad4..11aa9e80 100644
--- a/modules/ui/emblems-editor.js
+++ b/modules/ui/emblems-editor.js
@@ -1,17 +1,7 @@
"use strict";
function editEmblem(type, id, el) {
if (customization) return;
-
- if (!id && d3.event) {
- const parent = d3.event.target.parentNode;
- const [g, t] = parent.id === "burgEmblems" ? [pack.burgs, "burg"] :
- parent.id === "provinceEmblems" ? [pack.provinces, "province"] :
- [pack.states, "state"];
- const i = +d3.event.target.dataset.i;
- type = t;
- id = type+"COA"+i;
- el = g[i];
- }
+ if (!id && d3.event) defineEmblemData(d3.event);
emblems.selectAll(":scope > use").call(d3.drag().on("drag", dragEmblem)).classed("draggable", true);
@@ -23,19 +13,31 @@ function editEmblem(type, id, el) {
updateElementSelectors(type, id, el);
$("#emblemEditor").dialog({
- title: "Edit Emblem", resizable: true, width: "auto", height: "auto",
+ title: "Edit Emblem", resizable: true, width: "18em", height: "auto",
position: {my: "left top", at: "left+10 top+10", of: "svg", collision: "fit"},
close: closeEmblemEditor
});
- if (modules.editEmblem) return;
- modules.editEmblem = true;
+ // add listeners,then remove on closure
+ emblemStates.oninput = selectState;
+ emblemProvinces.oninput = selectProvince;
+ emblemBurgs.oninput = selectBurg;
+ document.getElementById("emblemShapeSelector").oninput = changeShape;
+ document.getElementById("emblemsRegenerate").onclick = regenerate;
+ document.getElementById("emblemsArmoria").onclick = openInArmoria;
+ document.getElementById("emblemsDownload").onclick = download;
+ document.getElementById("emblemsFocus").onclick = showArea;
- // add listeners
- emblemStates.addEventListener("input", selectState);
- emblemProvinces.addEventListener("input", selectProvince);
- emblemBurgs.addEventListener("input", selectBurg);
- document.getElementById("emblemsFocus").addEventListener("click", showArea);
+ function defineEmblemData(e) {
+ const parent = e.target.parentNode;
+ const [g, t] = parent.id === "burgEmblems" ? [pack.burgs, "burg"] :
+ parent.id === "provinceEmblems" ? [pack.provinces, "province"] :
+ [pack.states, "state"];
+ const i = +e.target.dataset.i;
+ type = t;
+ id = type+"COA"+i;
+ el = g[i];
+ }
function updateElementSelectors(type, id, el) {
let state = 0, province = 0, burg = 0;
@@ -81,7 +83,10 @@ function editEmblem(type, id, el) {
function updateEmblemData(type, id, el) {
if (!el.coa) return;
document.getElementById("emblemImage").setAttribute("href", "#" + id);
- document.getElementById("emblemArmiger").innerText = el.fullName || el.name;
+ 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;
}
function selectState() {
@@ -127,6 +132,85 @@ function editEmblem(type, id, el) {
updateElementSelectors(type, id, el);
}
+ function changeShape() {
+ el.coa.shield = this.value;
+ document.getElementById(id).remove();
+ COArenderer.trigger(id, el.coa);
+ }
+
+ function showArea() {
+ highlightEmblemElement(type, el);
+ }
+
+ function regenerate() {
+ let parent = null;
+ if (type === "province") parent = pack.states[el.state].coa;
+ else if (type === "burg") {
+ const province = pack.cells.province[el.cell];
+ parent = province ? pack.provinces[province].coa : pack.states[el.state].coa;
+ }
+
+ const shield = el.coa.shield;
+ el.coa = COA.generate(parent);
+ el.coa.shield = shield;
+
+ document.getElementById(id).remove();
+ COArenderer.trigger(id, el.coa);
+ }
+
+ function openInArmoria() {
+ const json = JSON.stringify(el.coa).replaceAll("#", "%23");
+ const url = `http://azgaar.github.io/Armoria/?coa=${json}`;
+ openURL(url);
+ }
+
+ function download() {
+ const coa = document.getElementById(id);
+ const canvas = document.createElement("canvas");
+ const ctx = canvas.getContext("2d");
+ canvas.width = 500;
+ canvas.height = 500;
+
+ const url = getURL(coa, el.coa);
+ const img = new Image();
+ img.src = url;
+ img.onload = () => {
+ URL.revokeObjectURL(url);
+ ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
+ drawCanvas(canvas, el);
+ }
+
+ function drawCanvas(canvas, el) {
+ const link = document.createElement("a");
+ link.download = getFileName(`Emblem ${el.fullName || el.name}`) + ".png";
+ canvas.toBlob(function (blob) {
+ link.href = window.URL.createObjectURL(blob);
+ document.body.appendChild(link);
+ link.click();
+ setTimeout(function () {
+ canvas.remove();
+ window.URL.revokeObjectURL(link.href);
+ }, 5000);
+ });
+ }
+ }
+
+ function getURL(svg, coa) {
+ const clone = svg.cloneNode(true); // clone svg
+ const d = clone.getElementsByTagName("defs")[0];
+
+ d.insertAdjacentHTML("beforeend", document.getElementById(coa.shield).outerHTML); // copy shield to defs
+ svg.querySelectorAll("[fill^=url]").forEach(el => {
+ const id = el.getAttribute("fill").match(/\#([^)]+)\)/)[1];
+ d.insertAdjacentHTML("beforeend", document.getElementById(id).outerHTML);
+ });
+
+ const serialized = (new XMLSerializer()).serializeToString(clone);
+ const blob = new Blob([serialized], { type: 'image/svg+xml;charset=utf-8' });
+ const url = window.URL.createObjectURL(blob);
+ return url;
+ }
+
function dragEmblem() {
const tr = parseTransform(this.getAttribute("transform"));
const x = +tr[0] - d3.event.x, y = +tr[1] - d3.event.y;
@@ -137,10 +221,6 @@ function editEmblem(type, id, el) {
});
}
- function showArea() {
- highlightEmblemElement(type, el);
- }
-
function closeEmblemEditor() {
emblems.selectAll(":scope > use").call(d3.drag().on("drag", null)).attr("class", null);
}
diff --git a/modules/ui/general.js b/modules/ui/general.js
index be1b8abe..16f5d221 100644
--- a/modules/ui/general.js
+++ b/modules/ui/general.js
@@ -94,7 +94,7 @@ function showMapTooltip(point, e, i, g) {
tip(e.target.parentNode.dataset.name + ". Click to edit");
return;
}
- if (group === "emblems") {
+ if (group === "emblems" && e.target.tagName === "use") {
const parent = e.target.parentNode;
const [g, type] = parent.id === "burgEmblems" ? [pack.burgs, "burg"] :
parent.id === "provinceEmblems" ? [pack.provinces, "province"] :
|