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)
|
||||
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.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 {
|
||||
console.log('L.vectorGrid.protobuf is available, attempting to use OpenStreetMap vector tiles');
|
||||
|
||||
const vectorProvider = tileProviders.osmVector;
|
||||
|
||||
// Style configuration for OpenStreetMap Shortbread schema
|
||||
// Style configuration to match OSM raster tiles appearance
|
||||
const vectorTileStyles = {
|
||||
// Water features
|
||||
water_polygons: {
|
||||
// Water features - hide at lower zoom levels to match raster tiles
|
||||
'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,
|
||||
fillColor: '#a0c8f0',
|
||||
fillColor: '#aad3df',
|
||||
fillOpacity: 1,
|
||||
weight: 0
|
||||
},
|
||||
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,
|
||||
'water_lines': {
|
||||
weight: 1,
|
||||
color: '#cccccc'
|
||||
color: '#aad3df',
|
||||
opacity: 0.6
|
||||
},
|
||||
// Transportation (roads)
|
||||
transport_lines: function(properties: any) {
|
||||
// Land - match OSM raster background
|
||||
'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;
|
||||
if (kind === 'motorway' || kind === 'trunk') {
|
||||
// Motorways - orange
|
||||
if (kind === 'motorway' || kind === 'motorway_link') {
|
||||
return {
|
||||
weight: 4,
|
||||
color: '#e9ac77',
|
||||
color: '#e892a2',
|
||||
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 {
|
||||
weight: 3,
|
||||
color: '#ffd380',
|
||||
color: '#fcd6a4',
|
||||
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 {
|
||||
weight: 2,
|
||||
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
|
||||
};
|
||||
}
|
||||
},
|
||||
// Places
|
||||
places: function(properties: any, zoom: number) {
|
||||
if (zoom < 10) return { weight: 0 }; // Hide at low zoom
|
||||
// Default road style
|
||||
return {
|
||||
weight: 0,
|
||||
fillOpacity: 0,
|
||||
interactive: false
|
||||
weight: 1,
|
||||
color: '#ffffff',
|
||||
opacity: 0.8
|
||||
};
|
||||
},
|
||||
// Default style for unmatched layers
|
||||
_default: {
|
||||
'streets_med': function(properties: any) {
|
||||
// Medium priority streets
|
||||
return {
|
||||
weight: 2,
|
||||
color: '#ffffff',
|
||||
opacity: 0.9
|
||||
};
|
||||
},
|
||||
'streets_low': {
|
||||
// Low priority streets
|
||||
weight: 1,
|
||||
color: '#cccccc',
|
||||
opacity: 0.5
|
||||
color: '#ffffff',
|
||||
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
|
||||
tileLayer = (L as any).vectorGrid.protobuf(vectorProvider.url, {
|
||||
attribution: vectorProvider.attribution,
|
||||
maxZoom: vectorProvider.maxZoom,
|
||||
vectorTileLayerStyles: vectorTileStyles,
|
||||
interactive: true,
|
||||
maxNativeZoom: vectorProvider.maxZoom,
|
||||
maxZoom: 19,
|
||||
rendererFactory: L.canvas.tile,
|
||||
interactive: false,
|
||||
getFeatureId: function(feature: any) {
|
||||
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>
|
||||
<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.markercluster@1.5.3/dist/MarkerCluster.css" />
|
||||
<link rel="stylesheet" href="https://unpkg.com/leaflet.markercluster@1.5.3/dist/MarkerCluster.Default.css" />
|
||||
|
||||
<!-- Core libraries -->
|
||||
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
|
||||
<script src="https://unpkg.com/leaflet.heat@0.2.0/dist/leaflet-heat.js"></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>
|
||||
<!-- Core libraries -->
|
||||
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js">
|
||||
</script>
|
||||
<script src="https://unpkg.com/leaflet.heat@0.2.0/dist/leaflet-heat.js">
|
||||
</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 -->
|
||||
<script src="https://unpkg.com/chart.js@4.5.0/dist/chart.umd.js"></script>
|
||||
<script src="https://unpkg.com/chartjs-adapter-date-fns@3.0.0/dist/chartjs-adapter-date-fns.bundle.min.js"></script>
|
||||
<!-- Chart.js -->
|
||||
<script src="https://unpkg.com/chart.js@4.5.0/dist/chart.umd.js">
|
||||
</script>
|
||||
<script src="https://unpkg.com/chartjs-adapter-date-fns@3.0.0/dist/chartjs-adapter-date-fns.bundle.min.js">
|
||||
</script>
|
||||
|
||||
<!-- Topbar -->
|
||||
<script src="https://unpkg.com/topbar@3.0.0/topbar.min.js"></script>
|
||||
<!-- Topbar -->
|
||||
<script src="https://unpkg.com/topbar@3.0.0/topbar.min.js">
|
||||
</script>
|
||||
|
||||
<!-- Leaflet VectorGrid for vector tiles -->
|
||||
<script src="https://unpkg.com/leaflet.vectorgrid@1.3.0/dist/Leaflet.VectorGrid.bundled.js"></script>
|
||||
<!-- Leaflet VectorGrid for vector tiles -->
|
||||
<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>
|
||||
<script>
|
||||
|
|
|
|||
|
|
@ -15,10 +15,10 @@ defmodule AprsmeWeb.Router do
|
|||
plug :put_root_layout, {AprsmeWeb.Layouts, :root}
|
||||
plug :protect_from_forgery
|
||||
|
||||
plug :put_secure_browser_headers, %{
|
||||
"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:"
|
||||
}
|
||||
# plug :put_secure_browser_headers, %{
|
||||
# "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:"
|
||||
# }
|
||||
|
||||
plug :fetch_current_user
|
||||
plug AprsmeWeb.Plugs.SetLocale
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue