mirror of
https://github.com/Azgaar/Fantasy-Map-Generator.git
synced 2026-02-04 17:41:23 +01:00
refactor: unify ice data structure and streamline ice element handling
This commit is contained in:
parent
a7d9fb3242
commit
f2d98e5bc7
6 changed files with 105 additions and 113 deletions
|
|
@ -1041,7 +1041,8 @@ export function resolveVersionConflicts(mapVersion) {
|
|||
// v1.110.0 moved ice data from SVG to data model
|
||||
// Migrate old ice SVG elements to new pack.ice structure
|
||||
if (!pack.ice) {
|
||||
pack.ice = { glaciers: [], icebergs: [] };
|
||||
pack.ice = [];
|
||||
let iceId = 0;
|
||||
|
||||
const iceLayer = document.getElementById("ice");
|
||||
if (iceLayer) {
|
||||
|
|
@ -1051,15 +1052,15 @@ export function resolveVersionConflicts(mapVersion) {
|
|||
const points = [...polygon.points].map(svgPoint => [svgPoint.x, svgPoint.y]);
|
||||
|
||||
const transform = polygon.getAttribute("transform");
|
||||
|
||||
if (transform) {
|
||||
pack.ice.glaciers.push({
|
||||
const iceElement = {
|
||||
i: iceId++,
|
||||
points,
|
||||
offset: parseTransform(transform)
|
||||
});
|
||||
} else {
|
||||
pack.ice.glaciers.push({ points });
|
||||
type: "glacier"
|
||||
};
|
||||
if (transform) {
|
||||
iceElement.offset = parseTransform(transform);
|
||||
}
|
||||
pack.ice.push(iceElement);
|
||||
});
|
||||
|
||||
// Migrate icebergs
|
||||
|
|
@ -1074,21 +1075,17 @@ export function resolveVersionConflicts(mapVersion) {
|
|||
const points = [...polygon.points].map(svgPoint => [svgPoint.x, svgPoint.y]);
|
||||
|
||||
const transform = polygon.getAttribute("transform");
|
||||
const iceElement = {
|
||||
i: iceId++,
|
||||
points,
|
||||
type: "iceberg",
|
||||
cellId,
|
||||
size
|
||||
};
|
||||
if (transform) {
|
||||
pack.ice.icebergs.push({
|
||||
cellId,
|
||||
size,
|
||||
points,
|
||||
offset: parseTransform(transform)
|
||||
});
|
||||
} else {
|
||||
pack.ice.icebergs.push({
|
||||
cellId,
|
||||
size,
|
||||
points
|
||||
});
|
||||
iceElement.offset = parseTransform(transform);
|
||||
}
|
||||
|
||||
pack.ice.push(iceElement);
|
||||
});
|
||||
|
||||
// Clear old SVG elements
|
||||
|
|
|
|||
|
|
@ -2,17 +2,16 @@
|
|||
|
||||
// Ice layer data model - separates ice data from SVG rendering
|
||||
window.Ice = (function () {
|
||||
// Initialize ice data structure
|
||||
function initialize() {
|
||||
pack.ice = {
|
||||
glaciers: [], // auto-generated glaciers on cold land
|
||||
icebergs: [] // manually edited and auto-generated icebergs on cold water
|
||||
};
|
||||
|
||||
// Find next available id for new ice element
|
||||
function getNextId() {
|
||||
if (pack.ice.length === 0) return 0;
|
||||
return Math.max(...pack.ice.map(element => element.i)) + 1;
|
||||
}
|
||||
|
||||
// Generate glaciers and icebergs based on temperature and height
|
||||
function generate() {
|
||||
initialize();
|
||||
clear();
|
||||
const { cells, features } = grid;
|
||||
const { temp, h } = cells;
|
||||
Math.random = aleaPRNG(seed);
|
||||
|
|
@ -31,8 +30,10 @@ window.Ice = (function () {
|
|||
if (isolines[type]?.polygons) {
|
||||
isolines[type].polygons.forEach(points => {
|
||||
const clipped = clipPoly(points);
|
||||
pack.ice.glaciers.push({
|
||||
points: clipped
|
||||
pack.ice.push({
|
||||
i: getNextId(),
|
||||
points: clipped,
|
||||
type: "glacier"
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
@ -57,10 +58,12 @@ window.Ice = (function () {
|
|||
rn(lerp(cy, y, size), 2)
|
||||
]);
|
||||
|
||||
pack.ice.icebergs.push({
|
||||
pack.ice.push({
|
||||
i: getNextId(),
|
||||
points,
|
||||
type: "iceberg",
|
||||
cellId,
|
||||
size,
|
||||
points
|
||||
size
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -71,44 +74,41 @@ window.Ice = (function () {
|
|||
rn(lerp(cx, x, size), 2),
|
||||
rn(lerp(cy, y, size), 2)
|
||||
]);
|
||||
//here we use the lose equality to find the first undefined or empty or null slot
|
||||
const nextIndex = pack.ice.icebergs.findIndex(iceberg => iceberg == undefined);
|
||||
if (nextIndex !== -1) {
|
||||
pack.ice.icebergs[nextIndex] = {
|
||||
cellId,
|
||||
size,
|
||||
points
|
||||
};
|
||||
redrawIceberg(nextIndex);
|
||||
} else {
|
||||
pack.ice.icebergs.push({
|
||||
cellId,
|
||||
size,
|
||||
points
|
||||
});
|
||||
redrawIceberg(pack.ice.icebergs.length - 1);
|
||||
const id = getNextId();
|
||||
pack.ice.push({
|
||||
i: id,
|
||||
points,
|
||||
type: "iceberg",
|
||||
cellId,
|
||||
size
|
||||
});
|
||||
redrawIceberg(id);
|
||||
}
|
||||
|
||||
function removeIce(id) {
|
||||
const index = pack.ice.findIndex(element => element.i === id);
|
||||
if (index !== -1) {
|
||||
const type = pack.ice.find(element => element.i === id).type;
|
||||
pack.ice.splice(index, 1);
|
||||
if (type === "glacier") {
|
||||
redrawGlacier(id);
|
||||
} else {
|
||||
redrawIceberg(id);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
function removeIce(type, index) {
|
||||
if (type === "glacier" && pack.ice.glaciers[index]) {
|
||||
delete pack.ice.glaciers[index];
|
||||
redrawGlacier(index);
|
||||
} else if (type === "iceberg" && pack.ice.icebergs[index]) {
|
||||
delete pack.ice.icebergs[index];
|
||||
redrawIceberg(index);
|
||||
function updateIceberg(id, points, size) {
|
||||
const iceberg = pack.ice.find(element => element.i === id);
|
||||
if (iceberg) {
|
||||
iceberg.points = points;
|
||||
iceberg.size = size;
|
||||
}
|
||||
}
|
||||
|
||||
function updateIceberg(index, points, size) {
|
||||
if (pack.ice.icebergs[index]) {
|
||||
pack.ice.icebergs[index].points = points;
|
||||
pack.ice.icebergs[index].size = size;
|
||||
}
|
||||
}
|
||||
|
||||
function randomizeIcebergShape(index) {
|
||||
const iceberg = pack.ice.icebergs[index];
|
||||
function randomizeIcebergShape(id) {
|
||||
const iceberg = pack.ice.find(element => element.i === id);
|
||||
if (!iceberg) return;
|
||||
|
||||
const cellId = iceberg.cellId;
|
||||
|
|
@ -127,8 +127,8 @@ window.Ice = (function () {
|
|||
iceberg.points = points;
|
||||
}
|
||||
|
||||
function changeIcebergSize(index, newSize) {
|
||||
const iceberg = pack.ice.icebergs[index];
|
||||
function changeIcebergSize(id, newSize) {
|
||||
const iceberg = pack.ice.find(element => element.i === id);
|
||||
if (!iceberg) return;
|
||||
|
||||
const cellId = iceberg.cellId;
|
||||
|
|
@ -150,12 +150,10 @@ window.Ice = (function () {
|
|||
|
||||
// Clear all ice
|
||||
function clear() {
|
||||
pack.ice.glaciers = [];
|
||||
pack.ice.icebergs = [];
|
||||
pack.ice = [];
|
||||
}
|
||||
|
||||
return {
|
||||
initialize,
|
||||
generate,
|
||||
addIceberg,
|
||||
removeIce,
|
||||
|
|
|
|||
|
|
@ -406,7 +406,7 @@ async function parseLoadedData(data, mapVersion) {
|
|||
pack.cells.province = data[27] ? Uint16Array.from(data[27].split(",")) : new Uint16Array(pack.cells.i.length);
|
||||
// data[28] had deprecated cells.crossroad
|
||||
pack.cells.routes = data[36] ? JSON.parse(data[36]) : {};
|
||||
pack.ice = data[39] ? JSON.parse(data[39]) : {glaciers: [], icebergs: []};
|
||||
pack.ice = data[39] ? JSON.parse(data[39]) : [];
|
||||
|
||||
if (data[31]) {
|
||||
const namesDL = data[31].split("/");
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ async function saveMap(method) {
|
|||
$(this).dialog("close");
|
||||
}
|
||||
},
|
||||
position: {my: "center", at: "center", of: "svg"}
|
||||
position: { my: "center", at: "center", of: "svg" }
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -90,8 +90,8 @@ function prepareMapData() {
|
|||
|
||||
const serializedSVG = new XMLSerializer().serializeToString(cloneEl);
|
||||
|
||||
const {spacing, cellsX, cellsY, boundary, points, features, cellsDesired} = grid;
|
||||
const gridGeneral = JSON.stringify({spacing, cellsX, cellsY, boundary, points, features, cellsDesired});
|
||||
const { spacing, cellsX, cellsY, boundary, points, features, cellsDesired } = grid;
|
||||
const gridGeneral = JSON.stringify({ spacing, cellsX, cellsY, boundary, points, features, cellsDesired });
|
||||
const packFeatures = JSON.stringify(pack.features);
|
||||
const cultures = JSON.stringify(pack.cultures);
|
||||
const states = JSON.stringify(pack.states);
|
||||
|
|
@ -103,10 +103,7 @@ function prepareMapData() {
|
|||
const cellRoutes = JSON.stringify(pack.cells.routes);
|
||||
const routes = JSON.stringify(pack.routes);
|
||||
const zones = JSON.stringify(pack.zones);
|
||||
|
||||
const icebergs = pack.ice.icebergs.filter(iceberg => iceberg !== undefined);
|
||||
const glaciers = pack.ice.glaciers.filter(glacier => glacier !== undefined);
|
||||
const ice = JSON.stringify({icebergs, glaciers});
|
||||
const ice = JSON.stringify(pack.ice);
|
||||
|
||||
// store name array only if not the same as default
|
||||
const defaultNB = Names.getNameBases();
|
||||
|
|
@ -168,14 +165,14 @@ function prepareMapData() {
|
|||
|
||||
// save map file to indexedDB
|
||||
async function saveToStorage(mapData, showTip = false) {
|
||||
const blob = new Blob([mapData], {type: "text/plain"});
|
||||
const blob = new Blob([mapData], { type: "text/plain" });
|
||||
await ldb.set("lastMap", blob);
|
||||
showTip && tip("Map is saved to the browser storage", false, "success");
|
||||
}
|
||||
|
||||
// download map file
|
||||
function saveToMachine(mapData, filename) {
|
||||
const blob = new Blob([mapData], {type: "text/plain"});
|
||||
const blob = new Blob([mapData], { type: "text/plain" });
|
||||
const URL = window.URL.createObjectURL(blob);
|
||||
|
||||
const link = document.createElement("a");
|
||||
|
|
|
|||
|
|
@ -9,14 +9,13 @@ function drawIce() {
|
|||
|
||||
let html = "";
|
||||
|
||||
// Draw glaciers
|
||||
pack.ice.glaciers.forEach((glacier, index) => {
|
||||
html += getGlacierHtml(glacier, index);
|
||||
});
|
||||
|
||||
// Draw icebergs
|
||||
pack.ice.icebergs.forEach((iceberg, index) => {
|
||||
html += getIcebergHtml(iceberg, index);
|
||||
// Draw all ice elements
|
||||
pack.ice.forEach(iceElement => {
|
||||
if (iceElement.type === "glacier") {
|
||||
html += getGlacierHtml(iceElement);
|
||||
} else if (iceElement.type === "iceberg") {
|
||||
html += getIcebergHtml(iceElement);
|
||||
}
|
||||
});
|
||||
|
||||
ice.html(html);
|
||||
|
|
@ -24,18 +23,18 @@ function drawIce() {
|
|||
TIME && console.timeEnd("drawIce");
|
||||
}
|
||||
|
||||
function redrawIceberg(index) {
|
||||
function redrawIceberg(id) {
|
||||
TIME && console.time("redrawIceberg");
|
||||
const iceberg = pack.ice.icebergs[index];
|
||||
let el = ice.selectAll(`polygon[data-index="${index}"]:not([type="glacier"])`);
|
||||
const iceberg = pack.ice.find(element => element.i === id);
|
||||
let el = ice.selectAll(`polygon[data-id="${id}"]:not([type="glacier"])`);
|
||||
if (!iceberg && !el.empty()) {
|
||||
el.remove();
|
||||
} else {
|
||||
if (el.empty()) {
|
||||
// Create new element if it doesn't exist
|
||||
const polygon = getIcebergHtml(iceberg, index);
|
||||
const polygon = getIcebergHtml(iceberg);
|
||||
ice.node().insertAdjacentHTML("beforeend", polygon);
|
||||
el = ice.selectAll(`polygon[data-index="${index}"]:not([type="glacier"])`);
|
||||
el = ice.selectAll(`polygon[data-id="${id}"]:not([type="glacier"])`);
|
||||
}
|
||||
el.attr("points", iceberg.points);
|
||||
el.attr("transform", iceberg.offset ? `translate(${iceberg.offset[0]},${iceberg.offset[1]})` : null);
|
||||
|
|
@ -43,18 +42,18 @@ function redrawIceberg(index) {
|
|||
TIME && console.timeEnd("redrawIceberg");
|
||||
}
|
||||
|
||||
function redrawGlacier(index) {
|
||||
function redrawGlacier(id) {
|
||||
TIME && console.time("redrawGlacier");
|
||||
const glacier = pack.ice.glaciers[index];
|
||||
let el = ice.selectAll(`polygon[data-index="${index}"][type="glacier"]`);
|
||||
const glacier = pack.ice.find(element => element.i === id);
|
||||
let el = ice.selectAll(`polygon[data-id="${id}"][type="glacier"]`);
|
||||
if (!glacier && !el.empty()) {
|
||||
el.remove();
|
||||
} else {
|
||||
if (el.empty()) {
|
||||
// Create new element if it doesn't exist
|
||||
const polygon = getGlacierHtml(glacier, index);
|
||||
const polygon = getGlacierHtml(glacier);
|
||||
ice.node().insertAdjacentHTML("beforeend", polygon);
|
||||
el = ice.selectAll(`polygon[data-index="${index}"][type="glacier"]`);
|
||||
el = ice.selectAll(`polygon[data-id="${id}"][type="glacier"]`);
|
||||
}
|
||||
el.attr("points", glacier.points);
|
||||
el.attr("transform", glacier.offset ? `translate(${glacier.offset[0]},${glacier.offset[1]})` : null);
|
||||
|
|
@ -62,10 +61,10 @@ function redrawGlacier(index) {
|
|||
TIME && console.timeEnd("redrawGlacier");
|
||||
}
|
||||
|
||||
function getGlacierHtml(glacier, index) {
|
||||
return `<polygon points="${glacier.points}" type="glacier" data-index="${index}" ${glacier.offset ? `transform="translate(${glacier.offset[0]},${glacier.offset[1]})"` : ""}/>`;
|
||||
function getGlacierHtml(glacier) {
|
||||
return `<polygon points="${glacier.points}" type="glacier" data-id="${glacier.i}" ${glacier.offset ? `transform="translate(${glacier.offset[0]},${glacier.offset[1]})"` : ""}/>`;
|
||||
}
|
||||
|
||||
function getIcebergHtml(iceberg, index) {
|
||||
return `<polygon points="${iceberg.points}" data-index="${index}" ${iceberg.offset ? `transform="translate(${iceberg.offset[0]},${iceberg.offset[1]})"` : ""}/>`;
|
||||
function getIcebergHtml(iceberg) {
|
||||
return `<polygon points="${iceberg.points}" data-id="${iceberg.i}" ${iceberg.offset ? `transform="translate(${iceberg.offset[0]},${iceberg.offset[1]})"` : ""}/>`;
|
||||
}
|
||||
|
|
@ -7,13 +7,14 @@ function editIce(element) {
|
|||
if (!layerIsOn("toggleIce")) toggleIce();
|
||||
|
||||
elSelected = d3.select(d3.event.target);
|
||||
const index = +elSelected.attr("data-index");
|
||||
const id = +elSelected.attr("data-id");
|
||||
const iceElement = pack.ice.find(el => el.i === id);
|
||||
const isGlacier = elSelected.attr("type") === "glacier";
|
||||
const type = isGlacier ? "Glacier" : "Iceberg";
|
||||
|
||||
document.getElementById("iceRandomize").style.display = isGlacier ? "none" : "inline-block";
|
||||
document.getElementById("iceSize").style.display = isGlacier ? "none" : "inline-block";
|
||||
if (!isGlacier) document.getElementById("iceSize").value = isGlacier ? "" : pack.ice.icebergs[index].size;
|
||||
if (!isGlacier) document.getElementById("iceSize").value = iceElement?.size || "";
|
||||
|
||||
ice.selectAll("*").classed("draggable", true).call(d3.drag().on("drag", dragElement));
|
||||
|
||||
|
|
@ -35,16 +36,16 @@ function editIce(element) {
|
|||
|
||||
|
||||
function randomizeShape() {
|
||||
const idx = +elSelected.attr("data-index");
|
||||
Ice.randomizeIcebergShape(idx);
|
||||
redrawIceberg(idx);
|
||||
const selectedId = +elSelected.attr("data-id");
|
||||
Ice.randomizeIcebergShape(selectedId);
|
||||
redrawIceberg(selectedId);
|
||||
}
|
||||
|
||||
function changeSize() {
|
||||
const newSize = +this.value;
|
||||
const idx = +elSelected.attr("data-index");
|
||||
Ice.changeIcebergSize(idx, newSize);
|
||||
redrawIceberg(idx);
|
||||
const selectedId = +elSelected.attr("data-id");
|
||||
Ice.changeIcebergSize(selectedId, newSize);
|
||||
redrawIceberg(selectedId);
|
||||
}
|
||||
|
||||
function toggleAdd() {
|
||||
|
|
@ -77,7 +78,7 @@ function editIce(element) {
|
|||
buttons: {
|
||||
Remove: function () {
|
||||
$(this).dialog("close");
|
||||
Ice.removeIce(type.toLowerCase(), +elSelected.attr("data-index"));
|
||||
Ice.removeIce(+elSelected.attr("data-id"));
|
||||
$("#iceEditor").dialog("close");
|
||||
},
|
||||
Cancel: function () {
|
||||
|
|
@ -88,7 +89,7 @@ function editIce(element) {
|
|||
}
|
||||
|
||||
function dragElement() {
|
||||
const idx = +elSelected.attr("data-index");
|
||||
const selectedId = +elSelected.attr("data-id");
|
||||
const initialTransform = parseTransform(this.getAttribute("transform"));
|
||||
const dx = initialTransform[0] - d3.event.x;
|
||||
const dy = initialTransform[1] - d3.event.y;
|
||||
|
|
@ -101,7 +102,7 @@ function editIce(element) {
|
|||
|
||||
// Update data model with new position
|
||||
const offset = [dx + x, dy + y];
|
||||
const iceData = elSelected.attr("type") === "glacier" ? pack.ice.glaciers[idx] : pack.ice.icebergs[idx];
|
||||
const iceData = pack.ice.find(element => element.i === selectedId);
|
||||
if (iceData) {
|
||||
// Store offset for visual positioning, actual geometry stays in points
|
||||
iceData.offset = offset;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue