Fix measurements in popup details

This commit is contained in:
2026-07-07 22:17:58 -05:00
parent 100340fbb4
commit 900e195926
2 changed files with 87 additions and 27 deletions
+60 -27
View File
@@ -5,6 +5,7 @@ const TILE_MAX_NATIVE_ZOOM = 19;
const MAP_MAX_ZOOM = 24;
const MAP_ZOOM_STEP = 0.25;
const WHEEL_PIXELS_PER_ZOOM_LEVEL = 240;
const FEET_PER_METER = 3.280839895;
const TIMELINE_PRESETS = [
{
id: "purchase",
@@ -330,7 +331,8 @@ function buildPopupContent(properties) {
const title = `<strong>${escapeHtml(name)}</strong>`;
const subtitle = name === label ? "" : `<div>${escapeHtml(label)}</div>`;
const allEntries = [...lifecycleEntries, ...entries, ...relationshipEntries];
if (allEntries.length === 0 && linkEntries.length === 0) {
const measurementTable = buildMeasurementTable(details?.measurements);
if (allEntries.length === 0 && linkEntries.length === 0 && !measurementTable) {
return `${title}${subtitle}`;
}
@@ -341,12 +343,16 @@ function buildPopupContent(properties) {
.map((link) => `<div><a href="${escapeHtml(link.url)}" target="_blank" rel="noreferrer">Info</a></div>`)
.join("");
return `${title}${subtitle}<div>${detailRows}${linkRows}</div>`;
return `${title}${subtitle}<div>${detailRows}${measurementTable}${linkRows}</div>`;
}
function shouldShowDetailField(key, details = {}) {
if (key === "measurements") {
return false;
}
if (
Array.isArray(details.measurements) &&
hasDatedMeasurements(details.measurements) &&
(key === "canopyDiameter" || key === "height")
) {
return false;
@@ -382,12 +388,8 @@ function formatDetailLabel(key) {
}
function formatDetailValue(key, value) {
if (key === "measurements") {
return formatPlantMeasurements(value);
}
if (key === "canopyDiameter" || key === "height") {
return `${value} m`;
return formatMetersAsFeet(value);
}
if (key === "offsetFeet" || key === "spacingFeet") {
@@ -397,32 +399,63 @@ function formatDetailValue(key, value) {
return String(value);
}
function formatPlantMeasurements(measurements) {
if (!Array.isArray(measurements)) {
return String(measurements);
}
return measurements.map(formatPlantMeasurement).join("; ");
function formatMetersAsFeet(value) {
return `${formatNumber(value * FEET_PER_METER)} ft`;
}
function formatPlantMeasurement(measurement) {
const parts = [];
function formatNumber(value) {
return Number(value.toFixed(1)).toString();
}
if (measurement.measuredDate) {
parts.push(formatDetailValue("measuredDate", measurement.measuredDate));
function buildMeasurementTable(measurements) {
const datedMeasurements = getDatedMeasurements(measurements);
if (!datedMeasurements.length) {
return "";
}
if (measurement.canopyDiameter !== undefined) {
parts.push(
`canopy ${formatDetailValue("canopyDiameter", measurement.canopyDiameter)}`,
);
const rows = datedMeasurements
.map(
(measurement) => `
<tr>
<td>${escapeHtml(measurement.measuredDate)}</td>
<td>${escapeHtml(formatOptionalMeasurement(measurement.canopyDiameter))}</td>
<td>${escapeHtml(formatOptionalMeasurement(measurement.height))}</td>
</tr>
`,
)
.join("");
return `
<div class="measurement-table-block">
<div><span>${escapeHtml(formatDetailLabel("measurements"))}:</span></div>
<table class="measurement-table">
<thead>
<tr>
<th>Date</th>
<th>Canopy dia.</th>
<th>Height</th>
</tr>
</thead>
<tbody>${rows}</tbody>
</table>
</div>
`;
}
function formatOptionalMeasurement(value) {
return value === undefined ? "" : formatMetersAsFeet(value);
}
function hasDatedMeasurements(measurements) {
return getDatedMeasurements(measurements).length > 0;
}
function getDatedMeasurements(measurements) {
if (!Array.isArray(measurements)) {
return [];
}
if (measurement.height !== undefined) {
parts.push(`height ${formatDetailValue("height", measurement.height)}`);
}
return parts.join(", ");
return measurements.filter((measurement) => measurement.measuredDate);
}
function escapeHtml(value) {
+27
View File
@@ -129,6 +129,33 @@ main {
font-family: "Iowan Old Style", "Palatino Linotype", "URW Palladio L", serif;
}
.measurement-table-block {
margin-top: 0.35rem;
}
.measurement-table {
width: 100%;
margin-top: 0.15rem;
border-collapse: collapse;
font-size: 0.92em;
}
.measurement-table th,
.measurement-table td {
padding: 0.12rem 0.35rem 0.12rem 0;
border-bottom: 1px solid rgba(87, 68, 38, 0.18);
text-align: left;
white-space: nowrap;
}
.measurement-table th {
font-weight: 700;
}
.measurement-table tbody tr:last-child td {
border-bottom: 0;
}
.timeline-control {
display: grid;
gap: 0.45rem;