feat: add automated crons, telemetry cleanup, RTL support, and manual road candidate tools
This commit is contained in:
@@ -17,29 +17,9 @@ import 'maplibre-gl/dist/maplibre-gl.css';
|
||||
|
||||
const TILES = (import.meta as any).env.VITE_TILES_URL || 'https://tiles.intaleqapp.com';
|
||||
|
||||
// "Our map" style, built inline from the public Martin vector tiles (same endpoints
|
||||
// the main app uses — no API key needed). Roads-focused for clean street comparison,
|
||||
// with our approved_roads drawn green. approved_roads tiles 404 until the table exists;
|
||||
// MapLibre degrades gracefully (just no green lines yet).
|
||||
const ourStyle = (): any => ({
|
||||
version: 8,
|
||||
glyphs: 'https://cdn.protomaps.com/fonts/pbf/{fontstack}/{range}.pbf',
|
||||
sources: {
|
||||
osm_lines: { type: 'vector', tiles: [`${TILES}/planet_osm_line/{z}/{x}/{y}`], maxzoom: 14 },
|
||||
osm_polys: { type: 'vector', tiles: [`${TILES}/planet_osm_polygon/{z}/{x}/{y}`], maxzoom: 14 },
|
||||
approved: { type: 'vector', tiles: [`${TILES}/approved_roads/{z}/{x}/{y}`], minzoom: 8, maxzoom: 18 },
|
||||
},
|
||||
layers: [
|
||||
{ id: 'bg', type: 'background', paint: { 'background-color': '#eef0f2' } },
|
||||
{ id: 'water', type: 'fill', source: 'osm_polys', 'source-layer': 'planet_osm_polygon', filter: ['in', 'natural', 'water', 'bay'], paint: { 'fill-color': '#a3ccff' } },
|
||||
{ id: 'roads-casing', type: 'line', source: 'osm_lines', 'source-layer': 'planet_osm_line', filter: ['has', 'highway'], paint: { 'line-color': '#c8ccd4', 'line-width': ['interpolate', ['linear'], ['zoom'], 10, 1.2, 16, 10] } },
|
||||
{ id: 'roads-core', type: 'line', source: 'osm_lines', 'source-layer': 'planet_osm_line', filter: ['has', 'highway'], paint: { 'line-color': '#ffffff', 'line-width': ['interpolate', ['linear'], ['zoom'], 10, 0.6, 16, 7] } },
|
||||
{ id: 'approved', type: 'line', source: 'approved', 'source-layer': 'approved_roads', paint: { 'line-color': '#22c55e', 'line-width': ['interpolate', ['linear'], ['zoom'], 10, 1.5, 16, 8] } },
|
||||
],
|
||||
});
|
||||
|
||||
type RefKey = 'esri-sat' | 'esri-streets' | 'osm';
|
||||
type RefKey = 'google-sat' | 'esri-sat' | 'esri-streets' | 'osm';
|
||||
const REFS: Record<RefKey, { label: string; tiles: string; attribution: string; maxzoom: number }> = {
|
||||
'google-sat': { label: '🛰️ Google Satellite', tiles: 'https://mt1.google.com/vt/lyrs=s&x={x}&y={y}&z={z}', attribution: '© Google', maxzoom: 20 },
|
||||
'esri-sat': { label: '🛰️ Esri Satellite', tiles: 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}', attribution: '© Esri, Maxar', maxzoom: 19 },
|
||||
'esri-streets': { label: '🗺️ Esri Streets', tiles: 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer/tile/{z}/{y}/{x}', attribution: '© Esri', maxzoom: 19 },
|
||||
'osm': { label: '🧭 OSM Standard', tiles: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png', attribution: '© OpenStreetMap', maxzoom: 19 },
|
||||
@@ -68,11 +48,16 @@ const CompareView: React.FC = () => {
|
||||
const start: [number, number] = [35.91, 31.95];
|
||||
const startZoom = 15;
|
||||
|
||||
const lMap = new maplibregl.Map({ container: leftDiv.current, style: ourStyle(), center: start, zoom: startZoom, attributionControl: false });
|
||||
const lMap = new maplibregl.Map({ container: leftDiv.current, style: TILES + '/style.json', center: start, zoom: startZoom, attributionControl: false });
|
||||
const rMap = new maplibregl.Map({ container: rightDiv.current, style: rasterStyle(REFS['esri-sat']), center: start, zoom: startZoom, attributionControl: false });
|
||||
lMap.addControl(new maplibregl.NavigationControl({ showCompass: false }), 'top-left');
|
||||
rMap.addControl(new maplibregl.AttributionControl({ compact: true }), 'bottom-right');
|
||||
|
||||
lMap.on('load', () => {
|
||||
lMap.addSource('approved', { type: 'vector', tiles: [`${TILES}/approved_roads/{z}/{x}/{y}`], minzoom: 8, maxzoom: 18 });
|
||||
lMap.addLayer({ id: 'approved', type: 'line', source: 'approved', 'source-layer': 'approved_roads', paint: { 'line-color': '#22c55e', 'line-width': ['interpolate', ['linear'], ['zoom'], 10, 1.5, 16, 8] } });
|
||||
});
|
||||
|
||||
// Keep the two views locked together. The guard stops the move→jumpTo→move loop.
|
||||
const link = (from: maplibregl.Map, to: maplibregl.Map) => {
|
||||
if (syncing.current) return;
|
||||
@@ -101,10 +86,6 @@ const CompareView: React.FC = () => {
|
||||
|
||||
const fmt = (n: number) => n.toFixed(6);
|
||||
const z = Math.round(center.zoom);
|
||||
const googleUrl = `https://www.google.com/maps/@${center.lat},${center.lng},${z}z/data=!3m1!1e3`; // 1e3 = satellite
|
||||
const bingUrl = `https://www.bing.com/maps?cp=${center.lat}~${center.lng}&lvl=${z}&style=h`; // h = aerial+labels
|
||||
const josmUrl = `https://www.openstreetmap.org/#map=${z}/${fmt(center.lat)}/${fmt(center.lng)}`;
|
||||
|
||||
const btn: React.CSSProperties = { background: '#1e293b', border: '1px solid #334155', color: '#cbd5e1', padding: '6px 10px', borderRadius: '8px', cursor: 'pointer', fontSize: '0.75rem', textDecoration: 'none', display: 'inline-flex', alignItems: 'center', gap: '5px' };
|
||||
|
||||
return (
|
||||
@@ -123,12 +104,6 @@ const CompareView: React.FC = () => {
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div style={{ display: 'flex', gap: '6px' }}>
|
||||
<a href={googleUrl} target="_blank" rel="noopener noreferrer" style={btn} title="Open Google Maps satellite at this point">Google ↗</a>
|
||||
<a href={bingUrl} target="_blank" rel="noopener noreferrer" style={btn} title="Open Bing aerial at this point">Bing ↗</a>
|
||||
<a href={josmUrl} target="_blank" rel="noopener noreferrer" style={btn} title="Open on openstreetmap.org">OSM ↗</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Maps */}
|
||||
|
||||
Reference in New Issue
Block a user