mirror of
https://github.com/Azgaar/Fantasy-Map-Generator.git
synced 2025-12-17 09:41:24 +01:00
v1.5.04 - Emblems layer and on map placement
This commit is contained in:
parent
968182512c
commit
549eefe7ba
12 changed files with 276 additions and 47 deletions
|
|
@ -2,6 +2,15 @@
|
|||
function editEmblem(type, id, el) {
|
||||
if (customization) return;
|
||||
|
||||
if (!id && d3.event) {
|
||||
const data = d3.event.target.__data__;
|
||||
type = data.type;
|
||||
id = data.id;
|
||||
el = data.el;
|
||||
}
|
||||
|
||||
emblems.selectAll(":scope > use").call(d3.drag().on("drag", dragEmblem)).classed("draggable", true);
|
||||
|
||||
const emblemStates = document.getElementById("emblemStates");
|
||||
const emblemProvinces = document.getElementById("emblemProvinces");
|
||||
const emblemBurgs = document.getElementById("emblemBurgs");
|
||||
|
|
@ -10,8 +19,9 @@ function editEmblem(type, id, el) {
|
|||
updateElementSelectors(type, id, el);
|
||||
|
||||
$("#emblemEditor").dialog({
|
||||
title: "Edit Emblem", resizable: true, width: "auto",
|
||||
position: {my: "left top", at: "left+10 top+10", of: "svg", collision: "fit"}
|
||||
title: "Edit Emblem", resizable: true, width: "auto", height: "auto",
|
||||
position: {my: "left top", at: "left+10 top+10", of: "svg", collision: "fit"},
|
||||
close: closeEmblemEditor
|
||||
});
|
||||
|
||||
if (modules.editEmblem) return;
|
||||
|
|
@ -32,13 +42,19 @@ function editEmblem(type, id, el) {
|
|||
|
||||
// define selected values
|
||||
if (type === "state") state = el.i;
|
||||
else if (type === "province") {province = el.i; state = states[el.state].i;}
|
||||
else {burg = el.i; province = provinces[cells.province[el.cell]].i; state = provinces[province].state;}
|
||||
else if (type === "province") {
|
||||
province = el.i
|
||||
state = states[el.state].i;
|
||||
} else {
|
||||
burg = el.i;
|
||||
province = cells.province[el.cell] ? provinces[cells.province[el.cell]].i : 0;
|
||||
state = provinces[province].state || 0;
|
||||
}
|
||||
|
||||
// update option list and select actual values
|
||||
emblemStates.options.length = 0;
|
||||
const neutralBurgs = burgs.filter(burg => burg.i && !burg.removed && !burg.state);
|
||||
if (neutralBurgs.length) emblemProvinces.options.add(new Option(states[0].name, 0, false, !state));
|
||||
if (neutralBurgs.length) emblemStates.options.add(new Option(states[0].name, 0, false, !state));
|
||||
const stateList = states.filter(state => state.i && !state.removed);
|
||||
stateList.forEach(s => emblemStates.options.add(new Option(s.name, s.i, false, s.i === state)));
|
||||
|
||||
|
|
@ -50,7 +66,7 @@ function editEmblem(type, id, el) {
|
|||
emblemBurgs.options.length = 0;
|
||||
emblemBurgs.options.add(new Option("", 0, false, !burg));
|
||||
const burgList = burgs.filter(burg => !burg.removed && province ? cells.province[burg.cell] === province : burg.state === state);
|
||||
burgList.forEach(b => emblemBurgs.options.add(new Option(b.name, b.i, false, b.i === burg)));
|
||||
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;
|
||||
|
||||
COArenderer.trigger(id, el.coa);
|
||||
|
|
@ -105,4 +121,18 @@ function editEmblem(type, id, el) {
|
|||
id = "burgCOA"+ burg;
|
||||
updateElementSelectors(type, id, el);
|
||||
}
|
||||
|
||||
function dragEmblem() {
|
||||
const tr = parseTransform(this.getAttribute("transform"));
|
||||
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)})`;
|
||||
this.setAttribute("transform", transform);
|
||||
});
|
||||
}
|
||||
|
||||
function closeEmblemEditor() {
|
||||
emblems.selectAll(":scope > use").call(d3.drag().on("drag", null)).attr("class", null);
|
||||
}
|
||||
}
|
||||
|
|
@ -21,7 +21,8 @@ function clicked() {
|
|||
const p = d3.mouse(this);
|
||||
const i = findCell(p[0], p[1]);
|
||||
|
||||
if (parent.id === "rivers") editRiver();
|
||||
if (parent.id === "emblems") editEmblem();
|
||||
else if (parent.id === "rivers") editRiver();
|
||||
else if (grand.id === "routes") editRoute();
|
||||
else if (el.tagName === "tspan" && grand.parentNode.parentNode.id === "labels") editLabel();
|
||||
else if (grand.id === "burgLabels") editBurg();
|
||||
|
|
|
|||
|
|
@ -94,6 +94,14 @@ function showMapTooltip(point, e, i, g) {
|
|||
tip(e.target.parentNode.dataset.name + ". Click to edit");
|
||||
return;
|
||||
}
|
||||
if (group === "emblems" && e.target.__data__?.el) {
|
||||
const el = d3.select(e.target);
|
||||
el.raise();
|
||||
const name = el.datum().el.fullName || el.datum().el.name || "";
|
||||
const type = el.datum().type || "";
|
||||
tip(`${name} ${type} emblem. Click to edit`);
|
||||
return;
|
||||
}
|
||||
if (group === "rivers") {
|
||||
const river = +e.target.id.slice(5);
|
||||
const r = pack.rivers.find(r => r.i === river);
|
||||
|
|
@ -171,7 +179,7 @@ function highlightEditorLine(editor, id, timeout = 15000) {
|
|||
Array.from(editor.getElementsByClassName("states hovered")).forEach(el => el.classList.remove("hovered")); // clear all hovered
|
||||
const hovered = Array.from(editor.querySelectorAll("div")).find(el => el.dataset.id == id);
|
||||
if (hovered) hovered.classList.add("hovered"); // add hovered class
|
||||
if (timeout) setTimeout(() => hovered.classList.remove("hovered"), timeout);
|
||||
if (timeout) setTimeout(() => {hovered && hovered.classList.remove("hovered")}, timeout);
|
||||
}
|
||||
|
||||
// get cell info on mouse move
|
||||
|
|
@ -454,6 +462,7 @@ document.addEventListener("keyup", event => {
|
|||
else if (key === 78) togglePopulation(); // "N" to toggle Population layer
|
||||
else if (key === 74) toggleIce(); // "J" to toggle Ice layer
|
||||
else if (key === 65) togglePrec(); // "A" to toggle Precipitation layer
|
||||
else if (key === 89) toggleEmblems(); // "Y" to toggle Emblems layer
|
||||
else if (key === 76) toggleLabels(); // "L" to toggle Labels layer
|
||||
else if (key === 73) toggleIcons(); // "I" to toggle Icons layer
|
||||
else if (key === 77) toggleMilitary(); // "M" to toggle Military layer
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ function restoreLayers() {
|
|||
if (layerIsOn("toggleProvinces")) drawProvinces();
|
||||
if (layerIsOn("toggleReligions")) drawReligions();
|
||||
if (layerIsOn("toggleIce")) drawIce();
|
||||
if (layerIsOn("toggleEmblems")) drawEmblems();
|
||||
|
||||
// states are getting rendered each time, if it's not required than layers should be hidden
|
||||
if (!layerIsOn("toggleBorders")) $('#borders').fadeOut();
|
||||
|
|
@ -877,6 +878,26 @@ function drawProvinces() {
|
|||
const labelsOn = provs.attr("data-labels") == 1;
|
||||
provs.selectAll("*").remove();
|
||||
|
||||
const provinces = pack.provinces;
|
||||
const {body, gap} = getProvincesVertices();
|
||||
|
||||
const g = provs.append("g").attr("id", "provincesBody");
|
||||
const bodyData = body.map((p, i) => [p.length > 10 ? p : null, i, provinces[i].color]).filter(d => d[0]);
|
||||
g.selectAll("path").data(bodyData).enter().append("path").attr("d", d => d[0]).attr("fill", d => d[2]).attr("stroke", "none").attr("id", d => "province"+d[1]);
|
||||
const gapData = gap.map((p, i) => [p.length > 10 ? p : null, i, provinces[i].color]).filter(d => d[0]);
|
||||
g.selectAll(".path").data(gapData).enter().append("path").attr("d", d => d[0]).attr("fill", "none").attr("stroke", d => d[2]).attr("id", d => "province-gap"+d[1]);
|
||||
|
||||
const labels = provs.append("g").attr("id", "provinceLabels");
|
||||
labels.style("display", `${labelsOn ? "block" : "none"}`);
|
||||
const labelData = provinces.filter(p => p.i && !p.removed);
|
||||
labels.selectAll(".path").data(labelData).enter().append("text")
|
||||
.attr("x", d => d.pole[0]).attr("y", d => d.pole[1])
|
||||
.attr("id", d => "provinceLabel"+d.i).text(d => d.name);
|
||||
|
||||
TIME && console.timeEnd("drawProvinces");
|
||||
}
|
||||
|
||||
function getProvincesVertices() {
|
||||
const cells = pack.cells, vertices = pack.vertices, provinces = pack.provinces, n = cells.i.length;
|
||||
const used = new Uint8Array(cells.i.length);
|
||||
const vArray = new Array(provinces.length); // store vertices array
|
||||
|
|
@ -906,18 +927,7 @@ function drawProvinces() {
|
|||
provinces[i].pole = polylabel(sorted, 1.0); // pole of inaccessibility
|
||||
});
|
||||
|
||||
const g = provs.append("g").attr("id", "provincesBody");
|
||||
const bodyData = body.map((p, i) => [p.length > 10 ? p : null, i, provinces[i].color]).filter(d => d[0]);
|
||||
g.selectAll("path").data(bodyData).enter().append("path").attr("d", d => d[0]).attr("fill", d => d[2]).attr("stroke", "none").attr("id", d => "province"+d[1]);
|
||||
const gapData = gap.map((p, i) => [p.length > 10 ? p : null, i, provinces[i].color]).filter(d => d[0]);
|
||||
g.selectAll(".path").data(gapData).enter().append("path").attr("d", d => d[0]).attr("fill", "none").attr("stroke", d => d[2]).attr("id", d => "province-gap"+d[1]);
|
||||
|
||||
const labels = provs.append("g").attr("id", "provinceLabels");
|
||||
labels.style("display", `${labelsOn ? "block" : "none"}`);
|
||||
const labelData = provinces.filter(p => p.i && !p.removed);
|
||||
labels.selectAll(".path").data(labelData).enter().append("text")
|
||||
.attr("x", d => d.pole[0]).attr("y", d => d.pole[1])
|
||||
.attr("id", d => "provinceLabel"+d.i).text(d => d.name);
|
||||
return {body, gap};
|
||||
|
||||
// connect vertices to chain
|
||||
function connectVertices(start, t, province) {
|
||||
|
|
@ -942,7 +952,7 @@ function drawProvinces() {
|
|||
chain.push([start, province, land]); // add starting vertex to sequence to close the path
|
||||
return chain;
|
||||
}
|
||||
TIME && console.timeEnd("drawProvinces");
|
||||
|
||||
}
|
||||
|
||||
function toggleGrid(event) {
|
||||
|
|
@ -1214,7 +1224,71 @@ function toggleZones(event) {
|
|||
if (event && isCtrlClick(event)) {editStyle("zones"); return;}
|
||||
turnButtonOff("toggleZones");
|
||||
$('#zones').fadeOut();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function toggleEmblems(event) {
|
||||
if (!layerIsOn("toggleEmblems")) {
|
||||
turnButtonOn("toggleEmblems");
|
||||
if (!emblems.selectAll("*").size()) drawEmblems();
|
||||
$('#emblems').fadeIn();
|
||||
if (event && isCtrlClick(event)) editStyle("emblems");
|
||||
} else {
|
||||
if (event && isCtrlClick(event)) {editStyle("emblems"); return;}
|
||||
$('#emblems').fadeOut();
|
||||
turnButtonOff("toggleEmblems");
|
||||
}
|
||||
}
|
||||
|
||||
function drawEmblems() {
|
||||
TIME && console.time("drawEmblems");
|
||||
const {states, provinces, burgs, cells} = pack;
|
||||
|
||||
let svg = "";
|
||||
|
||||
// const sizeBurgs = +emblems.attr("size-burgs") || 15;
|
||||
// burgs.filter(b => b.i && !b.removed && b.coa).forEach(burg => {
|
||||
// const {x, y} = burg;
|
||||
// COArenderer.trigger("burgCOA"+burg.i, burg.coa);
|
||||
// svg += `<use x=${x-sizeBurgs/2} y=${y-sizeBurgs/2} width=${sizeBurgs} height=${sizeBurgs} href="#burgCOA${burg.i}"></use>`;
|
||||
// });
|
||||
|
||||
const sizeProvinces = +emblems.attr("size-provinces") || 25;
|
||||
const provinceCOAs = provinces.filter(p => p.i && !p.removed && p.coa).map(province => {
|
||||
if (!province.pole) getProvincesVertices();
|
||||
const [x, y] = province.pole;
|
||||
COArenderer.trigger("provinceCOA"+province.i, province.coa);
|
||||
//svg += `<use x=${x-sizeProvinces/2} y=${y-sizeProvinces/2} width=${sizeProvinces} height=${sizeProvinces} href="#provinceCOA${province.i}"></use>`;
|
||||
return {type: "province", id: "provinceCOA"+province.i, x: x - sizeProvinces/2, y: y - sizeProvinces/2, size: sizeProvinces, el: province};
|
||||
});
|
||||
|
||||
const sizeStates = +emblems.attr("size-states") || 50;
|
||||
const stateCOAs = states.filter(s => s.i && !s.removed && s.coa).map(state => {
|
||||
const [x, y] = state.pole;
|
||||
COArenderer.trigger("stateCOA"+state.i, state.coa);
|
||||
//svg += `<use x=${x-sizeStates/2} y=${y-sizeStates/2} width=${sizeStates} height=${sizeStates} href="#stateCOA${state.i}"></use>`;
|
||||
return {type: "state", id: "stateCOA"+state.i, x: x - sizeStates/2, y: y - sizeStates/2, size: sizeStates, el: state};
|
||||
});
|
||||
|
||||
const nodes = provinceCOAs.concat(stateCOAs);
|
||||
// emblems.html(svg);
|
||||
|
||||
const simulation = d3.forceSimulation(nodes)
|
||||
.alphaMin(.6).alphaDecay(.2)
|
||||
.force('collision', d3.forceCollide().radius(d => d.size/2));
|
||||
|
||||
const node = emblems.selectAll("use").data(nodes).join("use")
|
||||
.attr("href", d => "#"+d.id)
|
||||
.attr("x", d => d.x)
|
||||
.attr("y", d => d.y)
|
||||
.attr("width", d => d.size)
|
||||
.attr("height", d => d.size);
|
||||
|
||||
simulation.on("tick", () => {
|
||||
node.attr("x", d => d.x).attr("y", d => d.y);
|
||||
});
|
||||
|
||||
TIME && console.timeEnd("drawEmblems");
|
||||
}
|
||||
|
||||
function layerIsOn(el) {
|
||||
|
|
@ -1262,6 +1336,7 @@ function getLayer(id) {
|
|||
if (id === "togglePopulation") return $("#population");
|
||||
if (id === "toggleIce") return $("#ice");
|
||||
if (id === "toggleTexture") return $("#texture");
|
||||
if (id === "toggleEmblems") return $("#emblems");
|
||||
if (id === "toggleLabels") return $("#labels");
|
||||
if (id === "toggleIcons") return $("#icons");
|
||||
if (id === "toggleMarkers") return $("#markers");
|
||||
|
|
|
|||
|
|
@ -114,6 +114,7 @@ optionsContent.addEventListener("input", function(event) {
|
|||
else if (id === "neutralOutput") neutralInput.value = value;
|
||||
else if (id === "manorsInput") changeBurgsNumberSlider(value);
|
||||
else if (id === "religionsInput") religionsOutput.value = value;
|
||||
else if (id === "emblemShape") changeEmblemShape(value);
|
||||
else if (id === "uiSizeInput") uiSizeOutput.value = value;
|
||||
else if (id === "uiSizeOutput") changeUIsize(value);
|
||||
else if (id === "tooltipSizeInput" || id === "tooltipSizeOutput") changeTooltipSize(value);
|
||||
|
|
@ -262,6 +263,17 @@ function changeCultureSet() {
|
|||
if (+culturesOutput.value > +max) culturesInput.value = culturesOutput.value = max;
|
||||
}
|
||||
|
||||
function changeEmblemShape(value) {
|
||||
const image = document.getElementById("emblemShapeImage");
|
||||
const shapeEl = document.getElementById(value);
|
||||
if (shapeEl) {
|
||||
const shape = shapeEl.querySelector("path").getAttribute("d");
|
||||
image.setAttribute("d", shape);
|
||||
} else {
|
||||
image.removeAttribute("d");
|
||||
}
|
||||
}
|
||||
|
||||
function changeStatesNumber(value) {
|
||||
regionsInput.value = regionsOutput.value = value;
|
||||
regionsOutput.style.color = +value ? null : "#b12117";
|
||||
|
|
@ -380,6 +392,7 @@ function randomizeOptions() {
|
|||
|
||||
// World settings
|
||||
generateEra();
|
||||
changeEmblemShape(emblemShape.value); // change emblem shape image
|
||||
}
|
||||
|
||||
// select heightmap template pseudo-randomly
|
||||
|
|
|
|||
|
|
@ -795,6 +795,8 @@ function applyDefaultStyle() {
|
|||
labels.select("#addedLabels").attr("fill", "#3e3e4b").attr("opacity", 1).attr("stroke", "#3a3a3a").attr("stroke-width", 0).attr("font-family", "Almendra SC").attr("data-font", "Almendra+SC").attr("font-size", 18).attr("data-size", 18).attr("filter", null);
|
||||
|
||||
fogging.attr("opacity", .98).attr("fill", "#30426f");
|
||||
|
||||
emblems.attr("opacity", .9).attr("size-states", 50).attr("size-provinces", 25).attr("size-burgs", 15).attr("filter", null);
|
||||
}
|
||||
|
||||
// apply style settings in JSON
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue