mirror of
https://github.com/Freika/dawarich.git
synced 2026-01-10 17:21:38 -05:00
Use canvas for map
This commit is contained in:
parent
e7c3714672
commit
e457631715
5 changed files with 133 additions and 52 deletions
File diff suppressed because one or more lines are too long
|
|
@ -1,21 +0,0 @@
|
|||
/* Ensure fog overlay is positioned relative to the map container */
|
||||
#fog {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(0, 0, 0, 0.8); /* Adjust the opacity here */
|
||||
pointer-events: none;
|
||||
mix-blend-mode: multiply;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.unfogged-circle {
|
||||
position: absolute;
|
||||
pointer-events: none;
|
||||
border-radius: 50%;
|
||||
background: white;
|
||||
mix-blend-mode: destination-out;
|
||||
filter: blur(3px); /* Apply no blur to the circles */
|
||||
}
|
||||
|
|
@ -84,7 +84,21 @@ export default class extends Controller {
|
|||
|
||||
this.polylinesLayer = createPolylinesLayer(this.markers, this.map, this.timezone, this.routeOpacity, this.userSettings, this.distanceUnit);
|
||||
this.heatmapLayer = L.heatLayer(this.heatmapMarkers, { radius: 20 }).addTo(this.map);
|
||||
this.fogOverlay = L.layerGroup(); // Initialize fog layer
|
||||
|
||||
// Create a proper Leaflet layer for fog
|
||||
this.fogOverlay = L.Layer.extend({
|
||||
onAdd: (map) => {
|
||||
this.initializeFogCanvas();
|
||||
this.updateFog(this.markers, this.clearFogRadius);
|
||||
},
|
||||
onRemove: (map) => {
|
||||
const fog = document.getElementById('fog');
|
||||
if (fog) {
|
||||
fog.remove();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this.areasLayer = L.layerGroup(); // Initialize areas layer
|
||||
this.photoMarkers = L.layerGroup();
|
||||
|
||||
|
|
@ -94,11 +108,12 @@ export default class extends Controller {
|
|||
this.addSettingsButton();
|
||||
}
|
||||
|
||||
// Initialize layers for the layer control
|
||||
const controlsLayer = {
|
||||
Points: this.markersLayer,
|
||||
Routes: this.polylinesLayer,
|
||||
Heatmap: this.heatmapLayer,
|
||||
"Fog of War": this.fogOverlay,
|
||||
"Fog of War": new this.fogOverlay(),
|
||||
"Scratch map": this.scratchLayer,
|
||||
Areas: this.areasLayer,
|
||||
Photos: this.photoMarkers
|
||||
|
|
@ -131,6 +146,7 @@ export default class extends Controller {
|
|||
maxWidth: 120
|
||||
}).addTo(this.map)
|
||||
|
||||
// Initialize layer control
|
||||
this.layerControl = L.control.layers(this.baseMaps(), controlsLayer).addTo(this.map);
|
||||
|
||||
// Fetch and draw areas when the map is loaded
|
||||
|
|
@ -230,6 +246,19 @@ export default class extends Controller {
|
|||
localStorage.setItem('mapPanelOpen', 'false');
|
||||
}
|
||||
}
|
||||
|
||||
// Update event handlers
|
||||
this.map.on('moveend', () => {
|
||||
if (document.getElementById('fog')) {
|
||||
this.updateFog(this.markers, this.clearFogRadius);
|
||||
}
|
||||
});
|
||||
|
||||
this.map.on('zoomend', () => {
|
||||
if (document.getElementById('fog')) {
|
||||
this.updateFog(this.markers, this.clearFogRadius);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
disconnect() {
|
||||
|
|
@ -528,41 +557,101 @@ export default class extends Controller {
|
|||
}
|
||||
|
||||
updateFog(markers, clearFogRadius) {
|
||||
var fog = document.getElementById('fog');
|
||||
fog.innerHTML = ''; // Clear previous circles
|
||||
markers.forEach((point) => {
|
||||
const radiusInPixels = this.metersToPixels(this.map, clearFogRadius);
|
||||
this.clearFog(point[0], point[1], radiusInPixels);
|
||||
const fog = document.getElementById('fog');
|
||||
if (!fog) {
|
||||
this.initializeFogCanvas();
|
||||
}
|
||||
requestAnimationFrame(() => this.drawFogCanvas(markers, clearFogRadius));
|
||||
}
|
||||
|
||||
initializeFogCanvas() {
|
||||
// Remove existing fog canvas if it exists
|
||||
const oldFog = document.getElementById('fog');
|
||||
if (oldFog) oldFog.remove();
|
||||
|
||||
// Create new fog canvas
|
||||
const fog = document.createElement('canvas');
|
||||
fog.id = 'fog';
|
||||
fog.style.position = 'absolute';
|
||||
fog.style.top = '0';
|
||||
fog.style.left = '0';
|
||||
fog.style.pointerEvents = 'none';
|
||||
fog.style.zIndex = '400';
|
||||
|
||||
// Set canvas size to match map container
|
||||
const mapSize = this.map.getSize();
|
||||
fog.width = mapSize.x;
|
||||
fog.height = mapSize.y;
|
||||
|
||||
// Add canvas to map container
|
||||
this.map.getContainer().appendChild(fog);
|
||||
|
||||
// Add resize handler
|
||||
this.map.on('resize', () => {
|
||||
const newSize = this.map.getSize();
|
||||
fog.width = newSize.x;
|
||||
fog.height = newSize.y;
|
||||
this.drawFogCanvas(this.markers, this.clearFogRadius);
|
||||
});
|
||||
}
|
||||
|
||||
drawFogCanvas(markers, clearFogRadius) {
|
||||
const fog = document.getElementById('fog');
|
||||
if (!fog) return;
|
||||
|
||||
const ctx = fog.getContext('2d');
|
||||
if (!ctx) return;
|
||||
|
||||
const size = this.map.getSize();
|
||||
|
||||
// Clear the canvas
|
||||
ctx.clearRect(0, 0, size.x, size.y);
|
||||
|
||||
// Keep the light fog for unexplored areas
|
||||
ctx.fillStyle = 'rgba(0, 0, 0, 0.4)';
|
||||
ctx.fillRect(0, 0, size.x, size.y);
|
||||
|
||||
// Set up for "cutting" holes
|
||||
ctx.globalCompositeOperation = 'destination-out';
|
||||
|
||||
// Draw clear circles for each point
|
||||
markers.forEach(point => {
|
||||
const latLng = L.latLng(point[0], point[1]);
|
||||
const pixelPoint = this.map.latLngToContainerPoint(latLng);
|
||||
const radiusInPixels = this.metersToPixels(this.map, clearFogRadius);
|
||||
|
||||
// Make explored areas completely transparent
|
||||
const gradient = ctx.createRadialGradient(
|
||||
pixelPoint.x, pixelPoint.y, 0,
|
||||
pixelPoint.x, pixelPoint.y, radiusInPixels
|
||||
);
|
||||
gradient.addColorStop(0, 'rgba(255, 255, 255, 1)'); // 100% transparent
|
||||
gradient.addColorStop(0.85, 'rgba(255, 255, 255, 1)'); // Still 100% transparent
|
||||
gradient.addColorStop(1, 'rgba(255, 255, 255, 0)'); // Fade to fog at edge
|
||||
|
||||
ctx.fillStyle = gradient;
|
||||
ctx.beginPath();
|
||||
ctx.arc(pixelPoint.x, pixelPoint.y, radiusInPixels, 0, Math.PI * 2);
|
||||
ctx.fill();
|
||||
});
|
||||
|
||||
// Reset composite operation
|
||||
ctx.globalCompositeOperation = 'source-over';
|
||||
}
|
||||
|
||||
metersToPixels(map, meters) {
|
||||
const zoom = map.getZoom();
|
||||
const latLng = map.getCenter(); // Get map center for correct projection
|
||||
const latLng = map.getCenter();
|
||||
const metersPerPixel = this.getMetersPerPixel(latLng.lat, zoom);
|
||||
return meters / metersPerPixel;
|
||||
}
|
||||
|
||||
getMetersPerPixel(latitude, zoom) {
|
||||
const earthCircumference = 40075016.686; // Earth's circumference in meters
|
||||
const earthCircumference = 40075016.686;
|
||||
const metersPerPixel = earthCircumference * Math.cos(latitude * Math.PI / 180) / Math.pow(2, zoom + 8);
|
||||
return metersPerPixel;
|
||||
}
|
||||
|
||||
clearFog(lat, lng, radius) {
|
||||
var fog = document.getElementById('fog');
|
||||
var point = this.map.latLngToContainerPoint([lat, lng]);
|
||||
var size = radius * 2;
|
||||
var circle = document.createElement('div');
|
||||
circle.className = 'unfogged-circle';
|
||||
circle.style.width = size + 'px';
|
||||
circle.style.height = size + 'px';
|
||||
circle.style.left = (point.x - radius) + 'px';
|
||||
circle.style.top = (point.y - radius) + 'px';
|
||||
circle.style.backdropFilter = 'blur(0px)'; // Remove blur for the circles
|
||||
fog.appendChild(circle);
|
||||
}
|
||||
|
||||
initializeDrawControl() {
|
||||
// Initialize the FeatureGroup to store editable layers
|
||||
this.drawnItems = new L.FeatureGroup();
|
||||
|
|
|
|||
|
|
@ -1,15 +1,19 @@
|
|||
import { createPopupContent } from "./popups";
|
||||
|
||||
export function createMarkersArray(markersData, userSettings) {
|
||||
// Create a canvas renderer
|
||||
const renderer = L.canvas({ padding: 0.5 });
|
||||
|
||||
if (userSettings.pointsRenderingMode === "simplified") {
|
||||
return createSimplifiedMarkers(markersData);
|
||||
return createSimplifiedMarkers(markersData, renderer);
|
||||
} else {
|
||||
return markersData.map((marker) => {
|
||||
const [lat, lon] = marker;
|
||||
|
||||
const popupContent = createPopupContent(marker, userSettings.timezone, userSettings.distanceUnit);
|
||||
let markerColor = marker[5] < 0 ? "orange" : "blue";
|
||||
|
||||
return L.circleMarker([lat, lon], {
|
||||
renderer: renderer, // Use canvas renderer
|
||||
radius: 4,
|
||||
color: markerColor,
|
||||
zIndexOffset: 1000,
|
||||
|
|
@ -19,7 +23,7 @@ export function createMarkersArray(markersData, userSettings) {
|
|||
}
|
||||
}
|
||||
|
||||
export function createSimplifiedMarkers(markersData) {
|
||||
export function createSimplifiedMarkers(markersData, renderer) {
|
||||
const distanceThreshold = 50; // meters
|
||||
const timeThreshold = 20000; // milliseconds (3 seconds)
|
||||
|
||||
|
|
@ -48,9 +52,15 @@ export function createSimplifiedMarkers(markersData) {
|
|||
const [lat, lon] = marker;
|
||||
const popupContent = createPopupContent(marker);
|
||||
let markerColor = marker[5] < 0 ? "orange" : "blue";
|
||||
|
||||
return L.circleMarker(
|
||||
[lat, lon],
|
||||
{ radius: 4, color: markerColor, zIndexOffset: 1000 }
|
||||
{
|
||||
renderer: renderer, // Use canvas renderer
|
||||
radius: 4,
|
||||
color: markerColor,
|
||||
zIndexOffset: 1000
|
||||
}
|
||||
).bindPopup(popupContent);
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -265,6 +265,9 @@ export function addHighlightOnHover(polylineGroup, map, polylineCoordinates, use
|
|||
}
|
||||
|
||||
export function createPolylinesLayer(markers, map, timezone, routeOpacity, userSettings, distanceUnit) {
|
||||
// Create a canvas renderer
|
||||
const renderer = L.canvas({ padding: 0.5 });
|
||||
|
||||
const splitPolylines = [];
|
||||
let currentPolyline = [];
|
||||
const distanceThresholdMeters = parseInt(userSettings.meters_between_routes) || 500;
|
||||
|
|
@ -298,7 +301,6 @@ export function createPolylinesLayer(markers, map, timezone, routeOpacity, userS
|
|||
|
||||
for (let i = 0; i < polylineCoordinates.length - 1; i++) {
|
||||
const speed = calculateSpeed(polylineCoordinates[i], polylineCoordinates[i + 1]);
|
||||
|
||||
const color = getSpeedColor(speed, userSettings.speed_colored_routes);
|
||||
|
||||
const segment = L.polyline(
|
||||
|
|
@ -307,11 +309,12 @@ export function createPolylinesLayer(markers, map, timezone, routeOpacity, userS
|
|||
[polylineCoordinates[i + 1][0], polylineCoordinates[i + 1][1]]
|
||||
],
|
||||
{
|
||||
renderer: renderer, // Use canvas renderer
|
||||
color: color,
|
||||
originalColor: color,
|
||||
opacity: routeOpacity,
|
||||
weight: 3,
|
||||
speed: speed, // Store the calculated speed
|
||||
speed: speed,
|
||||
startTime: polylineCoordinates[i][4],
|
||||
endTime: polylineCoordinates[i + 1][4]
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue