Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 93 additions & 0 deletions public/modules/ui/units-editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ function editUnits() {
ensureEl("distanceScaleInput").on("change", changeDistanceScale);
ensureEl("heightUnit").on("change", changeHeightUnit);
ensureEl("heightExponentInput").on("input", changeHeightExponent);
ensureEl("altitudeLegend").on("click", toggleLegend);
ensureEl("temperatureScale").on("change", changeTemperatureScale);

ensureEl("populationRateInput").on("change", changePopulationRate);
Expand Down Expand Up @@ -67,6 +68,7 @@ function editUnits() {
function changeHeightExponent() {
calculateTemperatures();
if (layerIsOn("toggleTemperature")) drawTemperature();
updateLegendIfVisible();
}
Comment on lines 68 to 72

function changeTemperatureScale() {
Expand Down Expand Up @@ -119,6 +121,97 @@ function editUnits() {
localStorage.removeItem("urbanDensity");
}

function toggleLegend() {
const isVisible = legend.selectAll("*").size() > 0;

if (isVisible) {
clearLegend();
} else {
updateAndDisplayLegend();
}
}

let legendHeightsCache = null;

function getLegendHeightsCache() {
const heights = pack?.cells?.h;
if (!heights) return null;

if (
legendHeightsCache &&
legendHeightsCache.heightsRef === heights &&
legendHeightsCache.heightsLen === heights.length
) {
return legendHeightsCache;
}

const countByHeight = new Map();
for (const h of heights) countByHeight.set(h, (countByHeight.get(h) || 0) + 1);

const sortedHeights = Array.from(countByHeight.keys()).sort((a, b) => a - b);

// Select a representative sample of heights across the range
const totalSamples = 10;
const step = Math.max(1, Math.floor(sortedHeights.length / totalSamples));
const sampledHeights = sortedHeights.filter(
(_, index) => index % step === 0 || index === sortedHeights.length - 1
);

legendHeightsCache = {
heightsRef: heights,
heightsLen: heights.length,
countByHeight,
sortedHeights,
sampledHeights
};

return legendHeightsCache;
}

function updateAndDisplayLegend() {
const cache = getLegendHeightsCache();
if (!cache) return;

const schemeName =
terrs.select("#landHeights").attr("scheme") ||
terrs.select("#oceanHeights").attr("scheme") ||
"bright";
const scheme = getColorScheme(schemeName);

const heightUnitSelect = ensureEl("heightUnit");
const heightUnitName =
heightUnitSelect.value === "custom_name"
? heightUnitSelect.nextElementSibling?.value || ""
: (heightUnitSelect.selectedOptions[0]?.text.match(/\(([^)]+)\)/)?.[1] ?? "");
Comment on lines +182 to +185

const sampled = cache.sampledHeights.map(height => {
const v = 1 - (height < 20 ? height - 5 : height) / 100;
const sRGB = scheme(v);
return {height, color: sRGB};
});

const data = sampled.map(c => [rn(c.height, 0), c.color, getHeight(c.height)]);

// Set the number of items per column
styleLegendColItems.value = data.length;

drawLegend(`Heights (in ${heightUnitName})`, data);

Comment on lines +195 to +199
// Center the legend label
const legendLabel = legend.select("#legendLabel");
const bbox = legend.node().getBBox();
legendLabel.attr("x", bbox.width / 2);

// Use shared legend positioning logic (defaults near bottom-right when data-x/y are unset)
if (window.fitLegendBox) fitLegendBox();
}

function updateLegendIfVisible() {
if (legend.selectAll("*").size() > 0) {
updateAndDisplayLegend();
}
}

function addRuler() {
if (!layerIsOn("toggleRulers")) toggleRulers();

Expand Down
5 changes: 5 additions & 0 deletions src/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -5340,6 +5340,11 @@
</slider-input>
</div>

<div data-tip="Toggle altitude legend. Granularity affects the amount of heights shown">
<span>Height legend:</span>
<button id="altitudeLegend" data-tip="Click to show the altitude legend" class="icon-list-bullet"></button>
</div>

<div class="unitsHeader" data-tip="Select Temperature scale">
<span class="icon-temperature-high"></span>
<label>Temperature:</label>
Expand Down
Loading