mirror of
https://github.com/gpxstudio/gpx.studio.git
synced 2026-02-05 16:03:14 +00:00
further improve event listener performance
This commit is contained in:
@@ -227,6 +227,56 @@ export class GPXLayer {
|
||||
layerEventManager.on('mouseleave', this.fileId, this.layerOnMouseLeaveBinded);
|
||||
layerEventManager.on('mousemove', this.fileId, this.layerOnMouseMoveBinded);
|
||||
}
|
||||
|
||||
let visibleTrackSegmentIds: string[] = [];
|
||||
file.forEachSegment((segment, trackIndex, segmentIndex) => {
|
||||
if (!segment._data.hidden) {
|
||||
visibleTrackSegmentIds.push(`${trackIndex}-${segmentIndex}`);
|
||||
}
|
||||
});
|
||||
const segmentFilter: FilterSpecification = [
|
||||
'in',
|
||||
['get', 'trackSegmentId'],
|
||||
['literal', visibleTrackSegmentIds],
|
||||
];
|
||||
|
||||
_map.setFilter(this.fileId, segmentFilter, { validate: false });
|
||||
|
||||
if (get(directionMarkers)) {
|
||||
if (!_map.getLayer(this.fileId + '-direction')) {
|
||||
_map.addLayer(
|
||||
{
|
||||
id: this.fileId + '-direction',
|
||||
type: 'symbol',
|
||||
source: this.fileId,
|
||||
layout: {
|
||||
'text-field': '»',
|
||||
'text-offset': [0, -0.1],
|
||||
'text-keep-upright': false,
|
||||
'text-max-angle': 361,
|
||||
'text-allow-overlap': true,
|
||||
'text-font': ['Open Sans Bold'],
|
||||
'symbol-placement': 'line',
|
||||
'symbol-spacing': 20,
|
||||
},
|
||||
paint: {
|
||||
'text-color': 'white',
|
||||
'text-opacity': 0.7,
|
||||
'text-halo-width': 0.2,
|
||||
'text-halo-color': 'white',
|
||||
},
|
||||
},
|
||||
ANCHOR_LAYER_KEY.directionMarkers
|
||||
);
|
||||
}
|
||||
|
||||
_map.setFilter(this.fileId + '-direction', segmentFilter, { validate: false });
|
||||
} else {
|
||||
if (_map.getLayer(this.fileId + '-direction')) {
|
||||
_map.removeLayer(this.fileId + '-direction');
|
||||
}
|
||||
}
|
||||
|
||||
let waypointSource = _map.getSource(this.fileId + '-waypoints') as
|
||||
| GeoJSONSource
|
||||
| undefined;
|
||||
@@ -284,57 +334,6 @@ export class GPXLayer {
|
||||
);
|
||||
}
|
||||
|
||||
if (get(directionMarkers)) {
|
||||
if (!_map.getLayer(this.fileId + '-direction')) {
|
||||
_map.addLayer(
|
||||
{
|
||||
id: this.fileId + '-direction',
|
||||
type: 'symbol',
|
||||
source: this.fileId,
|
||||
layout: {
|
||||
'text-field': '»',
|
||||
'text-offset': [0, -0.1],
|
||||
'text-keep-upright': false,
|
||||
'text-max-angle': 361,
|
||||
'text-allow-overlap': true,
|
||||
'text-font': ['Open Sans Bold'],
|
||||
'symbol-placement': 'line',
|
||||
'symbol-spacing': 20,
|
||||
},
|
||||
paint: {
|
||||
'text-color': 'white',
|
||||
'text-opacity': 0.7,
|
||||
'text-halo-width': 0.2,
|
||||
'text-halo-color': 'white',
|
||||
},
|
||||
},
|
||||
ANCHOR_LAYER_KEY.directionMarkers
|
||||
);
|
||||
}
|
||||
} else {
|
||||
if (_map.getLayer(this.fileId + '-direction')) {
|
||||
_map.removeLayer(this.fileId + '-direction');
|
||||
}
|
||||
}
|
||||
|
||||
let visibleTrackSegmentIds: string[] = [];
|
||||
file.forEachSegment((segment, trackIndex, segmentIndex) => {
|
||||
if (!segment._data.hidden) {
|
||||
visibleTrackSegmentIds.push(`${trackIndex}-${segmentIndex}`);
|
||||
}
|
||||
});
|
||||
const segmentFilter: FilterSpecification = [
|
||||
'in',
|
||||
['get', 'trackSegmentId'],
|
||||
['literal', visibleTrackSegmentIds],
|
||||
];
|
||||
|
||||
_map.setFilter(this.fileId, segmentFilter, { validate: false });
|
||||
|
||||
if (_map.getLayer(this.fileId + '-direction')) {
|
||||
_map.setFilter(this.fileId + '-direction', segmentFilter, { validate: false });
|
||||
}
|
||||
|
||||
let visibleWaypoints: number[] = [];
|
||||
file.wpt.forEach((waypoint, waypointIndex) => {
|
||||
if (!waypoint._data.hidden) {
|
||||
|
||||
@@ -76,7 +76,14 @@ export class OverpassLayer {
|
||||
update() {
|
||||
this.loadIcons();
|
||||
|
||||
let d = get(data);
|
||||
const fullData = get(data);
|
||||
const queries = getCurrentQueries();
|
||||
const d: GeoJSON.FeatureCollection = {
|
||||
type: 'FeatureCollection',
|
||||
features: fullData.features.filter((feature) =>
|
||||
queries.includes(feature.properties!.query)
|
||||
),
|
||||
};
|
||||
|
||||
try {
|
||||
let source = this.map.getSource('overpass') as GeoJSONSource | undefined;
|
||||
@@ -108,10 +115,6 @@ export class OverpassLayer {
|
||||
this.layerEventManager.on('mouseenter', 'overpass', this.onHoverBinded);
|
||||
this.layerEventManager.on('click', 'overpass', this.onHoverBinded);
|
||||
}
|
||||
|
||||
this.map.setFilter('overpass', ['in', 'query', ...getCurrentQueries()], {
|
||||
validate: false,
|
||||
});
|
||||
} catch (e) {
|
||||
// No reliable way to check if the map is ready to add sources and layers
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { fileStateCollection } from '$lib/logic/file-state';
|
||||
import maplibregl from 'maplibre-gl';
|
||||
|
||||
type MapLayerMouseEventListener = (e: maplibregl.MapLayerMouseEvent) => void;
|
||||
@@ -141,7 +142,10 @@ export class MapLayerEventManager {
|
||||
}
|
||||
|
||||
private _handleMouseMove(e: maplibregl.MapMouseEvent) {
|
||||
const layerIds = Object.keys(this._listeners);
|
||||
const layerIds = this._filterLayersContainingCoordinate(
|
||||
Object.keys(this._listeners),
|
||||
e.lngLat
|
||||
);
|
||||
const features =
|
||||
layerIds.length > 0
|
||||
? this._map.queryRenderedFeatures(e.point, { layers: layerIds })
|
||||
@@ -224,8 +228,11 @@ export class MapLayerEventManager {
|
||||
}
|
||||
|
||||
private _handleTouchStart(e: maplibregl.MapTouchEvent) {
|
||||
const layerIds = Object.keys(this._listeners).filter(
|
||||
(layerId) => this._listeners[layerId].touchstarts.length > 0
|
||||
const layerIds = this._filterLayersContainingCoordinate(
|
||||
Object.keys(this._listeners).filter(
|
||||
(layerId) => this._listeners[layerId].touchstarts.length > 0
|
||||
),
|
||||
e.lngLat
|
||||
);
|
||||
if (layerIds.length === 0) return;
|
||||
const features = this._map.queryRenderedFeatures(e.points[0], { layers: layerIds });
|
||||
@@ -250,4 +257,19 @@ export class MapLayerEventManager {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private _filterLayersContainingCoordinate(
|
||||
layerIds: string[],
|
||||
lngLat: maplibregl.LngLat
|
||||
): string[] {
|
||||
let result = layerIds.filter((layerId) => {
|
||||
const fileId = layerId.replace('-waypoints', '');
|
||||
if (fileId === layerId) {
|
||||
return fileStateCollection.getStatistics(fileId)?.inBBox(lngLat) ?? true;
|
||||
} else {
|
||||
return fileStateCollection.getStatistics(fileId)?.inWaypointBBox(lngLat) ?? true;
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -157,6 +157,9 @@ export class StyleManager {
|
||||
const terrain = this.getCurrentTerrain();
|
||||
if (JSON.stringify(mapTerrain) !== JSON.stringify(terrain)) {
|
||||
if (terrain.exaggeration > 0) {
|
||||
if (!map_.getSource(terrain.source)) {
|
||||
map_.addSource(terrain.source, terrainSources[terrain.source]);
|
||||
}
|
||||
map_.setTerrain(terrain);
|
||||
} else {
|
||||
map_.setTerrain(null);
|
||||
|
||||
@@ -1,18 +1,24 @@
|
||||
import { ListItem, ListLevel } from '$lib/components/file-list/file-list';
|
||||
import { GPXFile, GPXStatistics, GPXStatisticsGroup, type Track } from 'gpx';
|
||||
import maplibregl from 'maplibre-gl';
|
||||
|
||||
export class GPXStatisticsTree {
|
||||
level: ListLevel;
|
||||
statistics: {
|
||||
[key: string]: GPXStatisticsTree | GPXStatistics;
|
||||
} = {};
|
||||
wptBounds: maplibregl.LngLatBounds;
|
||||
|
||||
constructor(element: GPXFile | Track) {
|
||||
this.wptBounds = new maplibregl.LngLatBounds();
|
||||
if (element instanceof GPXFile) {
|
||||
this.level = ListLevel.FILE;
|
||||
element.children.forEach((child, index) => {
|
||||
this.statistics[index] = new GPXStatisticsTree(child);
|
||||
});
|
||||
element.wpt.forEach((wpt) => {
|
||||
this.wptBounds.extend(wpt.getCoordinates());
|
||||
});
|
||||
} else {
|
||||
this.level = ListLevel.TRACK;
|
||||
element.children.forEach((child, index) => {
|
||||
@@ -42,5 +48,27 @@ export class GPXStatisticsTree {
|
||||
}
|
||||
return statistics;
|
||||
}
|
||||
|
||||
inBBox(coordinates: { lat: number; lng: number }): boolean {
|
||||
for (let key in this.statistics) {
|
||||
const stats = this.statistics[key];
|
||||
if (stats instanceof GPXStatistics) {
|
||||
const bbox = new maplibregl.LngLatBounds(
|
||||
stats.global.bounds.southWest,
|
||||
stats.global.bounds.northEast
|
||||
);
|
||||
if (!bbox.isEmpty() && bbox.contains(coordinates)) {
|
||||
return true;
|
||||
}
|
||||
} else if (stats.inBBox(coordinates)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inWaypointBBox(coordinates: { lat: number; lng: number }): boolean {
|
||||
return !this.wptBounds.isEmpty() && this.wptBounds.contains(coordinates);
|
||||
}
|
||||
}
|
||||
export type GPXFileWithStatistics = { file: GPXFile; statistics: GPXStatisticsTree };
|
||||
|
||||
Reference in New Issue
Block a user