back to raster
This commit is contained in:
parent
992f0f6483
commit
206adb6b7d
3 changed files with 262 additions and 75 deletions
293
assets/js/map.ts
293
assets/js/map.ts
|
|
@ -287,105 +287,284 @@ let MapAPRSMap = {
|
||||||
// Try to use vector tiles if L.vectorGrid is available (loaded from CDN)
|
// Try to use vector tiles if L.vectorGrid is available (loaded from CDN)
|
||||||
let tileLayer: L.Layer;
|
let tileLayer: L.Layer;
|
||||||
|
|
||||||
// Check if L.vectorGrid is available
|
// Check if L.vectorGrid is available and if we should use vector tiles
|
||||||
console.log('Checking for L.vectorGrid:', typeof (L as any).vectorGrid);
|
console.log('Checking for L.vectorGrid:', typeof (L as any).vectorGrid);
|
||||||
console.log('Checking for L.vectorGrid.protobuf:', typeof (L as any).vectorGrid?.protobuf);
|
console.log('Checking for L.vectorGrid.protobuf:', typeof (L as any).vectorGrid?.protobuf);
|
||||||
|
|
||||||
if ((L as any).vectorGrid && (L as any).vectorGrid.protobuf) {
|
// Use raster tiles by default for better appearance
|
||||||
|
// Vector tiles have rendering issues with water features at lower zoom levels
|
||||||
|
const useVectorTiles = false; // Can be made configurable later
|
||||||
|
|
||||||
|
if (useVectorTiles && (L as any).vectorGrid && (L as any).vectorGrid.protobuf) {
|
||||||
try {
|
try {
|
||||||
console.log('L.vectorGrid.protobuf is available, attempting to use OpenStreetMap vector tiles');
|
console.log('L.vectorGrid.protobuf is available, attempting to use OpenStreetMap vector tiles');
|
||||||
|
|
||||||
const vectorProvider = tileProviders.osmVector;
|
const vectorProvider = tileProviders.osmVector;
|
||||||
|
|
||||||
// Style configuration for OpenStreetMap Shortbread schema
|
// Style configuration to match OSM raster tiles appearance
|
||||||
const vectorTileStyles = {
|
const vectorTileStyles = {
|
||||||
// Water features
|
// Water features - hide at lower zoom levels to match raster tiles
|
||||||
water_polygons: {
|
'water': function(properties: any, zoom: number) {
|
||||||
|
// Hide ALL water features at zoom 12 and below
|
||||||
|
if (zoom <= 12) {
|
||||||
|
return { fill: false, stroke: false, weight: 0, opacity: 0 };
|
||||||
|
}
|
||||||
|
// Only show water at zoom 13+
|
||||||
|
return {
|
||||||
|
fill: true,
|
||||||
|
fillColor: '#aad3df',
|
||||||
|
fillOpacity: 0.8,
|
||||||
|
weight: 0
|
||||||
|
};
|
||||||
|
},
|
||||||
|
'water_areas': function(properties: any, zoom: number) {
|
||||||
|
// Also hide water_areas at low zoom
|
||||||
|
if (zoom <= 12) {
|
||||||
|
return { fill: false, stroke: false, weight: 0, opacity: 0 };
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
fill: true,
|
||||||
|
fillColor: '#aad3df',
|
||||||
|
fillOpacity: 0.8,
|
||||||
|
weight: 0
|
||||||
|
};
|
||||||
|
},
|
||||||
|
'water_polygons': function(properties: any, zoom: number) {
|
||||||
|
// Hide water polygons too
|
||||||
|
if (zoom <= 12) {
|
||||||
|
return { fill: false, stroke: false, weight: 0, opacity: 0 };
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
fill: true,
|
||||||
|
fillColor: '#aad3df',
|
||||||
|
fillOpacity: 0.8,
|
||||||
|
weight: 0
|
||||||
|
};
|
||||||
|
},
|
||||||
|
'ocean': {
|
||||||
fill: true,
|
fill: true,
|
||||||
fillColor: '#a0c8f0',
|
fillColor: '#aad3df',
|
||||||
fillOpacity: 1,
|
fillOpacity: 1,
|
||||||
weight: 0
|
weight: 0
|
||||||
},
|
},
|
||||||
water_lines: {
|
'water_lines': {
|
||||||
weight: 2,
|
|
||||||
color: '#a0c8f0',
|
|
||||||
opacity: 1
|
|
||||||
},
|
|
||||||
water_areas: {
|
|
||||||
fill: true,
|
|
||||||
fillColor: '#a0c8f0',
|
|
||||||
fillOpacity: 1,
|
|
||||||
weight: 0
|
|
||||||
},
|
|
||||||
// Landuse and parks
|
|
||||||
landuse_areas: {
|
|
||||||
fill: true,
|
|
||||||
fillColor: '#f0f0f0',
|
|
||||||
fillOpacity: 0.6,
|
|
||||||
weight: 0
|
|
||||||
},
|
|
||||||
parks: {
|
|
||||||
fill: true,
|
|
||||||
fillColor: '#c8facc',
|
|
||||||
fillOpacity: 0.8,
|
|
||||||
weight: 0
|
|
||||||
},
|
|
||||||
// Buildings
|
|
||||||
buildings: {
|
|
||||||
fill: true,
|
|
||||||
fillColor: '#e0e0e0',
|
|
||||||
fillOpacity: 0.8,
|
|
||||||
weight: 1,
|
weight: 1,
|
||||||
color: '#cccccc'
|
color: '#aad3df',
|
||||||
|
opacity: 0.6
|
||||||
},
|
},
|
||||||
// Transportation (roads)
|
// Land - match OSM raster background
|
||||||
transport_lines: function(properties: any) {
|
'land': {
|
||||||
|
fill: true,
|
||||||
|
fillColor: '#f2efe9',
|
||||||
|
fillOpacity: 1,
|
||||||
|
weight: 0
|
||||||
|
},
|
||||||
|
// Landcover layers
|
||||||
|
'landcover': function(properties: any) {
|
||||||
|
const kind = properties.kind || properties.class;
|
||||||
|
// Parks and recreation areas - light green
|
||||||
|
if (kind === 'park' || kind === 'recreation_ground' || kind === 'grass') {
|
||||||
|
return {
|
||||||
|
fill: true,
|
||||||
|
fillColor: '#c8facc',
|
||||||
|
fillOpacity: 0.6,
|
||||||
|
weight: 0
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// Forests and woods - darker green
|
||||||
|
if (kind === 'forest' || kind === 'wood') {
|
||||||
|
return {
|
||||||
|
fill: true,
|
||||||
|
fillColor: '#add19e',
|
||||||
|
fillOpacity: 0.8,
|
||||||
|
weight: 0
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// Residential areas - light gray
|
||||||
|
if (kind === 'residential') {
|
||||||
|
return {
|
||||||
|
fill: true,
|
||||||
|
fillColor: '#e0e0e0',
|
||||||
|
fillOpacity: 0.3,
|
||||||
|
weight: 0
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// Commercial/industrial - slightly darker
|
||||||
|
if (kind === 'commercial' || kind === 'industrial') {
|
||||||
|
return {
|
||||||
|
fill: true,
|
||||||
|
fillColor: '#dfdfdf',
|
||||||
|
fillOpacity: 0.4,
|
||||||
|
weight: 0
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// Default landcover
|
||||||
|
return {
|
||||||
|
fill: true,
|
||||||
|
fillColor: '#f2efe9',
|
||||||
|
fillOpacity: 0.5,
|
||||||
|
weight: 0
|
||||||
|
};
|
||||||
|
},
|
||||||
|
// Streets/roads - match OSM styling
|
||||||
|
'streets': function(properties: any) {
|
||||||
const kind = properties.kind || properties.highway;
|
const kind = properties.kind || properties.highway;
|
||||||
if (kind === 'motorway' || kind === 'trunk') {
|
// Motorways - orange
|
||||||
|
if (kind === 'motorway' || kind === 'motorway_link') {
|
||||||
return {
|
return {
|
||||||
weight: 4,
|
weight: 4,
|
||||||
color: '#e9ac77',
|
color: '#e892a2',
|
||||||
opacity: 1
|
opacity: 1
|
||||||
};
|
};
|
||||||
} else if (kind === 'primary' || kind === 'secondary') {
|
}
|
||||||
|
// Trunk roads - pinkish
|
||||||
|
if (kind === 'trunk' || kind === 'trunk_link') {
|
||||||
|
return {
|
||||||
|
weight: 4,
|
||||||
|
color: '#f9b29c',
|
||||||
|
opacity: 1
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// Primary roads - orange/yellow
|
||||||
|
if (kind === 'primary' || kind === 'primary_link') {
|
||||||
return {
|
return {
|
||||||
weight: 3,
|
weight: 3,
|
||||||
color: '#ffd380',
|
color: '#fcd6a4',
|
||||||
opacity: 1
|
opacity: 1
|
||||||
};
|
};
|
||||||
} else {
|
}
|
||||||
|
// Secondary roads - yellow
|
||||||
|
if (kind === 'secondary' || kind === 'secondary_link') {
|
||||||
|
return {
|
||||||
|
weight: 2.5,
|
||||||
|
color: '#f7fabf',
|
||||||
|
opacity: 1
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// Tertiary roads
|
||||||
|
if (kind === 'tertiary' || kind === 'tertiary_link') {
|
||||||
return {
|
return {
|
||||||
weight: 2,
|
weight: 2,
|
||||||
color: '#ffffff',
|
color: '#ffffff',
|
||||||
|
opacity: 1
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// Residential streets
|
||||||
|
if (kind === 'residential' || kind === 'living_street') {
|
||||||
|
return {
|
||||||
|
weight: 1.5,
|
||||||
|
color: '#ffffff',
|
||||||
|
opacity: 0.9
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// Service roads
|
||||||
|
if (kind === 'service') {
|
||||||
|
return {
|
||||||
|
weight: 1,
|
||||||
|
color: '#ffffff',
|
||||||
opacity: 0.8
|
opacity: 0.8
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
},
|
// Default road style
|
||||||
// Places
|
|
||||||
places: function(properties: any, zoom: number) {
|
|
||||||
if (zoom < 10) return { weight: 0 }; // Hide at low zoom
|
|
||||||
return {
|
return {
|
||||||
weight: 0,
|
weight: 1,
|
||||||
fillOpacity: 0,
|
color: '#ffffff',
|
||||||
interactive: false
|
opacity: 0.8
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
// Default style for unmatched layers
|
'streets_med': function(properties: any) {
|
||||||
_default: {
|
// Medium priority streets
|
||||||
|
return {
|
||||||
|
weight: 2,
|
||||||
|
color: '#ffffff',
|
||||||
|
opacity: 0.9
|
||||||
|
};
|
||||||
|
},
|
||||||
|
'streets_low': {
|
||||||
|
// Low priority streets
|
||||||
weight: 1,
|
weight: 1,
|
||||||
color: '#cccccc',
|
color: '#ffffff',
|
||||||
opacity: 0.5
|
opacity: 0.7
|
||||||
|
},
|
||||||
|
// Buildings - subtle gray
|
||||||
|
'buildings': {
|
||||||
|
fill: true,
|
||||||
|
fillColor: '#d9d0c9',
|
||||||
|
fillOpacity: 0.7,
|
||||||
|
weight: 0.5,
|
||||||
|
color: '#cfc7c0',
|
||||||
|
opacity: 0.8
|
||||||
|
},
|
||||||
|
// POIs - hide them to match raster simplicity
|
||||||
|
'pois': {
|
||||||
|
weight: 0,
|
||||||
|
opacity: 0,
|
||||||
|
fillOpacity: 0
|
||||||
|
},
|
||||||
|
// Places - hide labels
|
||||||
|
'places': {
|
||||||
|
weight: 0,
|
||||||
|
opacity: 0,
|
||||||
|
fillOpacity: 0
|
||||||
|
},
|
||||||
|
// Boundaries - subtle
|
||||||
|
'boundaries': {
|
||||||
|
weight: 0.8,
|
||||||
|
color: '#a09090',
|
||||||
|
opacity: 0.4,
|
||||||
|
dashArray: '3, 3'
|
||||||
|
},
|
||||||
|
// Transit - hide for simplicity
|
||||||
|
'transit': {
|
||||||
|
weight: 0,
|
||||||
|
opacity: 0
|
||||||
|
},
|
||||||
|
// Default style - should rarely be used
|
||||||
|
'*': {
|
||||||
|
fill: false,
|
||||||
|
weight: 0,
|
||||||
|
opacity: 0
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Create vector grid layer using L.vectorGrid.protobuf
|
// Create vector grid layer using L.vectorGrid.protobuf
|
||||||
tileLayer = (L as any).vectorGrid.protobuf(vectorProvider.url, {
|
tileLayer = (L as any).vectorGrid.protobuf(vectorProvider.url, {
|
||||||
attribution: vectorProvider.attribution,
|
attribution: vectorProvider.attribution,
|
||||||
maxZoom: vectorProvider.maxZoom,
|
maxNativeZoom: vectorProvider.maxZoom,
|
||||||
vectorTileLayerStyles: vectorTileStyles,
|
maxZoom: 19,
|
||||||
interactive: true,
|
rendererFactory: L.canvas.tile,
|
||||||
|
interactive: false,
|
||||||
getFeatureId: function(feature: any) {
|
getFeatureId: function(feature: any) {
|
||||||
return feature.properties.osm_id || feature.properties.id;
|
return feature.properties.osm_id || feature.properties.id;
|
||||||
|
},
|
||||||
|
// Use a function for vectorTileLayerStyles to have full control
|
||||||
|
vectorTileLayerStyles: function(properties: any, zoom: number) {
|
||||||
|
// Access layer name from 'this' context
|
||||||
|
const layerName = this.layerName || '';
|
||||||
|
|
||||||
|
// Apply styles based on layer name
|
||||||
|
const styles = vectorTileStyles;
|
||||||
|
|
||||||
|
// Check if we have a specific style for this layer
|
||||||
|
if (styles[layerName]) {
|
||||||
|
const style = styles[layerName];
|
||||||
|
if (typeof style === 'function') {
|
||||||
|
return style.call(this, properties, zoom);
|
||||||
|
}
|
||||||
|
return style;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use wildcard style if defined
|
||||||
|
if (styles['*']) {
|
||||||
|
const style = styles['*'];
|
||||||
|
if (typeof style === 'function') {
|
||||||
|
return style.call(this, properties, zoom);
|
||||||
|
}
|
||||||
|
return style;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default: hide unknown features
|
||||||
|
return { fill: false, stroke: false, weight: 0, opacity: 0 };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -35,28 +35,36 @@
|
||||||
</.live_title>
|
</.live_title>
|
||||||
<link phx-track-static rel="stylesheet" href={~p"/assets/css/app.css"} />
|
<link phx-track-static rel="stylesheet" href={~p"/assets/css/app.css"} />
|
||||||
|
|
||||||
<!-- Leaflet CSS -->
|
<!-- Leaflet CSS -->
|
||||||
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />
|
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />
|
||||||
<link rel="stylesheet" href="https://unpkg.com/leaflet.markercluster@1.5.3/dist/MarkerCluster.css" />
|
<link rel="stylesheet" href="https://unpkg.com/leaflet.markercluster@1.5.3/dist/MarkerCluster.css" />
|
||||||
<link rel="stylesheet" href="https://unpkg.com/leaflet.markercluster@1.5.3/dist/MarkerCluster.Default.css" />
|
<link rel="stylesheet" href="https://unpkg.com/leaflet.markercluster@1.5.3/dist/MarkerCluster.Default.css" />
|
||||||
|
|
||||||
<!-- Core libraries -->
|
<!-- Core libraries -->
|
||||||
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
|
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js">
|
||||||
<script src="https://unpkg.com/leaflet.heat@0.2.0/dist/leaflet-heat.js"></script>
|
</script>
|
||||||
<script src="https://unpkg.com/leaflet.markercluster@1.5.3/dist/leaflet.markercluster.js"></script>
|
<script src="https://unpkg.com/leaflet.heat@0.2.0/dist/leaflet-heat.js">
|
||||||
<script src="https://unpkg.com/overlapping-marker-spiderfier-leaflet@0.2.7/oms.min.js"></script>
|
</script>
|
||||||
|
<script src="https://unpkg.com/leaflet.markercluster@1.5.3/dist/leaflet.markercluster.js">
|
||||||
|
</script>
|
||||||
|
<script src="https://unpkg.com/overlapping-marker-spiderfier-leaflet@0.2.7/oms.min.js">
|
||||||
|
</script>
|
||||||
|
|
||||||
<!-- Chart.js -->
|
<!-- Chart.js -->
|
||||||
<script src="https://unpkg.com/chart.js@4.5.0/dist/chart.umd.js"></script>
|
<script src="https://unpkg.com/chart.js@4.5.0/dist/chart.umd.js">
|
||||||
<script src="https://unpkg.com/chartjs-adapter-date-fns@3.0.0/dist/chartjs-adapter-date-fns.bundle.min.js"></script>
|
</script>
|
||||||
|
<script src="https://unpkg.com/chartjs-adapter-date-fns@3.0.0/dist/chartjs-adapter-date-fns.bundle.min.js">
|
||||||
|
</script>
|
||||||
|
|
||||||
<!-- Topbar -->
|
<!-- Topbar -->
|
||||||
<script src="https://unpkg.com/topbar@3.0.0/topbar.min.js"></script>
|
<script src="https://unpkg.com/topbar@3.0.0/topbar.min.js">
|
||||||
|
</script>
|
||||||
|
|
||||||
<!-- Leaflet VectorGrid for vector tiles -->
|
<!-- Leaflet VectorGrid for vector tiles -->
|
||||||
<script src="https://unpkg.com/leaflet.vectorgrid@1.3.0/dist/Leaflet.VectorGrid.bundled.js"></script>
|
<script src="https://unpkg.com/leaflet.vectorgrid@1.3.0/dist/Leaflet.VectorGrid.bundled.js">
|
||||||
|
</script>
|
||||||
|
|
||||||
<!-- App scripts -->
|
<!-- App scripts -->
|
||||||
<script defer phx-track-static type="text/javascript" src={~p"/assets/app.js"}>
|
<script defer phx-track-static type="text/javascript" src={~p"/assets/app.js"}>
|
||||||
</script>
|
</script>
|
||||||
<script>
|
<script>
|
||||||
|
|
|
||||||
|
|
@ -15,10 +15,10 @@ defmodule AprsmeWeb.Router do
|
||||||
plug :put_root_layout, {AprsmeWeb.Layouts, :root}
|
plug :put_root_layout, {AprsmeWeb.Layouts, :root}
|
||||||
plug :protect_from_forgery
|
plug :protect_from_forgery
|
||||||
|
|
||||||
plug :put_secure_browser_headers, %{
|
# plug :put_secure_browser_headers, %{
|
||||||
"content-security-policy" =>
|
# "content-security-policy" =>
|
||||||
"default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://js.sentry-cdn.com https://unpkg.com https://cdn.jsdelivr.net https://cdnjs.cloudflare.com; style-src 'self' 'unsafe-inline' https://unpkg.com; img-src 'self' data: https: http: blob:; font-src 'self' data:; connect-src 'self' wss: https://*.ingest.sentry.io https://*.sentry.io https://nominatim.openstreetmap.org https://tile.openstreetmap.org https://*.tile.openstreetmap.org https://*.tile.openstreetmap.de https://*.basemaps.cartocdn.com; media-src 'self'; object-src 'none'; frame-ancestors 'none'; base-uri 'self'; form-action 'self'; frame-src 'self'; manifest-src 'self'; worker-src 'self' blob:"
|
# "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://js.sentry-cdn.com https://unpkg.com https://cdn.jsdelivr.net https://cdnjs.cloudflare.com; style-src 'self' 'unsafe-inline' https://unpkg.com; img-src 'self' data: https: http: blob:; font-src 'self' data:; connect-src 'self' wss: https://*.ingest.sentry.io https://*.sentry.io https://nominatim.openstreetmap.org https://tile.openstreetmap.org https://*.tile.openstreetmap.org https://*.tile.openstreetmap.de https://*.basemaps.cartocdn.com; media-src 'self'; object-src 'none'; frame-ancestors 'none'; base-uri 'self'; form-action 'self'; frame-src 'self'; manifest-src 'self'; worker-src 'self' blob:"
|
||||||
}
|
# }
|
||||||
|
|
||||||
plug :fetch_current_user
|
plug :fetch_current_user
|
||||||
plug AprsmeWeb.Plugs.SetLocale
|
plug AprsmeWeb.Plugs.SetLocale
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue