layer instead of markers for routing controls

This commit is contained in:
vcoppe
2026-02-14 14:35:35 +01:00
parent 1137e851ce
commit 88abd72a41
8 changed files with 824 additions and 590 deletions

View File

@@ -5,6 +5,10 @@
map.onLoad((map_) => {
map_.on('contextmenu', (e) => {
if (map_.queryRenderedFeatures(e.point, { layers: ['routing-controls'] }).length) {
// Clicked on routing control, ignoring
return;
}
trackpointPopup?.setItem({
item: new TrackPoint({
attributes: {

View File

@@ -287,6 +287,7 @@ export class GPXLayer {
_map.addSource(this.fileId + '-waypoints', {
type: 'geojson',
data: this.currentWaypointData,
promoteId: 'waypointIndex',
});
}
@@ -645,7 +646,17 @@ export class GPXLayer {
| GeoJSONSource
| undefined;
if (waypointSource) {
waypointSource.setData(this.currentWaypointData!);
waypointSource.updateData({
update: [
{
id: this.draggedWaypointIndex,
newGeometry: {
type: 'Point',
coordinates: [e.lngLat.lng, e.lngLat.lat],
},
},
],
});
}
}

View File

@@ -50,39 +50,41 @@ export class StartEndMarkers {
const slicedStatistics = get(slicedGPXStatistics);
const hovered = get(hoveredPoint);
const hidden = get(allHidden);
if (statistics.global.length > 0 && tool !== Tool.ROUTING && !hidden) {
const start = statistics
.getTrackPoint(slicedStatistics?.[1] ?? 0)!
.trkpt.getCoordinates();
const end = statistics
.getTrackPoint(slicedStatistics?.[2] ?? statistics.global.length - 1)!
.trkpt.getCoordinates();
if (!hidden) {
const data: GeoJSON.FeatureCollection = {
type: 'FeatureCollection',
features: [
{
type: 'Feature',
geometry: {
type: 'Point',
coordinates: [start.lon, start.lat],
},
properties: {
icon: 'start-marker',
},
},
{
type: 'Feature',
geometry: {
type: 'Point',
coordinates: [end.lon, end.lat],
},
properties: {
icon: 'end-marker',
},
},
],
features: [],
};
if (statistics.global.length > 0 && tool !== Tool.ROUTING) {
const start = statistics
.getTrackPoint(slicedStatistics?.[1] ?? 0)!
.trkpt.getCoordinates();
const end = statistics
.getTrackPoint(slicedStatistics?.[2] ?? statistics.global.length - 1)!
.trkpt.getCoordinates();
data.features.push({
type: 'Feature',
geometry: {
type: 'Point',
coordinates: [start.lon, start.lat],
},
properties: {
icon: 'start-marker',
},
});
data.features.push({
type: 'Feature',
geometry: {
type: 'Point',
coordinates: [end.lon, end.lat],
},
properties: {
icon: 'end-marker',
},
});
}
if (hovered) {
data.features.push({
type: 'Feature',

View File

@@ -142,21 +142,7 @@ export class MapLayerEventManager {
}
private _handleMouseMove(e: maplibregl.MapMouseEvent) {
const layerIds = this._filterLayersIntersectingBounds(
Object.keys(this._listeners),
this._getBounds(e.point)
);
const features =
layerIds.length > 0
? this._map.queryRenderedFeatures(e.point, { layers: layerIds })
: [];
const featuresByLayer: Record<string, maplibregl.MapGeoJSONFeature[]> = {};
features.forEach((f) => {
if (!featuresByLayer[f.layer.id]) {
featuresByLayer[f.layer.id] = [];
}
featuresByLayer[f.layer.id].push(f);
});
const featuresByLayer = this._getRenderedFeaturesByLayer(e);
Object.keys(this._listeners).forEach((layerId) => {
const features = featuresByLayer[layerId] || [];
const listener = this._listeners[layerId];
@@ -183,7 +169,6 @@ export class MapLayerEventManager {
listener.mouseleaves.forEach((l) => l(event));
}
}
listener.features = features;
}
if (features.length > 0 && listener.mousemoves.length > 0) {
const event = new maplibregl.MapMouseEvent('mousemove', e.target, e.originalEvent, {
@@ -191,15 +176,19 @@ export class MapLayerEventManager {
});
listener.mousemoves.forEach((l) => l(event));
}
listener.features = features;
});
}
private _handleMouseClick(type: string, e: maplibregl.MapMouseEvent) {
Object.values(this._listeners).forEach((listener) => {
if (listener.features.length > 0) {
const featuresByLayer = this._getRenderedFeaturesByLayer(e);
Object.keys(this._listeners).forEach((layerId) => {
const features = featuresByLayer[layerId] || [];
const listener = this._listeners[layerId];
if (features.length > 0) {
if (type === 'click' && listener.clicks.length > 0) {
const event = new maplibregl.MapMouseEvent('click', e.target, e.originalEvent, {
features: listener.features,
features: features,
});
listener.clicks.forEach((l) => l(event));
} else if (type === 'contextmenu' && listener.contextmenus.length > 0) {
@@ -208,7 +197,7 @@ export class MapLayerEventManager {
e.target,
e.originalEvent,
{
features: listener.features,
features: features,
}
);
listener.contextmenus.forEach((l) => l(event));
@@ -218,7 +207,7 @@ export class MapLayerEventManager {
e.target,
e.originalEvent,
{
features: listener.features,
features: features,
}
);
listener.mousedowns.forEach((l) => l(event));
@@ -228,21 +217,7 @@ export class MapLayerEventManager {
}
private _handleTouchStart(e: maplibregl.MapTouchEvent) {
const layerIds = this._filterLayersIntersectingBounds(
Object.keys(this._listeners).filter(
(layerId) => this._listeners[layerId].touchstarts.length > 0
),
this._getBounds(e.point)
);
if (layerIds.length === 0) return;
const features = this._map.queryRenderedFeatures(e.points[0], { layers: layerIds });
const featuresByLayer: Record<string, maplibregl.MapGeoJSONFeature[]> = {};
features.forEach((f) => {
if (!featuresByLayer[f.layer.id]) {
featuresByLayer[f.layer.id] = [];
}
featuresByLayer[f.layer.id].push(f);
});
const featuresByLayer = this._getRenderedFeaturesByLayer(e);
Object.keys(this._listeners).forEach((layerId) => {
const features = featuresByLayer[layerId] || [];
const listener = this._listeners[layerId];
@@ -284,4 +259,23 @@ export class MapLayerEventManager {
});
return result;
}
private _getRenderedFeaturesByLayer(e: maplibregl.MapMouseEvent | maplibregl.MapTouchEvent) {
const layerIds = this._filterLayersIntersectingBounds(
Object.keys(this._listeners),
this._getBounds(e.point)
);
const features =
layerIds.length > 0
? this._map.queryRenderedFeatures(e.point, { layers: layerIds })
: [];
const featuresByLayer: Record<string, maplibregl.MapGeoJSONFeature[]> = {};
features.forEach((f) => {
if (!featuresByLayer[f.layer.id]) {
featuresByLayer[f.layer.id] = [];
}
featuresByLayer[f.layer.id].push(f);
});
return featuresByLayer;
}
}

View File

@@ -29,6 +29,7 @@ export const ANCHOR_LAYER_KEY = {
interactions: 'interactions-end',
overpass: 'overpass-end',
waypoints: 'waypoints-end',
routingControls: 'routing-controls-end',
};
const anchorLayers: maplibregl.LayerSpecification[] = Object.values(ANCHOR_LAYER_KEY).map((id) => ({
id: id,

View File

@@ -7,7 +7,8 @@ export enum MapCursorState {
TOOL_WITH_CROSSHAIR,
WAYPOINT_HOVER,
WAYPOINT_DRAGGING,
TRACKPOINT_DRAGGING,
ANCHOR_HOVER,
ANCHOR_DRAGGING,
SCISSORS,
SPLIT_CONTROL,
MAPILLARY_HOVER,
@@ -20,7 +21,8 @@ const cursorStyles = {
[MapCursorState.LAYER_HOVER]: 'pointer',
[MapCursorState.WAYPOINT_HOVER]: 'pointer',
[MapCursorState.WAYPOINT_DRAGGING]: 'grabbing',
[MapCursorState.TRACKPOINT_DRAGGING]: 'grabbing',
[MapCursorState.ANCHOR_HOVER]: 'pointer',
[MapCursorState.ANCHOR_DRAGGING]: 'grabbing',
[MapCursorState.TOOL_WITH_CROSSHAIR]: 'crosshair',
[MapCursorState.SCISSORS]: scissorsCursor,
[MapCursorState.SPLIT_CONTROL]: 'pointer',

View File

@@ -197,9 +197,9 @@ export function getElevation(
);
}
export function loadSVGIcon(map: maplibregl.Map, id: string, svg: string) {
export function loadSVGIcon(map: maplibregl.Map, id: string, svg: string, size: number = 100) {
if (!map.hasImage(id)) {
let icon = new Image(100, 100);
let icon = new Image(size, size);
icon.onload = () => {
if (!map.hasImage(id)) {
map.addImage(id, icon);