From 21710bc4261459888179b65b00740631ce0499db Mon Sep 17 00:00:00 2001 From: StempunkDev Date: Tue, 13 Jan 2026 23:40:37 +0100 Subject: [PATCH] sparse array implementation with reduced updates --- public/modules/ice.js | 48 ++++++++++++---------- public/modules/renderers/draw-ice.js | 60 +++++++++++++++++++++++++++- public/modules/ui/ice-editor.js | 13 +++--- 3 files changed, 90 insertions(+), 31 deletions(-) diff --git a/public/modules/ice.js b/public/modules/ice.js index 8dbbeeb3..31e98232 100644 --- a/public/modules/ice.js +++ b/public/modules/ice.js @@ -65,33 +65,41 @@ window.Ice = (function () { } } - // Add a new iceberg (manual editing) function addIceberg(cellId, size) { const [cx, cy] = grid.points[cellId]; const points = getGridPolygon(cellId).map(([x, y]) => [ rn(lerp(cx, x, size), 2), rn(lerp(cy, y, size), 2) ]); - - pack.ice.icebergs.push({ - cellId, - size, - points - }); - - return pack.ice.icebergs.length - 1; // return index - } - - // Remove ice element by index - function removeIce(type, index) { - if (type === "glacier" && pack.ice.glaciers[index]) { - pack.ice.glaciers.splice(index, 1); - } else if (type === "iceberg" && pack.ice.icebergs[index]) { - pack.ice.icebergs.splice(index, 1); + //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); + } + } + + 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); } } - // Update iceberg points and size function updateIceberg(index, points, size) { if (pack.ice.icebergs[index]) { pack.ice.icebergs[index].points = points; @@ -99,7 +107,6 @@ window.Ice = (function () { } } - // Randomize iceberg shape function randomizeIcebergShape(index) { const iceberg = pack.ice.icebergs[index]; if (!iceberg) return; @@ -120,7 +127,6 @@ window.Ice = (function () { iceberg.points = points; } - // Change iceberg size and recalculate points function changeIcebergSize(index, newSize) { const iceberg = pack.ice.icebergs[index]; if (!iceberg) return; @@ -129,7 +135,6 @@ window.Ice = (function () { const [cx, cy] = grid.points[cellId]; const oldSize = iceberg.size; - // Recalculate points based on new size const flat = iceberg.points.flat(); const pairs = []; while (flat.length) pairs.push(flat.splice(0, 2)); @@ -143,7 +148,6 @@ window.Ice = (function () { iceberg.size = newSize; } - // Get all ice data function getData() { return pack.ice; } diff --git a/public/modules/renderers/draw-ice.js b/public/modules/renderers/draw-ice.js index 156c589a..2598e77d 100644 --- a/public/modules/renderers/draw-ice.js +++ b/public/modules/renderers/draw-ice.js @@ -11,17 +11,73 @@ function drawIce() { // Draw glaciers pack.ice.glaciers.forEach((glacier, index) => { - html += ``; + html += getGlacierHtml(glacier, index); }); // Draw icebergs pack.ice.icebergs.forEach((iceberg, index) => { - html += ``; + html += getIcebergHtml(iceberg, index); }); ice.html(html); TIME && console.timeEnd("drawIce"); + + function getGlacierHtml(glacier, index) { + return ``; + } + + function getIcebergHtml(iceberg, index) { + return ``; + } +} + +function redrawIceberg(index) { + TIME && console.time("redrawIceberg"); + const iceberg = pack.ice.icebergs[index]; + let el = ice.selectAll(`.iceberg[data-index="${index}"]`); + if (!iceberg && !el.empty()) { + el.remove(); + } else { + if (el.empty()) { + // Create new element if it doesn't exist + const polygon = getIcebergHtml(iceberg, index); + ice.node().insertAdjacentHTML("beforeend", polygon); + el = ice.selectAll(`.iceberg[data-index="${index}"]`); + } + el.attr("points", iceberg.points); + el.attr("size", iceberg.size); + el.attr("cell", iceberg.cellId); + el.attr("transform", iceberg.offset ? `translate(${iceberg.offset[0]},${iceberg.offset[1]})` : null); + } + TIME && console.timeEnd("redrawIceberg"); + + function getIcebergHtml(iceberg, index) { + return ``; + } +} + +function redrawGlacier(index) { + TIME && console.time("redrawGlacier"); + const glacier = pack.ice.glaciers[index]; + let el = ice.selectAll(`.glacier[data-index="${index}"]`); + if (!glacier && !el.empty()) { + el.remove(); + } else { + if (el.empty()) { + // Create new element if it doesn't exist + const polygon = getGlacierHtml(glacier, index); + ice.node().insertAdjacentHTML("beforeend", polygon); + el = ice.selectAll(`.glacier[data-index="${index}"]`); + } + el.attr("points", glacier.points); + el.attr("transform", glacier.offset ? `translate(${glacier.offset[0]},${glacier.offset[1]})` : null); + } + TIME && console.timeEnd("redrawGlacier"); + + function getGlacierHtml(glacier, index) { + return ``; + } } // Re-render ice layer from data model diff --git a/public/modules/ui/ice-editor.js b/public/modules/ui/ice-editor.js index e446acda..568df931 100644 --- a/public/modules/ui/ice-editor.js +++ b/public/modules/ui/ice-editor.js @@ -23,7 +23,7 @@ function editIce() { }); if (!modules.editIce) { - modules.editIce = {currentIndex: index}; + modules.editIce = {currentIndex: index, isGlacier: isGlacier}; // add listeners document.getElementById("iceEditStyle").addEventListener("click", () => editStyle("ice")); document.getElementById("iceRandomize").addEventListener("click", randomizeShape); @@ -32,19 +32,20 @@ function editIce() { document.getElementById("iceRemove").addEventListener("click", removeIce); } modules.editIce.currentIndex = index; + modules.editIce.isGlacier = isGlacier; function randomizeShape() { const idx = modules.editIce.currentIndex; Ice.randomizeIcebergShape(idx); - redrawIce(); + redrawIceberg(idx); } function changeSize() { const newSize = +this.value; const idx = modules.editIce.currentIndex; Ice.changeIcebergSize(idx, newSize); - redrawIce(); + redrawIceberg(idx); } function toggleAdd() { @@ -64,13 +65,12 @@ function editIce() { const size = +document.getElementById("iceSize")?.value || 1; Ice.addIceberg(i, size); - redrawIce(); if (d3.event.shiftKey === false) toggleAdd(); } function removeIce() { - const type = isGlacier ? "Glacier" : "Iceberg"; + const type = modules.editIce.isGlacier ? "Glacier" : "Iceberg"; alertMessage.innerHTML = /* html */ `Are you sure you want to remove the ${type}?`; $("#alert").dialog({ resizable: false, @@ -78,8 +78,7 @@ function editIce() { buttons: { Remove: function () { $(this).dialog("close"); - Ice.removeIce(isGlacier ? "glacier" : "iceberg", index); - redrawIce(); + Ice.removeIce(type.toLowerCase(), modules.editIce.currentIndex); $("#iceEditor").dialog("close"); }, Cancel: function () {