mirror of
https://github.com/Azgaar/Fantasy-Map-Generator.git
synced 2025-12-16 17:31:24 +01:00
annotate template strings for syntax hightlight and format
This commit is contained in:
parent
5a35f0d320
commit
1573fad58d
35 changed files with 816 additions and 460 deletions
|
|
@ -1,7 +1,5 @@
|
|||
// fill-box cannot use Shadow DOM as it needs access to svg hatches
|
||||
// append stylesheet
|
||||
{
|
||||
const style = `
|
||||
const style = /* css */ `
|
||||
fill-box:not([disabled]) {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
|
@ -14,7 +12,8 @@
|
|||
fill-box > svg > rect {
|
||||
stroke: #666666;
|
||||
stroke-width: 2;
|
||||
}`;
|
||||
}
|
||||
`;
|
||||
|
||||
const styleElement = document.createElement("style");
|
||||
styleElement.setAttribute("type", "text/css");
|
||||
|
|
@ -24,7 +23,7 @@
|
|||
|
||||
{
|
||||
const template = document.createElement("template");
|
||||
template.innerHTML = `
|
||||
template.innerHTML = /* html */ `
|
||||
<svg>
|
||||
<rect x="0" y="0" width="100%" height="100%">
|
||||
</svg>
|
||||
|
|
@ -70,5 +69,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
// cannot use Shadow DOM here as need an access to svg hatches
|
||||
customElements.define("fill-box", FillBox);
|
||||
}
|
||||
|
|
|
|||
14
main.js
14
main.js
|
|
@ -176,8 +176,8 @@ oceanLayers.append("rect").attr("id", "oceanBase").attr("x", 0).attr("y", 0).att
|
|||
document.addEventListener("DOMContentLoaded", async () => {
|
||||
if (!location.hostname) {
|
||||
const wiki = "https://github.com/Azgaar/Fantasy-Map-Generator/wiki/Run-FMG-locally";
|
||||
alertMessage.innerHTML = `Fantasy Map Generator cannot run serverless.
|
||||
Follow the <a href="${wiki}" target="_blank">instructions</a> on how you can easily run a local web-server`;
|
||||
alertMessage.innerHTML = /* html */ `Fantasy Map Generator cannot run serverless. Follow the <a href="${wiki}" target="_blank">instructions</a> on how you can
|
||||
easily run a local web-server`;
|
||||
|
||||
$("#alert").dialog({
|
||||
resizable: false,
|
||||
|
|
@ -455,9 +455,10 @@ function showWelcomeMessage() {
|
|||
const discord = link("https://discordapp.com/invite/X7E84HU", "Discord server");
|
||||
const patreon = link("https://www.patreon.com/azgaar", "Patreon");
|
||||
|
||||
alertMessage.innerHTML = `The Fantasy Map Generator is updated up to version <strong>${version}</strong>.
|
||||
This version is compatible with ${changelog}, loaded <i>.map</i> files will be auto-updated.
|
||||
<ul><strong>Latest changes:</strong>
|
||||
alertMessage.innerHTML = /* html */ `The Fantasy Map Generator is updated up to version <strong>${version}</strong>. This version is compatible with ${changelog},
|
||||
loaded <i>.map</i> files will be auto-updated.
|
||||
<ul>
|
||||
<strong>Latest changes:</strong>
|
||||
<li>Submap tool by Goteguru</li>
|
||||
<li>Resample tool by Goteguru</li>
|
||||
<li>Pre-defined heightmaps</li>
|
||||
|
|
@ -713,8 +714,7 @@ async function generate() {
|
|||
const parsedError = parseError(error);
|
||||
clearMainTip();
|
||||
|
||||
alertMessage.innerHTML = `An error has occurred on map generation. Please retry.
|
||||
<br>If error is critical, clear the stored data and try again.
|
||||
alertMessage.innerHTML = /* html */ `An error has occurred on map generation. Please retry. <br />If error is critical, clear the stored data and try again.
|
||||
<p id="errorBox">${parsedError}</p>`;
|
||||
$("#alert").dialog({
|
||||
resizable: false,
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ window.BurgsAndStates = (function () {
|
|||
if (sorted.length < count * 10) {
|
||||
count = Math.floor(sorted.length / 10);
|
||||
if (!count) {
|
||||
WARN && console.warn(`There is no populated cells. Cannot generate states`);
|
||||
WARN && console.warn("There is no populated cells. Cannot generate states");
|
||||
return burgs;
|
||||
} else {
|
||||
WARN && console.warn(`Not enough populated cells (${sorted.length}). Will generate only ${count} states`);
|
||||
|
|
@ -883,7 +883,7 @@ window.BurgsAndStates = (function () {
|
|||
dd.forEach((r, d) => {
|
||||
if (r !== "Ally" || states[d].diplomacy.includes("Vassal")) return;
|
||||
if (states[d].diplomacy[attacker] !== "Rival" && ap / dp > 2 * gauss(1.6, 0.8, 0, 10, 2)) {
|
||||
const reason = states[d].diplomacy.includes("Enemy") ? `Being already at war,` : `Frightened by ${an},`;
|
||||
const reason = states[d].diplomacy.includes("Enemy") ? "Being already at war," : `Frightened by ${an},`;
|
||||
war.push(`${reason} ${states[d].name} severed the defense pact with ${dn}`);
|
||||
dd[d] = states[d].diplomacy[defender] = "Suspicion";
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -15,9 +15,8 @@ window.Cultures = (function () {
|
|||
if (!count) {
|
||||
WARN && console.warn(`There are no populated cells. Cannot generate cultures`);
|
||||
pack.cultures = [{name: "Wildlands", i: 0, base: 1, shield: "round"}];
|
||||
alertMessage.innerHTML = `
|
||||
The climate is harsh and people cannot live in this world.<br>
|
||||
No cultures, states and burgs will be created.<br>
|
||||
alertMessage.innerHTML = /* html */ ` The climate is harsh and people cannot live in this world.<br />
|
||||
No cultures, states and burgs will be created.<br />
|
||||
Please consider changing climate settings in the World Configurator`;
|
||||
$("#alert").dialog({
|
||||
resizable: false,
|
||||
|
|
@ -31,9 +30,8 @@ window.Cultures = (function () {
|
|||
return;
|
||||
} else {
|
||||
WARN && console.warn(`Not enough populated cells (${populated.length}). Will generate only ${count} cultures`);
|
||||
alertMessage.innerHTML = `
|
||||
There are only ${populated.length} populated cells and it's insufficient livable area.<br>
|
||||
Only ${count} out of ${culturesInput.value} requested cultures will be generated.<br>
|
||||
alertMessage.innerHTML = /* html */ ` There are only ${populated.length} populated cells and it's insufficient livable area.<br />
|
||||
Only ${count} out of ${culturesInput.value} requested cultures will be generated.<br />
|
||||
Please consider changing climate settings in the World Configurator`;
|
||||
$("#alert").dialog({
|
||||
resizable: false,
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ export function resolveVersionConflicts(version) {
|
|||
labels.selectAll("textPath").each(function () {
|
||||
const text = this.textContent;
|
||||
const shift = this.getComputedTextLength() / -1.5;
|
||||
this.innerHTML = `<tspan x="${shift}">${text}</tspan>`;
|
||||
this.innerHTML = /* html */ `<tspan x="${shift}">${text}</tspan>`;
|
||||
});
|
||||
|
||||
// v1.0 added new biome - Wetland
|
||||
|
|
@ -362,7 +362,7 @@ export function resolveVersionConflicts(version) {
|
|||
const pattern = document.getElementById("oceanic");
|
||||
const filter = pattern.firstElementChild.getAttribute("filter");
|
||||
const href = filter ? "./images/" + filter.replace("url(#", "").replace(")", "") + ".png" : "";
|
||||
pattern.innerHTML = `<image id="oceanicPattern" href=${href} width="100" height="100" opacity="0.2"></image>`;
|
||||
pattern.innerHTML = /* html */ `<image id="oceanicPattern" href=${href} width="100" height="100" opacity="0.2"></image>`;
|
||||
}
|
||||
|
||||
if (version < 1.62) {
|
||||
|
|
|
|||
|
|
@ -50,8 +50,8 @@ function loadMapPrompt(blob) {
|
|||
return;
|
||||
}
|
||||
|
||||
alertMessage.innerHTML = `Are you sure you want to load saved map?<br>
|
||||
All unsaved changes made to the current map will be lost`;
|
||||
alertMessage.innerHTML = /* html */ `Are you sure you want to load saved map?<br />
|
||||
All unsaved changes made to the current map will be lost`;
|
||||
$("#alert").dialog({
|
||||
resizable: false,
|
||||
title: "Load saved map",
|
||||
|
|
@ -94,9 +94,10 @@ function loadMapFromURL(maplink, random) {
|
|||
|
||||
function showUploadErrorMessage(error, URL, random) {
|
||||
ERROR && console.error(error);
|
||||
alertMessage.innerHTML = `Cannot load map from the ${link(URL, "link provided")}.
|
||||
${random ? `A new random map is generated. ` : ""}
|
||||
Please ensure the linked file is reachable and CORS is allowed on server side`;
|
||||
alertMessage.innerHTML = /* html */ `Cannot load map from the ${link(URL, "link provided")}. ${
|
||||
random ? `A new random map is generated. ` : ""
|
||||
} Please ensure the
|
||||
linked file is reachable and CORS is allowed on server side`;
|
||||
$("#alert").dialog({
|
||||
title: "Loading error",
|
||||
width: "32em",
|
||||
|
|
@ -563,8 +564,7 @@ async function parseLoadedData(data) {
|
|||
ERROR && console.error(error);
|
||||
clearMainTip();
|
||||
|
||||
alertMessage.innerHTML = `An error is occured on map loading. Select a different file to load,
|
||||
<br>generate a new random map or cancel the loading
|
||||
alertMessage.innerHTML = /* html */ `An error is occured on map loading. Select a different file to load, <br />generate a new random map or cancel the loading
|
||||
<p id="errorBox">${parseError(error)}</p>`;
|
||||
|
||||
$("#alert").dialog({
|
||||
|
|
|
|||
|
|
@ -92,23 +92,38 @@ function editBiomes() {
|
|||
totalArea += area;
|
||||
totalPopulation += population;
|
||||
|
||||
lines += `<div class="states biomes" data-id="${i}" data-name="${b.name[i]}" data-habitability="${b.habitability[i]}"
|
||||
data-cells=${b.cells[i]} data-area=${area} data-population=${population} data-color=${b.color[i]}>
|
||||
<fill-box fill="${b.color[i]}"></fill-box>
|
||||
<input data-tip="Biome name. Click and type to change" class="biomeName" value="${b.name[i]}" autocorrect="off" spellcheck="false">
|
||||
<span data-tip="Biome habitability percent" class="hide">%</span>
|
||||
<input data-tip="Biome habitability percent. Click and set new value to change" type="number" min=0 max=9999 class="biomeHabitability hide" value=${
|
||||
b.habitability[i]
|
||||
}>
|
||||
<span data-tip="Cells count" class="icon-check-empty hide"></span>
|
||||
<div data-tip="Cells count" class="biomeCells hide">${b.cells[i]}</div>
|
||||
<span data-tip="Biome area" style="padding-right: 4px" class="icon-map-o hide"></span>
|
||||
<div data-tip="Biome area" class="biomeArea hide">${si(area) + unit}</div>
|
||||
<span data-tip="${populationTip}" class="icon-male hide"></span>
|
||||
<div data-tip="${populationTip}" class="biomePopulation hide">${si(population)}</div>
|
||||
<span data-tip="Open Wikipedia article about the biome" class="icon-info-circled pointer hide"></span>
|
||||
${i > 12 && !b.cells[i] ? '<span data-tip="Remove the custom biome" class="icon-trash-empty hide"></span>' : ""}
|
||||
</div>`;
|
||||
lines += /* html */ `
|
||||
<div
|
||||
class="states biomes"
|
||||
data-id="${i}"
|
||||
data-name="${b.name[i]}"
|
||||
data-habitability="${b.habitability[i]}"
|
||||
data-cells=${b.cells[i]}
|
||||
data-area=${area}
|
||||
data-population=${population}
|
||||
data-color=${b.color[i]}
|
||||
>
|
||||
<fill-box fill="${b.color[i]}"></fill-box>
|
||||
<input data-tip="Biome name. Click and type to change" class="biomeName" value="${b.name[i]}" autocorrect="off" spellcheck="false" />
|
||||
<span data-tip="Biome habitability percent" class="hide">%</span>
|
||||
<input
|
||||
data-tip="Biome habitability percent. Click and set new value to change"
|
||||
type="number"
|
||||
min="0"
|
||||
max="9999"
|
||||
class="biomeHabitability hide"
|
||||
value=${b.habitability[i]}
|
||||
/>
|
||||
<span data-tip="Cells count" class="icon-check-empty hide"></span>
|
||||
<div data-tip="Cells count" class="biomeCells hide">${b.cells[i]}</div>
|
||||
<span data-tip="Biome area" style="padding-right: 4px" class="icon-map-o hide"></span>
|
||||
<div data-tip="Biome area" class="biomeArea hide">${si(area) + unit}</div>
|
||||
<span data-tip="${populationTip}" class="icon-male hide"></span>
|
||||
<div data-tip="${populationTip}" class="biomePopulation hide">${si(population)}</div>
|
||||
<span data-tip="Open Wikipedia article about the biome" class="icon-info-circled pointer hide"></span>
|
||||
${i > 12 && !b.cells[i] ? '<span data-tip="Remove the custom biome" class="icon-trash-empty hide"></span>' : ""}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
body.innerHTML = lines;
|
||||
|
||||
|
|
|
|||
|
|
@ -281,10 +281,10 @@ function editBurg(id) {
|
|||
const burgsToRemove = burgsInGroup.filter(b => !(pack.burgs[b].capital || pack.burgs[b].lock));
|
||||
const capital = burgsToRemove.length < burgsInGroup.length;
|
||||
|
||||
alertMessage.innerHTML = `Are you sure you want to remove
|
||||
${basic || capital ? "all unlocked elements in the burg group" : "the entire burg group"}?
|
||||
<br>Please note that capital or locked burgs will not be deleted.
|
||||
<br><br>Burgs to be removed: ${burgsToRemove.length}`;
|
||||
alertMessage.innerHTML = /* html */ `Are you sure you want to remove ${
|
||||
basic || capital ? "all unlocked elements in the burg group" : "the entire burg group"
|
||||
}?
|
||||
<br />Please note that capital or locked burgs will not be deleted. <br /><br />Burgs to be removed: ${burgsToRemove.length}`;
|
||||
$("#alert").dialog({
|
||||
resizable: false,
|
||||
title: "Remove burg group",
|
||||
|
|
@ -545,7 +545,7 @@ function editBurg(id) {
|
|||
function removeSelectedBurg() {
|
||||
const id = +elSelected.attr("data-id");
|
||||
if (pack.burgs[id].capital) {
|
||||
alertMessage.innerHTML = `You cannot remove the burg as it is a state capital.<br><br>
|
||||
alertMessage.innerHTML = /* html */ `You cannot remove the burg as it is a state capital.<br /><br />
|
||||
You can change the capital using Burgs Editor (shift + T)`;
|
||||
$("#alert").dialog({
|
||||
resizable: false,
|
||||
|
|
|
|||
|
|
@ -82,22 +82,30 @@ function overviewBurgs() {
|
|||
const province = prov ? pack.provinces[prov].name : "";
|
||||
const culture = pack.cultures[b.culture].name;
|
||||
|
||||
lines += `<div class="states" data-id=${b.i} data-name="${
|
||||
b.name
|
||||
}" data-state="${state}" data-province="${province}" data-culture="${culture}" data-population=${population} data-type="${type}">
|
||||
lines += /* html */ `<div
|
||||
class="states"
|
||||
data-id=${b.i}
|
||||
data-name="${b.name}"
|
||||
data-state="${state}"
|
||||
data-province="${province}"
|
||||
data-culture="${culture}"
|
||||
data-population=${population}
|
||||
data-type="${type}"
|
||||
>
|
||||
<span data-tip="Click to zoom into view" class="icon-dot-circled pointer"></span>
|
||||
<input data-tip="Burg name. Click and type to change" class="burgName" value="${b.name}" autocorrect="off" spellcheck="false">
|
||||
<input data-tip="Burg province" class="burgState" value="${province}" disabled>
|
||||
<input data-tip="Burg state" class="burgState" value="${state}" disabled>
|
||||
<select data-tip="Dominant culture. Click to change burg culture (to change cell culture use Cultures Editor)" class="stateCulture">${getCultureOptions(
|
||||
b.culture
|
||||
)}</select>
|
||||
<input data-tip="Burg name. Click and type to change" class="burgName" value="${b.name}" autocorrect="off" spellcheck="false" />
|
||||
<input data-tip="Burg province" class="burgState" value="${province}" disabled />
|
||||
<input data-tip="Burg state" class="burgState" value="${state}" disabled />
|
||||
<select data-tip="Dominant culture. Click to change burg culture (to change cell culture use Cultures Editor)" class="stateCulture">
|
||||
${getCultureOptions(b.culture)}
|
||||
</select>
|
||||
<span data-tip="Burg population" class="icon-male"></span>
|
||||
<input data-tip="Burg population. Type to change" class="burgPopulation" value=${si(population)}>
|
||||
<input data-tip="Burg population. Type to change" class="burgPopulation" value=${si(population)} />
|
||||
<div class="burgType">
|
||||
<span data-tip="${b.capital ? " This burg is a state capital" : "Click to assign a capital status"}" class="icon-star-empty${
|
||||
b.capital ? "" : " inactive pointer"
|
||||
}"></span>
|
||||
<span
|
||||
data-tip="${b.capital ? " This burg is a state capital" : "Click to assign a capital status"}"
|
||||
class="icon-star-empty${b.capital ? "" : " inactive pointer"}"
|
||||
></span>
|
||||
<span data-tip="Click to toggle port status" class="icon-anchor pointer${b.port ? "" : " inactive"}" style="font-size:.9em"></span>
|
||||
</div>
|
||||
<span data-tip="Edit burg" class="icon-pencil"></span>
|
||||
|
|
@ -312,11 +320,12 @@ function overviewBurgs() {
|
|||
const treeLayout = d3.pack().size([w, h]).padding(3);
|
||||
|
||||
// prepare svg
|
||||
alertMessage.innerHTML = `<select id="burgsTreeType" style="display:block; margin-left:13px; font-size:11px">
|
||||
alertMessage.innerHTML = /* html */ `<select id="burgsTreeType" style="display:block; margin-left:13px; font-size:11px">
|
||||
<option value="states" selected>Group by state</option>
|
||||
<option value="cultures">Group by culture</option>
|
||||
<option value="parent">Group by province and state</option>
|
||||
<option value="provinces">Group by province</option></select>`;
|
||||
<option value="provinces">Group by province</option>
|
||||
</select>`;
|
||||
alertMessage.innerHTML += `<div id='burgsInfo' class='chartInfo'>‍</div>`;
|
||||
const svg = d3
|
||||
.select("#alertMessage")
|
||||
|
|
@ -349,7 +358,7 @@ function overviewBurgs() {
|
|||
const parent = d.parent.data.name;
|
||||
const population = si(d.value * populationRate * urbanization);
|
||||
|
||||
burgsInfo.innerHTML = `${name}. ${parent}. Population: ${population}`;
|
||||
burgsInfo.innerHTML = /* html */ `${name}. ${parent}. Population: ${population}`;
|
||||
burgHighlightOn(ev);
|
||||
tip("Click to zoom into view");
|
||||
}
|
||||
|
|
@ -483,9 +492,8 @@ function overviewBurgs() {
|
|||
}
|
||||
|
||||
function renameBurgsInBulk() {
|
||||
alertMessage.innerHTML = `Download burgs list as a text file, make changes and re-upload the file.
|
||||
Make sure the file is a plain text document with each name on its own line (the dilimiter is CRLF).
|
||||
If you do not want to change the name, just leave it as is`;
|
||||
alertMessage.innerHTML = /* html */ `Download burgs list as a text file, make changes and re-upload the file. Make sure the file is a plain text document with each
|
||||
name on its own line (the dilimiter is CRLF). If you do not want to change the name, just leave it as is`;
|
||||
|
||||
$("#alert").dialog({
|
||||
title: "Burgs bulk renaming",
|
||||
|
|
|
|||
|
|
@ -5,7 +5,8 @@ function editCoastline(node = d3.event.target) {
|
|||
if (layerIsOn("toggleCells")) toggleCells();
|
||||
|
||||
$("#coastlineEditor").dialog({
|
||||
title: "Edit Coastline", resizable: false,
|
||||
title: "Edit Coastline",
|
||||
resizable: false,
|
||||
position: {my: "center top+20", at: "top", of: d3.event, collision: "fit"},
|
||||
close: closeCoastlineEditor
|
||||
});
|
||||
|
|
@ -33,13 +34,27 @@ function editCoastline(node = d3.event.target) {
|
|||
const v = pack.features[f].vertices; // coastline outer vertices
|
||||
|
||||
const l = pack.cells.i.length;
|
||||
const c = [... new Set(v.map(v => pack.vertices.c[v]).flat())].filter(c => c < l);
|
||||
debug.select("#vertices").selectAll("polygon").data(c).enter().append("polygon")
|
||||
.attr("points", d => getPackPolygon(d)).attr("data-c", d => d);
|
||||
const c = [...new Set(v.map(v => pack.vertices.c[v]).flat())].filter(c => c < l);
|
||||
debug
|
||||
.select("#vertices")
|
||||
.selectAll("polygon")
|
||||
.data(c)
|
||||
.enter()
|
||||
.append("polygon")
|
||||
.attr("points", d => getPackPolygon(d))
|
||||
.attr("data-c", d => d);
|
||||
|
||||
debug.select("#vertices").selectAll("circle").data(v).enter().append("circle")
|
||||
.attr("cx", d => pack.vertices.p[d][0]).attr("cy", d => pack.vertices.p[d][1])
|
||||
.attr("r", .4).attr("data-v", d => d).call(d3.drag().on("drag", dragVertex))
|
||||
debug
|
||||
.select("#vertices")
|
||||
.selectAll("circle")
|
||||
.data(v)
|
||||
.enter()
|
||||
.append("circle")
|
||||
.attr("cx", d => pack.vertices.p[d][0])
|
||||
.attr("cy", d => pack.vertices.p[d][1])
|
||||
.attr("r", 0.4)
|
||||
.attr("data-v", d => d)
|
||||
.call(d3.drag().on("drag", dragVertex))
|
||||
.on("mousemove", () => tip("Drag to move the vertex, please use for fine-tuning only. Edit heightmap to change actual cell heights"));
|
||||
|
||||
const unit = areaUnit.value === "square" ? " " + distanceUnitInput.value + "²" : " " + areaUnit.value;
|
||||
|
|
@ -48,12 +63,16 @@ function editCoastline(node = d3.event.target) {
|
|||
}
|
||||
|
||||
function dragVertex() {
|
||||
const x = rn(d3.event.x, 2), y = rn(d3.event.y, 2);
|
||||
const x = rn(d3.event.x, 2),
|
||||
y = rn(d3.event.y, 2);
|
||||
this.setAttribute("cx", x);
|
||||
this.setAttribute("cy", y);
|
||||
const v = +this.dataset.v;
|
||||
pack.vertices.p[v] = [x, y];
|
||||
debug.select("#vertices").selectAll("polygon").attr("points", d => getPackPolygon(d));
|
||||
debug
|
||||
.select("#vertices")
|
||||
.selectAll("polygon")
|
||||
.attr("points", d => getPackPolygon(d));
|
||||
redrawCoastline();
|
||||
}
|
||||
|
||||
|
|
@ -61,11 +80,14 @@ function editCoastline(node = d3.event.target) {
|
|||
lineGen.curve(d3.curveBasisClosed);
|
||||
const f = +elSelected.attr("data-f");
|
||||
const vertices = pack.features[f].vertices;
|
||||
const points = clipPoly(vertices.map(v => pack.vertices.p[v]), 1);
|
||||
const points = clipPoly(
|
||||
vertices.map(v => pack.vertices.p[v]),
|
||||
1
|
||||
);
|
||||
const d = round(lineGen(points));
|
||||
elSelected.attr("d", d);
|
||||
defs.select("mask#land > path#land_"+f).attr("d", d); // update land mask
|
||||
defs.select("mask#water > path#water_"+f).attr("d", d); // update water mask
|
||||
defs.select("mask#land > path#land_" + f).attr("d", d); // update land mask
|
||||
defs.select("mask#water > path#water_" + f).attr("d", d); // update water mask
|
||||
|
||||
const unit = areaUnit.value === "square" ? " " + distanceUnitInput.value + "²" : " " + areaUnit.value;
|
||||
const area = Math.abs(d3.polygonArea(points));
|
||||
|
|
@ -73,12 +95,12 @@ function editCoastline(node = d3.event.target) {
|
|||
}
|
||||
|
||||
function showGroupSection() {
|
||||
document.querySelectorAll("#coastlineEditor > button").forEach(el => el.style.display = "none");
|
||||
document.querySelectorAll("#coastlineEditor > button").forEach(el => (el.style.display = "none"));
|
||||
document.getElementById("coastlineGroupsSelection").style.display = "inline-block";
|
||||
}
|
||||
|
||||
function hideGroupSection() {
|
||||
document.querySelectorAll("#coastlineEditor > button").forEach(el => el.style.display = "inline-block");
|
||||
document.querySelectorAll("#coastlineEditor > button").forEach(el => (el.style.display = "inline-block"));
|
||||
document.getElementById("coastlineGroupsSelection").style.display = "none";
|
||||
document.getElementById("coastlineGroupName").style.display = "none";
|
||||
document.getElementById("coastlineGroupName").value = "";
|
||||
|
|
@ -90,7 +112,7 @@ function editCoastline(node = d3.event.target) {
|
|||
const select = document.getElementById("coastlineGroup");
|
||||
select.options.length = 0; // remove all options
|
||||
|
||||
coastline.selectAll("g").each(function() {
|
||||
coastline.selectAll("g").each(function () {
|
||||
select.options.add(new Option(this.id, this.id, false, this.id === group));
|
||||
});
|
||||
}
|
||||
|
|
@ -111,8 +133,14 @@ function editCoastline(node = d3.event.target) {
|
|||
}
|
||||
|
||||
function createNewGroup() {
|
||||
if (!this.value) {tip("Please provide a valid group name"); return;}
|
||||
const group = this.value.toLowerCase().replace(/ /g, "_").replace(/[^\w\s]/gi, "");
|
||||
if (!this.value) {
|
||||
tip("Please provide a valid group name");
|
||||
return;
|
||||
}
|
||||
const group = this.value
|
||||
.toLowerCase()
|
||||
.replace(/ /g, "_")
|
||||
.replace(/[^\w\s]/gi, "");
|
||||
|
||||
if (document.getElementById(group)) {
|
||||
tip("Element with this id already exists. Please provide a unique name", false, "error");
|
||||
|
|
@ -155,11 +183,14 @@ function editCoastline(node = d3.event.target) {
|
|||
}
|
||||
|
||||
const count = elSelected.node().parentNode.childElementCount;
|
||||
alertMessage.innerHTML = `Are you sure you want to remove the group?
|
||||
All coastline elements of the group (${count}) will be moved under <i>sea_island</i> group`;
|
||||
$("#alert").dialog({resizable: false, title: "Remove coastline group", width:"26em",
|
||||
alertMessage.innerHTML = /* html */ `Are you sure you want to remove the group? All coastline elements of the group (${count}) will be moved under
|
||||
<i>sea_island</i> group`;
|
||||
$("#alert").dialog({
|
||||
resizable: false,
|
||||
title: "Remove coastline group",
|
||||
width: "26em",
|
||||
buttons: {
|
||||
Remove: function() {
|
||||
Remove: function () {
|
||||
$(this).dialog("close");
|
||||
const sea = document.getElementById("sea_island");
|
||||
const groupEl = document.getElementById(group);
|
||||
|
|
@ -170,7 +201,9 @@ function editCoastline(node = d3.event.target) {
|
|||
document.getElementById("coastlineGroup").selectedOptions[0].remove();
|
||||
document.getElementById("coastlineGroup").value = "sea_island";
|
||||
},
|
||||
Cancel: function() {$(this).dialog("close");}
|
||||
Cancel: function () {
|
||||
$(this).dialog("close");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -84,22 +84,37 @@ function editCultures() {
|
|||
|
||||
if (!c.i) {
|
||||
// Uncultured (neutral) line
|
||||
lines += `<div class="states" data-id=${c.i} data-name="${c.name}" data-color="" data-cells=${c.cells}
|
||||
data-area=${area} data-population=${population} data-base=${c.base} data-type="" data-expansionism="" data-emblems="${c.shield}">
|
||||
lines += /* html */ `<div
|
||||
class="states"
|
||||
data-id=${c.i}
|
||||
data-name="${c.name}"
|
||||
data-color=""
|
||||
data-cells=${c.cells}
|
||||
data-area=${area}
|
||||
data-population=${population}
|
||||
data-base=${c.base}
|
||||
data-type=""
|
||||
data-expansionism=""
|
||||
data-emblems="${c.shield}"
|
||||
>
|
||||
<svg width="9" height="9" class="placeholder"></svg>
|
||||
<input data-tip="Neutral culture name. Click and type to change" class="cultureName italic" value="${c.name}" autocorrect="off" spellcheck="false">
|
||||
<input data-tip="Neutral culture name. Click and type to change" class="cultureName italic" value="${c.name}" autocorrect="off" spellcheck="false" />
|
||||
<span class="icon-cw placeholder"></span>
|
||||
<span data-tip="Cells count" class="icon-check-empty hide"></span>
|
||||
<div data-tip="Cells count" class="stateCells hide">${c.cells}</div>
|
||||
<span class="icon-resize-full placeholder hide"></span>
|
||||
<input class="statePower placeholder hide" type="number">
|
||||
<select class="cultureType placeholder">${getTypeOptions(c.type)}</select>
|
||||
<input class="statePower placeholder hide" type="number" />
|
||||
<select class="cultureType placeholder">
|
||||
${getTypeOptions(c.type)}
|
||||
</select>
|
||||
<span data-tip="Culture area" style="padding-right: 4px" class="icon-map-o hide"></span>
|
||||
<div data-tip="Culture area" class="biomeArea hide">${si(area) + unit}</div>
|
||||
<span data-tip="${populationTip}" class="icon-male hide"></span>
|
||||
<div data-tip="${populationTip}" class="culturePopulation hide">${si(population)}</div>
|
||||
<span data-tip="Click to re-generate names for burgs with this culture assigned" class="icon-arrows-cw hide"></span>
|
||||
<select data-tip="Culture namesbase. Click to change. Click on arrows to re-generate names" class="cultureBase">${getBaseOptions(c.base)}</select>
|
||||
<select data-tip="Culture namesbase. Click to change. Click on arrows to re-generate names" class="cultureBase">
|
||||
${getBaseOptions(c.base)}
|
||||
</select>
|
||||
${
|
||||
selectShape
|
||||
? `<select data-tip="Emblem shape associated with culture. Click to change" class="cultureShape hide">${getShapeOptions(c.shield)}</select>`
|
||||
|
|
@ -109,24 +124,45 @@ function editCultures() {
|
|||
continue;
|
||||
}
|
||||
|
||||
lines += `<div class="states cultures" data-id=${c.i} data-name="${c.name}" data-color="${c.color}" data-cells=${c.cells}
|
||||
data-area=${area} data-population=${population} data-base=${c.base} data-type=${c.type} data-expansionism=${c.expansionism} data-emblems="${c.shield}">
|
||||
lines += /* html */ `<div
|
||||
class="states cultures"
|
||||
data-id=${c.i}
|
||||
data-name="${c.name}"
|
||||
data-color="${c.color}"
|
||||
data-cells=${c.cells}
|
||||
data-area=${area}
|
||||
data-population=${population}
|
||||
data-base=${c.base}
|
||||
data-type=${c.type}
|
||||
data-expansionism=${c.expansionism}
|
||||
data-emblems="${c.shield}"
|
||||
>
|
||||
<fill-box fill="${c.color}"></fill-box>
|
||||
<input data-tip="Culture name. Click and type to change" class="cultureName" value="${c.name}" autocorrect="off" spellcheck="false">
|
||||
<input data-tip="Culture name. Click and type to change" class="cultureName" value="${c.name}" autocorrect="off" spellcheck="false" />
|
||||
<span data-tip="Regenerate culture name" class="icon-cw hiddenIcon" style="visibility: hidden"></span>
|
||||
<span data-tip="Cells count" class="icon-check-empty hide"></span>
|
||||
<div data-tip="Cells count" class="stateCells hide">${c.cells}</div>
|
||||
<span data-tip="Culture expansionism. Defines competitive size" class="icon-resize-full hide"></span>
|
||||
<input data-tip="Culture expansionism. Defines competitive size. Click to change, then click Recalculate to apply change" class="statePower hide" type="number" min=0 max=99 step=.1 value=${
|
||||
c.expansionism
|
||||
}>
|
||||
<select data-tip="Culture type. Defines growth model. Click to change" class="cultureType">${getTypeOptions(c.type)}</select>
|
||||
<input
|
||||
data-tip="Culture expansionism. Defines competitive size. Click to change, then click Recalculate to apply change"
|
||||
class="statePower hide"
|
||||
type="number"
|
||||
min="0"
|
||||
max="99"
|
||||
step=".1"
|
||||
value=${c.expansionism}
|
||||
/>
|
||||
<select data-tip="Culture type. Defines growth model. Click to change" class="cultureType">
|
||||
${getTypeOptions(c.type)}
|
||||
</select>
|
||||
<span data-tip="Culture area" style="padding-right: 4px" class="icon-map-o hide"></span>
|
||||
<div data-tip="Culture area" class="biomeArea hide">${si(area) + unit}</div>
|
||||
<span data-tip="${populationTip}" class="icon-male hide"></span>
|
||||
<div data-tip="${populationTip}" class="culturePopulation hide">${si(population)}</div>
|
||||
<span data-tip="Click to re-generate names for burgs with this culture assigned" class="icon-arrows-cw hide"></span>
|
||||
<select data-tip="Culture namesbase. Click to change. Click on arrows to re-generate names" class="cultureBase">${getBaseOptions(c.base)}</select>
|
||||
<select data-tip="Culture namesbase. Click to change. Click on arrows to re-generate names" class="cultureBase">
|
||||
${getBaseOptions(c.base)}
|
||||
</select>
|
||||
${
|
||||
selectShape
|
||||
? `<select data-tip="Emblem shape associated with culture. Click to change" class="cultureShape hide">${getShapeOptions(c.shield)}</select>`
|
||||
|
|
@ -200,7 +236,7 @@ function editCultures() {
|
|||
const rural = c.rural * populationRate;
|
||||
const urban = c.urban * populationRate * urbanization;
|
||||
const population = rural + urban > 0 ? si(rn(rural + urban)) + " people" : "Extinct";
|
||||
info.innerHTML = `${c.name} culture. ${c.type}. ${population}`;
|
||||
info.innerHTML = /* html */ `${c.name} culture. ${c.type}. ${population}`;
|
||||
tip("Drag to change parent, drag to itself to move to the top level. Hold CTRL and click to change abbreviation");
|
||||
}
|
||||
|
||||
|
|
@ -347,10 +383,9 @@ function editCultures() {
|
|||
const l = n => Number(n).toLocaleString();
|
||||
const burgs = pack.burgs.filter(b => !b.removed && b.culture === culture);
|
||||
|
||||
alertMessage.innerHTML = `
|
||||
Rural: <input type="number" min=0 step=1 id="ruralPop" value=${rural} style="width:6em">
|
||||
Urban: <input type="number" min=0 step=1 id="urbanPop" value=${urban} style="width:6em" ${burgs.length ? "" : "disabled"}>
|
||||
<p>Total population: ${l(total)} ⇒ <span id="totalPop">${l(total)}</span> (<span id="totalPopPerc">100</span>%)</p>`;
|
||||
alertMessage.innerHTML = /* html */ ` Rural: <input type="number" min="0" step="1" id="ruralPop" value=${rural} style="width:6em" /> Urban:
|
||||
<input type="number" min="0" step="1" id="urbanPop" value=${urban} style="width:6em" ${burgs.length ? "" : "disabled"} />
|
||||
<p>Total population: ${l(total)} ⇒ <span id="totalPop">${l(total)}</span> (<span id="totalPopPerc">100</span>%)</p>`;
|
||||
|
||||
const update = function () {
|
||||
const totalNew = ruralPop.valueAsNumber + urbanPop.valueAsNumber;
|
||||
|
|
@ -898,8 +933,10 @@ function editCultures() {
|
|||
const shapes = Object.keys(COA.shields.types)
|
||||
.map(type => Object.keys(COA.shields[type]))
|
||||
.flat();
|
||||
const populated = pack.cells.pop.map((c, i) => c? i: null).filter(c => c);
|
||||
cultures.forEach((item) => {if (item.i) item.removed = true});
|
||||
const populated = pack.cells.pop.map((c, i) => (c ? i : null)).filter(c => c);
|
||||
cultures.forEach(item => {
|
||||
if (item.i) item.removed = true;
|
||||
});
|
||||
for (const c of csv.iterator((a, b) => +a[0] > +b[0])) {
|
||||
let current;
|
||||
if (+c.id < cultures.length) {
|
||||
|
|
@ -934,7 +971,7 @@ function editCultures() {
|
|||
current.base = nameBaseIndex === -1 ? 0 : nameBaseIndex;
|
||||
}
|
||||
|
||||
cultures.filter(c => c.removed).forEach(c => removeCultureModel(c.i))
|
||||
cultures.filter(c => c.removed).forEach(c => removeCultureModel(c.i));
|
||||
|
||||
drawCultures();
|
||||
refreshCulturesEditor();
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ function editDiplomacy() {
|
|||
const selectedName = states[selectedId].name;
|
||||
|
||||
COArenderer.trigger("stateCOA" + selectedId, states[selectedId].coa);
|
||||
let lines = `<div class="states Self" data-id=${selectedId} data-tip="List below shows relations to ${selectedName}">
|
||||
let lines = /* html */ `<div class="states Self" data-id=${selectedId} data-tip="List below shows relations to ${selectedName}">
|
||||
<div style="width: max-content">${states[selectedId].fullName}</div>
|
||||
<svg class="coaIcon" viewBox="0 0 200 200"><use href="#stateCOA${selectedId}"></use></svg>
|
||||
</div>`;
|
||||
|
|
@ -98,7 +98,7 @@ function editDiplomacy() {
|
|||
const name = state.fullName.length < 23 ? state.fullName : state.name;
|
||||
COArenderer.trigger("stateCOA" + state.i, state.coa);
|
||||
|
||||
lines += `<div class="states" data-id=${state.i} data-name="${name}" data-relations="${relation}">
|
||||
lines += /* html */ `<div class="states" data-id=${state.i} data-name="${name}" data-relations="${relation}">
|
||||
<svg data-tip="${tipSelect}" class="coaIcon" viewBox="0 0 200 200"><use href="#stateCOA${state.i}"></use></svg>
|
||||
<div data-tip="${tipSelect}" style="width: 12em">${name}</div>
|
||||
<div data-tip="${tipChange}" class="changeRelations" style="width: 6em">
|
||||
|
|
@ -202,7 +202,7 @@ function editDiplomacy() {
|
|||
const object = states[objectId];
|
||||
const footer = `<div style="margin-top: 0.7em"><svg class="coaIcon" viewBox="0 0 200 200"><use href="#stateCOA${object.i}"></use></svg> <b>${object.fullName}</b></div>`;
|
||||
|
||||
alertMessage.innerHTML = `<div style="overflow: hidden">${header} ${options} ${footer}</div>`;
|
||||
alertMessage.innerHTML = /* html */ `<div style="overflow: hidden">${header} ${options} ${footer}</div>`;
|
||||
|
||||
$("#alert").dialog({
|
||||
width: fitContent(),
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ function closeDialogs(except = "#except") {
|
|||
function moveCircle(x, y, r = 20) {
|
||||
let circle = document.getElementById("brushCircle");
|
||||
if (!circle) {
|
||||
const html = `<circle id="brushCircle" cx=${x} cy=${y} r=${r}></circle>`;
|
||||
const html = /* html */ `<circle id="brushCircle" cx=${x} cy=${y} r=${r}></circle>`;
|
||||
document.getElementById("debug").insertAdjacentHTML("afterBegin", html);
|
||||
} else {
|
||||
circle.setAttribute("cx", x);
|
||||
|
|
@ -192,9 +192,9 @@ function moveBurgToGroup(id, g) {
|
|||
|
||||
function moveAllBurgsToGroup(fromGroup, toGroup) {
|
||||
const groupToMove = document.querySelector(`#burgIcons #${fromGroup}`);
|
||||
const burgsToMove = Array.from(groupToMove.children).map(x=>x.dataset.id);
|
||||
addBurgsGroup(toGroup)
|
||||
burgsToMove.forEach(x=>moveBurgToGroup(x, toGroup));
|
||||
const burgsToMove = Array.from(groupToMove.children).map(x => x.dataset.id);
|
||||
addBurgsGroup(toGroup);
|
||||
burgsToMove.forEach(x => moveBurgToGroup(x, toGroup));
|
||||
}
|
||||
|
||||
function addBurgsGroup(group) {
|
||||
|
|
@ -495,18 +495,17 @@ function createPicker() {
|
|||
.attr("width", 303)
|
||||
.attr("height", 20)
|
||||
.on("mousemove", () => tip("Color value in different color spaces. Edit to change"));
|
||||
const html = `
|
||||
<label style="margin-right: 6px">HSL:
|
||||
<input type="number" id="pickerHSL_H" data-space="hsl" min=0 max=360 value="231">,
|
||||
<input type="number" id="pickerHSL_S" data-space="hsl" min=0 max=100 value="70">,
|
||||
<input type="number" id="pickerHSL_L" data-space="hsl" min=0 max=100 value="70">
|
||||
</label>
|
||||
<label style="margin-right: 6px">RGB:
|
||||
<input type="number" id="pickerRGB_R" data-space="rgb" min=0 max=255 value="125">,
|
||||
<input type="number" id="pickerRGB_G" data-space="rgb" min=0 max=255 value="142">,
|
||||
<input type="number" id="pickerRGB_B" data-space="rgb" min=0 max=255 value="232">
|
||||
</label>
|
||||
<label>HEX: <input type="text" id="pickerHEX" data-space="hex" style="width:42px" autocorrect="off" spellcheck="false" value="#7d8ee8"></label>`;
|
||||
const html = /* html */ ` <label style="margin-right: 6px"
|
||||
>HSL: <input type="number" id="pickerHSL_H" data-space="hsl" min="0" max="360" value="231" />,
|
||||
<input type="number" id="pickerHSL_S" data-space="hsl" min="0" max="100" value="70" />,
|
||||
<input type="number" id="pickerHSL_L" data-space="hsl" min="0" max="100" value="70" />
|
||||
</label>
|
||||
<label style="margin-right: 6px"
|
||||
>RGB: <input type="number" id="pickerRGB_R" data-space="rgb" min="0" max="255" value="125" />,
|
||||
<input type="number" id="pickerRGB_G" data-space="rgb" min="0" max="255" value="142" />,
|
||||
<input type="number" id="pickerRGB_B" data-space="rgb" min="0" max="255" value="232" />
|
||||
</label>
|
||||
<label>HEX: <input type="text" id="pickerHEX" data-space="hex" style="width:42px" autocorrect="off" spellcheck="false" value="#7d8ee8" /></label>`;
|
||||
spaces.node().insertAdjacentHTML("beforeend", html);
|
||||
spaces.selectAll("input").on("change", changePickerSpace);
|
||||
|
||||
|
|
@ -523,7 +522,7 @@ function createPicker() {
|
|||
.attr("fill", d)
|
||||
.attr("class", i ? "" : "selected")
|
||||
.attr("x", (i % 14) * 22 + 4)
|
||||
.attr("y", 40 + Math.floor(i / 14)*20)
|
||||
.attr("y", 40 + Math.floor(i / 14) * 20)
|
||||
.attr("width", 16)
|
||||
.attr("height", 16);
|
||||
});
|
||||
|
|
@ -534,9 +533,9 @@ function createPicker() {
|
|||
.attr("id", "picker_" + this.id)
|
||||
.attr("fill", "url(#" + this.id + ")")
|
||||
.attr("x", (i % 14) * 22 + 4)
|
||||
.attr("y", Math.floor(i / 14)*20 + 20 + (number * 2))
|
||||
.attr("y", Math.floor(i / 14) * 20 + 20 + number * 2)
|
||||
.attr("width", 16)
|
||||
.attr("height", 16)
|
||||
.attr("height", 16);
|
||||
});
|
||||
|
||||
colors
|
||||
|
|
@ -546,7 +545,9 @@ function createPicker() {
|
|||
hatches
|
||||
.selectAll("rect")
|
||||
.on("click", pickerFillClicked)
|
||||
.on("mouseover", function() { tip("Click to fill with the hatching " + this.id) });
|
||||
.on("mouseover", function () {
|
||||
tip("Click to fill with the hatching " + this.id);
|
||||
});
|
||||
|
||||
// append box
|
||||
const bbox = picker.node().getBBox();
|
||||
|
|
@ -562,10 +563,15 @@ function createPicker() {
|
|||
.attr("fill", "#ffffff")
|
||||
.attr("stroke", "#5d4651")
|
||||
.on("mousemove", pos);
|
||||
picker.insert("text", ":first-child").attr("x", width-20).attr("y", -10).attr("id", "pickerCloseText").text("✕");
|
||||
picker
|
||||
.insert("text", ":first-child")
|
||||
.attr("x", width - 20)
|
||||
.attr("y", -10)
|
||||
.attr("id", "pickerCloseText")
|
||||
.text("✕");
|
||||
picker
|
||||
.insert("rect", ":first-child")
|
||||
.attr("x", width-23)
|
||||
.attr("x", width - 23)
|
||||
.attr("y", -21)
|
||||
.attr("id", "pickerCloseRect")
|
||||
.attr("width", 14)
|
||||
|
|
|
|||
|
|
@ -13,7 +13,10 @@ function editEmblem(type, id, el) {
|
|||
updateElementSelectors(type, id, el);
|
||||
|
||||
$("#emblemEditor").dialog({
|
||||
title: "Edit Emblem", resizable: true, width: "18.2em", height: "auto",
|
||||
title: "Edit Emblem",
|
||||
resizable: true,
|
||||
width: "18.2em",
|
||||
height: "auto",
|
||||
position: {my: "left top", at: "left+10 top+10", of: "svg", collision: "fit"},
|
||||
close: closeEmblemEditor
|
||||
});
|
||||
|
|
@ -41,17 +44,17 @@ function editEmblem(type, id, el) {
|
|||
|
||||
function defineEmblemData(e) {
|
||||
const parent = e.target.parentNode;
|
||||
const [g, t] = parent.id === "burgEmblems" ? [pack.burgs, "burg"] :
|
||||
parent.id === "provinceEmblems" ? [pack.provinces, "province"] :
|
||||
[pack.states, "state"];
|
||||
const [g, t] = parent.id === "burgEmblems" ? [pack.burgs, "burg"] : parent.id === "provinceEmblems" ? [pack.provinces, "province"] : [pack.states, "state"];
|
||||
const i = +e.target.dataset.i;
|
||||
type = t;
|
||||
id = type+"COA"+i;
|
||||
id = type + "COA" + i;
|
||||
el = g[i];
|
||||
}
|
||||
|
||||
function updateElementSelectors(type, id, el) {
|
||||
let state = 0, province = 0, burg = 0;
|
||||
let state = 0,
|
||||
province = 0,
|
||||
burg = 0;
|
||||
|
||||
// set active type
|
||||
emblemStates.parentElement.className = type === "state" ? "active" : "";
|
||||
|
|
@ -61,7 +64,7 @@ function editEmblem(type, id, el) {
|
|||
// define selected values
|
||||
if (type === "state") state = el.i;
|
||||
else if (type === "province") {
|
||||
province = el.i
|
||||
province = el.i;
|
||||
state = pack.states[el.state].i;
|
||||
} else {
|
||||
burg = el.i;
|
||||
|
|
@ -85,7 +88,7 @@ function editEmblem(type, id, el) {
|
|||
|
||||
emblemBurgs.options.length = 0;
|
||||
emblemBurgs.options.add(new Option("", 0, false, !burg));
|
||||
const burgList = validBurgs.filter(burg => province ? pack.cells.province[burg.cell] === province : burg.state === state);
|
||||
const burgList = validBurgs.filter(burg => (province ? pack.cells.province[burg.cell] === province : burg.state === state));
|
||||
burgList.forEach(b => emblemBurgs.options.add(new Option(b.capital ? "👑 " + b.name : b.name, b.i, false, b.i === burg)));
|
||||
emblemBurgs.options[0].disabled = true;
|
||||
|
||||
|
|
@ -116,14 +119,14 @@ function editEmblem(type, id, el) {
|
|||
if (state) {
|
||||
type = "state";
|
||||
el = pack.states[state];
|
||||
id = "stateCOA"+ state;
|
||||
id = "stateCOA" + state;
|
||||
} else {
|
||||
// select neutral burg if state is changed to Neutrals
|
||||
const neutralBurgs = pack.burgs.filter(burg => burg.i && !burg.removed && !burg.state);
|
||||
if (!neutralBurgs.length) return;
|
||||
type = "burg";
|
||||
el = neutralBurgs[0];
|
||||
id = "burgCOA"+ neutralBurgs[0].i;
|
||||
id = "burgCOA" + neutralBurgs[0].i;
|
||||
}
|
||||
updateElementSelectors(type, id, el);
|
||||
}
|
||||
|
|
@ -134,13 +137,13 @@ function editEmblem(type, id, el) {
|
|||
if (province) {
|
||||
type = "province";
|
||||
el = pack.provinces[province];
|
||||
id = "provinceCOA"+ province;
|
||||
id = "provinceCOA" + province;
|
||||
} else {
|
||||
// select state if province is changed to null value
|
||||
const state = +emblemStates.value;
|
||||
type = "state";
|
||||
el = pack.states[state];
|
||||
id = "stateCOA"+ state;
|
||||
id = "stateCOA" + state;
|
||||
}
|
||||
|
||||
updateElementSelectors(type, id, el);
|
||||
|
|
@ -150,7 +153,7 @@ function editEmblem(type, id, el) {
|
|||
const burg = +this.value;
|
||||
type = "burg";
|
||||
el = pack.burgs[burg];
|
||||
id = "burgCOA"+ burg;
|
||||
id = "burgCOA" + burg;
|
||||
updateElementSelectors(type, id, el);
|
||||
}
|
||||
|
||||
|
|
@ -166,23 +169,26 @@ function editEmblem(type, id, el) {
|
|||
}
|
||||
|
||||
function changeSize() {
|
||||
const size = el.coaSize = +this.value;
|
||||
const size = (el.coaSize = +this.value);
|
||||
document.getElementById("emblemSizeSlider").value = size;
|
||||
document.getElementById("emblemSizeNumber").value = size;
|
||||
|
||||
const g = emblems.select("#"+type+"Emblems");
|
||||
g.select("[data-i='"+el.i+"']").remove();
|
||||
const g = emblems.select("#" + type + "Emblems");
|
||||
g.select("[data-i='" + el.i + "']").remove();
|
||||
if (!size) return;
|
||||
|
||||
// re-append use element
|
||||
const categotySize = +g.attr("font-size");
|
||||
const shift = categotySize * size / 2;
|
||||
const shift = (categotySize * size) / 2;
|
||||
const x = el.x || el.pole[0];
|
||||
const y = el.y || el.pole[1];
|
||||
g.append("use").attr("data-i", el.i)
|
||||
.attr("x", rn(x - shift), 2).attr("y", rn(y - shift), 2)
|
||||
.attr("width", size+"em").attr("height", size+"em")
|
||||
.attr("href", "#"+id);
|
||||
g.append("use")
|
||||
.attr("data-i", el.i)
|
||||
.attr("x", rn(x - shift), 2)
|
||||
.attr("y", rn(y - shift), 2)
|
||||
.attr("width", size + "em")
|
||||
.attr("height", size + "em")
|
||||
.attr("href", "#" + id);
|
||||
}
|
||||
|
||||
function regenerate() {
|
||||
|
|
@ -194,7 +200,7 @@ function editEmblem(type, id, el) {
|
|||
}
|
||||
|
||||
const shield = el.coa.shield || COA.getShield(el.culture || parent?.culture || 0, el.state);
|
||||
el.coa = COA.generate(parent ? parent.coa : null, .3, .1, null);
|
||||
el.coa = COA.generate(parent ? parent.coa : null, 0.3, 0.1, null);
|
||||
el.coa.shield = shield;
|
||||
emblemShapeSelector.disabled = false;
|
||||
emblemShapeSelector.value = el.coa.shield;
|
||||
|
|
@ -229,7 +235,7 @@ function editEmblem(type, id, el) {
|
|||
|
||||
const reader = new FileReader();
|
||||
|
||||
reader.onload = function(readerEvent) {
|
||||
reader.onload = function (readerEvent) {
|
||||
const result = readerEvent.target.result;
|
||||
const defs = document.getElementById("defs-emblems");
|
||||
const coa = document.getElementById(id); // old emblem
|
||||
|
|
@ -266,7 +272,8 @@ function editEmblem(type, id, el) {
|
|||
emblemShapeSelector.disabled = true;
|
||||
};
|
||||
|
||||
if (type === "image") reader.readAsDataURL(file); else reader.readAsText(file);
|
||||
if (type === "image") reader.readAsDataURL(file);
|
||||
else reader.readAsText(file);
|
||||
}
|
||||
|
||||
function toggleDownload() {
|
||||
|
|
@ -282,7 +289,8 @@ function editEmblem(type, id, el) {
|
|||
const link = document.createElement("a");
|
||||
link.download = getFileName(`Emblem ${el.fullName || el.name}`) + "." + format;
|
||||
|
||||
if (format === "svg") downloadSVG(url, link); else downloadRaster(format, url, link, size);
|
||||
if (format === "svg") downloadSVG(url, link);
|
||||
else downloadRaster(format, url, link, size);
|
||||
document.getElementById("emblemDownloadControl").classList.add("hidden");
|
||||
}
|
||||
|
||||
|
|
@ -299,22 +307,22 @@ function editEmblem(type, id, el) {
|
|||
|
||||
const img = new Image();
|
||||
img.src = url;
|
||||
img.onload = function() {
|
||||
img.onload = function () {
|
||||
if (format === "jpeg") {
|
||||
ctx.fillStyle = "#fff";
|
||||
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
||||
}
|
||||
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
|
||||
const dataURL = canvas.toDataURL("image/" + format, .92);
|
||||
const dataURL = canvas.toDataURL("image/" + format, 0.92);
|
||||
link.href = dataURL;
|
||||
link.click();
|
||||
window.setTimeout(() => window.URL.revokeObjectURL(dataURL), 6000);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
async function getURL(svg, size) {
|
||||
const serialized = getSVG(svg, size);
|
||||
const blob = new Blob([serialized], {type: 'image/svg+xml;charset=utf-8'});
|
||||
const blob = new Blob([serialized], {type: "image/svg+xml;charset=utf-8"});
|
||||
const url = window.URL.createObjectURL(blob);
|
||||
window.setTimeout(() => window.URL.revokeObjectURL(url), 6000);
|
||||
return url;
|
||||
|
|
@ -324,7 +332,7 @@ function editEmblem(type, id, el) {
|
|||
const clone = svg.cloneNode(true);
|
||||
clone.setAttribute("width", size);
|
||||
clone.setAttribute("height", size);
|
||||
return (new XMLSerializer()).serializeToString(clone);
|
||||
return new XMLSerializer().serializeToString(clone);
|
||||
}
|
||||
|
||||
async function downloadGallery() {
|
||||
|
|
@ -338,70 +346,135 @@ function editEmblem(type, id, el) {
|
|||
function runDownload() {
|
||||
const back = `<a href="javascript:history.back()">Go Back</a>`;
|
||||
|
||||
const stateSection = `<div><h2>States</h2>` + validStates.map(state => {
|
||||
const el = document.getElementById("stateCOA"+state.i);
|
||||
return `<figure id="state_${state.i}"><a href="#provinces_${state.i}"><figcaption>${state.fullName}</figcaption>${getSVG(el, 200)}</a></figure>`;
|
||||
}).join("") + `</div>`;
|
||||
const stateSection =
|
||||
`<div><h2>States</h2>` +
|
||||
validStates
|
||||
.map(state => {
|
||||
const el = document.getElementById("stateCOA" + state.i);
|
||||
return `<figure id="state_${state.i}"><a href="#provinces_${state.i}"><figcaption>${state.fullName}</figcaption>${getSVG(el, 200)}</a></figure>`;
|
||||
})
|
||||
.join("") +
|
||||
`</div>`;
|
||||
|
||||
const provinceSections = validStates.map(state => {
|
||||
const stateProvinces = validProvinces.filter(p => p.state === state.i);
|
||||
const figures = stateProvinces.map(province => {
|
||||
const el = document.getElementById("provinceCOA"+province.i);
|
||||
return `<figure id="province_${province.i}"><a href="#burgs_${province.i}"><figcaption>${province.fullName}</figcaption>${getSVG(el, 200)}</a></figure>`;
|
||||
}).join("");
|
||||
return stateProvinces.length ? `<div id="provinces_${state.i}">${back}<h2>${state.fullName} provinces</h2>${figures}</div>` : "";
|
||||
}).join("");
|
||||
const provinceSections = validStates
|
||||
.map(state => {
|
||||
const stateProvinces = validProvinces.filter(p => p.state === state.i);
|
||||
const figures = stateProvinces
|
||||
.map(province => {
|
||||
const el = document.getElementById("provinceCOA" + province.i);
|
||||
return `<figure id="province_${province.i}"><a href="#burgs_${province.i}"><figcaption>${province.fullName}</figcaption>${getSVG(
|
||||
el,
|
||||
200
|
||||
)}</a></figure>`;
|
||||
})
|
||||
.join("");
|
||||
return stateProvinces.length ? `<div id="provinces_${state.i}">${back}<h2>${state.fullName} provinces</h2>${figures}</div>` : "";
|
||||
})
|
||||
.join("");
|
||||
|
||||
const burgSections = validStates.map(state => {
|
||||
const stateBurgs = validBurgs.filter(b => b.state === state.i);
|
||||
let stateBurgSections = validProvinces.filter(p => p.state === state.i).map(province => {
|
||||
const provinceBurgs = stateBurgs.filter(b => pack.cells.province[b.cell] === province.i);
|
||||
const provinceBurgFigures = provinceBurgs.map(burg => {
|
||||
const el = document.getElementById("burgCOA"+burg.i);
|
||||
return `<figure id="burg_${burg.i}"><figcaption>${burg.name}</figcaption>${getSVG(el, 200)}</figure>`;
|
||||
}).join("");
|
||||
return provinceBurgs.length ? `<div id="burgs_${province.i}">${back}<h2>${province.fullName} burgs</h2>${provinceBurgFigures}</div>` : "";
|
||||
}).join("");
|
||||
const burgSections = validStates
|
||||
.map(state => {
|
||||
const stateBurgs = validBurgs.filter(b => b.state === state.i);
|
||||
let stateBurgSections = validProvinces
|
||||
.filter(p => p.state === state.i)
|
||||
.map(province => {
|
||||
const provinceBurgs = stateBurgs.filter(b => pack.cells.province[b.cell] === province.i);
|
||||
const provinceBurgFigures = provinceBurgs
|
||||
.map(burg => {
|
||||
const el = document.getElementById("burgCOA" + burg.i);
|
||||
return `<figure id="burg_${burg.i}"><figcaption>${burg.name}</figcaption>${getSVG(el, 200)}</figure>`;
|
||||
})
|
||||
.join("");
|
||||
return provinceBurgs.length ? `<div id="burgs_${province.i}">${back}<h2>${province.fullName} burgs</h2>${provinceBurgFigures}</div>` : "";
|
||||
})
|
||||
.join("");
|
||||
|
||||
const stateBurgOutOfProvinces = stateBurgs.filter(b => !pack.cells.province[b.cell]);
|
||||
const stateBurgOutOfProvincesFigures = stateBurgOutOfProvinces.map(burg => {
|
||||
const el = document.getElementById("burgCOA"+burg.i);
|
||||
return `<figure id="burg_${burg.i}"><figcaption>${burg.name}</figcaption>${getSVG(el, 200)}</figure>`;
|
||||
}).join("");
|
||||
if (stateBurgOutOfProvincesFigures) stateBurgSections += `<div><h2>${state.fullName} burgs under direct control</h2>${stateBurgOutOfProvincesFigures}</div>`;
|
||||
return stateBurgSections;
|
||||
}).join("");
|
||||
const stateBurgOutOfProvinces = stateBurgs.filter(b => !pack.cells.province[b.cell]);
|
||||
const stateBurgOutOfProvincesFigures = stateBurgOutOfProvinces
|
||||
.map(burg => {
|
||||
const el = document.getElementById("burgCOA" + burg.i);
|
||||
return `<figure id="burg_${burg.i}"><figcaption>${burg.name}</figcaption>${getSVG(el, 200)}</figure>`;
|
||||
})
|
||||
.join("");
|
||||
if (stateBurgOutOfProvincesFigures)
|
||||
stateBurgSections += `<div><h2>${state.fullName} burgs under direct control</h2>${stateBurgOutOfProvincesFigures}</div>`;
|
||||
return stateBurgSections;
|
||||
})
|
||||
.join("");
|
||||
|
||||
const neutralBurgs = validBurgs.filter(b => !b.state);
|
||||
const neutralsSection = neutralBurgs.length ? "<div><h2>Independent burgs</h2>" + neutralBurgs.map(burg => {
|
||||
const el = document.getElementById("burgCOA"+burg.i);
|
||||
return `<figure id="burg_${burg.i}"><figcaption>${burg.name}</figcaption>${getSVG(el, 200)}</figure>`;
|
||||
}).join("") + "</div>" : "";
|
||||
const neutralsSection = neutralBurgs.length
|
||||
? "<div><h2>Independent burgs</h2>" +
|
||||
neutralBurgs
|
||||
.map(burg => {
|
||||
const el = document.getElementById("burgCOA" + burg.i);
|
||||
return `<figure id="burg_${burg.i}"><figcaption>${burg.name}</figcaption>${getSVG(el, 200)}</figure>`;
|
||||
})
|
||||
.join("") +
|
||||
"</div>"
|
||||
: "";
|
||||
|
||||
const FMG = `<a href="https://azgaar.github.io/Fantasy-Map-Generator" target="_blank">Azgaar's Fantasy Map Generator</a>`;
|
||||
const license = `<a target="_blank" href="https://github.com/Azgaar/Armoria#license">the license</a>`;
|
||||
const html = `<!DOCTYPE html><html><head><title>${mapName.value} Emblems Gallery</title></head>
|
||||
<style type="text/css">
|
||||
body { margin: 0; padding: 1em; font-family: serif; }
|
||||
h1, h2 { font-family: 'Forum'; }
|
||||
div { width: 100%; max-width: 1018px; margin: 0 auto; border-bottom: 1px solid #ddd; }
|
||||
figure { margin: 0 0 2em; display: inline-block; transition: .2s; }
|
||||
figure:hover { background-color: #f6f6f6; }
|
||||
figcaption { text-align: center; margin: .4em 0; width: 200px; font-family: 'Overlock SC' }
|
||||
address { width: 100%; max-width: 1018px; margin: 0 auto; }
|
||||
a { color: black; }
|
||||
figure > a { text-decoration: none; }
|
||||
div > a { float: right; font-family: monospace; margin-top: .8em; }
|
||||
</style>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Forum&family=Overlock+SC" rel="stylesheet">
|
||||
<body>
|
||||
<div><h1>${mapName.value} Emblems Gallery</h1></div>
|
||||
${stateSection}
|
||||
${provinceSections}
|
||||
${burgSections}
|
||||
${neutralsSection}
|
||||
<address>Generated by ${FMG}. The tool is free, but images may be copyrighted, see ${license}</address>
|
||||
</body></html>`;
|
||||
const html = /* html */ `<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>${mapName.value} Emblems Gallery</title>
|
||||
</head>
|
||||
<style type="text/css">
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 1em;
|
||||
font-family: serif;
|
||||
}
|
||||
h1,
|
||||
h2 {
|
||||
font-family: "Forum";
|
||||
}
|
||||
div {
|
||||
width: 100%;
|
||||
max-width: 1018px;
|
||||
margin: 0 auto;
|
||||
border-bottom: 1px solid #ddd;
|
||||
}
|
||||
figure {
|
||||
margin: 0 0 2em;
|
||||
display: inline-block;
|
||||
transition: 0.2s;
|
||||
}
|
||||
figure:hover {
|
||||
background-color: #f6f6f6;
|
||||
}
|
||||
figcaption {
|
||||
text-align: center;
|
||||
margin: 0.4em 0;
|
||||
width: 200px;
|
||||
font-family: "Overlock SC";
|
||||
}
|
||||
address {
|
||||
width: 100%;
|
||||
max-width: 1018px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
a {
|
||||
color: black;
|
||||
}
|
||||
figure > a {
|
||||
text-decoration: none;
|
||||
}
|
||||
div > a {
|
||||
float: right;
|
||||
font-family: monospace;
|
||||
margin-top: 0.8em;
|
||||
}
|
||||
</style>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Forum&family=Overlock+SC" rel="stylesheet" />
|
||||
<body>
|
||||
<div><h1>${mapName.value} Emblems Gallery</h1></div>
|
||||
${stateSection} ${provinceSections} ${burgSections} ${neutralsSection}
|
||||
<address>Generated by ${FMG}. The tool is free, but images may be copyrighted, see ${license}</address>
|
||||
</body>
|
||||
</html>`;
|
||||
downloadFile(html, name + ".html", "text/plain");
|
||||
}
|
||||
}
|
||||
|
|
@ -409,9 +482,9 @@ function editEmblem(type, id, el) {
|
|||
async function renderAllEmblems(states, provinces, burgs) {
|
||||
tip("Preparing for download...", true, "warn");
|
||||
|
||||
const statePromises = states.map(state => COArenderer.trigger("stateCOA"+state.i, state.coa));
|
||||
const provincePromises = provinces.map(province => COArenderer.trigger("provinceCOA"+province.i, province.coa));
|
||||
const burgPromises = burgs.map(burg => COArenderer.trigger("burgCOA"+burg.i, burg.coa));
|
||||
const statePromises = states.map(state => COArenderer.trigger("stateCOA" + state.i, state.coa));
|
||||
const provincePromises = provinces.map(province => COArenderer.trigger("provinceCOA" + province.i, province.coa));
|
||||
const burgPromises = burgs.map(burg => COArenderer.trigger("burgCOA" + burg.i, burg.coa));
|
||||
const promises = [...statePromises, ...provincePromises, ...burgPromises];
|
||||
|
||||
return Promise.allSettled(promises).then(res => clearMainTip());
|
||||
|
|
@ -419,10 +492,11 @@ function editEmblem(type, id, el) {
|
|||
|
||||
function dragEmblem() {
|
||||
const tr = parseTransform(this.getAttribute("transform"));
|
||||
const x = +tr[0] - d3.event.x, y = +tr[1] - d3.event.y;
|
||||
const x = +tr[0] - d3.event.x,
|
||||
y = +tr[1] - d3.event.y;
|
||||
|
||||
d3.event.on("drag", function() {
|
||||
const transform = `translate(${(x + d3.event.x)},${(y + d3.event.y)})`;
|
||||
d3.event.on("drag", function () {
|
||||
const transform = `translate(${x + d3.event.x},${y + d3.event.y})`;
|
||||
this.setAttribute("transform", transform);
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -405,7 +405,7 @@ document.querySelectorAll("[data-locked]").forEach(function (e) {
|
|||
|
||||
// lock option
|
||||
function lock(id) {
|
||||
const input = document.querySelector("[data-stored=\"" + id + "\"]");
|
||||
const input = document.querySelector('[data-stored="' + id + '"]');
|
||||
if (input) localStorage.setItem(id, input.value);
|
||||
const el = document.getElementById("lock_" + id);
|
||||
if (!el) return;
|
||||
|
|
@ -467,15 +467,18 @@ function showInfo() {
|
|||
const QAA = link("https://github.com/Azgaar/Fantasy-Map-Generator/wiki/Q&A", "Q&A page");
|
||||
const VideoTutorial = link("https://youtube.com/playlist?list=PLtgiuDC8iVR2gIG8zMTRn7T_L0arl9h1C", "Video tutorial");
|
||||
|
||||
alertMessage.innerHTML = `
|
||||
<b>Fantasy Map Generator</b> (FMG) is a free open-source application.
|
||||
It means that you own all created maps and can use them as you wish.
|
||||
alertMessage.innerHTML = /* html */ `<b>Fantasy Map Generator</b> (FMG) is a free open-source application. It means that you own all created maps and can use them as
|
||||
you wish.
|
||||
|
||||
<p>The development is community-backed, you can donate on ${Patreon}.
|
||||
You can also help creating overviews, tutorials and spreding the word about the Generator.</p>
|
||||
<p>
|
||||
The development is community-backed, you can donate on ${Patreon}. You can also help creating overviews, tutorials and spreding the word about the
|
||||
Generator.
|
||||
</p>
|
||||
|
||||
<p>The best way to get help is to contact the community on ${Discord} and ${Reddit}.
|
||||
Before asking questions, please check out the ${QuickStart}, the ${QAA}, and ${VideoTutorial}.</p>
|
||||
<p>
|
||||
The best way to get help is to contact the community on ${Discord} and ${Reddit}. Before asking questions, please check out the ${QuickStart}, the ${QAA},
|
||||
and ${VideoTutorial}.
|
||||
</p>
|
||||
|
||||
<p>Check out our another project: ${Armoria} — heraldry generator and editor.</p>
|
||||
|
||||
|
|
|
|||
|
|
@ -2,12 +2,14 @@
|
|||
|
||||
function editHeightmap() {
|
||||
void (function selectEditMode() {
|
||||
alertMessage.innerHTML = `Heightmap is a core element on which all other data (rivers, burgs, states etc) is based.
|
||||
So the best edit approach is to <i>erase</i> the secondary data and let the system automatically regenerate it on edit completion.
|
||||
alertMessage.innerHTML = /* html */ `Heightmap is a core element on which all other data (rivers, burgs, states etc) is based. So the best edit approach is to
|
||||
<i>erase</i> the secondary data and let the system automatically regenerate it on edit completion.
|
||||
<p><i>Erase</i> mode also allows you Convert an Image into a heightmap or use Template Editor.</p>
|
||||
<p>You can <i>keep</i> the data, but you won't be able to change the coastline.</p>
|
||||
<p>Try <i>risk</i> mode to change the coastline and keep the data. The data will be restored as much as possible, but it can cause unpredictable errors.</p>
|
||||
<p>Please <span class="pseudoLink" onclick=dowloadMap(); editHeightmap();>save the map</span> before editing the heightmap!</p>
|
||||
<p>
|
||||
Try <i>risk</i> mode to change the coastline and keep the data. The data will be restored as much as possible, but it can cause unpredictable errors.
|
||||
</p>
|
||||
<p>Please <span class="pseudoLink" onclick="dowloadMap();" editHeightmap();>save the map</span> before editing the heightmap!</p>
|
||||
<p style="margin-bottom: 0">Check out ${link("https://github.com/Azgaar/Fantasy-Map-Generator/wiki/Heightmap-customization", "wiki")} for guidance.</p>`;
|
||||
|
||||
$("#alert").dialog({
|
||||
|
|
@ -107,7 +109,7 @@ function editHeightmap() {
|
|||
heightmapInfoX.innerHTML = rn(p[0]);
|
||||
heightmapInfoY.innerHTML = rn(p[1]);
|
||||
heightmapInfoCell.innerHTML = cell;
|
||||
heightmapInfoHeight.innerHTML = `${grid.cells.h[cell]} (${getHeight(grid.cells.h[cell])})`;
|
||||
heightmapInfoHeight.innerHTML = /* html */ `${grid.cells.h[cell]} (${getHeight(grid.cells.h[cell])})`;
|
||||
if (tooltip.dataset.main) showMainTip();
|
||||
|
||||
// move radius circle if drag mode is active
|
||||
|
|
@ -485,7 +487,7 @@ function editHeightmap() {
|
|||
|
||||
function updateStatistics() {
|
||||
const landCells = grid.cells.h.reduce((s, h) => (h >= 20 ? s + 1 : s));
|
||||
landmassCounter.innerHTML = `${landCells} (${rn((landCells / grid.cells.i.length) * 100)}%)`;
|
||||
landmassCounter.innerHTML = /* html */ `${landCells} (${rn((landCells / grid.cells.i.length) * 100)}%)`;
|
||||
landmassAverage.innerHTML = rn(d3.mean(grid.cells.h));
|
||||
}
|
||||
|
||||
|
|
@ -1247,11 +1249,8 @@ function editHeightmap() {
|
|||
function closeImageConverter(event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
alertMessage.innerHTML = `
|
||||
Are you sure you want to close the Image Converter?
|
||||
Click "Cancel" to geck back to convertion.
|
||||
Click "Complete" to apply the conversion.
|
||||
Click "Close" to exit conversion mode and restore previous heightmap`;
|
||||
alertMessage.innerHTML = /* html */ ` Are you sure you want to close the Image Converter? Click "Cancel" to geck back to convertion. Click "Complete" to apply
|
||||
the conversion. Click "Close" to exit conversion mode and restore previous heightmap`;
|
||||
|
||||
$("#alert").dialog({
|
||||
resizable: false,
|
||||
|
|
|
|||
|
|
@ -12,7 +12,8 @@ function editIce() {
|
|||
ice.selectAll("*").classed("draggable", true).call(d3.drag().on("drag", dragElement));
|
||||
|
||||
$("#iceEditor").dialog({
|
||||
title: "Edit "+type, resizable: false,
|
||||
title: "Edit " + type,
|
||||
resizable: false,
|
||||
position: {my: "center top+60", at: "top", of: d3.event, collision: "fit"},
|
||||
close: closeEditor
|
||||
});
|
||||
|
|
@ -30,8 +31,9 @@ function editIce() {
|
|||
function randomizeShape() {
|
||||
const c = grid.points[+elSelected.attr("cell")];
|
||||
const s = +elSelected.attr("size");
|
||||
const i = ra(grid.cells.i), cn = grid.points[i];
|
||||
const poly = getGridPolygon(i).map(p => [p[0]-cn[0], p[1]-cn[1]]);
|
||||
const i = ra(grid.cells.i),
|
||||
cn = grid.points[i];
|
||||
const poly = getGridPolygon(i).map(p => [p[0] - cn[0], p[1] - cn[1]]);
|
||||
const points = poly.map(p => [rn(c[0] + p[0] * s, 2), rn(c[1] + p[1] * s, 2)]);
|
||||
elSelected.attr("points", points);
|
||||
}
|
||||
|
|
@ -39,10 +41,13 @@ function editIce() {
|
|||
function changeSize() {
|
||||
const c = grid.points[+elSelected.attr("cell")];
|
||||
const s = +elSelected.attr("size");
|
||||
const flat = elSelected.attr("points").split(",").map(el => +el);
|
||||
const flat = elSelected
|
||||
.attr("points")
|
||||
.split(",")
|
||||
.map(el => +el);
|
||||
const pairs = [];
|
||||
while (flat.length) pairs.push(flat.splice(0,2));
|
||||
const poly = pairs.map(p => [(p[0]-c[0]) / s, (p[1]-c[1]) / s]);
|
||||
while (flat.length) pairs.push(flat.splice(0, 2));
|
||||
const poly = pairs.map(p => [(p[0] - c[0]) / s, (p[1] - c[1]) / s]);
|
||||
const size = +this.value;
|
||||
const points = poly.map(p => [rn(c[0] + p[0] * size, 2), rn(c[1] + p[1] * size, 2)]);
|
||||
elSelected.attr("points", points).attr("size", size);
|
||||
|
|
@ -65,7 +70,7 @@ function editIce() {
|
|||
const c = grid.points[i];
|
||||
const s = +document.getElementById("iceSize").value;
|
||||
|
||||
const points = getGridPolygon(i).map(p => [(p[0] + (c[0]-p[0]) / s)|0, (p[1] + (c[1]-p[1]) / s)|0]);
|
||||
const points = getGridPolygon(i).map(p => [(p[0] + (c[0] - p[0]) / s) | 0, (p[1] + (c[1] - p[1]) / s) | 0]);
|
||||
const iceberg = ice.append("polygon").attr("points", points).attr("cell", i).attr("size", s);
|
||||
iceberg.call(d3.drag().on("drag", dragElement));
|
||||
if (d3.event.shiftKey === false) toggleAdd();
|
||||
|
|
@ -73,26 +78,32 @@ function editIce() {
|
|||
|
||||
function removeIce() {
|
||||
const type = elSelected.attr("type") ? "Glacier" : "Iceberg";
|
||||
alertMessage.innerHTML = `Are you sure you want to remove the ${type}?`;
|
||||
$("#alert").dialog({resizable: false, title: "Remove "+type,
|
||||
alertMessage.innerHTML = /* html */ `Are you sure you want to remove the ${type}?`;
|
||||
$("#alert").dialog({
|
||||
resizable: false,
|
||||
title: "Remove " + type,
|
||||
buttons: {
|
||||
Remove: function() {
|
||||
Remove: function () {
|
||||
$(this).dialog("close");
|
||||
elSelected.remove();
|
||||
$("#iceEditor").dialog("close");
|
||||
},
|
||||
Cancel: function() {$(this).dialog("close");}
|
||||
Cancel: function () {
|
||||
$(this).dialog("close");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function dragElement() {
|
||||
const tr = parseTransform(this.getAttribute("transform"));
|
||||
const dx = +tr[0] - d3.event.x, dy = +tr[1] - d3.event.y;
|
||||
const dx = +tr[0] - d3.event.x,
|
||||
dy = +tr[1] - d3.event.y;
|
||||
|
||||
d3.event.on("drag", function() {
|
||||
const x = d3.event.x, y = d3.event.y;
|
||||
this.setAttribute("transform", `translate(${(dx+x)},${(dy+y)})`);
|
||||
d3.event.on("drag", function () {
|
||||
const x = d3.event.x,
|
||||
y = d3.event.y;
|
||||
this.setAttribute("transform", `translate(${dx + x},${dy + y})`);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -257,9 +257,10 @@ function editLabel() {
|
|||
const group = elSelected.node().parentNode.id;
|
||||
const basic = group === "states" || group === "addedLabels";
|
||||
const count = elSelected.node().parentNode.childElementCount;
|
||||
alertMessage.innerHTML = `Are you sure you want to remove
|
||||
${basic ? "all elements in the group" : "the entire label group"}?
|
||||
<br><br>Labels to be removed: ${count}`;
|
||||
alertMessage.innerHTML = /* html */ `Are you sure you want to remove ${
|
||||
basic ? "all elements in the group" : "the entire label group"
|
||||
}? <br /><br />Labels to be
|
||||
removed: ${count}`;
|
||||
$("#alert").dialog({
|
||||
resizable: false,
|
||||
title: "Remove route group",
|
||||
|
|
|
|||
|
|
@ -5,7 +5,8 @@ function editLake() {
|
|||
if (layerIsOn("toggleCells")) toggleCells();
|
||||
|
||||
$("#lakeEditor").dialog({
|
||||
title: "Edit Lake", resizable: false,
|
||||
title: "Edit Lake",
|
||||
resizable: false,
|
||||
position: {my: "center top+20", at: "top", of: d3.event, collision: "fit"},
|
||||
close: closeLakesEditor
|
||||
});
|
||||
|
|
@ -71,23 +72,41 @@ function editLake() {
|
|||
function drawLakeVertices() {
|
||||
const v = getLake().vertices; // lake outer vertices
|
||||
|
||||
const c = [... new Set(v.map(v => pack.vertices.c[v]).flat())];
|
||||
debug.select("#vertices").selectAll("polygon").data(c).enter().append("polygon")
|
||||
.attr("points", d => getPackPolygon(d)).attr("data-c", d => d);
|
||||
const c = [...new Set(v.map(v => pack.vertices.c[v]).flat())];
|
||||
debug
|
||||
.select("#vertices")
|
||||
.selectAll("polygon")
|
||||
.data(c)
|
||||
.enter()
|
||||
.append("polygon")
|
||||
.attr("points", d => getPackPolygon(d))
|
||||
.attr("data-c", d => d);
|
||||
|
||||
debug.select("#vertices").selectAll("circle").data(v).enter().append("circle")
|
||||
.attr("cx", d => pack.vertices.p[d][0]).attr("cy", d => pack.vertices.p[d][1])
|
||||
.attr("r", .4).attr("data-v", d => d).call(d3.drag().on("drag", dragVertex))
|
||||
debug
|
||||
.select("#vertices")
|
||||
.selectAll("circle")
|
||||
.data(v)
|
||||
.enter()
|
||||
.append("circle")
|
||||
.attr("cx", d => pack.vertices.p[d][0])
|
||||
.attr("cy", d => pack.vertices.p[d][1])
|
||||
.attr("r", 0.4)
|
||||
.attr("data-v", d => d)
|
||||
.call(d3.drag().on("drag", dragVertex))
|
||||
.on("mousemove", () => tip("Drag to move the vertex, please use for fine-tuning only. Edit heightmap to change actual cell heights"));
|
||||
}
|
||||
|
||||
function dragVertex() {
|
||||
const x = rn(d3.event.x, 2), y = rn(d3.event.y, 2);
|
||||
const x = rn(d3.event.x, 2),
|
||||
y = rn(d3.event.y, 2);
|
||||
this.setAttribute("cx", x);
|
||||
this.setAttribute("cy", y);
|
||||
const v = +this.dataset.v;
|
||||
pack.vertices.p[v] = [x, y];
|
||||
debug.select("#vertices").selectAll("polygon").attr("points", d => getPackPolygon(d));
|
||||
debug
|
||||
.select("#vertices")
|
||||
.selectAll("polygon")
|
||||
.attr("points", d => getPackPolygon(d));
|
||||
redrawLake();
|
||||
}
|
||||
|
||||
|
|
@ -97,7 +116,7 @@ function editLake() {
|
|||
const points = feature.vertices.map(v => pack.vertices.p[v]);
|
||||
const d = round(lineGen(points));
|
||||
elSelected.attr("d", d);
|
||||
defs.select("mask#land > path#land_"+feature.i).attr("d", d); // update land mask
|
||||
defs.select("mask#land > path#land_" + feature.i).attr("d", d); // update land mask
|
||||
|
||||
const unit = areaUnit.value === "square" ? " " + distanceUnitInput.value + "²" : " " + areaUnit.value;
|
||||
feature.area = Math.abs(d3.polygonArea(points));
|
||||
|
|
@ -115,7 +134,7 @@ function editLake() {
|
|||
|
||||
function generateNameRandom() {
|
||||
const lake = getLake();
|
||||
lake.name = lakeName.value = Names.getBase(rand(nameBases.length-1));
|
||||
lake.name = lakeName.value = Names.getBase(rand(nameBases.length - 1));
|
||||
}
|
||||
|
||||
function selectLakeGroup(node) {
|
||||
|
|
@ -123,7 +142,7 @@ function editLake() {
|
|||
const select = document.getElementById("lakeGroup");
|
||||
select.options.length = 0; // remove all options
|
||||
|
||||
lakes.selectAll("g").each(function() {
|
||||
lakes.selectAll("g").each(function () {
|
||||
select.options.add(new Option(this.id, this.id, false, this.id === group));
|
||||
});
|
||||
}
|
||||
|
|
@ -145,8 +164,14 @@ function editLake() {
|
|||
}
|
||||
|
||||
function createNewGroup() {
|
||||
if (!this.value) {tip("Please provide a valid group name"); return;}
|
||||
const group = this.value.toLowerCase().replace(/ /g, "_").replace(/[^\w\s]/gi, "");
|
||||
if (!this.value) {
|
||||
tip("Please provide a valid group name");
|
||||
return;
|
||||
}
|
||||
const group = this.value
|
||||
.toLowerCase()
|
||||
.replace(/ /g, "_")
|
||||
.replace(/[^\w\s]/gi, "");
|
||||
|
||||
if (document.getElementById(group)) {
|
||||
tip("Element with this id already exists. Please provide a unique name", false, "error");
|
||||
|
|
@ -189,11 +214,13 @@ function editLake() {
|
|||
}
|
||||
|
||||
const count = elSelected.node().parentNode.childElementCount;
|
||||
alertMessage.innerHTML = `Are you sure you want to remove the group?
|
||||
All lakes of the group (${count}) will be turned into Freshwater`;
|
||||
$("#alert").dialog({resizable: false, title: "Remove lake group", width:"26em",
|
||||
alertMessage.innerHTML = /* html */ `Are you sure you want to remove the group? All lakes of the group (${count}) will be turned into Freshwater`;
|
||||
$("#alert").dialog({
|
||||
resizable: false,
|
||||
title: "Remove lake group",
|
||||
width: "26em",
|
||||
buttons: {
|
||||
Remove: function() {
|
||||
Remove: function () {
|
||||
$(this).dialog("close");
|
||||
const freshwater = document.getElementById("freshwater");
|
||||
const groupEl = document.getElementById(group);
|
||||
|
|
@ -204,7 +231,9 @@ function editLake() {
|
|||
document.getElementById("lakeGroup").selectedOptions[0].remove();
|
||||
document.getElementById("lakeGroup").value = "freshwater";
|
||||
},
|
||||
Cancel: function() {$(this).dialog("close");}
|
||||
Cancel: function () {
|
||||
$(this).dialog("close");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -75,18 +75,30 @@ function overviewMilitary() {
|
|||
const sortData = options.military.map(u => `data-${u.name}="${getForces(u)}"`).join(" ");
|
||||
const lineData = options.military.map(u => `<div data-type="${u.name}" data-tip="State ${u.name} units number">${getForces(u)}</div>`).join(" ");
|
||||
|
||||
lines += `<div class="states" data-id=${s.i} data-state="${s.name}" ${sortData} data-total="${total}"
|
||||
data-population="${population}" data-rate="${rate}" data-alert="${s.alert}">
|
||||
lines += /* html */ `<div
|
||||
class="states"
|
||||
data-id=${s.i}
|
||||
data-state="${s.name}"
|
||||
${sortData}
|
||||
data-total="${total}"
|
||||
data-population="${population}"
|
||||
data-rate="${rate}"
|
||||
data-alert="${s.alert}"
|
||||
>
|
||||
<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 />
|
||||
${lineData}
|
||||
<div data-type="total" data-tip="Total state military personnel (considering crew)" style="font-weight: bold">${si(total)}</div>
|
||||
<div data-type="population" data-tip="State population">${si(population)}</div>
|
||||
<div data-type="rate" data-tip="Military personnel rate (% of state population). Depends on war alert">${rn(rate, 2)}%</div>
|
||||
<input data-tip="War Alert. Editable modifier to military forces number, depends of political situation" style="width:4.1em" type="number" min=0 step=.01 value="${rn(
|
||||
s.alert,
|
||||
2
|
||||
)}">
|
||||
<input
|
||||
data-tip="War Alert. Editable modifier to military forces number, depends of political situation"
|
||||
style="width:4.1em"
|
||||
type="number"
|
||||
min="0"
|
||||
step=".01"
|
||||
value="${rn(s.alert, 2)}"
|
||||
/>
|
||||
<span data-tip="Show regiments list" class="icon-list-bullet pointer"></span>
|
||||
</div>`;
|
||||
}
|
||||
|
|
@ -290,21 +302,28 @@ function overviewMilitary() {
|
|||
${getLimitText(unit[attr])}
|
||||
</button>`;
|
||||
|
||||
row.innerHTML = `<td><button data-type="icon" data-tip="Click to select unit icon">${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>
|
||||
row.innerHTML = /* html */ `<td><button data-type="icon" data-tip="Click to select unit icon">${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>
|
||||
<td>${getLimitButton("cultures")}</td>
|
||||
<td>${getLimitButton("religions")}</td>
|
||||
<td><input data-tip="Enter conscription percentage for rural population" type="number" min=0 max=100 step=.01 value="${rural}"></td>
|
||||
<td><input data-tip="Enter conscription percentage for urban population" type="number" min=0 max=100 step=.01 value="${urban}"></td>
|
||||
<td><input data-tip="Enter average number of people in crew (for total personnel calculation)" type="number" min=1 step=1 value="${crew}"></td>
|
||||
<td><input data-tip="Enter military power (used for battle simulation)" type="number" min=0 step=.1 value="${power}"></td>
|
||||
<td><select data-tip="Select unit type to apply special rules on forces recalculation">${typeOptions}</select></td>
|
||||
<td><input data-tip="Enter conscription percentage for rural population" type="number" min="0" max="100" step=".01" value="${rural}" /></td>
|
||||
<td><input data-tip="Enter conscription percentage for urban population" type="number" min="0" max="100" step=".01" value="${urban}" /></td>
|
||||
<td><input data-tip="Enter average number of people in crew (for total personnel calculation)" type="number" min="1" step="1" value="${crew}" /></td>
|
||||
<td><input data-tip="Enter military power (used for battle simulation)" type="number" min="0" step=".1" value="${power}" /></td>
|
||||
<td>
|
||||
<select data-tip="Select unit type to apply special rules on forces recalculation">
|
||||
${typeOptions}
|
||||
</select>
|
||||
</td>
|
||||
<td data-tip="Check if unit is <b>separate</b> and can be stacked only with the same units">
|
||||
<input id="${name}Separate" type="checkbox" class="checkbox" ${separate ? "checked" : ""}>
|
||||
<label for="${name}Separate" class="checkbox-label"></label></td>
|
||||
<td data-tip="Remove the unit"><span data-tip="Remove unit type" class="icon-trash-empty pointer" onclick="this.parentElement.parentElement.remove();"></span></td>`;
|
||||
<input id="${name}Separate" type="checkbox" class="checkbox" ${separate ? "checked" : ""} />
|
||||
<label for="${name}Separate" class="checkbox-label"></label>
|
||||
</td>
|
||||
<td data-tip="Remove the unit">
|
||||
<span data-tip="Remove unit type" class="icon-trash-empty pointer" onclick="this.parentElement.parentElement.remove();"></span>
|
||||
</td>`;
|
||||
tableBody.appendChild(row);
|
||||
}
|
||||
|
||||
|
|
@ -326,7 +345,12 @@ function overviewMilitary() {
|
|||
<label for="el${i}" class="checkbox-label">${fullName || name}</label>
|
||||
</td></tr>`
|
||||
);
|
||||
alertMessage.innerHTML = `<b>Limit unit by ${type}:</b><table style="margin-top:.3em"><tbody>${lines.join("")}</tbody></table>`;
|
||||
alertMessage.innerHTML = /* html */ `<b>Limit unit by ${type}:</b>
|
||||
<table style="margin-top:.3em">
|
||||
<tbody>
|
||||
${lines.join("")}
|
||||
</tbody>
|
||||
</table>`;
|
||||
|
||||
$("#alert").dialog({
|
||||
width: fitContent(),
|
||||
|
|
|
|||
|
|
@ -154,15 +154,15 @@ function editNamesbase() {
|
|||
return "<span data-tip='Namesbase variety is good' style='color:green'>[good]</span>";
|
||||
};
|
||||
|
||||
alertMessage.innerHTML = `<div style="line-height: 1.6em; max-width: 20em">
|
||||
alertMessage.innerHTML = /* html */ `<div style="line-height: 1.6em; max-width: 20em">
|
||||
<div data-tip="Number of names provided">Namesbase length: ${length} ${getLengthQuality()}</div>
|
||||
<div data-tip="Average number of generation variants for each key in the chain">Namesbase variety: ${variety} ${getVarietyLevel()}</div>
|
||||
<hr>
|
||||
<hr />
|
||||
<div data-tip="The shortest name length">Min name length: ${d3.min(wordsLength)}</div>
|
||||
<div data-tip="The longest name length">Max name length: ${d3.max(wordsLength)}</div>
|
||||
<div data-tip="Average name length">Mean name length: ${rn(d3.mean(wordsLength), 1)}</div>
|
||||
<div data-tip="Common name length">Median name length: ${d3.median(wordsLength)}</div>
|
||||
<hr>
|
||||
<hr />
|
||||
<div data-tip="Characters outside of Basic Latin have bad font support">Non-basic chars: ${nonBasicLatinChars}</div>
|
||||
<div data-tip="Characters that are frequently (more than 3 times) doubled">Doubled chars: ${doubled.join("")}</div>
|
||||
<div data-tip="Names used more than one time">Duplicates: ${duplicates}</div>
|
||||
|
|
@ -196,7 +196,7 @@ function editNamesbase() {
|
|||
}
|
||||
|
||||
function namesbaseRestoreDefault() {
|
||||
alertMessage.innerHTML = `Are you sure you want to restore default namesbase?`;
|
||||
alertMessage.innerHTML = /* html */ `Are you sure you want to restore default namesbase?`;
|
||||
$("#alert").dialog({
|
||||
resizable: false,
|
||||
title: "Restore default data",
|
||||
|
|
|
|||
|
|
@ -296,7 +296,9 @@ function showSeedHistoryDialog() {
|
|||
const button = `<i data-tip="Click to generate a map with this seed" onclick="restoreSeed(${i})" class="icon-history optionsSeedRestore"></i>`;
|
||||
return `<li>Seed: ${h.seed} ${button}. Size: ${h.width}x${h.height}. Template: ${h.template}. Created: ${created}</li>`;
|
||||
});
|
||||
alertMessage.innerHTML = `<ol style="margin: 0; padding-left: 1.5em">${lines.join("")}</ol>`;
|
||||
alertMessage.innerHTML = /* html */ `<ol style="margin: 0; padding-left: 1.5em">
|
||||
${lines.join("")}
|
||||
</ol>`;
|
||||
|
||||
$("#alert").dialog({
|
||||
resizable: false,
|
||||
|
|
@ -677,8 +679,8 @@ function regeneratePrompt(source) {
|
|||
const workingTime = (Date.now() - last(mapHistory).created) / 60000; // minutes
|
||||
if (workingTime < 5) return regenerateMap(source);
|
||||
|
||||
alertMessage.innerHTML = `Are you sure you want to generate a new map?<br>
|
||||
All unsaved changes made to the current map will be lost`;
|
||||
alertMessage.innerHTML = /* html */ `Are you sure you want to generate a new map?<br />
|
||||
All unsaved changes made to the current map will be lost`;
|
||||
$("#alert").dialog({
|
||||
resizable: false,
|
||||
title: "Generate new map",
|
||||
|
|
@ -752,13 +754,13 @@ async function showLoadPane() {
|
|||
document.getElementById("loadFromDropboxSelect").style.display = "block";
|
||||
const loadFromDropboxButtons = document.getElementById("loadFromDropboxButtons");
|
||||
const fileSelect = document.getElementById("loadFromDropboxSelect");
|
||||
fileSelect.innerHTML = `<option value="" disabled selected>Loading...</option>`;
|
||||
fileSelect.innerHTML = /* html */ `<option value="" disabled selected>Loading...</option>`;
|
||||
|
||||
const files = await Cloud.providers.dropbox.list();
|
||||
|
||||
if (!files) {
|
||||
loadFromDropboxButtons.style.display = "none";
|
||||
fileSelect.innerHTML = `<option value="" disabled selected>Save files to Dropbox first</option>`;
|
||||
fileSelect.innerHTML = /* html */ `<option value="" disabled selected>Save files to Dropbox first</option>`;
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -841,7 +843,7 @@ function openSaveTiles() {
|
|||
loading = setInterval(() => (status.innerHTML += "."), 1000);
|
||||
saveTiles().then(() => {
|
||||
clearInterval(loading);
|
||||
status.innerHTML = `Done. Check file in "Downloads" (crtl + J)`;
|
||||
status.innerHTML = /* html */ `Done. Check file in "Downloads" (crtl + J)`;
|
||||
setTimeout(() => (status.innerHTML = ""), 8000);
|
||||
});
|
||||
},
|
||||
|
|
@ -874,7 +876,7 @@ function updateTilesOptions() {
|
|||
const sizeY = graphHeight * scale * tilesY;
|
||||
const totalSize = sizeX * sizeY;
|
||||
|
||||
tileSize.innerHTML = `${sizeX} x ${sizeY} px`;
|
||||
tileSize.innerHTML = /* html */ `${sizeX} x ${sizeY} px`;
|
||||
tileSize.style.color = totalSize > 1e9 ? "#d00b0b" : totalSize > 1e8 ? "#9e6409" : "#1a941a";
|
||||
|
||||
// draw tiles
|
||||
|
|
|
|||
|
|
@ -131,25 +131,37 @@ function editProvinces() {
|
|||
const separable = p.burg && p.burg !== pack.states[p.state].capital;
|
||||
const focused = defs.select("#fog #focusProvince" + p.i).size();
|
||||
COArenderer.trigger("provinceCOA" + p.i, p.coa);
|
||||
lines += `<div class="states" data-id=${p.i} data-name="${p.name}" data-form="${p.formName}" data-color="${
|
||||
p.color
|
||||
}" data-capital="${capital}" data-state="${stateName}" data-area=${area} data-population=${population}>
|
||||
lines += /* html */ `<div
|
||||
class="states"
|
||||
data-id=${p.i}
|
||||
data-name="${p.name}"
|
||||
data-form="${p.formName}"
|
||||
data-color="${p.color}"
|
||||
data-capital="${capital}"
|
||||
data-state="${stateName}"
|
||||
data-area=${area}
|
||||
data-population=${population}
|
||||
>
|
||||
<fill-box fill="${p.color}"></fill-box>
|
||||
<input data-tip="Province name. Click to change" class="name pointer" value="${p.name}" readonly>
|
||||
<input data-tip="Province name. Click to change" class="name pointer" value="${p.name}" readonly />
|
||||
<svg data-tip="Click to show and edit province emblem" class="coaIcon pointer hide" viewBox="0 0 200 200"><use href="#provinceCOA${p.i}"></use></svg>
|
||||
<input data-tip="Province form name. Click to change" class="name pointer hide" value="${p.formName}" readonly>
|
||||
<input data-tip="Province form name. Click to change" class="name pointer hide" value="${p.formName}" readonly />
|
||||
<span data-tip="Province capital. Click to zoom into view" class="icon-star-empty pointer hide ${p.burg ? "" : "placeholder"}"></span>
|
||||
<select data-tip="Province capital. Click to select from burgs within the state. No capital means the province is governed from the state capital" class="cultureBase hide ${
|
||||
p.burgs.length ? "" : "placeholder"
|
||||
}">${p.burgs.length ? getCapitalOptions(p.burgs, p.burg) : ""}</select>
|
||||
<select
|
||||
data-tip="Province capital. Click to select from burgs within the state. No capital means the province is governed from the state capital"
|
||||
class="cultureBase hide ${p.burgs.length ? "" : "placeholder"}"
|
||||
>
|
||||
${p.burgs.length ? getCapitalOptions(p.burgs, p.burg) : ""}
|
||||
</select>
|
||||
<input data-tip="Province owner" class="provinceOwner" value="${stateName}" disabled">
|
||||
<span data-tip="Province area" style="padding-right: 4px" class="icon-map-o hide"></span>
|
||||
<div data-tip="Province area" class="biomeArea hide">${si(area) + unit}</div>
|
||||
<span data-tip="${populationTip}" class="icon-male hide"></span>
|
||||
<div data-tip="${populationTip}" class="culturePopulation hide">${si(population)}</div>
|
||||
<span data-tip="Declare province independence (turn non-capital province with burgs into a new state)" class="icon-flag-empty ${
|
||||
separable ? "" : "placeholder"
|
||||
} hide"></span>
|
||||
<span
|
||||
data-tip="Declare province independence (turn non-capital province with burgs into a new state)"
|
||||
class="icon-flag-empty ${separable ? "" : "placeholder"} hide"
|
||||
></span>
|
||||
<span data-tip="Toggle province focus" class="icon-pin ${focused ? "" : " inactive"} hide"></span>
|
||||
<span data-tip="Remove the province" class="icon-trash-empty hide"></span>
|
||||
</div>`;
|
||||
|
|
@ -360,10 +372,9 @@ function editProvinces() {
|
|||
const total = rural + urban;
|
||||
const l = n => Number(n).toLocaleString();
|
||||
|
||||
alertMessage.innerHTML = `
|
||||
Rural: <input type="number" min=0 step=1 id="ruralPop" value=${rural} style="width:6em">
|
||||
Urban: <input type="number" min=0 step=1 id="urbanPop" value=${urban} style="width:6em" ${p.burgs.length ? "" : "disabled"}>
|
||||
<p>Total population: ${l(total)} ⇒ <span id="totalPop">${l(total)}</span> (<span id="totalPopPerc">100</span>%)</p>`;
|
||||
alertMessage.innerHTML = /* html */ ` Rural: <input type="number" min="0" step="1" id="ruralPop" value=${rural} style="width:6em" /> Urban:
|
||||
<input type="number" min="0" step="1" id="urbanPop" value=${urban} style="width:6em" ${p.burgs.length ? "" : "disabled"} />
|
||||
<p>Total population: ${l(total)} ⇒ <span id="totalPop">${l(total)}</span> (<span id="totalPopPerc">100</span>%)</p>`;
|
||||
|
||||
const update = function () {
|
||||
const totalNew = ruralPop.valueAsNumber + urbanPop.valueAsNumber;
|
||||
|
|
@ -424,7 +435,7 @@ function editProvinces() {
|
|||
}
|
||||
|
||||
function removeProvince(p) {
|
||||
alertMessage.innerHTML = `Are you sure you want to remove the province? <br>This action cannot be reverted`;
|
||||
alertMessage.innerHTML = /* html */ `Are you sure you want to remove the province? <br />This action cannot be reverted`;
|
||||
$("#alert").dialog({
|
||||
resizable: false,
|
||||
title: "Remove province",
|
||||
|
|
@ -588,7 +599,7 @@ function editProvinces() {
|
|||
const treeLayout = d3.treemap().size([w, h]).padding(2);
|
||||
|
||||
// prepare svg
|
||||
alertMessage.innerHTML = `<select id="provincesTreeType" style="display:block; margin-left:13px; font-size:11px">
|
||||
alertMessage.innerHTML = /* html */ `<select id="provincesTreeType" style="display:block; margin-left:13px; font-size:11px">
|
||||
<option value="area" selected>Area</option>
|
||||
<option value="population">Total population</option>
|
||||
<option value="rural">Rural population</option>
|
||||
|
|
@ -635,7 +646,7 @@ function editProvinces() {
|
|||
? "Urban population: " + si(urban)
|
||||
: "Population: " + si(rural + urban);
|
||||
|
||||
provinceInfo.innerHTML = `${name}. ${state}. ${value}`;
|
||||
provinceInfo.innerHTML = /* html */ `${name}. ${state}. ${value}`;
|
||||
provinceHighlightOn(ev);
|
||||
}
|
||||
|
||||
|
|
@ -1027,7 +1038,7 @@ function editProvinces() {
|
|||
}
|
||||
|
||||
function removeAllProvinces() {
|
||||
alertMessage.innerHTML = `Are you sure you want to remove all provinces? <br>This action cannot be reverted`;
|
||||
alertMessage.innerHTML = /* html */ `Are you sure you want to remove all provinces? <br />This action cannot be reverted`;
|
||||
$("#alert").dialog({
|
||||
resizable: false,
|
||||
title: "Remove all provinces",
|
||||
|
|
|
|||
|
|
@ -60,11 +60,11 @@ function overviewRegiments(state) {
|
|||
.map(u => `<div data-type="${u.name}" data-tip="${capitalize(u.name)} units number">${r.u[u.name] || 0}</div>`)
|
||||
.join(" ");
|
||||
|
||||
lines += `<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>
|
||||
<input data-tip="${s.fullName}" style="width:6em" value="${s.name}" readonly />
|
||||
<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}
|
||||
<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>
|
||||
|
|
@ -74,7 +74,7 @@ function overviewRegiments(state) {
|
|||
}
|
||||
}
|
||||
|
||||
lines += `<div id="regimentsTotalLine" class="totalLine" data-tip="Total of all displayed regiments">
|
||||
lines += /* html */ `<div id="regimentsTotalLine" class="totalLine" data-tip="Total of all displayed regiments">
|
||||
<div style="width: 21em; margin-left: 1em">Regiments: ${regiments.length}</div>
|
||||
${options.military.map(u => `<div style="width:5em">${si(d3.sum(regiments.map(r => r.u[u.name] || 0)))}</div>`).join(" ")}
|
||||
<div style="width:5em">${si(d3.sum(regiments.map(r => r.a)))}</div>
|
||||
|
|
|
|||
|
|
@ -254,7 +254,7 @@ function editReliefIcon() {
|
|||
let selection = null;
|
||||
const pressed = reliefTools.querySelector("button.pressed");
|
||||
if (pressed.id === "reliefIndividual") {
|
||||
alertMessage.innerHTML = `Are you sure you want to remove the icon?`;
|
||||
alertMessage.innerHTML = "Are you sure you want to remove the icon?";
|
||||
selection = elSelected;
|
||||
} else {
|
||||
const type = reliefIconsDiv.querySelector("svg.pressed")?.dataset.type;
|
||||
|
|
|
|||
|
|
@ -77,14 +77,26 @@ function editReligions() {
|
|||
totalPopulation += population;
|
||||
|
||||
if (r.i) {
|
||||
lines += `<div class="states religions" data-id=${r.i} data-name="${r.name}" data-color="${r.color}" data-area=${area}
|
||||
data-population=${population} data-type=${r.type} data-form=${r.form} data-deity="${r.deity ? r.deity : ""}" data-expansionism=${r.expansionism}>
|
||||
lines += /* html */ `<div
|
||||
class="states religions"
|
||||
data-id=${r.i}
|
||||
data-name="${r.name}"
|
||||
data-color="${r.color}"
|
||||
data-area=${area}
|
||||
data-population=${population}
|
||||
data-type=${r.type}
|
||||
data-form=${r.form}
|
||||
data-deity="${r.deity ? r.deity : ""}"
|
||||
data-expansionism=${r.expansionism}
|
||||
>
|
||||
<fill-box fill="${r.color}"></fill-box>
|
||||
<input data-tip="Religion name. Click and type to change" class="religionName" value="${r.name}" autocorrect="off" spellcheck="false">
|
||||
<select data-tip="Religion type" class="religionType">${getTypeOptions(r.type)}</select>
|
||||
<input data-tip="Religion form" class="religionForm hide" value="${r.form}" autocorrect="off" spellcheck="false">
|
||||
<input data-tip="Religion name. Click and type to change" class="religionName" value="${r.name}" autocorrect="off" spellcheck="false" />
|
||||
<select data-tip="Religion type" class="religionType">
|
||||
${getTypeOptions(r.type)}
|
||||
</select>
|
||||
<input data-tip="Religion form" class="religionForm hide" value="${r.form}" autocorrect="off" spellcheck="false" />
|
||||
<span data-tip="Click to re-generate supreme deity" class="icon-arrows-cw hide"></span>
|
||||
<input data-tip="Religion supreme deity" class="religionDeity hide" value="${r.deity ? r.deity : ""}" autocorrect="off" spellcheck="false">
|
||||
<input data-tip="Religion supreme deity" class="religionDeity hide" value="${r.deity ? r.deity : ""}" autocorrect="off" spellcheck="false" />
|
||||
<span data-tip="Religion area" style="padding-right: 4px" class="icon-map-o hide"></span>
|
||||
<div data-tip="Religion area" class="biomeArea hide">${si(area) + unit}</div>
|
||||
<span data-tip="${populationTip}" class="icon-male hide"></span>
|
||||
|
|
@ -93,15 +105,26 @@ function editReligions() {
|
|||
</div>`;
|
||||
} else {
|
||||
// No religion (neutral) line
|
||||
lines += `<div class="states" data-id=${r.i} data-name="${
|
||||
r.name
|
||||
}" data-color="" data-area=${area} data-population=${population} data-type="" data-form="" data-deity="" data-expansionism="">
|
||||
lines += /* html */ `<div
|
||||
class="states"
|
||||
data-id=${r.i}
|
||||
data-name="${r.name}"
|
||||
data-color=""
|
||||
data-area=${area}
|
||||
data-population=${population}
|
||||
data-type=""
|
||||
data-form=""
|
||||
data-deity=""
|
||||
data-expansionism=""
|
||||
>
|
||||
<svg width="9" height="9" class="placeholder"></svg>
|
||||
<input data-tip="Religion name. Click and type to change" class="religionName italic" value="${r.name}" autocorrect="off" spellcheck="false">
|
||||
<select data-tip="Religion type" class="religionType placeholder">${getTypeOptions(r.type)}</select>
|
||||
<input data-tip="Religion form" class="religionForm placeholder hide" value="" autocorrect="off" spellcheck="false">
|
||||
<input data-tip="Religion name. Click and type to change" class="religionName italic" value="${r.name}" autocorrect="off" spellcheck="false" />
|
||||
<select data-tip="Religion type" class="religionType placeholder">
|
||||
${getTypeOptions(r.type)}
|
||||
</select>
|
||||
<input data-tip="Religion form" class="religionForm placeholder hide" value="" autocorrect="off" spellcheck="false" />
|
||||
<span data-tip="Click to re-generate supreme deity" class="icon-arrows-cw placeholder hide"></span>
|
||||
<input data-tip="Religion supreme deity" class="religionDeity placeholder hide" value="" autocorrect="off" spellcheck="false">
|
||||
<input data-tip="Religion supreme deity" class="religionDeity placeholder hide" value="" autocorrect="off" spellcheck="false" />
|
||||
<span data-tip="Religion area" style="padding-right: 4px" class="icon-map-o hide"></span>
|
||||
<div data-tip="Religion area" class="biomeArea hide">${si(area) + unit}</div>
|
||||
<span data-tip="${populationTip}" class="icon-male hide"></span>
|
||||
|
|
@ -163,7 +186,7 @@ function editReligions() {
|
|||
const rural = r.rural * populationRate;
|
||||
const urban = r.urban * populationRate * urbanization;
|
||||
const population = rural + urban > 0 ? ". " + si(rn(rural + urban)) + " believers" : ". Extinct";
|
||||
info.innerHTML = `${r.name}${type}${form}${population}`;
|
||||
info.innerHTML = /* html */ `${r.name}${type}${form}${population}`;
|
||||
tip("Drag to change parent, drag to itself to move to the top level. Hold CTRL and click to change abbreviation");
|
||||
}
|
||||
|
||||
|
|
@ -279,11 +302,15 @@ function editReligions() {
|
|||
const l = n => Number(n).toLocaleString();
|
||||
const burgs = pack.burgs.filter(b => !b.removed && pack.cells.religion[b.cell] === religion);
|
||||
|
||||
alertMessage.innerHTML = `<p><i>Please note all population of religion territory is considered
|
||||
believers of this religion. It means believers number change will directly change population</i></p>
|
||||
Rural: <input type="number" min=0 step=1 id="ruralPop" value=${rural} style="width:6em">
|
||||
Urban: <input type="number" min=0 step=1 id="urbanPop" value=${urban} style="width:6em" ${burgs.length ? "" : "disabled"}>
|
||||
<p>Total believers: ${l(total)} ⇒ <span id="totalPop">${l(total)}</span> (<span id="totalPopPerc">100</span>%)</p>`;
|
||||
alertMessage.innerHTML = /* html */ `<p>
|
||||
<i
|
||||
>Please note all population of religion territory is considered believers of this religion. It means believers number change will directly change
|
||||
population</i
|
||||
>
|
||||
</p>
|
||||
Rural: <input type="number" min="0" step="1" id="ruralPop" value=${rural} style="width:6em" /> Urban:
|
||||
<input type="number" min="0" step="1" id="urbanPop" value=${urban} style="width:6em" ${burgs.length ? "" : "disabled"} />
|
||||
<p>Total believers: ${l(total)} ⇒ <span id="totalPop">${l(total)}</span> (<span id="totalPopPerc">100</span>%)</p>`;
|
||||
|
||||
const update = function () {
|
||||
const totalNew = ruralPop.valueAsNumber + urbanPop.valueAsNumber;
|
||||
|
|
|
|||
|
|
@ -38,14 +38,23 @@ function overviewRivers() {
|
|||
const width = rn(r.width * distanceScaleInput.value, 3) + " " + unit;
|
||||
const basin = pack.rivers.find(river => river.i === r.basin)?.name;
|
||||
|
||||
lines += `<div class="states" data-id=${r.i} data-name="${r.name}" data-type="${r.type}" data-discharge="${r.discharge}" data-length="${r.length}" data-width="${r.width}" data-basin="${basin}">
|
||||
lines += /* html */ `<div
|
||||
class="states"
|
||||
data-id=${r.i}
|
||||
data-name="${r.name}"
|
||||
data-type="${r.type}"
|
||||
data-discharge="${r.discharge}"
|
||||
data-length="${r.length}"
|
||||
data-width="${r.width}"
|
||||
data-basin="${basin}"
|
||||
>
|
||||
<span data-tip="Click to focus on river" class="icon-dot-circled pointer"></span>
|
||||
<div data-tip="River name" class="riverName">${r.name}</div>
|
||||
<div data-tip="River type name" class="riverType">${r.type}</div>
|
||||
<div data-tip="River discharge (flux power)" class="biomeArea">${discharge}</div>
|
||||
<div data-tip="River length from source to mouth" class="biomeArea">${length}</div>
|
||||
<div data-tip="River mouth width" class="biomeArea">${width}</div>
|
||||
<input data-tip="River basin (name of the main stem)" class="stateName" value="${basin}" disabled>
|
||||
<input data-tip="River basin (name of the main stem)" class="stateName" value="${basin}" disabled />
|
||||
<span data-tip="Edit river" class="icon-pencil"></span>
|
||||
<span data-tip="Remove river" class="icon-trash-empty"></span>
|
||||
</div>`;
|
||||
|
|
@ -136,8 +145,7 @@ function overviewRivers() {
|
|||
|
||||
function triggerRiverRemove() {
|
||||
const river = +this.parentNode.dataset.id;
|
||||
alertMessage.innerHTML = `Are you sure you want to remove the river?
|
||||
All tributaries will be auto-removed`;
|
||||
alertMessage.innerHTML = /* html */ `Are you sure you want to remove the river? All tributaries will be auto-removed`;
|
||||
|
||||
$("#alert").dialog({
|
||||
resizable: false,
|
||||
|
|
@ -157,7 +165,7 @@ function overviewRivers() {
|
|||
}
|
||||
|
||||
function triggerAllRiversRemove() {
|
||||
alertMessage.innerHTML = `Are you sure you want to remove all rivers?`;
|
||||
alertMessage.innerHTML = /* html */ `Are you sure you want to remove all rivers?`;
|
||||
$("#alert").dialog({
|
||||
resizable: false,
|
||||
title: "Remove all rivers",
|
||||
|
|
|
|||
|
|
@ -6,7 +6,8 @@ function editRoute(onClick) {
|
|||
if (!layerIsOn("toggleRoutes")) toggleRoutes();
|
||||
|
||||
$("#routeEditor").dialog({
|
||||
title: "Edit Route", resizable: false,
|
||||
title: "Edit Route",
|
||||
resizable: false,
|
||||
position: {my: "center top+60", at: "top", of: d3.event, collision: "fit"},
|
||||
close: closeRoutesEditor
|
||||
});
|
||||
|
|
@ -41,14 +42,14 @@ function editRoute(onClick) {
|
|||
function showEditorTips() {
|
||||
showMainTip();
|
||||
if (routeNew.classList.contains("pressed")) return;
|
||||
if (d3.event.target.id === elSelected.attr("id")) tip("Click to add a control point"); else
|
||||
if (d3.event.target.parentNode.id === "controlPoints") tip("Drag to move, click to delete the control point");
|
||||
if (d3.event.target.id === elSelected.attr("id")) tip("Click to add a control point");
|
||||
else if (d3.event.target.parentNode.id === "controlPoints") tip("Drag to move, click to delete the control point");
|
||||
}
|
||||
|
||||
function drawControlPoints(node) {
|
||||
const l = node.getTotalLength();
|
||||
const increment = l / Math.ceil(l / 4);
|
||||
for (let i=0; i <= l; i += increment) {
|
||||
for (let i = 0; i <= l; i += increment) {
|
||||
const point = node.getPointAtLength(i);
|
||||
addControlPoint([point.x, point.y]);
|
||||
}
|
||||
|
|
@ -56,8 +57,12 @@ function editRoute(onClick) {
|
|||
}
|
||||
|
||||
function addControlPoint(point, before = null) {
|
||||
debug.select("#controlPoints").insert("circle", before)
|
||||
.attr("cx", point[0]).attr("cy", point[1]).attr("r", .6)
|
||||
debug
|
||||
.select("#controlPoints")
|
||||
.insert("circle", before)
|
||||
.attr("cx", point[0])
|
||||
.attr("cy", point[1])
|
||||
.attr("r", 0.6)
|
||||
.call(d3.drag().on("drag", dragControlPoint))
|
||||
.on("click", clickControlPoint);
|
||||
}
|
||||
|
|
@ -67,7 +72,7 @@ function editRoute(onClick) {
|
|||
const controls = document.getElementById("controlPoints").querySelectorAll("circle");
|
||||
const points = Array.from(controls).map(circle => [+circle.getAttribute("cx"), +circle.getAttribute("cy")]);
|
||||
const index = getSegmentId(points, point, 2);
|
||||
addControlPoint(point, ":nth-child(" + (index+1) + ")");
|
||||
addControlPoint(point, ":nth-child(" + (index + 1) + ")");
|
||||
|
||||
redrawRoute();
|
||||
}
|
||||
|
|
@ -79,11 +84,14 @@ function editRoute(onClick) {
|
|||
}
|
||||
|
||||
function redrawRoute() {
|
||||
lineGen.curve(d3.curveCatmullRom.alpha(.1));
|
||||
lineGen.curve(d3.curveCatmullRom.alpha(0.1));
|
||||
const points = [];
|
||||
debug.select("#controlPoints").selectAll("circle").each(function() {
|
||||
points.push([this.getAttribute("cx"), this.getAttribute("cy")]);
|
||||
});
|
||||
debug
|
||||
.select("#controlPoints")
|
||||
.selectAll("circle")
|
||||
.each(function () {
|
||||
points.push([this.getAttribute("cx"), this.getAttribute("cy")]);
|
||||
});
|
||||
|
||||
elSelected.attr("d", round(lineGen(points)));
|
||||
const l = elSelected.node().getTotalLength();
|
||||
|
|
@ -98,12 +106,12 @@ function editRoute(onClick) {
|
|||
}
|
||||
|
||||
function showGroupSection() {
|
||||
document.querySelectorAll("#routeEditor > button").forEach(el => el.style.display = "none");
|
||||
document.querySelectorAll("#routeEditor > button").forEach(el => (el.style.display = "none"));
|
||||
document.getElementById("routeGroupsSelection").style.display = "inline-block";
|
||||
}
|
||||
|
||||
function hideGroupSection() {
|
||||
document.querySelectorAll("#routeEditor > button").forEach(el => el.style.display = "inline-block");
|
||||
document.querySelectorAll("#routeEditor > button").forEach(el => (el.style.display = "inline-block"));
|
||||
document.getElementById("routeGroupsSelection").style.display = "none";
|
||||
document.getElementById("routeGroupName").style.display = "none";
|
||||
document.getElementById("routeGroupName").value = "";
|
||||
|
|
@ -115,7 +123,7 @@ function editRoute(onClick) {
|
|||
const select = document.getElementById("routeGroup");
|
||||
select.options.length = 0; // remove all options
|
||||
|
||||
routes.selectAll("g").each(function() {
|
||||
routes.selectAll("g").each(function () {
|
||||
select.options.add(new Option(this.id, this.id, false, this.id === group));
|
||||
});
|
||||
}
|
||||
|
|
@ -136,8 +144,14 @@ function editRoute(onClick) {
|
|||
}
|
||||
|
||||
function createNewGroup() {
|
||||
if (!this.value) {tip("Please provide a valid group name"); return;}
|
||||
const group = this.value.toLowerCase().replace(/ /g, "_").replace(/[^\w\s]/gi, "");
|
||||
if (!this.value) {
|
||||
tip("Please provide a valid group name");
|
||||
return;
|
||||
}
|
||||
const group = this.value
|
||||
.toLowerCase()
|
||||
.replace(/ /g, "_")
|
||||
.replace(/[^\w\s]/gi, "");
|
||||
|
||||
if (document.getElementById(group)) {
|
||||
tip("Element with this id already exists. Please provide a unique name", false, "error");
|
||||
|
|
@ -174,19 +188,28 @@ function editRoute(onClick) {
|
|||
const group = elSelected.node().parentNode.id;
|
||||
const basic = ["roads", "trails", "searoutes"].includes(group);
|
||||
const count = elSelected.node().parentNode.childElementCount;
|
||||
alertMessage.innerHTML = `Are you sure you want to remove
|
||||
${basic ? "all elements in the group" : "the entire route group"}?
|
||||
<br><br>Routes to be removed: ${count}`;
|
||||
$("#alert").dialog({resizable: false, title: "Remove route group",
|
||||
alertMessage.innerHTML = /* html */ `Are you sure you want to remove ${
|
||||
basic ? "all elements in the group" : "the entire route group"
|
||||
}? <br /><br />Routes to be
|
||||
removed: ${count}`;
|
||||
$("#alert").dialog({
|
||||
resizable: false,
|
||||
title: "Remove route group",
|
||||
buttons: {
|
||||
Remove: function() {
|
||||
Remove: function () {
|
||||
$(this).dialog("close");
|
||||
$("#routeEditor").dialog("close");
|
||||
hideGroupSection();
|
||||
if (basic) routes.select("#"+group).selectAll("path").remove();
|
||||
else routes.select("#"+group).remove();
|
||||
if (basic)
|
||||
routes
|
||||
.select("#" + group)
|
||||
.selectAll("path")
|
||||
.remove();
|
||||
else routes.select("#" + group).remove();
|
||||
},
|
||||
Cancel: function() {$(this).dialog("close");}
|
||||
Cancel: function () {
|
||||
$(this).dialog("close");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -203,24 +226,31 @@ function editRoute(onClick) {
|
|||
|
||||
function clickControlPoint() {
|
||||
if (routeSplit.classList.contains("pressed")) splitRoute(this);
|
||||
else {this.remove(); redrawRoute();}
|
||||
else {
|
||||
this.remove();
|
||||
redrawRoute();
|
||||
}
|
||||
}
|
||||
|
||||
function splitRoute(clicked) {
|
||||
lineGen.curve(d3.curveCatmullRom.alpha(.1));
|
||||
lineGen.curve(d3.curveCatmullRom.alpha(0.1));
|
||||
const group = d3.select(elSelected.node().parentNode);
|
||||
routeSplit.classList.remove("pressed");
|
||||
|
||||
const points1 = [], points2 = [];
|
||||
const points1 = [],
|
||||
points2 = [];
|
||||
let points = points1;
|
||||
debug.select("#controlPoints").selectAll("circle").each(function() {
|
||||
points.push([this.getAttribute("cx"), this.getAttribute("cy")]);
|
||||
if (this === clicked) {
|
||||
points = points2;
|
||||
debug
|
||||
.select("#controlPoints")
|
||||
.selectAll("circle")
|
||||
.each(function () {
|
||||
points.push([this.getAttribute("cx"), this.getAttribute("cy")]);
|
||||
}
|
||||
this.remove();
|
||||
});
|
||||
if (this === clicked) {
|
||||
points = points2;
|
||||
points.push([this.getAttribute("cx"), this.getAttribute("cy")]);
|
||||
}
|
||||
this.remove();
|
||||
});
|
||||
|
||||
elSelected.attr("d", round(lineGen(points1)));
|
||||
const id = getNextId("route");
|
||||
|
|
@ -263,14 +293,18 @@ function editRoute(onClick) {
|
|||
|
||||
function removeRoute() {
|
||||
alertMessage.innerHTML = "Are you sure you want to remove the route?";
|
||||
$("#alert").dialog({resizable: false, title: "Remove route",
|
||||
$("#alert").dialog({
|
||||
resizable: false,
|
||||
title: "Remove route",
|
||||
buttons: {
|
||||
Remove: function() {
|
||||
Remove: function () {
|
||||
$(this).dialog("close");
|
||||
elSelected.remove();
|
||||
$("#routeEditor").dialog("close");
|
||||
},
|
||||
Cancel: function() {$(this).dialog("close");}
|
||||
Cancel: function () {
|
||||
$(this).dialog("close");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -100,24 +100,41 @@ function editStates() {
|
|||
|
||||
if (!s.i) {
|
||||
// Neutral line
|
||||
lines += `<div class="states" data-id=${s.i} data-name="${s.name}" data-cells=${s.cells} data-area=${area}
|
||||
data-population=${population} data-burgs=${s.burgs} data-color="" data-form="" data-capital="" data-culture="" data-type="" data-expansionism="">
|
||||
lines += /* html */ `<div
|
||||
class="states"
|
||||
data-id=${s.i}
|
||||
data-name="${s.name}"
|
||||
data-cells=${s.cells}
|
||||
data-area=${area}
|
||||
data-population=${population}
|
||||
data-burgs=${s.burgs}
|
||||
data-color=""
|
||||
data-form=""
|
||||
data-capital=""
|
||||
data-culture=""
|
||||
data-type=""
|
||||
data-expansionism=""
|
||||
>
|
||||
<svg width="1em" height="1em" class="placeholder"></svg>
|
||||
<input data-tip="Neutral lands name. Click to change" class="stateName name pointer italic" value="${s.name}" readonly>
|
||||
<input data-tip="Neutral lands name. Click to change" class="stateName name pointer italic" value="${s.name}" readonly />
|
||||
<svg class="coaIcon placeholder hide"></svg>
|
||||
<input class="stateForm placeholder" value="none">
|
||||
<input class="stateForm placeholder" value="none" />
|
||||
<span class="icon-star-empty placeholder hide"></span>
|
||||
<input class="stateCapital placeholder hide">
|
||||
<select class="stateCulture placeholder hide">${getCultureOptions(0)}</select>
|
||||
<input class="stateCapital placeholder hide" />
|
||||
<select class="stateCulture placeholder hide">
|
||||
${getCultureOptions(0)}
|
||||
</select>
|
||||
<span data-tip="Burgs count" style="padding-right: 1px" class="icon-dot-circled hide"></span>
|
||||
<div data-tip="Burgs count" class="stateBurgs hide">${s.burgs}</div>
|
||||
<span data-tip="Neutral lands area" style="padding-right: 4px" class="icon-map-o hide"></span>
|
||||
<div data-tip="Neutral lands area" class="biomeArea hide">${si(area) + unit}</div>
|
||||
<span data-tip="${populationTip}" class="icon-male hide"></span>
|
||||
<div data-tip="${populationTip}" class="culturePopulation hide">${si(population)}</div>
|
||||
<select class="cultureType ${hidden} placeholder show hide">${getTypeOptions(0)}</select>
|
||||
<select class="cultureType ${hidden} placeholder show hide">
|
||||
${getTypeOptions(0)}
|
||||
</select>
|
||||
<span class="icon-resize-full ${hidden} placeholder show hide"></span>
|
||||
<input class="statePower ${hidden} placeholder show hide" type="number" value=0>
|
||||
<input class="statePower ${hidden} placeholder show hide" type="number" value="0" />
|
||||
<span data-tip="Cells count" class="icon-check-empty ${hidden} show hide"></span>
|
||||
<div data-tip="Cells count" class="stateCells ${hidden} show hide">${s.cells}</div>
|
||||
</div>`;
|
||||
|
|
@ -126,26 +143,49 @@ function editStates() {
|
|||
|
||||
const capital = pack.burgs[s.capital].name;
|
||||
COArenderer.trigger("stateCOA" + s.i, s.coa);
|
||||
lines += `<div class="states" data-id=${s.i} data-name="${s.name}" data-form="${s.formName}" data-capital="${capital}"
|
||||
data-color="${s.color}" data-cells=${s.cells} data-area=${area} data-population=${population} data-burgs=${s.burgs}
|
||||
data-culture=${pack.cultures[s.culture].name} data-type=${s.type} data-expansionism=${s.expansionism}>
|
||||
lines += /* html */ `<div
|
||||
class="states"
|
||||
data-id=${s.i}
|
||||
data-name="${s.name}"
|
||||
data-form="${s.formName}"
|
||||
data-capital="${capital}"
|
||||
data-color="${s.color}"
|
||||
data-cells=${s.cells}
|
||||
data-area=${area}
|
||||
data-population=${population}
|
||||
data-burgs=${s.burgs}
|
||||
data-culture=${pack.cultures[s.culture].name}
|
||||
data-type=${s.type}
|
||||
data-expansionism=${s.expansionism}
|
||||
>
|
||||
<fill-box fill="${s.color}"></fill-box>
|
||||
<input data-tip="State name. Click to change" class="stateName name pointer" value="${s.name}" readonly>
|
||||
<input data-tip="State name. Click to change" class="stateName name pointer" value="${s.name}" readonly />
|
||||
<svg data-tip="Click to show and edit state emblem" class="coaIcon pointer hide" viewBox="0 0 200 200"><use href="#stateCOA${s.i}"></use></svg>
|
||||
<input data-tip="State form name. Click to change" class="stateForm name pointer" value="${s.formName}" readonly>
|
||||
<input data-tip="State form name. Click to change" class="stateForm name pointer" value="${s.formName}" readonly />
|
||||
<span data-tip="State capital. Click to zoom into view" class="icon-star-empty pointer hide"></span>
|
||||
<input data-tip="Capital name. Click and type to rename" class="stateCapital hide" value="${capital}" autocorrect="off" spellcheck="false"/>
|
||||
<select data-tip="Dominant culture. Click to change" class="stateCulture hide">${getCultureOptions(s.culture)}</select>
|
||||
<input data-tip="Capital name. Click and type to rename" class="stateCapital hide" value="${capital}" autocorrect="off" spellcheck="false" />
|
||||
<select data-tip="Dominant culture. Click to change" class="stateCulture hide">
|
||||
${getCultureOptions(s.culture)}
|
||||
</select>
|
||||
<span data-tip="Burgs count" style="padding-right: 1px" class="icon-dot-circled hide"></span>
|
||||
<div data-tip="Burgs count" class="stateBurgs hide">${s.burgs}</div>
|
||||
<span data-tip="State area" style="padding-right: 4px" class="icon-map-o hide"></span>
|
||||
<div data-tip="State area" class="biomeArea hide">${si(area) + unit}</div>
|
||||
<span data-tip="${populationTip}" class="icon-male hide"></span>
|
||||
<div data-tip="${populationTip}" class="culturePopulation hide">${si(population)}</div>
|
||||
<select data-tip="State type. Defines growth model. Click to change" class="cultureType ${hidden} show hide">${getTypeOptions(s.type)}</select>
|
||||
<select data-tip="State type. Defines growth model. Click to change" class="cultureType ${hidden} show hide">
|
||||
${getTypeOptions(s.type)}
|
||||
</select>
|
||||
<span data-tip="State expansionism" class="icon-resize-full ${hidden} show hide"></span>
|
||||
<input data-tip="Expansionism (defines competitive size). Change to re-calculate states based on new value"
|
||||
class="statePower ${hidden} show hide" type="number" min=0 max=99 step=.1 value=${s.expansionism}>
|
||||
<input
|
||||
data-tip="Expansionism (defines competitive size). Change to re-calculate states based on new value"
|
||||
class="statePower ${hidden} show hide"
|
||||
type="number"
|
||||
min="0"
|
||||
max="99"
|
||||
step=".1"
|
||||
value=${s.expansionism}
|
||||
/>
|
||||
<span data-tip="Cells count" class="icon-check-empty ${hidden} show hide"></span>
|
||||
<div data-tip="Cells count" class="stateCells ${hidden} show hide">${s.cells}</div>
|
||||
<span data-tip="Toggle state focus" class="icon-pin ${focused ? "" : " inactive"} hide"></span>
|
||||
|
|
@ -373,10 +413,9 @@ function editStates() {
|
|||
const total = rural + urban;
|
||||
const l = n => Number(n).toLocaleString();
|
||||
|
||||
alertMessage.innerHTML = `
|
||||
Rural: <input type="number" min=0 step=1 id="ruralPop" value=${rural} style="width:6em">
|
||||
Urban: <input type="number" min=0 step=1 id="urbanPop" value=${urban} style="width:6em" ${s.burgs ? "" : "disabled"}>
|
||||
<p>Total population: ${l(total)} ⇒ <span id="totalPop">${l(total)}</span> (<span id="totalPopPerc">100</span>%)</p>`;
|
||||
alertMessage.innerHTML = /* html */ ` Rural: <input type="number" min="0" step="1" id="ruralPop" value=${rural} style="width:6em" /> Urban:
|
||||
<input type="number" min="0" step="1" id="urbanPop" value=${urban} style="width:6em" ${s.burgs ? "" : "disabled"} />
|
||||
<p>Total population: ${l(total)} ⇒ <span id="totalPop">${l(total)}</span> (<span id="totalPopPerc">100</span>%)</p>`;
|
||||
|
||||
const update = function () {
|
||||
const totalNew = ruralPop.valueAsNumber + urbanPop.valueAsNumber;
|
||||
|
|
@ -592,7 +631,7 @@ function editStates() {
|
|||
const treeLayout = d3.pack().size([w, h]).padding(3);
|
||||
|
||||
// prepare svg
|
||||
alertMessage.innerHTML = `<select id="statesTreeType" style="display:block; margin-left:13px; font-size:11px">
|
||||
alertMessage.innerHTML = /* html */ `<select id="statesTreeType" style="display:block; margin-left:13px; font-size:11px">
|
||||
<option value="area" selected>Area</option>
|
||||
<option value="population">Total population</option>
|
||||
<option value="rural">Rural population</option>
|
||||
|
|
@ -664,7 +703,7 @@ function editStates() {
|
|||
? "Burgs number: " + d.data.burgs
|
||||
: "Population: " + si(rural + urban);
|
||||
|
||||
statesInfo.innerHTML = `${state}. ${value}`;
|
||||
statesInfo.innerHTML = /* html */ `${state}. ${value}`;
|
||||
stateHighlightOn(ev);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -712,8 +712,8 @@ emblemsBurgSizeInput.addEventListener("change", drawEmblems);
|
|||
|
||||
// request a URL to image to be used as a texture
|
||||
function textureProvideURL() {
|
||||
alertMessage.innerHTML = `Provide an image URL to be used as a texture:
|
||||
<input id="textureURL" type="url" style="width: 100%" placeholder="http://www.example.com/image.jpg" oninput="fetchTextureURL(this.value)">
|
||||
alertMessage.innerHTML = /* html */ `Provide an image URL to be used as a texture:
|
||||
<input id="textureURL" type="url" style="width: 100%" placeholder="http://www.example.com/image.jpg" oninput="fetchTextureURL(this.value)" />
|
||||
<canvas id="texturePreview" width="256px" height="144px"></canvas>`;
|
||||
$("#alert").dialog({
|
||||
resizable: false,
|
||||
|
|
|
|||
|
|
@ -203,8 +203,7 @@ window.UISubmap = (function () {
|
|||
ERROR && console.error(error);
|
||||
clearMainTip();
|
||||
|
||||
alertMessage.innerHTML = `Map resampling failed:
|
||||
<br>You may retry after clearing stored data or contact us at discord.
|
||||
alertMessage.innerHTML = /* html */ `Map resampling failed: <br />You may retry after clearing stored data or contact us at discord.
|
||||
<p id="errorBox">${parseError(error)}</p>`;
|
||||
$("#alert").dialog({
|
||||
resizable: false,
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ toolsContent.addEventListener("click", function (event) {
|
|||
return;
|
||||
}
|
||||
|
||||
alertMessage.innerHTML = `Regeneration will remove all the custom changes for the element.<br><br>Are you sure you want to proceed?`;
|
||||
alertMessage.innerHTML = /* html */ `Regeneration will remove all the custom changes for the element.<br /><br />Are you sure you want to proceed?`;
|
||||
$("#alert").dialog({
|
||||
resizable: false,
|
||||
title: "Regenerate element",
|
||||
|
|
|
|||
|
|
@ -277,9 +277,8 @@ function editUnits() {
|
|||
|
||||
function removeAllRulers() {
|
||||
if (!rulers.data.length) return;
|
||||
alertMessage.innerHTML = `
|
||||
Are you sure you want to remove all placed rulers?
|
||||
<br>If you just want to hide rulers, toggle the Rulers layer off in Menu`;
|
||||
alertMessage.innerHTML = /* html */ ` Are you sure you want to remove all placed rulers?
|
||||
<br />If you just want to hide rulers, toggle the Rulers layer off in Menu`;
|
||||
$("#alert").dialog({
|
||||
resizable: false,
|
||||
title: "Remove all rulers",
|
||||
|
|
|
|||
|
|
@ -77,12 +77,12 @@ function editWorld() {
|
|||
const scale = +distanceScaleInput.value,
|
||||
unit = distanceUnitInput.value;
|
||||
const meridian = toKilometer(eqD * 2 * scale);
|
||||
document.getElementById("mapSize").innerHTML = `${graphWidth}x${graphHeight}`;
|
||||
document.getElementById("mapSizeFriendly").innerHTML = `${rn(graphWidth * scale)}x${rn(graphHeight * scale)} ${unit}`;
|
||||
document.getElementById("mapSize").innerHTML = /* html */ `${graphWidth}x${graphHeight}`;
|
||||
document.getElementById("mapSizeFriendly").innerHTML = /* html */ `${rn(graphWidth * scale)}x${rn(graphHeight * scale)} ${unit}`;
|
||||
document.getElementById("meridianLength").innerHTML = rn(eqD * 2);
|
||||
document.getElementById("meridianLengthFriendly").innerHTML = `${rn(eqD * 2 * scale)} ${unit}`;
|
||||
document.getElementById("meridianLengthFriendly").innerHTML = /* html */ `${rn(eqD * 2 * scale)} ${unit}`;
|
||||
document.getElementById("meridianLengthEarth").innerHTML = meridian ? " = " + rn(meridian / 200) + "%🌏" : "";
|
||||
document.getElementById("mapCoordinates").innerHTML = `${lat(mc.latN)} ${Math.abs(rn(mc.lonW))}°W; ${lat(mc.latS)} ${rn(mc.lonE)}°E`;
|
||||
document.getElementById("mapCoordinates").innerHTML = /* html */ `${lat(mc.latN)} ${Math.abs(rn(mc.lonW))}°W; ${lat(mc.latS)} ${rn(mc.lonE)}°E`;
|
||||
|
||||
function toKilometer(v) {
|
||||
if (unit === "km") return v;
|
||||
|
|
|
|||
|
|
@ -110,7 +110,7 @@ function editZones() {
|
|||
const totalArea = (zonesFooterArea.dataset.area = graphWidth * graphHeight * distanceScaleInput.value ** 2);
|
||||
const totalPop = (d3.sum(pack.cells.pop) + d3.sum(pack.burgs.filter(b => !b.removed).map(b => b.population)) * urbanization) * populationRate;
|
||||
zonesFooterPopulation.dataset.population = totalPop;
|
||||
zonesFooterNumber.innerHTML = `${filteredZones.length} of ${zones.length}`;
|
||||
zonesFooterNumber.innerHTML = /* html */ `${filteredZones.length} of ${zones.length}`;
|
||||
zonesFooterCells.innerHTML = pack.cells.i.length;
|
||||
zonesFooterArea.innerHTML = si(totalArea) + unit;
|
||||
zonesFooterPopulation.innerHTML = si(totalPop);
|
||||
|
|
@ -414,10 +414,9 @@ function editZones() {
|
|||
const total = rural + urban;
|
||||
const l = n => Number(n).toLocaleString();
|
||||
|
||||
alertMessage.innerHTML = `
|
||||
Rural: <input type="number" min=0 step=1 id="ruralPop" value=${rural} style="width:6em">
|
||||
Urban: <input type="number" min=0 step=1 id="urbanPop" value=${urban} style="width:6em" ${burgs.length ? "" : "disabled"}>
|
||||
<p>Total population: ${l(total)} ⇒ <span id="totalPop">${l(total)}</span> (<span id="totalPopPerc">100</span>%)</p>`;
|
||||
alertMessage.innerHTML = /* html */ `Rural: <input type="number" min="0" step="1" id="ruralPop" value=${rural} style="width:6em" /> Urban:
|
||||
<input type="number" min="0" step="1" id="urbanPop" value=${urban} style="width:6em" ${burgs.length ? "" : "disabled"} />
|
||||
<p>Total population: ${l(total)} ⇒ <span id="totalPop">${l(total)}</span> (<span id="totalPopPerc">100</span>%)</p>`;
|
||||
|
||||
const update = function () {
|
||||
const totalNew = ruralPop.valueAsNumber + urbanPop.valueAsNumber;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue