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;
}
.regimentImage {
object-fit: contain;
}
#statesHalo {
fill: none;
stroke-linecap: round;

View file

@ -3555,9 +3555,9 @@
<input id="markerType" style="width: 10.3em" />
</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>
<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>
</div>
@ -3646,10 +3646,10 @@
></i>
</div>
<div data-tip="Regiment emblem. Paste any Unicode symbol or select from the predefined list">
<div class="label italic">Emblem:</div>
<input id="regimentEmblem" style="width: 5em" />
<button id="regimentEmblemSelect" style="padding: 0; width: 4.5em">select</button>
<div data-tip="Regiment emblem" style="display: flex; align-items: center">
<div class="label">Emblem:</div>
<div id="regimentEmblem" style="font-size: 1.5em; width: 3.7em"></div>
<button id="regimentEmblemChange" style="padding: 0; width: 4.5em">change</button>
</div>
<div id="regimentComposition" class="table"></div>
@ -5770,17 +5770,25 @@
</div>
<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 style="font-style: italic; font-size: 1.2em; margin: 0.4em 0 0 0.4em">
<div>
<b>Unicode emojis</b>
<div style="font-style: italic">
<span>Select from the list or paste a Unicode character here: </span>
<input id="iconInput" style="width: 2.5em" />
<span>. See <a href="https://emojipedia.org" target="_blank">Emojipedia</a> for reference</span>
<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>
<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 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/routes-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/markers-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.107.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/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/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/tools.js?v=1.106.0"></script>
<script defer src="modules/ui/editors.js?v=1.107.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/heightmap-editor.js?v=1.105.2"></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/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/military-overview.js?v=1.99.00"></script>
<script defer src="modules/ui/regiments-overview.js?v=1.104.0"></script>
<script defer src="modules/ui/markers-overview.js?v=1.99.00"></script>
<script defer src="modules/ui/regiment-editor.js?v=1.104.14"></script>
<script defer src="modules/ui/military-overview.js?v=1.107.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.107.0"></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/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/submap-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/jquery.ui.touch-punch.min.js"></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/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-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-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-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-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-burg-labels.js?v=1.104.0"></script>
<script defer src="modules/renderers/draw-burg-icons.js?v=1.104.0"></script>

View file

@ -459,19 +459,6 @@ async function parseLoadedData(data, mapVersion) {
if (isVisible(scaleBar)) turnOn("toggleScaleBar");
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();
}

View file

@ -11,7 +11,7 @@ window.Markers = (function () {
/*
Default markers config:
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
dy: icon offset in y direction, in pixels
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);
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});
notes.push({id: `regiment${s.i}-${r.i}`, name: r.name, legend});
};
return {

View file

@ -42,9 +42,12 @@ function drawMarker(marker, rescale = 1) {
const viewX = rn(x - zoomSize / 2, 1);
const viewY = rn(y - zoomSize, 1);
const isExternal = icon.startsWith("http");
return /* html */ `
<svg id="${id}" viewbox="0 0 30 30" width="${zoomSize}" height="${zoomSize}" x="${viewX}" y="${viewY}">
<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>`;
}

View file

@ -54,14 +54,14 @@ const drawRegiments = function (regiments, s) {
.attr("class", "regimentIcon")
.attr("x", d => x(d) - size)
.attr("y", d => d.y)
.text(d => d.icon);
.text(d => (d.icon.startsWith("http") ? "" : d.icon));
g.append("image")
.attr("class", "regimentImage")
.attr("x", d => x(d) - h)
.attr("y", d => y(d))
.attr("height", h)
.attr("width", h)
.text(d => d.image);
.attr("href", d => (d.icon.startsWith("http") ? d.icon : ""));
};
const drawRegiment = function (reg, stateId) {
@ -102,14 +102,14 @@ const drawRegiment = function (reg, stateId) {
.attr("class", "regimentIcon")
.attr("x", x1 - size)
.attr("y", reg.y)
.text(reg.icon);
.text(reg.icon.startsWith("http") ? "" : reg.icon);
g.append("image")
.attr("class", "regimentImage")
.attr("x", x1 - h)
.attr("y", y1)
.attr("height", h)
.attr("width", h)
.text(reg.image);
.attr("href", reg.icon.startsWith("http") ? reg.icon : "");
};
// move one regiment to another
@ -137,12 +137,12 @@ const moveRegiment = function (reg, x, y) {
.transition(move)
.attr("x", x1(x) - size)
.attr("y", y)
.attr("height", '6')
.attr("width", '6');
.attr("height", "6")
.attr("width", "6");
el.select(".regimentImage")
.transition(move)
.attr("x", x1(x) - h)
.attr("y", y1(y))
.attr("height", '6')
.attr("width", '6')
.attr("height", "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) {
if (!callback) return;
$("#iconSelector").dialog();
@ -991,11 +967,8 @@ function selectIcon(initial, callback) {
const table = byId("iconTable");
const input = byId("iconInput");
input.value = initial;
if(window.iconReload) {
table.innerHTML = null;
window.iconReload = false;
}
if (!table.innerHTML.includes('⚔️')) {
if (!table.innerHTML) {
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 = "";
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);
const cell = row.insertCell(i % 17);
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 => {
if (e.target.tagName === "TD" && e.target.textContent) {
if (e.target.tagName === "TD") {
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 => {
if (e.target.tagName === "TD" && e.target.textContent) {
tip(`Click to select ${e.target.textContent} icon`);
}
if (e.target.tagName === "IMG" && e.target.src) {
tip(`Click to select ${e.target.src} icon`);
}
if (e.target.tagName === "TD") tip(`Click to select ${e.target.textContent} 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({
width: fitContent(),
title: "Select Icon",
buttons: {
Apply: function () {
callback(input.value || "");
$(this).dialog("close");
},
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);
if (document.getElementById("notesEditor").offsetParent) editNotes(element.id, element.id);
if (byId("notesEditor").offsetParent) editNotes(element.id, element.id);
// dom elements
const markerType = document.getElementById("markerType");
const markerIcon = document.getElementById("markerIcon");
const markerIconSelect = document.getElementById("markerIconSelect");
const markerIconSize = document.getElementById("markerIconSize");
const markerIconShiftX = document.getElementById("markerIconShiftX");
const markerIconShiftY = document.getElementById("markerIconShiftY");
const markerSize = document.getElementById("markerSize");
const markerPin = document.getElementById("markerPin");
const markerFill = document.getElementById("markerFill");
const markerStroke = document.getElementById("markerStroke");
const markerType = byId("markerType");
const markerIconSelect = byId("markerIconSelect");
const markerIconSize = byId("markerIconSize");
const markerIconShiftX = byId("markerIconShiftX");
const markerIconShiftY = byId("markerIconShiftY");
const markerSize = byId("markerSize");
const markerPin = byId("markerPin");
const markerFill = byId("markerFill");
const markerStroke = byId("markerStroke");
const markerNotes = document.getElementById("markerNotes");
const markerLock = document.getElementById("markerLock");
const addMarker = document.getElementById("addMarker");
const markerAdd = document.getElementById("markerAdd");
const markerRemove = document.getElementById("markerRemove");
const markerNotes = byId("markerNotes");
const markerLock = byId("markerLock");
const addMarker = byId("addMarker");
const markerAdd = byId("markerAdd");
const markerRemove = byId("markerRemove");
updateInputs();
@ -39,8 +38,7 @@ function editMarker(markerI) {
const listeners = [
listen(markerType, "change", changeMarkerType),
listen(markerIcon, "input", changeMarkerIcon),
listen(markerIconSelect, "click", selectMarkerIcon),
listen(markerIconSelect, "click", changeMarkerIcon),
listen(markerIconSize, "input", changeIconSize),
listen(markerIconShiftX, "input", changeIconShiftX),
listen(markerIconShiftY, "input", changeIconShiftY),
@ -61,7 +59,7 @@ function editMarker(markerI) {
return [element, marker];
}
const element = document.getElementById(`marker${markerI}`);
const element = byId(`marker${markerI}`);
const marker = pack.markers.find(({i}) => i === markerI);
return [element, marker];
}
@ -97,19 +95,20 @@ function editMarker(markerI) {
}
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;
markerIcon.value = icon;
markerIconSize.value = px;
markerIconShiftX.value = dx;
markerIconShiftY.value = dy;
markerSize.value = size;
markerPin.value = pin;
markerFill.value = fill;
markerStroke.value = stroke;
markerType.value = marker.type || "";
markerIconSize.value = marker.px || 12;
markerIconShiftX.value = marker.dx || 50;
markerIconShiftY.value = marker.dy || 50;
markerSize.value = marker.size || 30;
markerPin.value = marker.pin || "bubble";
markerFill.value = marker.fill || "#ffffff";
markerStroke.value = marker.stroke || "#000000";
markerLock.className = lock ? "icon-lock" : "icon-lock-open";
markerLock.className = marker.lock ? "icon-lock" : "icon-lock-open";
}
function changeMarkerType() {
@ -117,18 +116,12 @@ function editMarker(markerI) {
}
function changeMarkerIcon() {
const icon = this.value;
getSameTypeMarkers().forEach(marker => {
marker.icon = icon;
redrawIcon(marker);
});
}
selectIcon(marker.icon, value => {
const isExternal = value.startsWith("http");
byId("markerIcon").innerHTML = isExternal ? `<img src="${value}" style="width: 1em; height: 1em;">` : value;
function selectMarkerIcon() {
selectIcon(marker.icon, icon => {
markerIcon.value = icon;
getSameTypeMarkers().forEach(marker => {
marker.icon = icon;
marker.icon = value;
redrawIcon(marker);
});
});
@ -165,7 +158,7 @@ function editMarker(markerI) {
getSameTypeMarkers().forEach(marker => {
marker.size = size;
const {i, x, y, hidden} = marker;
const el = !hidden && document.getElementById(`marker${i}`);
const el = !hidden && byId(`marker${i}`);
if (!el) return;
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}) {
const iconElement = !hidden && document.querySelector(`#marker${i} > text`);
if (iconElement) {
iconElement.innerHTML = icon;
iconElement.setAttribute("x", dx + "%");
iconElement.setAttribute("y", dy + "%");
iconElement.setAttribute("font-size", px + "px");
const isExternal = icon.startsWith("http");
const iconText = !hidden && document.querySelector(`#marker${i} > text`);
if (iconText) {
iconText.innerHTML = isExternal ? "" : icon;
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() {
Markers.deleteMarker(marker.i)
Markers.deleteMarker(marker.i);
element.remove();
$("#markerEditor").dialog("close");
if (document.getElementById("markersOverviewRefresh").offsetParent) markersOverviewRefresh.click();
if (byId("markersOverviewRefresh").offsetParent) markersOverviewRefresh.click();
}
function closeMarkerEditor() {

View file

@ -69,8 +69,14 @@ function overviewMarkers() {
function addLines() {
const lines = pack.markers
.map(({i, type, icon, pinned, lock}) => {
return `<div class="states" data-i=${i} data-type="${type}">
<div data-tip="Marker icon and type" style="width:12em">${icon} ${type}</div>
return /* html */ `
<div class="states" data-i=${i} data-type="${type}">
${
icon.startsWith("http")
? `<img src="${icon}" data-tip="Marker icon" style="width:1.2em; height:1.2em; vertical-align: middle;">`
: `<span data-tip="Marker icon" style="width:1.2em">${icon}</span>`
}
<div data-tip="Marker type" style="width:10em">${type}</div>
<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>
<span style="padding-right:.1em" data-tip="Pin marker (display only pinned markers)" class="icon-pin ${

View file

@ -284,7 +284,14 @@ function overviewMilitary() {
if (el.tagName !== "BUTTON") return;
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") {
const {i, name, color} = biomesData;
const biomesArray = Array(i.length).fill(null);
@ -329,9 +336,15 @@ function overviewMilitary() {
${getLimitText(unit[attr])}
</button>`;
row.innerHTML = /* html */ `<td><button data-type="icon" data-tip="Click to select unit icon">${
icon || " "
}</button></td>
row.innerHTML = /* html */ `<td>
<button data-type="icon" data-tip="Click to select unit icon">
${
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>${getLimitButton("biomes")}</td>
<td>${getLimitButton("states")}</td>
@ -424,7 +437,11 @@ function overviewMilitary() {
const [icon, name, biomes, states, cultures, religions, rural, urban, crew, power, type, separate] =
elements.map(el => {
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 (el.type === "number") return +el.value || 0;
if (el.type === "checkbox") return +el.checked || 0;

View file

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

View file

@ -67,14 +67,24 @@ function overviewRegiments(state) {
)
.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>
<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 />
${lineData}
<div data-type="total" data-tip="Total military personnel (not considering crew)" style="font-weight: bold">${r.a}</div>
<span data-tip="Edit regiment" onclick="editRegiment('#regiment${s.i}-${r.i}')" class="icon-pencil pointer"></span>
<div data-type="total" data-tip="Total military personnel (not considering crew)" style="font-weight: bold">${
r.a
}</div>
<span data-tip="Edit regiment" onclick="editRegiment('#regiment${s.i}-${
r.i
}')" class="icon-pencil pointer"></span>
</div>`;
regiments.push(r);

View file

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

View file

@ -13,7 +13,7 @@
* 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");
{