diff --git a/index.css b/index.css index c327c8b7..7e4ba024 100644 --- a/index.css +++ b/index.css @@ -37,6 +37,10 @@ input { text-indent: 1px; } +input:read-only { + cursor: default; +} + textarea { padding: 2px; text-indent: 1px; @@ -121,6 +125,11 @@ button, select, a, .pointer { pointer-events: none; } +#armies text { + pointer-events: none; + user-select: none; +} + #statesBody, #provincesBody, #relig, #biomes, #cults { stroke-width: .6; fill-rule: evenodd; @@ -209,29 +218,6 @@ i.icon-lock { cursor: pointer; } -#armies rect { - stroke-width: .3; - stroke: #000; -} - -#armies text { - pointer-events: none; - user-select: none; - stroke: none; - fill: #fff; - text-shadow: 0 0 4px #000; - font-size: 6px; - dominant-baseline: central; - text-anchor: middle; - font-family: Helvetica; -} - -#regimentBase { - stroke-width: .3; - stroke: #000; - cursor: move; -} - .chartInfo { text-align: center; font-family: sans-serif; diff --git a/index.html b/index.html index 175ee49e..c9676d1d 100644 --- a/index.html +++ b/index.html @@ -45,6 +45,20 @@ + + @@ -890,7 +904,7 @@ - + @@ -1188,8 +1202,8 @@
Foreground - - #53679f + + #466eab
@@ -2388,6 +2402,12 @@
+
+
Emblem:
+ + +
+
@@ -3270,7 +3290,6 @@ - @@ -3283,7 +3302,7 @@ Urban % Crew Type - S + Sep. diff --git a/main.js b/main.js index 3b117a47..49f345d5 100644 --- a/main.js +++ b/main.js @@ -304,7 +304,7 @@ function findBurgForMFCG(params) { // apply default biomes data function applyDefaultBiomesSystem() { const name = ["Marine","Hot desert","Cold desert","Savanna","Grassland","Tropical seasonal forest","Temperate deciduous forest","Tropical rainforest","Temperate rainforest","Taiga","Tundra","Glacier","Wetland"]; - const color = ["#53679f","#fbe79f","#b5b887","#d2d082","#c8d68f","#b6d95d","#29bc56","#7dcb35","#409c43","#4b6b32","#96784b","#d5e7eb","#0b9131"]; + const color = ["#466eab","#fbe79f","#b5b887","#d2d082","#c8d68f","#b6d95d","#29bc56","#7dcb35","#409c43","#4b6b32","#96784b","#d5e7eb","#0b9131"]; const habitability = [0,4,10,22,30,50,100,80,90,12,4,0,12]; const iconsDensity = [0,3,2,120,120,120,120,150,150,100,5,0,150]; const icons = [{},{dune:3, cactus:6, deadTree:1},{dune:9, deadTree:1},{acacia:1, grass:9},{grass:1},{acacia:8, palm:1},{deciduous:1},{acacia:5, palm:3, deciduous:1, swamp:1},{deciduous:6, swamp:1},{conifer:1},{grass:1},{},{swamp:1}]; diff --git a/modules/burgs-and-states.js b/modules/burgs-and-states.js index 16aef4cf..34fa3bee 100644 --- a/modules/burgs-and-states.js +++ b/modules/burgs-and-states.js @@ -595,13 +595,14 @@ console.timeEnd("assignColors"); } - // generate historical wars + // generate historical conflicts of each state const generateCampaigns = function() { const wars = {"War":4, "Conflict":2, "Campaign":4, "Invasion":2, "Rebellion":2, "Conquest":2, "Intervention":1, "Expedition":1, "Crusade":1}; pack.states.forEach(s => { if (!s.i || s.removed) return; - s.campaigns = (s.neighbors||[0]).map(i => { + const n = s.neighbors.length ? s.neighbors : [0]; + s.campaigns = n.map(i => { const name = i && P(.8) ? pack.states[i].name : Names.getCultureShort(s.culture); const start = gauss(options.year-100, 150, 1, options.year-6), end = start + gauss(4, 5, 1, options.year - start - 1); return {name:getAdjective(name) + " " + rw(wars), start, end}; diff --git a/modules/military-generator.js b/modules/military-generator.js index 104da91b..99b91bad 100644 --- a/modules/military-generator.js +++ b/modules/military-generator.js @@ -7,7 +7,7 @@ let cells, p, states; const generate = function() { - console.time("calculateMilitaryForces"); + console.time("generateMilitaryForces"); cells = pack.cells, p = cells.p, states = pack.states; const valid = states.filter(s => s.i && !s.removed); // valid states @@ -142,13 +142,14 @@ } } + armies.selectAll("g").remove(); // clear armies layer const expected = 3 * populationRate.value; // expected regiment size const mergeable = (n, s) => (!n.s && !s.s) || n.u === s.u; // get regiments for each state valid.forEach(s => { s.military = createRegiments(s.temp.platoons, s); delete s.temp; // do not store temp data - drawRegiments(s.military, s.i, s.color); + drawRegiments(s.military, s.i); }); function createRegiments(nodes, s) { @@ -184,35 +185,55 @@ // generate name for regiments regiments.forEach(r => { r.name = getName(r, regiments); + r.icon = getEmblem(r); generateNote(r, s); }); return regiments; } - console.timeEnd("calculateMilitaryForces"); + console.timeEnd("generateMilitaryForces"); } - function drawRegiments(regiments, s, color) { - const size = 3; - const army = armies.append("g").attr("id", "army"+s).attr("fill", color); - const g = army.selectAll("g").data(regiments).enter().append("g").attr("id", d => "regiment"+s+"-"+d.i); - g.append("rect").attr("data-name", d => d.name).attr("data-state", s).attr("data-id", d => d.i) - .attr("x", d => d.n ? d.x-size*2 : d.x-size*3).attr("y", d => d.y-size) - .attr("width", d => d.n ? size*4 : size*6).attr("height", size*2); - g.append("text").attr("x", d => d.x).attr("y", d => d.y).text(d => d.a); + function drawRegiments(regiments, s) { + const size = +armies.attr("data-size"); + const w = d => d.n ? size * 4 : size * 6; + const h = size * 2; + const x = d => rn(d.x - w(d) / 2, 2); + const y = d => rn(d.y - size, 2); + + const baseColor = pack.states[s].color[0] === "#" ? pack.states[s].color : "#999"; + const darkerColor = d3.color(baseColor).darker().hex(); + const army = armies.append("g").attr("id", "army"+s).attr("fill", baseColor); + + const g = army.selectAll("g").data(regiments).enter().append("g") + .attr("id", d => "regiment"+s+"-"+d.i).attr("data-name", d => d.name).attr("data-state", s).attr("data-id", d => d.i); + g.append("rect").attr("x", d => x(d)).attr("y", d => y(d)).attr("width", d => w(d)).attr("height", h); + g.append("text").attr("x", d => d.x).attr("y", d => d.y).text(d => getTotal(d)); + g.append("rect").attr("fill", darkerColor).attr("x", d => x(d)-h).attr("y", d => y(d)).attr("width", h).attr("height", h); + g.append("text").attr("class", "regimentIcon").attr("x", d => x(d)-size).attr("y", d => d.y).text(d => d.icon); } const drawRegiment = function(reg, s, x = reg.x, y = reg.y) { - const size = 3; + const size = +armies.attr("data-size"); + const w = reg.n ? size * 4 : size * 6; + const h = size * 2; + const x1 = rn(x - w / 2, 2); + const y1 = rn(y - size, 2); - const g = armies.select("g#army"+s).append("g").attr("id", "regiment"+s+"-"+reg.i); - g.append("rect").attr("data-name", reg.name).attr("data-state", s).attr("data-id", reg.i) - .attr("x", reg.n ? x-size*2 : x-size*3).attr("y", y-size) - .attr("width", reg.n ? size*4 : size*6).attr("height", size*2); - g.append("text").attr("x", x).attr("y", y).text(reg.a); + const army = armies.select("g#army"+s); + const darkerColor = d3.color(army.attr("fill")).darker().hex(); + + const g = army.append("g").attr("id", "regiment"+s+"-"+reg.i).attr("data-name", reg.name).attr("data-state", s).attr("data-id", reg.i); + g.append("rect").attr("x", x1).attr("y", y1).attr("width", w).attr("height", h); + g.append("text").attr("x", x).attr("y", y).text(getTotal(reg)); + g.append("rect").attr("fill", darkerColor).attr("x", x1-h).attr("y", y1).attr("width", h).attr("height", h); + g.append("text").attr("class", "regimentIcon").attr("x", x1-size).attr("y", y).text(reg.icon); } + // utilize si function to make regiment total text fit regiment box + const getTotal = reg => reg.a > (reg.n ? 999 : 99999) ? si(reg.a) : reg.a; + const getName = function(r, regiments) { const proper = r.n ? null : cells.province[r.cell] ? pack.provinces[cells.province[r.cell]].name : @@ -222,6 +243,18 @@ return `${number}${proper?` (${proper}) `:` `}${form}`; } + // get default regiment emblem + const getEmblem = function(r) { + if (r.n) return "🌊"; + if (!Object.values(r.u).length) return "🛡️"; + const mainUnit = Object.entries(r.u).sort((a,b) => b[1]-a[1])[0][0]; + const type = options.military.find(u => u.name === mainUnit).type; + if (type === "ranged") return "🏹"; + if (type === "mounted") return "🐴"; + if (type === "machinery") return "💣"; + else return "⚔️"; + } + const generateNote = function(r, s) { const base = cells.burg[r.cell] ? pack.burgs[cells.burg[r.cell]].name : cells.province[r.cell] ? pack.provinces[cells.province[r.cell]].fullName : null; @@ -231,11 +264,12 @@ const troops = `\r\n\r\nRegiment composition:\r\n${composition}.`; const campaign = ra(s.campaigns); - const year = rand(campaign.start, campaign.end); - const legend = `Regiment was formed in ${year} ${options.era} during the ${campaign.name}. ${station}${troops}`; - notes.push({id:`regiment${s.i}-${r.i}`, name:r.name, legend}); + const year = campaign ? rand(campaign.start, campaign.end) : gauss(options.year-100, 150, 1, options.year-6); + const conflict = campaign ? ` during the ${campaign.name}` : ""; + const legend = `Regiment was formed in ${year} ${options.era}${conflict}. ${station}${troops}`; + notes.push({id:`regiment${s.i}-${r.i}`, name:`${r.icon} ${r.name}`, legend}); } - return {generate, getName, generateNote, drawRegiment}; + return {generate, getName, generateNote, drawRegiment, getTotal, getEmblem}; }))); \ No newline at end of file diff --git a/modules/ui/3d.js b/modules/ui/3d.js index 01b2f05e..7be66592 100644 --- a/modules/ui/3d.js +++ b/modules/ui/3d.js @@ -6,7 +6,7 @@ // set default options const options = {scale: 50, lightness: .7, shadow: .5, sun: {x: 100, y: 600, z: 1000}, rotateMesh: 0, rotateGlobe: .5, - skyColor: "#9ecef5", waterColor: "#53679f", extendedWater: 0, resolution: 2}; + skyColor: "#9ecef5", waterColor: "#466eab", extendedWater: 0, resolution: 2}; // set variables let Renderer, scene, camera, controls, animationFrame, material, texture, diff --git a/modules/ui/general.js b/modules/ui/general.js index f08b2b51..c679164c 100644 --- a/modules/ui/general.js +++ b/modules/ui/general.js @@ -88,7 +88,7 @@ function showMapTooltip(point, e, i, g) { const land = pack.cells.h[i] >= 20; // specific elements - if (group === "armies") {tip(e.target.dataset.name + ". Click to edit"); return;} + if (group === "armies") {tip(e.target.parentNode.dataset.name + ". Click to edit"); return;} if (group === "rivers") {tip(getRiverName(e.target.id) + "Click to edit"); return;} if (group === "routes") {tip("Click to edit the Route"); return;} if (group === "terrain") {tip("Click to edit the Relief Icon"); return;} diff --git a/modules/ui/military-overview.js b/modules/ui/military-overview.js index efb3d4f9..edbd8123 100644 --- a/modules/ui/military-overview.js +++ b/modules/ui/military-overview.js @@ -25,9 +25,8 @@ function overviewMilitary() { document.getElementById("militaryExport").addEventListener("click", downloadMilitaryData); body.addEventListener("change", function(ev) { - const el = ev.target, line = el.parentNode, state = +line.dataset.id, type = el.dataset.type; - if (type && type !== "alert") changeForces(state, line, type, +el.value); else - if (type === "alert") changeAlert(state, line, +el.value); + const el = ev.target, line = el.parentNode, state = +line.dataset.id; + changeAlert(state, line, +el.value); }); // update military types in header and tooltips @@ -57,7 +56,7 @@ function overviewMilitary() { const rate = total / population * 100; const sortData = options.military.map(u => `data-${u.name}="${getForces(u)}"`).join(" "); - const lineData = options.military.map(u => ``).join(" "); + const lineData = options.military.map(u => `
${getForces(u)}
`).join(" "); lines += `
@@ -66,7 +65,7 @@ function overviewMilitary() {
${si(total)}
${si(population)}
${rn(rate, 2)}%
- +
`; } body.insertAdjacentHTML("beforeend", lines); @@ -78,30 +77,27 @@ function overviewMilitary() { applySorting(militaryHeader); } - function changeForces(state, line, type, value) { - const s = pack.states[state]; - if (!s.military.alert) {tip("Value won't be applied as War Alert is 0. Change Alert value to positive first", false, "error"); return;} - - line.dataset[type] = value; - s.military[type] = value / populationRate.value / s.military.alert; - updateTotal(s.military, line); - updateFooter(); - } - function changeAlert(state, line, alert) { const s = pack.states[state]; - s.military.alert = line.dataset.alert = alert; - const getForces = u => rn(s.military[u.name] * alert * populationRate.value)||0; - options.military.forEach(u => line.dataset[u.name] = line.querySelector(`input[data-type='${u.name}']`).value = getForces(u)); - updateTotal(s.military, line); - updateFooter(); - } + const dif = s.alert || alert ? alert / s.alert : 0; // modifier + s.alert = line.dataset.alert = alert; - function updateTotal(m, line) { - line.dataset.total = rn(d3.sum(options.military.map(u => (m[u.name]||0) * u.crew)) * m.alert * populationRate.value); - line.dataset.rate = line.dataset.total / line.dataset.population * 100; - line.querySelector("div[data-type='total']>b").innerHTML = si(line.dataset.total); - line.querySelector("div[data-type='rate']").innerHTML = rn(line.dataset.rate, 2) + "%"; + s.military.forEach(r => { + Object.keys(r.u).forEach(u => r.u[u] = rn(r.u[u] * dif)); // change units value + r.a = d3.sum(Object.values(r.u)); // change total + armies.select(`g>g#regiment${s.i}-${r.i}>text`).text(Military.getTotal(r)); // change icon text + }); + + const getForces = u => s.military.reduce((s, r) => s+(r.u[u.name]||0), 0); + options.military.forEach(u => line.dataset[u.name] = line.querySelector(`div[data-type='${u.name}']`).innerHTML = getForces(u)); + + const population = rn((s.rural + s.urban * urbanization.value) * populationRate.value); + const total = line.dataset.total = options.military.reduce((s, u) => s + getForces(u) * u.crew, 0); + const rate = line.dataset.rate = total / population * 100; + line.querySelector("div[data-type='total']>b").innerHTML = si(total); + line.querySelector("div[data-type='rate']").innerHTML = rn(rate, 2) + "%"; + + updateFooter(); } function updateFooter() { @@ -138,7 +134,7 @@ function overviewMilitary() { } function stateHighlightOff() { - debug.selectAll(".highlight").each(function(el) { + debug.selectAll(".highlight").each(function() { d3.select(this).call(removePath); }); } @@ -159,7 +155,7 @@ function overviewMilitary() { Cancel: function() {$(this).dialog("close");} }, open: function() { const buttons = $(this).dialog("widget").find(".ui-dialog-buttonset > button"); - buttons[0].addEventListener("mousemove", () => tip("Apply military units settings. All forces will be recalculated!")); + buttons[0].addEventListener("mousemove", () => tip("Apply military units settings. All forces will be recalculated!")); buttons[1].addEventListener("mousemove", () => tip("Add new military unit to the table")); buttons[2].addEventListener("mousemove", () => tip("Restore default military units and settings")); buttons[3].addEventListener("mousemove", () => tip("Close the window without saving the changes")); @@ -201,7 +197,7 @@ function overviewMilitary() { return {name:name.replace(/[&\/\\#, +()$~%.'":*?<>{}]/g, '_'), rural:+rural||0, urban:+urban||0, crew:+crew||0, type, separate:+separate||0}; }); localStorage.setItem("military", JSON.stringify(options.military)); - calculateMilitaryForces(); + Military.generate(); updateHeaders(); addLines(); } @@ -209,8 +205,17 @@ function overviewMilitary() { } function militaryRecalculate() { - calculateMilitaryForces(); - addLines(); + alertMessage.innerHTML = "Are you sure you want to recalculate military forces for all states?"; + $("#alert").dialog({resizable: false, title: "Remove regiment", + buttons: { + Recalculate: function() { + $(this).dialog("close"); + Military.generate(); + addLines(); + }, + Cancel: function() {$(this).dialog("close");} + } + }); } function downloadMilitaryData() { @@ -223,7 +228,7 @@ function overviewMilitary() { data += units.map(u => el.dataset[u]).join(",") + ","; data += el.dataset.total + ","; data += el.dataset.population + ","; - data += el.dataset.rate + ","; + data += rn(el.dataset.rate,2) + "%,"; data += el.dataset.alert + "\n"; }); diff --git a/modules/ui/regiment-editor.js b/modules/ui/regiment-editor.js index f99fe8ad..11b1e6ad 100644 --- a/modules/ui/regiment-editor.js +++ b/modules/ui/regiment-editor.js @@ -6,7 +6,7 @@ function editRegiment() { armies.selectAll(":scope > g").classed("draggable", true); armies.selectAll(":scope > g > g").call(d3.drag().on("drag", dragRegiment)); - elSelected = d3.event.target; + elSelected = d3.event.target.parentElement; // select g element if (!pack.states[elSelected.dataset.state]) return; if (!regiment()) return; updateRegimentData(regiment()); @@ -25,6 +25,8 @@ function editRegiment() { document.getElementById("regimentNameRestore").addEventListener("click", restoreName); document.getElementById("regimentType").addEventListener("click", changeType); document.getElementById("regimentName").addEventListener("change", changeName); + document.getElementById("regimentEmblem").addEventListener("input", changeEmblem); + document.getElementById("regimentEmblemSelect").addEventListener("click", selectEmblem); document.getElementById("regimentRegenerateLegend").addEventListener("click", regenerateLegend); document.getElementById("regimentLegend").addEventListener("click", editLegend); document.getElementById("regimentSplit").addEventListener("click", splitRegiment); @@ -40,6 +42,7 @@ function editRegiment() { function updateRegimentData(regiment) { document.getElementById("regimentType").className = regiment.n ? "icon-anchor" :"icon-users"; document.getElementById("regimentName").value = regiment.name; + document.getElementById("regimentEmblem").value = regiment.icon; const composition = document.getElementById("regimentComposition"); composition.innerHTML = options.military.map(u => { @@ -54,12 +57,13 @@ function editRegiment() { function drawBase() { const reg = regiment(); - const tr = parseTransform(elSelected.parentNode.getAttribute("transform")); + const tr = parseTransform(elSelected.getAttribute("transform")); const tx = +tr[0], ty = +tr[1]; - const x2 = +elSelected.nextSibling.getAttribute("x"), y2 = +elSelected.nextSibling.getAttribute("y"); + const x2 = +elSelected.querySelector("text").getAttribute("x"), y2 = +elSelected.querySelector("text").getAttribute("y"); const clr = pack.states[elSelected.dataset.state].color; - const base = viewbox.insert("g", "g#armies").attr("id", "regimentBase"); + const base = viewbox.insert("g", "g#armies").attr("id", "regimentBase") + .attr("stroke-width", .3).attr("stroke", "#000").attr("cursor", "move"); base.on("mouseenter", d => {tip("Regiment base. Drag to re-base the regiment", true);}).on("mouseleave", d => {tip('', true);}); base.append("line").attr("x1", reg.x).attr("y1", reg.y).attr("x2", x2+tx).attr("y2", y2+ty).attr("class", "dragLine"); @@ -71,9 +75,15 @@ function editRegiment() { reg.n = +!reg.n; document.getElementById("regimentType").className = reg.n ? "icon-anchor" :"icon-users"; - const size = 3; - elSelected.setAttribute("x", reg.n ? reg.x-size*2 : reg.x-size*3); - elSelected.setAttribute("width", reg.n ? size*4 : size*6); + const size = +armies.attr("data-size"); + const baseRect = elSelected.querySelectorAll("rect")[0]; + const iconRect = elSelected.querySelectorAll("rect")[1]; + const icon = elSelected.querySelector(".regimentIcon"); + const x = reg.n ? reg.x-size*2 : reg.x-size*3; + baseRect.setAttribute("x", x); + baseRect.setAttribute("width", reg.n ? size*4 : size*6); + iconRect.setAttribute("x", x - size*2); + icon.setAttribute("x", x - size); } function changeName() { @@ -86,12 +96,50 @@ function editRegiment() { elSelected.dataset.name = reg.name = document.getElementById("regimentName").value = name; } + function changeEmblem() { + const emblem = document.getElementById("regimentEmblem").value; + regiment().icon = elSelected.querySelector(".regimentIcon").innerHTML = emblem; + } + + function selectEmblem() { + const emblems = ["⚔️","🏹","🐴","💣","🌊","🎯","⚓","🔮","📯","🛡️","👑", + "☠️","🎆","🗡️","⛏️","🔥","🐾","🎪","🏰","⚜️","⛓️","❤️","📜","🔱","🌈","🌠","💥","☀️","🍀", + "🔰","🕸️","⚗️","☣️","☢️","🎖️","⚕️","☸️","✡️","🚩","🏳️","🏴","🌈","💪","✊","👊","🤜","🤝","🙏","🧙","💂","🤴","🧛","🧟","🧞","🧝", + "🦄","🐲","🐉","🐎","🦓","🐺","🦊","🐱","🐈","🦁","🐯","🐅","🐆","🐕","🦌","🐵","🐒","🦍", + "🦅","🕊️","🐓","🦇","🐦","🦉","🐮","🐄","🐂","🐃","🐷","🐖","🐗","🐏","🐑","🐐","🐫","🦒","🐘","🦏", + "🐭","🐁","🐀","🐹","🐰","🐇","🦔","🐸","🐊","🐢","🦎","🐍","🐳","🐬","🦈","🐙","🦑","🐌","🦋","🐜","🐝","🐞","🦗","🕷️","🦂","🦀"]; + + alertMessage.innerHTML = ""; + const container = document.createElement("div"); + container.style.userSelect = "none"; + container.style.cursor = "pointer"; + container.style.fontSize = "2em"; + container.style.width = "47vw"; + container.innerHTML = emblems.map(i => `${i}`).join(""); + container.addEventListener("mouseover", e => showTip(e), false); + container.addEventListener("click", e => clickEmblem(e), false); + alertMessage.appendChild(container); + + $("#alert").dialog({resizable: false, width: fitContent(), title: "Select emblem"}); + + function showTip(e) { + if (e.target.tagName !== "SPAN") return; + tip(`Click to select ${e.target.innerHTML} emblem`); + } + + function clickEmblem(e) { + if (e.target.tagName !== "SPAN") return; + document.getElementById("regimentEmblem").value = e.target.innerHTML; + changeEmblem(); + } + } + function changeUnit() { const u = this.dataset.u; const reg = regiment(); reg.u[u] = (+this.value)||0; reg.a = d3.sum(Object.values(reg.u)); - elSelected.nextSibling.innerHTML = reg.a; + elSelected.querySelector("text").innerHTML = Military.getTotal(reg); if (militaryOverviewRefresh.offsetParent) militaryOverviewRefresh.click(); } @@ -105,11 +153,11 @@ function editRegiment() { reg.a = d3.sum(Object.values(u1)); // old reg total const a = d3.sum(Object.values(u2)); // new reg total - const newReg = {a, cell:reg.cell, i, n:reg.n, u:u2, x:reg.x, y:reg.y}; + const newReg = {a, cell:reg.cell, i, n:reg.n, u:u2, x:reg.x, y:reg.y, icon: reg.icon}; newReg.name = Military.getName(newReg, military); military.push(newReg); - elSelected.parentNode.remove(); // undraw old reg + elSelected.remove(); // undraw old reg Military.drawRegiment(reg, state, reg.x, reg.y-6); // draw old reg above Military.drawRegiment(newReg, state, reg.x, reg.y+6); // draw new reg below @@ -134,7 +182,7 @@ function editRegiment() { const state = elSelected.dataset.state, military = pack.states[state].military; const i = military.length ? last(military).i + 1 : 0; const n = +(pack.cells.h[cell] < 20); // naval or land - const reg = {a:0, cell, i, n, u:{}, x, y}; + const reg = {a:0, cell, i, n, u:{}, x, y, icon:"🛡️"}; reg.name = Military.getName(reg, military); military.push(reg); Military.drawRegiment(reg, state); @@ -155,45 +203,35 @@ function editRegiment() { } function attachRegimentOnClick() { - const target = d3.event.target, army = target.parentElement.parentElement; + const target = d3.event.target, regSelected = target.parentElement, army = regSelected.parentElement; + const oldState = +elSelected.dataset.state, newState = +regSelected.dataset.state; - if (army.parentElement.id !== "armies") { - tip("Please click on a regiment", false, "error"); - return; - } + if (army.parentElement.id !== "armies") {tip("Please click on a regiment", false, "error"); return;} + if (regSelected === elSelected) {tip("Cannot attach regiment to itself. Please click on another regiment", false, "error"); return;} + //if (army !== elSelected.parentElement) {tip("Cannot attach to a regiment of other state", false, "error"); return;}; - if (target === elSelected) { - tip("Cannot attach regiment to itself. Please click on another regiment", false, "error"); - return; - } - - if (army !== elSelected.parentElement.parentElement) { - tip("Cannot attach this regiment to regiment of other state", false, "error"); - return; - }; - const reg = regiment(); // reg to be attached - const sel = pack.states[target.dataset.state].military.find(r => r.i == target.dataset.id); // reg to attach to + const sel = pack.states[newState].military.find(r => r.i == regSelected.dataset.id); // reg to attach to for (const unit of options.military) { const u = unit.name; if (reg.u[u]) sel.u[u] ? sel.u[u] += reg.u[u] : sel.u[u] = reg.u[u]; } sel.a = d3.sum(Object.values(sel.u)); // reg total - target.nextSibling.innerHTML = sel.a; // update selected reg total text + regSelected.querySelector("text").innerHTML = Military.getTotal(sel); // update selected reg total text // remove attached regiment - const military = pack.states[elSelected.dataset.state].military; + const military = pack.states[oldState].military; military.splice(military.indexOf(reg), 1); - const index = notes.findIndex(n => n.id === elSelected.parentNode.id); + const index = notes.findIndex(n => n.id === elSelected.id); if (index != -1) notes.splice(index, 1); - elSelected.parentNode.remove(); + elSelected.remove(); $("#regimentEditor").dialog("close"); } function regenerateLegend() { - const index = notes.findIndex(n => n.id === elSelected.parentNode.id); + const index = notes.findIndex(n => n.id === elSelected.id); if (index != -1) notes.splice(index, 1); const s = pack.states[elSelected.dataset.state]; @@ -201,7 +239,7 @@ function editRegiment() { } function editLegend() { - editNotes(elSelected.parentNode.id, regiment().name); + editNotes(elSelected.id, regiment().name); } function removeRegiment() { @@ -215,9 +253,9 @@ function editRegiment() { if (regIndex === -1) return; military.splice(regIndex, 1); - const index = notes.findIndex(n => n.id === elSelected.parentNode.id); + const index = notes.findIndex(n => n.id === elSelected.id); if (index != -1) notes.splice(index, 1); - elSelected.parentNode.remove(); + elSelected.remove(); if (militaryOverviewRefresh.offsetParent) militaryOverviewRefresh.click(); $("#regimentEditor").dialog("close"); @@ -233,10 +271,10 @@ function editRegiment() { d3.select(this).raise(); d3.select(this.parentNode).raise(); - const self = elSelected.parentNode === this; + const self = elSelected === this; const baseLine = viewbox.select("g#regimentBase > line"); - const x2 = +elSelected.nextSibling.getAttribute("x"); - const y2 = +elSelected.nextSibling.getAttribute("y"); + const text = elSelected.querySelector("text"); + const x2 = +text.getAttribute("x"), y2 = +text.getAttribute("y"); d3.event.on("drag", function() { const x = dx + d3.event.x, y = dy + d3.event.y; diff --git a/modules/ui/style.js b/modules/ui/style.js index a924fb1c..1d88b804 100644 --- a/modules/ui/style.js +++ b/modules/ui/style.js @@ -693,6 +693,8 @@ function addDefaulsStyles() { // set default style function applyDefaultStyle() { + armies.attr("font-size", 6).attr("data-size", 3); + biomes.attr("opacity", null).attr("filter", null).attr("mask", null); stateBorders.attr("opacity", .8).attr("stroke", "#56566d").attr("stroke-width", 1).attr("stroke-dasharray", "2").attr("stroke-linecap", "butt").attr("filter", null); provinceBorders.attr("opacity", .8).attr("stroke", "#56566d").attr("stroke-width", .2).attr("stroke-dasharray", "1").attr("stroke-linecap", "butt").attr("filter", null); @@ -742,7 +744,7 @@ function applyDefaultStyle() { // ocean and svg default style svg.attr("background-color", "#000000").attr("data-filter", null).attr("filter", null); ocean.attr("opacity", null); - oceanLayers.select("rect").attr("fill", "#53679f"); + oceanLayers.select("rect").attr("fill", "#466eab"); // old color #53679f oceanLayers.attr("filter", null).attr("layers", "-6,-3,-1"); oceanPattern.attr("opacity", null); svg.select("#oceanicPattern").attr("filter", "url(#pattern1)"); diff --git a/modules/utils.js b/modules/utils.js index e94a4967..463fb0be 100644 --- a/modules/utils.js +++ b/modules/utils.js @@ -250,11 +250,11 @@ function round(s, d = 1) { // corvent number to short string with SI postfix function si(n) { - if (n >= 1e9) {return rn(n / 1e9, 1) + "B";} - if (n >= 1e8) {return rn(n / 1e6) + "M";} - if (n >= 1e6) {return rn(n / 1e6, 1) + "M";} - if (n >= 1e4) {return rn(n / 1e3) + "K";} - if (n >= 1e3) {return rn(n / 1e3, 1) + "K";} + if (n >= 1e9) return rn(n / 1e9, 1) + "B"; + if (n >= 1e8) return rn(n / 1e6) + "M"; + if (n >= 1e6) return rn(n / 1e6, 1) + "M"; + if (n >= 1e4) return rn(n / 1e3) + "K"; + if (n >= 1e3) return rn(n / 1e3, 1) + "K"; return rn(n); }