Files
osm-import-tools/web/templates/city-boundaries-report.html
2026-08-28 14:23:26 -07:00

244 lines
9.8 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>City Boundaries Report</title>
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />
<link rel="stylesheet" href="{{ url_for('static', filename='map-ui.css') }}">
<style>
.legend-item {
display: flex;
align-items: center;
margin: 4px 0;
cursor: pointer;
font-size: 11px;
}
.legend-item input[type="checkbox"] {
margin-right: 6px;
}
.legend-swatch {
width: 11px;
height: 11px;
border-radius: 50%;
margin-right: 6px;
flex-shrink: 0;
border: 1px solid rgba(0,0,0,0.25);
}
.legend-label {
flex: 1;
}
.legend-count {
color: #888;
font-variant-numeric: tabular-nums;
}
.no-data-msg {
font-size: 11px;
color: #999;
font-style: italic;
margin-top: 6px;
}
.view-toggle {
display: flex;
gap: 4px;
margin: 6px 0 10px;
}
.view-btn {
flex: 1;
padding: 6px 4px;
font-size: 11px;
font-weight: 600;
border: 1px solid #ccc;
background: #f8f9fa;
color: #555;
border-radius: 4px;
cursor: pointer;
}
.view-btn.active {
background: #6f42c1;
color: white;
border-color: #6f42c1;
}
.view-toggle .view-btn {
flex: 1 1 0;
}
#boundaryLog {
display: none;
max-height: 120px;
overflow-y: auto;
background: #1a1a2e;
color: #ddd;
font-family: monospace;
font-size: 10px;
padding: 6px;
border-radius: 4px;
margin-top: 6px;
white-space: pre-wrap;
}
.boundary-meta {
font-size: 10px;
color: #999;
margin: 4px 0 8px;
}
</style>
</head>
<body>
<div id="map"></div>
<button class="hamburger-button" id="hamburgerButton" aria-label="Toggle menu">
<span></span>
<span></span>
<span></span>
</button>
<div class="overlay" id="overlay"></div>
<div class="controls" id="controls">
<a href="/reports" class="btn-back">&#8592; Back to Reports</a>
<h3>City Boundaries</h3>
<p style="font-size:11px;color:#666;margin-bottom:8px;">
County source data vs matched OSM addresses.
</p>
<div class="file-input-group">
<label for="countySelect" style="display:block;margin-bottom:3px;font-weight:500;font-size:11px;">County:</label>
<select id="countySelect">
{% for county in counties %}
<option value="{{ county.id }}" {% if county.id not in available_counties %}disabled{% endif %}>
{{ county.name }}{% if county.id not in available_counties %} (no data){% endif %}
</option>
{% endfor %}
</select>
</div>
<div class="file-input-group">
<label for="fieldSelect" style="display:block;margin-bottom:3px;font-weight:500;font-size:11px;">Compare:</label>
<select id="fieldSelect">
<option value="postal_community" selected>Postal community (USPS mailing city)</option>
<option value="city">City (legal/municipal jurisdiction)</option>
</select>
<span class="hint" style="font-size:10px;color:#999;">These two often differ — a parcel can be legally inside one city but addressed to another for mail.</span>
</div>
<div class="view-toggle" id="viewToggle">
<button class="view-btn active" data-view="agreement">Agreement Status</button>
<button class="view-btn" data-view="city-names">City Names</button>
<button class="view-btn" data-view="boundary-check">Boundary Check</button>
</div>
<div id="agreementSection">
<h3>Legend</h3>
<div id="legend">
<label class="legend-item" data-status="mismatch">
<input type="checkbox" checked>
<span class="legend-swatch" style="background:#dc3545;"></span>
<span class="legend-label">Mismatch</span>
<span class="legend-count" id="count-mismatch">–</span>
</label>
<label class="legend-item" data-status="county_only">
<input type="checkbox" checked>
<span class="legend-swatch" style="background:#fd7e14;"></span>
<span class="legend-label">Missing in OSM</span>
<span class="legend-count" id="count-county_only">–</span>
</label>
<label class="legend-item" data-status="osm_only">
<input type="checkbox" checked>
<span class="legend-swatch" style="background:#17a2b8;"></span>
<span class="legend-label">Missing in county</span>
<span class="legend-count" id="count-osm_only">–</span>
</label>
<label class="legend-item" data-status="both_missing">
<input type="checkbox" checked>
<span class="legend-swatch" style="background:#6c757d;"></span>
<span class="legend-label">Both missing</span>
<span class="legend-count" id="count-both_missing">–</span>
</label>
<label class="legend-item" data-status="match">
<input type="checkbox">
<span class="legend-swatch" style="background:#28a745;"></span>
<span class="legend-label">Match</span>
<span class="legend-count" id="count-match">–</span>
</label>
</div>
<p style="font-size:10px;color:#999;margin-top:4px;">"Match" is unchecked by default (usually the majority of points) — check it to see agreeing addresses too.</p>
</div>
<div id="cityNameSection" style="display:none;">
<p style="font-size:11px;color:#666;margin-bottom:8px;">
What the source data thinks each address's city is — not an agreement check.
Click any point for the exact name.
</p>
<div class="file-input-group">
<label for="citySourceSelect" style="display:block;margin-bottom:3px;font-weight:500;font-size:11px;">Color by:</label>
<select id="citySourceSelect">
<option value="county" selected>County (source data)</option>
<option value="osm">OpenStreetMap</option>
</select>
</div>
<h3>Cities</h3>
<div id="cityLegend"><!-- filled dynamically --></div>
</div>
<div id="boundarySection" style="display:none;">
<p style="font-size:11px;color:#666;margin-bottom:8px;">
Point-in-polygon check against the traced/imported boundary at
<code>map-checker/boundary.geojson</code> (see the Boundary
Tracer tool) — precise, but only as good as that boundary.
Independent of the county/OSM tag comparison above; spans all
configured counties at once rather than one at a time.
</p>
<button id="runBoundaryCheckBtn">Run boundary check</button>
<div class="boundary-meta" id="boundaryMeta"></div>
<pre id="boundaryLog"></pre>
<h3 style="margin-top:10px;">Legend</h3>
<div id="boundaryLegend">
<label class="legend-item" data-flag="__outline__">
<input type="checkbox" checked>
<span class="legend-swatch" style="background:none;border-color:#6f42c1;border-width:2px;"></span>
<span class="legend-label">Traced boundary</span>
</label>
<label class="legend-item" data-flag="inside_but_not_labeled">
<input type="checkbox" checked>
<span class="legend-swatch" style="background:#dc3545;"></span>
<span class="legend-label">Inside, not labeled expected city</span>
<span class="legend-count" id="count-inside_but_not_labeled">–</span>
</label>
<label class="legend-item" data-flag="outside_but_labeled">
<input type="checkbox" checked>
<span class="legend-swatch" style="background:#fd7e14;"></span>
<span class="legend-label">Outside, labeled expected city</span>
<span class="legend-count" id="count-outside_but_labeled">–</span>
</label>
</div>
<p class="no-data-msg" id="boundaryNoData" style="display:none;">
No boundary check has been run yet — click "Run boundary check" above.
</p>
</div>
<div id="status" class="status hidden"></div>
</div>
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
<script src="{{ url_for('static', filename='map-ui.js') }}"></script>
<script>
const AVAILABLE_COUNTIES = {{ available_counties | tojson }};
const PINNED_CITIES = {{ pinned_cities | tojson }};
const IS_AUTHENTICATED = {{ 'true' if current_user else 'false' }};
</script>
<script src="{{ url_for('static', filename='report-map.js') }}"></script>
</body>
</html>