From 3aaddcf1a7649b797f1324abf6862f6f53a204c4 Mon Sep 17 00:00:00 2001 From: Azgaar Date: Sun, 31 Jan 2021 15:29:25 +0300 Subject: [PATCH] v1.5.04 - smarter coa generation, coa download --- index.css | 9 +- index.html | 181 ++++++++++++++++++++++++++--------- modules/burgs-and-states.js | 17 +++- modules/coa-generator.js | 41 ++++++-- modules/ui/editors.js | 4 +- modules/ui/emblems-editor.js | 128 ++++++++++++++++++++----- modules/ui/general.js | 2 +- 7 files changed, 294 insertions(+), 88 deletions(-) diff --git a/index.css b/index.css index b5df6d00..89cf0fb6 100644 --- a/index.css +++ b/index.css @@ -1573,12 +1573,17 @@ rect.fillRect { } #emblemBody .label { - width: 5.5em; + width: 6em; display: inline-block; } #emblemBody select { - width: 8em; + width: 9em; +} + + +#emblemsBottom { + margin-top: 4px; } #picker text { diff --git a/index.html b/index.html index a93044a0..87b3f7cc 100644 --- a/index.html +++ b/index.html @@ -37,7 +37,7 @@ - + @@ -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"] :