feat: make lined icons work for all elements, v1.107.0

This commit is contained in:
Azgaar 2025-02-08 14:05:28 +01:00
parent 7b8ffd025f
commit d51deffdac
15 changed files with 283 additions and 245 deletions

View file

@ -186,10 +186,6 @@ t,
font-size: 0.8em; font-size: 0.8em;
} }
.regimentImage {
object-fit: contain;
}
#statesHalo { #statesHalo {
fill: none; fill: none;
stroke-linecap: round; stroke-linecap: round;

View file

@ -3555,9 +3555,9 @@
<input id="markerType" style="width: 10.3em" /> <input id="markerType" style="width: 10.3em" />
</div> </div>
<div data-tip="Marker icon. Paste any Unicode symbol or select from the predefined list"> <div data-tip="Marker icon" style="display: flex; align-items: center">
<div class="label">Icon:</div> <div class="label">Icon:</div>
<input id="markerIcon" style="width: 5em" /> <div id="markerIcon" style="font-size: 1.5em; width: 3.7em">👑</div>
<button id="markerIconSelect" style="width: 5em">select</button> <button id="markerIconSelect" style="width: 5em">select</button>
</div> </div>
@ -3646,10 +3646,10 @@
></i> ></i>
</div> </div>
<div data-tip="Regiment emblem. Paste any Unicode symbol or select from the predefined list"> <div data-tip="Regiment emblem" style="display: flex; align-items: center">
<div class="label italic">Emblem:</div> <div class="label">Emblem:</div>
<input id="regimentEmblem" style="width: 5em" /> <div id="regimentEmblem" style="font-size: 1.5em; width: 3.7em"></div>
<button id="regimentEmblemSelect" style="padding: 0; width: 4.5em">select</button> <button id="regimentEmblemChange" style="padding: 0; width: 4.5em">change</button>
</div> </div>
<div id="regimentComposition" class="table"></div> <div id="regimentComposition" class="table"></div>
@ -5770,17 +5770,25 @@
</div> </div>
<div id="iconSelector" style="display: none" class="dialog"> <div id="iconSelector" style="display: none" class="dialog">
<table id="iconTable" class="table pointer" style="font-size: 2em; text-align: center; width: 100%"></table> <div>
<div style="font-style: italic; font-size: 1.2em; margin: 0.4em 0 0 0.4em"> <b>Unicode emojis</b>
<span>Select from the list or paste a Unicode character here: </span> <div style="font-style: italic">
<input id="iconInput" style="width: 2.5em"/> <span>Select from the list or paste a Unicode character here: </span>
<span>. See <a href="https://emojipedia.org" target="_blank">Emojipedia</a> for reference</span> <input id="iconInput" style="width: 2.5em" />
<span>. See <a href="https://emojidb.org" target="_blank">EmojiDB</a> to search for emojis</span>
</div>
<table id="iconTable" class="table pointer" style="font-size: 2em; text-align: center; width: 100%"></table>
</div>
<div style="margin-top: 0.5em">
<b>External images</b>
<div style="font-style: italic">
<span>Paste link to the image here: </span>
<input id="imageInput" style="width: 20em" />
<button id="addImage" type="button">Add</button>
</div>
<div id="addedIcons" class="pointer" style="display: flex; flex-wrap: wrap; max-width: 420px"></div>
</div> </div>
<span>
<span>You can past a regiment picture link here: </span>
<input id="imageInput" style="width: 12em" />
<button id="addImage" type="button" class="ui-button ui-corner-all ui-widget">Add</button>
</span>
</div> </div>
<div id="submapTool" style="display: none" class="dialog"> <div id="submapTool" style="display: none" class="dialog">
@ -8092,8 +8100,8 @@
<script src="modules/provinces-generator.js?v=1.106.0"></script> <script src="modules/provinces-generator.js?v=1.106.0"></script>
<script src="modules/routes-generator.js?v=1.106.0"></script> <script src="modules/routes-generator.js?v=1.106.0"></script>
<script src="modules/religions-generator.js?v=1.106.0"></script> <script src="modules/religions-generator.js?v=1.106.0"></script>
<script src="modules/military-generator.js?v=1.104.0"></script> <script src="modules/military-generator.js?v=1.107.0"></script>
<script src="modules/markers-generator.js?v=1.104.0"></script> <script src="modules/markers-generator.js?v=1.107.0"></script>
<script src="modules/zones-generator.js?v=1.106.0"></script> <script src="modules/zones-generator.js?v=1.106.0"></script>
<script src="modules/coa-generator.js?v=1.99.00"></script> <script src="modules/coa-generator.js?v=1.99.00"></script>
<script src="modules/resample.js?v=1.106.4"></script> <script src="modules/resample.js?v=1.106.4"></script>
@ -8111,8 +8119,8 @@
<script defer src="modules/relief-icons.js?v=1.99.05"></script> <script defer src="modules/relief-icons.js?v=1.99.05"></script>
<script defer src="modules/ui/style.js?v=1.104.0"></script> <script defer src="modules/ui/style.js?v=1.104.0"></script>
<script defer src="modules/ui/editors.js?v=1.106.1"></script> <script defer src="modules/ui/editors.js?v=1.107.0"></script>
<script defer src="modules/ui/tools.js?v=1.106.0"></script> <script defer src="modules/ui/tools.js?v=1.107.0"></script>
<script defer src="modules/ui/world-configurator.js?v=1.105.4"></script> <script defer src="modules/ui/world-configurator.js?v=1.105.4"></script>
<script defer src="modules/ui/heightmap-editor.js?v=1.105.2"></script> <script defer src="modules/ui/heightmap-editor.js?v=1.105.2"></script>
<script defer src="modules/ui/provinces-editor.js?v=1.106.1"></script> <script defer src="modules/ui/provinces-editor.js?v=1.106.1"></script>
@ -8139,13 +8147,13 @@
<script defer src="modules/ui/burgs-overview.js?v=1.105.15"></script> <script defer src="modules/ui/burgs-overview.js?v=1.105.15"></script>
<script defer src="modules/ui/routes-overview.js?v=1.104.3"></script> <script defer src="modules/ui/routes-overview.js?v=1.104.3"></script>
<script defer src="modules/ui/rivers-overview.js?v=1.99.00"></script> <script defer src="modules/ui/rivers-overview.js?v=1.99.00"></script>
<script defer src="modules/ui/military-overview.js?v=1.99.00"></script> <script defer src="modules/ui/military-overview.js?v=1.107.0"></script>
<script defer src="modules/ui/regiments-overview.js?v=1.104.0"></script> <script defer src="modules/ui/regiments-overview.js?v=1.107.0"></script>
<script defer src="modules/ui/markers-overview.js?v=1.99.00"></script> <script defer src="modules/ui/markers-overview.js?v=1.107.0"></script>
<script defer src="modules/ui/regiment-editor.js?v=1.104.14"></script> <script defer src="modules/ui/regiment-editor.js?v=1.107.0"></script>
<script defer src="modules/ui/battle-screen.js?v=1.99.00"></script> <script defer src="modules/ui/battle-screen.js?v=1.99.00"></script>
<script defer src="modules/ui/emblems-editor.js?v=1.99.00"></script> <script defer src="modules/ui/emblems-editor.js?v=1.99.00"></script>
<script defer src="modules/ui/markers-editor.js?v=1.99.00"></script> <script defer src="modules/ui/markers-editor.js?v=1.107.0"></script>
<script defer src="modules/ui/3d.js?v=1.99.00"></script> <script defer src="modules/ui/3d.js?v=1.99.00"></script>
<script defer src="modules/ui/submap-tool.js?v=1.106.2"></script> <script defer src="modules/ui/submap-tool.js?v=1.106.2"></script>
<script defer src="modules/ui/transform-tool.js?v=1.106.2"></script> <script defer src="modules/ui/transform-tool.js?v=1.106.2"></script>
@ -8154,18 +8162,18 @@
<script defer src="libs/rgbquant.min.js"></script> <script defer src="libs/rgbquant.min.js"></script>
<script defer src="libs/jquery.ui.touch-punch.min.js"></script> <script defer src="libs/jquery.ui.touch-punch.min.js"></script>
<script defer src="modules/io/save.js?v=1.100.00"></script> <script defer src="modules/io/save.js?v=1.100.00"></script>
<script defer src="modules/io/load.js?v=1.105.24"></script> <script defer src="modules/io/load.js?v=1.107.0"></script>
<script defer src="modules/io/cloud.js?v=1.106.0"></script> <script defer src="modules/io/cloud.js?v=1.106.0"></script>
<script defer src="modules/io/export.js?v=1.100.00"></script> <script defer src="modules/io/export.js?v=1.100.00"></script>
<script defer src="modules/renderers/draw-features.js?v=1.106.0"></script> <script defer src="modules/renderers/draw-features.js?v=1.106.0"></script>
<script defer src="modules/renderers/draw-borders.js?v=1.104.0"></script> <script defer src="modules/renderers/draw-borders.js?v=1.104.0"></script>
<script defer src="modules/renderers/draw-heightmap.js?v=1.104.0"></script> <script defer src="modules/renderers/draw-heightmap.js?v=1.104.0"></script>
<script defer src="modules/renderers/draw-markers.js?v=1.104.0"></script> <script defer src="modules/renderers/draw-markers.js?v=1.107.0"></script>
<script defer src="modules/renderers/draw-scalebar.js?v=1.104.0"></script> <script defer src="modules/renderers/draw-scalebar.js?v=1.104.0"></script>
<script defer src="modules/renderers/draw-temperature.js?v=1.104.0"></script> <script defer src="modules/renderers/draw-temperature.js?v=1.104.0"></script>
<script defer src="modules/renderers/draw-emblems.js?v=1.104.0"></script> <script defer src="modules/renderers/draw-emblems.js?v=1.104.0"></script>
<script defer src="modules/renderers/draw-military.js?v=1.104.13"></script> <script defer src="modules/renderers/draw-military.js?v=1.107.0"></script>
<script defer src="modules/renderers/draw-state-labels.js?v=1.106.0"></script> <script defer src="modules/renderers/draw-state-labels.js?v=1.106.0"></script>
<script defer src="modules/renderers/draw-burg-labels.js?v=1.104.0"></script> <script defer src="modules/renderers/draw-burg-labels.js?v=1.104.0"></script>
<script defer src="modules/renderers/draw-burg-icons.js?v=1.104.0"></script> <script defer src="modules/renderers/draw-burg-icons.js?v=1.104.0"></script>

View file

@ -458,20 +458,7 @@ async function parseLoadedData(data, mapVersion) {
if (isVisible(ruler)) turnOn("toggleRulers"); if (isVisible(ruler)) turnOn("toggleRulers");
if (isVisible(scaleBar)) turnOn("toggleScaleBar"); if (isVisible(scaleBar)) turnOn("toggleScaleBar");
if (isVisibleNode(byId("vignette"))) turnOn("toggleVignette"); if (isVisibleNode(byId("vignette"))) turnOn("toggleVignette");
window.uniquePictures = [];
window.iconReload = true;
$("#armies").each(function(id, armyGroup) {
$(armyGroup).children().each(function(aId, army){
$(army).children().each(function(rId, regiment){
if($(regiment).find(".regimentImage").length !== 0 && $(regiment).find(".regimentImage").attr('href')) {
let icon = $(regiment).find(".regimentImage").attr('href');
window.uniquePictures.push(icon);
}
});
});
});
window.uniquePictures = [...new Set(uniquePictures)];
getCurrentPreset(); getCurrentPreset();
} }

View file

@ -11,7 +11,7 @@ window.Markers = (function () {
/* /*
Default markers config: Default markers config:
type - short description (snake-case) type - short description (snake-case)
icon - unicode character, make sure it's supported by most of the browsers. Source: emojipedia.org icon - unicode character or url to image
dx: icon offset in x direction, in pixels dx: icon offset in x direction, in pixels
dy: icon offset in y direction, in pixels dy: icon offset in y direction, in pixels
min: minimum number of candidates to add at least 1 marker min: minimum number of candidates to add at least 1 marker

View file

@ -380,7 +380,7 @@ window.Military = (function () {
: gauss(options.year - 100, 150, 1, options.year - 6); : gauss(options.year - 100, 150, 1, options.year - 6);
const conflict = campaign ? ` during the ${campaign.name}` : ""; const conflict = campaign ? ` during the ${campaign.name}` : "";
const legend = `Regiment was formed in ${year} ${options.era}${conflict}. ${station}${troops}`; 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}); notes.push({id: `regiment${s.i}-${r.i}`, name: r.name, legend});
}; };
return { return {

View file

@ -42,9 +42,12 @@ function drawMarker(marker, rescale = 1) {
const viewX = rn(x - zoomSize / 2, 1); const viewX = rn(x - zoomSize / 2, 1);
const viewY = rn(y - zoomSize, 1); const viewY = rn(y - zoomSize, 1);
const isExternal = icon.startsWith("http");
return /* html */ ` return /* html */ `
<svg id="${id}" viewbox="0 0 30 30" width="${zoomSize}" height="${zoomSize}" x="${viewX}" y="${viewY}"> <svg id="${id}" viewbox="0 0 30 30" width="${zoomSize}" height="${zoomSize}" x="${viewX}" y="${viewY}">
<g>${getPin(pin, fill, stroke)}</g> <g>${getPin(pin, fill, stroke)}</g>
<text x="${dx}%" y="${dy}%" font-size="${px}px" >${icon}</text> <text x="${dx}%" y="${dy}%" font-size="${px}px" >${isExternal ? "" : icon}</text>
<image x="${dx / 2}%" y="${dy / 2}%" width="${px}px" height="${px}px" href="${isExternal ? icon : ""}" />
</svg>`; </svg>`;
} }

View file

@ -54,14 +54,14 @@ const drawRegiments = function (regiments, s) {
.attr("class", "regimentIcon") .attr("class", "regimentIcon")
.attr("x", d => x(d) - size) .attr("x", d => x(d) - size)
.attr("y", d => d.y) .attr("y", d => d.y)
.text(d => d.icon); .text(d => (d.icon.startsWith("http") ? "" : d.icon));
g.append("image") g.append("image")
.attr("class", "regimentImage") .attr("class", "regimentImage")
.attr("x", d => x(d) - h) .attr("x", d => x(d) - h)
.attr("y", d => y(d)) .attr("y", d => y(d))
.attr("height", h) .attr("height", h)
.attr("width", h) .attr("width", h)
.text(d => d.image); .attr("href", d => (d.icon.startsWith("http") ? d.icon : ""));
}; };
const drawRegiment = function (reg, stateId) { const drawRegiment = function (reg, stateId) {
@ -102,14 +102,14 @@ const drawRegiment = function (reg, stateId) {
.attr("class", "regimentIcon") .attr("class", "regimentIcon")
.attr("x", x1 - size) .attr("x", x1 - size)
.attr("y", reg.y) .attr("y", reg.y)
.text(reg.icon); .text(reg.icon.startsWith("http") ? "" : reg.icon);
g.append("image") g.append("image")
.attr("class", "regimentImage") .attr("class", "regimentImage")
.attr("x", x1 - h) .attr("x", x1 - h)
.attr("y", y1) .attr("y", y1)
.attr("height", h) .attr("height", h)
.attr("width", h) .attr("width", h)
.text(reg.image); .attr("href", reg.icon.startsWith("http") ? reg.icon : "");
}; };
// move one regiment to another // move one regiment to another
@ -137,12 +137,12 @@ const moveRegiment = function (reg, x, y) {
.transition(move) .transition(move)
.attr("x", x1(x) - size) .attr("x", x1(x) - size)
.attr("y", y) .attr("y", y)
.attr("height", '6') .attr("height", "6")
.attr("width", '6'); .attr("width", "6");
el.select(".regimentImage") el.select(".regimentImage")
.transition(move) .transition(move)
.attr("x", x1(x) - h) .attr("x", x1(x) - h)
.attr("y", y1(y)) .attr("y", y1(y))
.attr("height", '6') .attr("height", "6")
.attr("width", '6') .attr("width", "6");
}; };

View file

@ -960,30 +960,6 @@ function highlightElement(element, zoom) {
} }
} }
$('#addImage').click(function(){
let icon = $('#imageInput').val();
addImage(icon);
});
function addImage(icon) {
let row = "";
let lastRowId = $('#iconTable').children('tbody').children('tr').length;
let lastRow = $('#iconTable').children('tbody').children('tr:last-child');
let countLastRow = lastRow.children().length;
if(icon.includes("http")) {
icon = '<img height="46" width="46" src="'+icon+'"/>';
const table = byId("iconTable");
if(countLastRow > 16) {
row = table.insertRow(lastRowId);
} else {
row = table.rows[lastRowId-1];
}
const cell = row.insertCell(lastRow % 17);
cell.innerHTML = icon;
}
};
function selectIcon(initial, callback) { function selectIcon(initial, callback) {
if (!callback) return; if (!callback) return;
$("#iconSelector").dialog(); $("#iconSelector").dialog();
@ -991,11 +967,8 @@ function selectIcon(initial, callback) {
const table = byId("iconTable"); const table = byId("iconTable");
const input = byId("iconInput"); const input = byId("iconInput");
input.value = initial; input.value = initial;
if(window.iconReload) {
table.innerHTML = null; if (!table.innerHTML) {
window.iconReload = false;
}
if (!table.innerHTML.includes('⚔️')) {
const icons = [ const icons = [
"⚔️", "⚔️",
"🏹", "🏹",
@ -1183,48 +1156,75 @@ function selectIcon(initial, callback) {
"🍻", "🍻",
"🍺", "🍺",
"🍲", "🍲",
"🍷", "🍷"
]; ];
if(window.uniquePictures) { //if a load has been load, we might get already installed pictures list
window.uniquePictures.forEach((element) => icons.push(element));
}
let row = ""; let row = "";
for (let i = 0; i < icons.length; i++) { for (let i = 0; i < icons.length; i++) {
if(icons[i].includes("http")) {
icons[i] = '<img height="46" width="46" src="'+icons[i]+'"/>';
}
if (i % 17 === 0) row = table.insertRow((i / 17) | 0); if (i % 17 === 0) row = table.insertRow((i / 17) | 0);
const cell = row.insertCell(i % 17); const cell = row.insertCell(i % 17);
cell.innerHTML = icons[i]; cell.innerHTML = icons[i];
} }
// find external images used as icons and show them
const externalResources = new Set();
const isExternal = url => url.startsWith("http");
options.military.forEach(unit => {
if (isExternal(unit.icon)) externalResources.add(unit.icon);
});
pack.states.forEach(state => {
state?.military?.forEach(regiment => {
if (isExternal(regiment.icon)) externalResources.add(regiment.icon);
});
});
externalResources.forEach(addExternalImage);
} }
input.oninput = () => callback(input.value);
table.onclick = e => { table.onclick = e => {
if (e.target.tagName === "TD" && e.target.textContent) { if (e.target.tagName === "TD") {
input.value = e.target.textContent; input.value = e.target.textContent;
callback(input.value);
} }
if (e.target.tagName === "IMG" && e.target.src) {
input.value = e.target.src;
}
input.oninput = e => callback(input.value);
callback(input.value || "");
}; };
table.onmouseover = e => { table.onmouseover = e => {
if (e.target.tagName === "TD" && e.target.textContent) { if (e.target.tagName === "TD") tip(`Click to select ${e.target.textContent} icon`);
tip(`Click to select ${e.target.textContent} icon`);
}
if (e.target.tagName === "IMG" && e.target.src) {
tip(`Click to select ${e.target.src} icon`);
}
}; };
function addExternalImage(url) {
const addedIcons = byId("addedIcons");
const image = document.createElement("div");
image.style.cssText = `width: 2.2em; height: 2.2em; background-size: cover; background-image: url(${url})`;
addedIcons.appendChild(image);
image.onclick = () => callback(ulr);
}
byId("addImage").onclick = function () {
const input = this.previousElementSibling;
const ulr = input.value;
if (!ulr) return tip("Enter image URL to add", false, "error", 4000);
if (!ulr.match(/^(http|https):\/\//)) return tip("Enter valid URL", false, "error", 4000);
addExternalImage(ulr);
callback(ulr);
input.value = "";
};
byId("addedIcons")
.querySelectorAll("div")
.forEach(div => {
div.onclick = () => callback(div.style.backgroundImage.slice(5, -2));
});
$("#iconSelector").dialog({ $("#iconSelector").dialog({
width: fitContent(), width: fitContent(),
title: "Select Icon", title: "Select Icon",
buttons: { buttons: {
Apply: function () { Apply: function () {
callback(input.value || "");
$(this).dialog("close"); $(this).dialog("close");
}, },
Close: function () { Close: function () {

View file

@ -8,25 +8,24 @@ function editMarker(markerI) {
elSelected = d3.select(element).raise().call(d3.drag().on("start", dragMarker)).classed("draggable", true); elSelected = d3.select(element).raise().call(d3.drag().on("start", dragMarker)).classed("draggable", true);
if (document.getElementById("notesEditor").offsetParent) editNotes(element.id, element.id); if (byId("notesEditor").offsetParent) editNotes(element.id, element.id);
// dom elements // dom elements
const markerType = document.getElementById("markerType"); const markerType = byId("markerType");
const markerIcon = document.getElementById("markerIcon"); const markerIconSelect = byId("markerIconSelect");
const markerIconSelect = document.getElementById("markerIconSelect"); const markerIconSize = byId("markerIconSize");
const markerIconSize = document.getElementById("markerIconSize"); const markerIconShiftX = byId("markerIconShiftX");
const markerIconShiftX = document.getElementById("markerIconShiftX"); const markerIconShiftY = byId("markerIconShiftY");
const markerIconShiftY = document.getElementById("markerIconShiftY"); const markerSize = byId("markerSize");
const markerSize = document.getElementById("markerSize"); const markerPin = byId("markerPin");
const markerPin = document.getElementById("markerPin"); const markerFill = byId("markerFill");
const markerFill = document.getElementById("markerFill"); const markerStroke = byId("markerStroke");
const markerStroke = document.getElementById("markerStroke");
const markerNotes = document.getElementById("markerNotes"); const markerNotes = byId("markerNotes");
const markerLock = document.getElementById("markerLock"); const markerLock = byId("markerLock");
const addMarker = document.getElementById("addMarker"); const addMarker = byId("addMarker");
const markerAdd = document.getElementById("markerAdd"); const markerAdd = byId("markerAdd");
const markerRemove = document.getElementById("markerRemove"); const markerRemove = byId("markerRemove");
updateInputs(); updateInputs();
@ -39,8 +38,7 @@ function editMarker(markerI) {
const listeners = [ const listeners = [
listen(markerType, "change", changeMarkerType), listen(markerType, "change", changeMarkerType),
listen(markerIcon, "input", changeMarkerIcon), listen(markerIconSelect, "click", changeMarkerIcon),
listen(markerIconSelect, "click", selectMarkerIcon),
listen(markerIconSize, "input", changeIconSize), listen(markerIconSize, "input", changeIconSize),
listen(markerIconShiftX, "input", changeIconShiftX), listen(markerIconShiftX, "input", changeIconShiftX),
listen(markerIconShiftY, "input", changeIconShiftY), listen(markerIconShiftY, "input", changeIconShiftY),
@ -61,7 +59,7 @@ function editMarker(markerI) {
return [element, marker]; return [element, marker];
} }
const element = document.getElementById(`marker${markerI}`); const element = byId(`marker${markerI}`);
const marker = pack.markers.find(({i}) => i === markerI); const marker = pack.markers.find(({i}) => i === markerI);
return [element, marker]; return [element, marker];
} }
@ -97,19 +95,20 @@ function editMarker(markerI) {
} }
function updateInputs() { function updateInputs() {
const {icon, type = "", size = 30, dx = 50, dy = 50, px = 12, stroke = "#000000", fill = "#ffffff", pin = "bubble", lock} = marker; byId("markerIcon").innerHTML = marker.icon.startsWith("http")
? `<img src="${marker.icon}" style="width: 1em; height: 1em;">`
: marker.icon;
markerType.value = type; markerType.value = marker.type || "";
markerIcon.value = icon; markerIconSize.value = marker.px || 12;
markerIconSize.value = px; markerIconShiftX.value = marker.dx || 50;
markerIconShiftX.value = dx; markerIconShiftY.value = marker.dy || 50;
markerIconShiftY.value = dy; markerSize.value = marker.size || 30;
markerSize.value = size; markerPin.value = marker.pin || "bubble";
markerPin.value = pin; markerFill.value = marker.fill || "#ffffff";
markerFill.value = fill; markerStroke.value = marker.stroke || "#000000";
markerStroke.value = stroke;
markerLock.className = lock ? "icon-lock" : "icon-lock-open"; markerLock.className = marker.lock ? "icon-lock" : "icon-lock-open";
} }
function changeMarkerType() { function changeMarkerType() {
@ -117,18 +116,12 @@ function editMarker(markerI) {
} }
function changeMarkerIcon() { function changeMarkerIcon() {
const icon = this.value; selectIcon(marker.icon, value => {
getSameTypeMarkers().forEach(marker => { const isExternal = value.startsWith("http");
marker.icon = icon; byId("markerIcon").innerHTML = isExternal ? `<img src="${value}" style="width: 1em; height: 1em;">` : value;
redrawIcon(marker);
});
}
function selectMarkerIcon() {
selectIcon(marker.icon, icon => {
markerIcon.value = icon;
getSameTypeMarkers().forEach(marker => { getSameTypeMarkers().forEach(marker => {
marker.icon = icon; marker.icon = value;
redrawIcon(marker); redrawIcon(marker);
}); });
}); });
@ -165,7 +158,7 @@ function editMarker(markerI) {
getSameTypeMarkers().forEach(marker => { getSameTypeMarkers().forEach(marker => {
marker.size = size; marker.size = size;
const {i, x, y, hidden} = marker; const {i, x, y, hidden} = marker;
const el = !hidden && document.getElementById(`marker${i}`); const el = !hidden && byId(`marker${i}`);
if (!el) return; if (!el) return;
const zoomedSize = rescale ? Math.max(rn(size / 5 + 24 / scale, 2), 1) : size; const zoomedSize = rescale ? Math.max(rn(size / 5 + 24 / scale, 2), 1) : size;
@ -201,12 +194,23 @@ function editMarker(markerI) {
} }
function redrawIcon({i, hidden, icon, dx = 50, dy = 50, px = 12}) { function redrawIcon({i, hidden, icon, dx = 50, dy = 50, px = 12}) {
const iconElement = !hidden && document.querySelector(`#marker${i} > text`); const isExternal = icon.startsWith("http");
if (iconElement) {
iconElement.innerHTML = icon; const iconText = !hidden && document.querySelector(`#marker${i} > text`);
iconElement.setAttribute("x", dx + "%"); if (iconText) {
iconElement.setAttribute("y", dy + "%"); iconText.innerHTML = isExternal ? "" : icon;
iconElement.setAttribute("font-size", px + "px"); iconText.setAttribute("x", dx + "%");
iconText.setAttribute("y", dy + "%");
iconText.setAttribute("font-size", px + "px");
}
const iconImage = !hidden && document.querySelector(`#marker${i} > image`);
if (iconImage) {
iconImage.setAttribute("x", dx / 2 + "%");
iconImage.setAttribute("y", dy / 2 + "%");
iconImage.setAttribute("width", px + "px");
iconImage.setAttribute("height", px + "px");
iconImage.setAttribute("href", isExternal ? icon : "");
} }
} }
@ -241,10 +245,10 @@ function editMarker(markerI) {
} }
function deleteMarker() { function deleteMarker() {
Markers.deleteMarker(marker.i) Markers.deleteMarker(marker.i);
element.remove(); element.remove();
$("#markerEditor").dialog("close"); $("#markerEditor").dialog("close");
if (document.getElementById("markersOverviewRefresh").offsetParent) markersOverviewRefresh.click(); if (byId("markersOverviewRefresh").offsetParent) markersOverviewRefresh.click();
} }
function closeMarkerEditor() { function closeMarkerEditor() {

View file

@ -69,18 +69,24 @@ function overviewMarkers() {
function addLines() { function addLines() {
const lines = pack.markers const lines = pack.markers
.map(({i, type, icon, pinned, lock}) => { .map(({i, type, icon, pinned, lock}) => {
return `<div class="states" data-i=${i} data-type="${type}"> return /* html */ `
<div data-tip="Marker icon and type" style="width:12em">${icon} ${type}</div> <div class="states" data-i=${i} data-type="${type}">
<span style="padding-right:.1em" data-tip="Edit marker" class="icon-pencil"></span> ${
<span style="padding-right:.1em" data-tip="Focus on marker position" class="icon-dot-circled pointer"></span> icon.startsWith("http")
<span style="padding-right:.1em" data-tip="Pin marker (display only pinned markers)" class="icon-pin ${ ? `<img src="${icon}" data-tip="Marker icon" style="width:1.2em; height:1.2em; vertical-align: middle;">`
pinned ? "" : "inactive" : `<span data-tip="Marker icon" style="width:1.2em">${icon}</span>`
}" pointer"></span> }
<span style="padding-right:.1em" class="locks pointer ${ <div data-tip="Marker type" style="width:10em">${type}</div>
lock ? "icon-lock" : "icon-lock-open inactive" <span style="padding-right:.1em" data-tip="Edit marker" class="icon-pencil"></span>
}" onmouseover="showElementLockTip(event)"></span> <span style="padding-right:.1em" data-tip="Focus on marker position" class="icon-dot-circled pointer"></span>
<span data-tip="Remove marker" class="icon-trash-empty"></span> <span style="padding-right:.1em" data-tip="Pin marker (display only pinned markers)" class="icon-pin ${
</div>`; pinned ? "" : "inactive"
}" pointer"></span>
<span style="padding-right:.1em" class="locks pointer ${
lock ? "icon-lock" : "icon-lock-open inactive"
}" onmouseover="showElementLockTip(event)"></span>
<span data-tip="Remove marker" class="icon-trash-empty"></span>
</div>`;
}) })
.join(""); .join("");

View file

@ -284,7 +284,14 @@ function overviewMilitary() {
if (el.tagName !== "BUTTON") return; if (el.tagName !== "BUTTON") return;
const type = el.dataset.type; const type = el.dataset.type;
if (type === "icon") return selectIcon(el.textContent, v => (el.textContent = v)); if (type === "icon") {
return selectIcon(el.textContent, function (value) {
el.innerHTML = value.startsWith("http")
? `<img src="${value}" style="width:1.2em;height:1.2em;pointer-events:none;">`
: value;
});
}
if (type === "biomes") { if (type === "biomes") {
const {i, name, color} = biomesData; const {i, name, color} = biomesData;
const biomesArray = Array(i.length).fill(null); const biomesArray = Array(i.length).fill(null);
@ -329,9 +336,15 @@ function overviewMilitary() {
${getLimitText(unit[attr])} ${getLimitText(unit[attr])}
</button>`; </button>`;
row.innerHTML = /* html */ `<td><button data-type="icon" data-tip="Click to select unit icon">${ row.innerHTML = /* html */ `<td>
icon || " " <button data-type="icon" data-tip="Click to select unit icon">
}</button></td> ${
icon.startsWith("http")
? `<img src="${icon}" style="width:1.2em;height:1.2em;pointer-events:none;">`
: icon || ""
}
</button>
</td>
<td><input data-tip="Type unit name. If name is changed for existing unit, old unit will be replaced" value="${name}" /></td> <td><input data-tip="Type unit name. If name is changed for existing unit, old unit will be replaced" value="${name}" /></td>
<td>${getLimitButton("biomes")}</td> <td>${getLimitButton("biomes")}</td>
<td>${getLimitButton("states")}</td> <td>${getLimitButton("states")}</td>
@ -424,7 +437,11 @@ function overviewMilitary() {
const [icon, name, biomes, states, cultures, religions, rural, urban, crew, power, type, separate] = const [icon, name, biomes, states, cultures, religions, rural, urban, crew, power, type, separate] =
elements.map(el => { elements.map(el => {
const {type, value} = el.dataset || {}; const {type, value} = el.dataset || {};
if (type === "icon") return el.textContent || ""; if (type === "icon") {
const value = el.innerHTML.trim();
const isImage = value.startsWith("<img");
return isImage ? value.match(/src="([^"]*)"/)[1] : value || "";
}
if (type) return value ? value.split(",").map(v => parseInt(v)) : null; if (type) return value ? value.split(",").map(v => parseInt(v)) : null;
if (el.type === "number") return +el.value || 0; if (el.type === "number") return +el.value || 0;
if (el.type === "checkbox") return +el.checked || 0; if (el.type === "checkbox") return +el.checked || 0;

View file

@ -24,18 +24,17 @@ function editRegiment(selector) {
modules.editRegiment = true; modules.editRegiment = true;
// add listeners // add listeners
document.getElementById("regimentNameRestore").addEventListener("click", restoreName); byId("regimentNameRestore").addEventListener("click", restoreName);
document.getElementById("regimentType").addEventListener("click", changeType); byId("regimentType").addEventListener("click", changeType);
document.getElementById("regimentName").addEventListener("change", changeName); byId("regimentName").addEventListener("change", changeName);
document.getElementById("regimentEmblem").addEventListener("input", changeEmblem); byId("regimentEmblemChange").addEventListener("click", changeEmblem);
document.getElementById("regimentEmblemSelect").addEventListener("click", selectEmblem); byId("regimentAttack").addEventListener("click", toggleAttack);
document.getElementById("regimentAttack").addEventListener("click", toggleAttack); byId("regimentRegenerateLegend").addEventListener("click", regenerateLegend);
document.getElementById("regimentRegenerateLegend").addEventListener("click", regenerateLegend); byId("regimentLegend").addEventListener("click", editLegend);
document.getElementById("regimentLegend").addEventListener("click", editLegend); byId("regimentSplit").addEventListener("click", splitRegiment);
document.getElementById("regimentSplit").addEventListener("click", splitRegiment); byId("regimentAdd").addEventListener("click", toggleAdd);
document.getElementById("regimentAdd").addEventListener("click", toggleAdd); byId("regimentAttach").addEventListener("click", toggleAttach);
document.getElementById("regimentAttach").addEventListener("click", toggleAttach); byId("regimentRemove").addEventListener("click", removeRegiment);
document.getElementById("regimentRemove").addEventListener("click", removeRegiment);
// get regiment data element // get regiment data element
function getRegiment() { function getRegiment() {
@ -43,15 +42,13 @@ function editRegiment(selector) {
} }
function updateRegimentData(regiment) { function updateRegimentData(regiment) {
document.getElementById("regimentType").className = regiment.n ? "icon-anchor" : "icon-users"; byId("regimentType").className = regiment.n ? "icon-anchor" : "icon-users";
document.getElementById("regimentName").value = regiment.name; byId("regimentName").value = regiment.name;
if(regiment.image) { byId("regimentEmblem").innerHTML = regiment.icon.startsWith("http")
document.getElementById("regimentEmblem").value = regiment.image; ? `<img src="${regiment.icon}" style="width: 1em; height: 1em;">`
} else { : regiment.icon;
document.getElementById("regimentEmblem").value = regiment.icon;
}
const composition = document.getElementById("regimentComposition");
const composition = byId("regimentComposition");
composition.innerHTML = options.military composition.innerHTML = options.military
.map(u => { .map(u => {
return `<div data-tip="${capitalize(u.name)} number. Input to change"> return `<div data-tip="${capitalize(u.name)} number. Input to change">
@ -130,7 +127,7 @@ function editRegiment(selector) {
function changeType() { function changeType() {
const reg = getRegiment(); const reg = getRegiment();
reg.n = +!reg.n; reg.n = +!reg.n;
document.getElementById("regimentType").className = reg.n ? "icon-anchor" : "icon-users"; byId("regimentType").className = reg.n ? "icon-anchor" : "icon-users";
const size = +armies.attr("box-size"); const size = +armies.attr("box-size");
const baseRect = elSelected.querySelectorAll("rect")[0]; const baseRect = elSelected.querySelectorAll("rect")[0];
@ -153,25 +150,19 @@ function editRegiment(selector) {
const reg = getRegiment(), const reg = getRegiment(),
regs = pack.states[elSelected.dataset.state].military; regs = pack.states[elSelected.dataset.state].military;
const name = Military.getName(reg, regs); const name = Military.getName(reg, regs);
elSelected.dataset.name = reg.name = document.getElementById("regimentName").value = name; elSelected.dataset.name = reg.name = byId("regimentName").value = name;
}
function selectEmblem() {
selectIcon(regimentEmblem.value, v => {
regimentEmblem.value = v;
changeEmblem();
});
} }
function changeEmblem() { function changeEmblem() {
const emblem = document.getElementById("regimentEmblem").value; const regiment = getRegiment();
if(emblem.includes("http")) {
elSelected.querySelector(".regimentImage").setAttribute("href", emblem); selectIcon(regiment.icon, value => {
getRegiment().icon = elSelected.querySelector(".regimentIcon").innerHTML = ""; regiment.icon = value;
} else { const isExternal = value.startsWith("http");
getRegiment().icon = elSelected.querySelector(".regimentIcon").innerHTML = emblem; byId("regimentEmblem").innerHTML = isExternal ? `<img src="${value}" style="width: 1em; height: 1em;">` : value;
elSelected.querySelector(".regimentImage").setAttribute("href", ""); elSelected.querySelector(".regimentIcon").innerHTML = isExternal ? "" : value;
} elSelected.querySelector(".regimentImage").setAttribute("href", isExternal ? value : "");
});
} }
function changeUnit() { function changeUnit() {
@ -224,7 +215,7 @@ function editRegiment(selector) {
bx: reg.bx, bx: reg.bx,
by: reg.by, by: reg.by,
state, state,
icon: reg.icon, icon: reg.icon
}; };
newReg.name = Military.getName(newReg, military); newReg.name = Military.getName(newReg, military);
military.push(newReg); military.push(newReg);
@ -235,8 +226,8 @@ function editRegiment(selector) {
} }
function toggleAdd() { function toggleAdd() {
document.getElementById("regimentAdd").classList.toggle("pressed"); byId("regimentAdd").classList.toggle("pressed");
if (document.getElementById("regimentAdd").classList.contains("pressed")) { if (byId("regimentAdd").classList.contains("pressed")) {
viewbox.style("cursor", "crosshair").on("click", addRegimentOnClick); viewbox.style("cursor", "crosshair").on("click", addRegimentOnClick);
tip("Click on map to create new regiment or fleet", true); tip("Click on map to create new regiment or fleet", true);
} else { } else {
@ -263,8 +254,8 @@ function editRegiment(selector) {
} }
function toggleAttack() { function toggleAttack() {
document.getElementById("regimentAttack").classList.toggle("pressed"); byId("regimentAttack").classList.toggle("pressed");
if (document.getElementById("regimentAttack").classList.contains("pressed")) { if (byId("regimentAttack").classList.contains("pressed")) {
viewbox.style("cursor", "crosshair").on("click", attackRegimentOnClick); viewbox.style("cursor", "crosshair").on("click", attackRegimentOnClick);
tip("Click on another regiment to initiate battle", true); tip("Click on another regiment to initiate battle", true);
armies.selectAll(":scope > g").classed("draggable", false); armies.selectAll(":scope > g").classed("draggable", false);
@ -335,8 +326,8 @@ function editRegiment(selector) {
} }
function toggleAttach() { function toggleAttach() {
document.getElementById("regimentAttach").classList.toggle("pressed"); byId("regimentAttach").classList.toggle("pressed");
if (document.getElementById("regimentAttach").classList.contains("pressed")) { if (byId("regimentAttach").classList.contains("pressed")) {
viewbox.style("cursor", "crosshair").on("click", attachRegimentOnClick); viewbox.style("cursor", "crosshair").on("click", attachRegimentOnClick);
tip("Click on another regiment to unite both regiments. The current regiment will be removed", true); tip("Click on another regiment to unite both regiments. The current regiment will be removed", true);
armies.selectAll(":scope > g").classed("draggable", false); armies.selectAll(":scope > g").classed("draggable", false);
@ -462,7 +453,7 @@ function editRegiment(selector) {
icon.setAttribute("y", y); icon.setAttribute("y", y);
image.setAttribute("x", x1 - h); image.setAttribute("x", x1 - h);
image.setAttribute("y", y1); image.setAttribute("y", y1);
if (self) {; if (self) {
baseLine.attr("x2", x).attr("y2", y); baseLine.attr("x2", x).attr("y2", y);
rotationControl rotationControl
.attr("cx", x1 + w) .attr("cx", x1 + w)
@ -493,9 +484,9 @@ function editRegiment(selector) {
viewbox.selectAll("g#regimentBase").remove(); viewbox.selectAll("g#regimentBase").remove();
armies.selectAll(":scope > g").classed("draggable", false); armies.selectAll(":scope > g").classed("draggable", false);
armies.selectAll("g>g").call(d3.drag().on("drag", null)); armies.selectAll("g>g").call(d3.drag().on("drag", null));
document.getElementById("regimentAdd").classList.remove("pressed"); byId("regimentAdd").classList.remove("pressed");
document.getElementById("regimentAttack").classList.remove("pressed"); byId("regimentAttack").classList.remove("pressed");
document.getElementById("regimentAttach").classList.remove("pressed"); byId("regimentAttach").classList.remove("pressed");
restoreDefaultEvents(); restoreDefaultEvents();
elSelected = null; elSelected = null;
} }

View file

@ -67,14 +67,24 @@ function overviewRegiments(state) {
) )
.join(" "); .join(" ");
lines += /* html */ `<div class="states" data-id="${r.i}" data-s="${s.i}" data-state="${s.name}" data-name="${r.name}" ${sortData} data-total="${r.a}"> lines += /* html */ `<div class="states" data-id="${r.i}" data-s="${s.i}" data-state="${s.name}" data-name="${
r.name
}" ${sortData} data-total="${r.a}">
<fill-box data-tip="${s.fullName}" fill="${s.color}" disabled></fill-box> <fill-box data-tip="${s.fullName}" fill="${s.color}" disabled></fill-box>
<input data-tip="${s.fullName}" style="width:6em" value="${s.name}" readonly /> <input data-tip="${s.fullName}" style="width:6em" value="${s.name}" readonly />
<span data-tip="Regiment's emblem" style="width:1em">${r.icon}</span> ${
r.icon.startsWith("http")
? `<img src="${r.icon}" data-tip="Regiment's emblem" style="width:1.2em; height:1.2em; vertical-align: middle;">`
: `<span data-tip="Regiment's emblem" style="width:1em">${r.icon}</span>`
}
<input data-tip="Regiment's name" style="width:13em" value="${r.name}" readonly /> <input data-tip="Regiment's name" style="width:13em" value="${r.name}" readonly />
${lineData} ${lineData}
<div data-type="total" data-tip="Total military personnel (not considering crew)" style="font-weight: bold">${r.a}</div> <div data-type="total" data-tip="Total military personnel (not considering crew)" style="font-weight: bold">${
<span data-tip="Edit regiment" onclick="editRegiment('#regiment${s.i}-${r.i}')" class="icon-pencil pointer"></span> r.a
}</div>
<span data-tip="Edit regiment" onclick="editRegiment('#regiment${s.i}-${
r.i
}')" class="icon-pencil pointer"></span>
</div>`; </div>`;
regiments.push(r); regiments.push(r);

View file

@ -860,33 +860,47 @@ function configMarkersGeneration() {
drawConfigTable(); drawConfigTable();
function drawConfigTable() { function drawConfigTable() {
const {markers} = pack;
const config = Markers.getConfig(); const config = Markers.getConfig();
const headers = `<thead style='font-weight:bold'><tr>
const headers = /* html */ `<thead style='font-weight:bold'><tr>
<td data-tip="Marker type name">Type</td> <td data-tip="Marker type name">Type</td>
<td data-tip="Marker icon">Icon</td> <td data-tip="Marker icon">Icon</td>
<td data-tip="Marker number multiplier">Multiplier</td> <td data-tip="Marker number multiplier">Multiplier</td>
<td data-tip="Number of markers of that type on the current map">Number</td> <td data-tip="Number of markers of that type on the current map">Number</td>
</tr></thead>`; </tr></thead>`;
const lines = config.map(({type, icon, multiplier}, index) => {
const inputId = `markerIconInput${index}`; const lines = config.map(({type, icon, multiplier}) => {
return `<tr> const isExternal = icon.startsWith("http");
<td><input value="${type}" /></td>
return /* html */ `<tr>
<td><input class="type" value="${type}" /></td>
<td style="position: relative"> <td style="position: relative">
<input id="${inputId}" style="width: 5em" value="${icon}" /> <img class="image" src="${isExternal ? icon : ""}" ${
<i class="icon-edit pointer" style="position: absolute; margin:.4em 0 0 -1.4em; font-size:.85em"></i> isExternal ? "" : "hidden"
} style="width:1.2em; height:1.2em; vertical-align: middle;">
<span class="emoji" style="font-size:1.2em">${isExternal ? "" : icon}</span>
<button class="changeIcon icon-pencil"></button>
</td> </td>
<td><input type="number" min="0" max="100" step="0.1" value="${multiplier}" /></td> <td><input class="multiplier" type="number" min="0" max="100" step="0.1" value="${multiplier}" /></td>
<td style="text-align:center">${markers.filter(marker => marker.type === type).length}</td> <td style="text-align:center">${pack.markers.filter(marker => marker.type === type).length}</td>
</tr>`; </tr>`;
}); });
const table = `<table class="table">${headers}<tbody>${lines.join("")}</tbody></table>`; const table = `<table class="table">${headers}<tbody>${lines.join("")}</tbody></table>`;
alertMessage.innerHTML = table; alertMessage.innerHTML = table;
alertMessage.querySelectorAll("i").forEach(selectIconButton => { alertMessage.querySelectorAll("button.changeIcon").forEach(selectIconButton => {
selectIconButton.addEventListener("click", function () { selectIconButton.addEventListener("click", function () {
const input = this.previousElementSibling; const image = this.parentElement.querySelector(".image");
selectIcon(input.value, icon => (input.value = icon)); const emoji = this.parentElement.querySelector(".emoji");
const icon = image.getAttribute("src") || emoji.textContent;
selectIcon(icon, value => {
const isExternal = value.startsWith("http");
image.setAttribute("src", isExternal ? value : "");
image.hidden = !isExternal;
emoji.textContent = isExternal ? "" : value;
});
}); });
}); });
} }
@ -894,12 +908,14 @@ function configMarkersGeneration() {
const applyChanges = () => { const applyChanges = () => {
const rows = alertMessage.querySelectorAll("tbody > tr"); const rows = alertMessage.querySelectorAll("tbody > tr");
const rowsData = Array.from(rows).map(row => { const rowsData = Array.from(rows).map(row => {
const inputs = row.querySelectorAll("input"); const type = row.querySelector(".type").value;
return {
type: inputs[0].value, const image = row.querySelector(".image");
icon: inputs[1].value, const emoji = row.querySelector(".emoji");
multiplier: parseFloat(inputs[2].value) const icon = image.getAttribute("src") || emoji.textContent;
};
const multiplier = parseFloat(row.querySelector(".multiplier").value);
return {type, icon, multiplier};
}); });
const config = Markers.getConfig(); const config = Markers.getConfig();

View file

@ -13,7 +13,7 @@
* Example: 1.102.2 -> Major version 1, Minor version 102, Patch version 2 * Example: 1.102.2 -> Major version 1, Minor version 102, Patch version 2
*/ */
const VERSION = "1.106.7"; const VERSION = "1.107.0";
if (parseMapVersion(VERSION) !== VERSION) alert("versioning.js: Invalid format or parsing function"); if (parseMapVersion(VERSION) !== VERSION) alert("versioning.js: Invalid format or parsing function");
{ {