mirror of
https://github.com/Azgaar/Fantasy-Map-Generator.git
synced 2025-12-16 17:31:24 +01:00
Merge pull request #1187 from Azgaar/linked-icons
Custom images for Markers and Regiments
This commit is contained in:
commit
92b0b4d306
15 changed files with 302 additions and 158 deletions
55
index.html
55
index.html
|
|
@ -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,11 +5770,24 @@
|
|||
</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>
|
||||
</div>
|
||||
|
||||
|
|
@ -8087,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>
|
||||
|
|
@ -8106,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>
|
||||
|
|
@ -8134,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>
|
||||
|
|
@ -8149,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>
|
||||
|
|
|
|||
|
|
@ -977,4 +977,10 @@ export function resolveVersionConflicts(mapVersion) {
|
|||
BurgsAndStates.getPoles();
|
||||
Provinces.getPoles();
|
||||
}
|
||||
|
||||
if (isOlderThan("1.107.0")) {
|
||||
// v1.107.0 allowed custom images for markers and regiments
|
||||
if (layerIsOn("toggleMarkers")) drawMarkers();
|
||||
if (layerIsOn("toggleMilitary")) drawMilitary();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -471,7 +471,7 @@ async function parseLoadedData(data, mapVersion) {
|
|||
|
||||
{
|
||||
// dynamically import and run auto-update script
|
||||
const {resolveVersionConflicts} = await import("../dynamic/auto-update.js?v=1.105.24");
|
||||
const {resolveVersionConflicts} = await import("../dynamic/auto-update.js?v=1.107.0");
|
||||
resolveVersionConflicts(mapVersion);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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>`;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,7 +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)
|
||||
.attr("href", d => (d.icon.startsWith("http") ? d.icon : ""));
|
||||
};
|
||||
|
||||
const drawRegiment = function (reg, stateId) {
|
||||
|
|
@ -95,7 +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)
|
||||
.attr("href", reg.icon.startsWith("http") ? reg.icon : "");
|
||||
};
|
||||
|
||||
// move one regiment to another
|
||||
|
|
@ -122,5 +136,13 @@ const moveRegiment = function (reg, x, y) {
|
|||
el.select(".regimentIcon")
|
||||
.transition(move)
|
||||
.attr("x", x1(x) - size)
|
||||
.attr("y", y);
|
||||
.attr("y", y)
|
||||
.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");
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1165,25 +1165,66 @@ function selectIcon(initial, callback) {
|
|||
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 = e => callback(input.value);
|
||||
input.oninput = () => callback(input.value);
|
||||
|
||||
table.onclick = e => {
|
||||
if (e.target.tagName === "TD") {
|
||||
input.value = e.target.textContent;
|
||||
callback(input.value);
|
||||
}
|
||||
};
|
||||
|
||||
table.onmouseover = e => {
|
||||
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 () {
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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 ${
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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,11 +42,13 @@ function editRegiment(selector) {
|
|||
}
|
||||
|
||||
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");
|
||||
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">
|
||||
|
|
@ -126,12 +127,13 @@ 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];
|
||||
const iconRect = elSelected.querySelectorAll("rect")[1];
|
||||
const icon = elSelected.querySelector(".regimentIcon");
|
||||
const image = 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);
|
||||
|
|
@ -148,19 +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;
|
||||
getRegiment().icon = elSelected.querySelector(".regimentIcon").innerHTML = emblem;
|
||||
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,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 {
|
||||
|
|
@ -252,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);
|
||||
|
|
@ -324,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);
|
||||
|
|
@ -427,6 +429,7 @@ function editRegiment(selector) {
|
|||
const text = this.querySelector("text");
|
||||
const iconRect = this.querySelectorAll("rect")[1];
|
||||
const icon = this.querySelector(".regimentIcon");
|
||||
const image = this.querySelector(".regimentImage");
|
||||
|
||||
const self = elSelected === this;
|
||||
const baseLine = viewbox.select("g#regimentBase > line");
|
||||
|
|
@ -448,6 +451,8 @@ function editRegiment(selector) {
|
|||
iconRect.setAttribute("y", y1);
|
||||
icon.setAttribute("x", x1 - size);
|
||||
icon.setAttribute("y", y);
|
||||
image.setAttribute("x", x1 - h);
|
||||
image.setAttribute("y", y1);
|
||||
if (self) {
|
||||
baseLine.attr("x2", x).attr("y2", y);
|
||||
rotationControl
|
||||
|
|
@ -479,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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
||||
{
|
||||
|
|
@ -37,6 +37,7 @@ if (parseMapVersion(VERSION) !== VERSION) alert("versioning.js: Invalid format o
|
|||
|
||||
<ul>
|
||||
<strong>Latest changes:</strong>
|
||||
<li>Ability to set custom image as Marker or Regiment icon</li>
|
||||
<li>Submap and Transform tools rework</li>
|
||||
<li>Azgaar Bot to answer questions and provide help</li>
|
||||
<li>Labels: ability to set letter spacing</li>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue