mirror of
https://github.com/gpxstudio/gpx.studio.git
synced 2025-08-31 23:53:25 +00:00
148 lines
4.5 KiB
TypeScript
148 lines
4.5 KiB
TypeScript
import mapboxgl, { type LayerSpecification, type VectorSourceSpecification } from "mapbox-gl";
|
|
import { Viewer, type ViewerBearingEvent } from 'mapillary-js/dist/mapillary.module';
|
|
import 'mapillary-js/dist/mapillary.css';
|
|
import { resetCursor, setPointerCursor } from "$lib/utils";
|
|
import type { Writable } from "svelte/store";
|
|
|
|
const mapillarySource: VectorSourceSpecification = {
|
|
type: 'vector',
|
|
tiles: ['https://tiles.mapillary.com/maps/vtp/mly1_computed_public/2/{z}/{x}/{y}?access_token=MLY|4381405525255083|3204871ec181638c3c31320490f03011'],
|
|
minzoom: 6,
|
|
maxzoom: 14,
|
|
};
|
|
|
|
const mapillarySequenceLayer: LayerSpecification = {
|
|
id: 'mapillary-sequence',
|
|
type: 'line',
|
|
source: 'mapillary',
|
|
'source-layer': 'sequence',
|
|
paint: {
|
|
'line-color': 'rgb(0, 150, 70)',
|
|
'line-opacity': 0.7,
|
|
'line-width': 5,
|
|
},
|
|
layout: {
|
|
'line-cap': 'round',
|
|
'line-join': 'round',
|
|
},
|
|
};
|
|
|
|
const mapillaryImageLayer: LayerSpecification = {
|
|
id: 'mapillary-image',
|
|
type: 'circle',
|
|
source: 'mapillary',
|
|
'source-layer': 'image',
|
|
paint: {
|
|
'circle-color': 'rgb(0, 150, 70)',
|
|
'circle-radius': 5,
|
|
'circle-opacity': 0.7,
|
|
},
|
|
};
|
|
|
|
export class MapillaryLayer {
|
|
map: mapboxgl.Map;
|
|
marker: mapboxgl.Marker;
|
|
viewer: Viewer;
|
|
|
|
active = false;
|
|
popupOpen: Writable<boolean>;
|
|
|
|
addBinded = this.add.bind(this);
|
|
onMouseEnterBinded = this.onMouseEnter.bind(this);
|
|
onMouseLeaveBinded = this.onMouseLeave.bind(this);
|
|
|
|
constructor(map: mapboxgl.Map, container: HTMLElement, popupOpen: Writable<boolean>) {
|
|
this.map = map;
|
|
|
|
this.viewer = new Viewer({
|
|
accessToken: 'MLY|4381405525255083|3204871ec181638c3c31320490f03011',
|
|
container,
|
|
});
|
|
|
|
const element = document.createElement('div');
|
|
element.className = 'mapboxgl-user-location mapboxgl-user-location-show-heading';
|
|
const dot = document.createElement('div');
|
|
dot.className = 'mapboxgl-user-location-dot';
|
|
const heading = document.createElement('div');
|
|
heading.className = 'mapboxgl-user-location-heading';
|
|
element.appendChild(dot);
|
|
element.appendChild(heading);
|
|
|
|
this.marker = new mapboxgl.Marker({
|
|
rotationAlignment: 'map',
|
|
element
|
|
});
|
|
|
|
this.viewer.on('position', async () => {
|
|
if (this.active) {
|
|
popupOpen.set(true);
|
|
let latLng = await this.viewer.getPosition();
|
|
this.marker.setLngLat(latLng).addTo(this.map);
|
|
if (!this.map.getBounds()?.contains(latLng)) {
|
|
this.map.panTo(latLng);
|
|
}
|
|
}
|
|
});
|
|
|
|
this.viewer.on('bearing', (e: ViewerBearingEvent) => {
|
|
if (this.active) {
|
|
this.marker.setRotation(e.bearing);
|
|
}
|
|
});
|
|
|
|
this.popupOpen = popupOpen;
|
|
}
|
|
|
|
add() {
|
|
if (!this.map.getSource('mapillary')) {
|
|
this.map.addSource('mapillary', mapillarySource);
|
|
}
|
|
if (!this.map.getLayer('mapillary-sequence')) {
|
|
this.map.addLayer(mapillarySequenceLayer);
|
|
}
|
|
if (!this.map.getLayer('mapillary-image')) {
|
|
this.map.addLayer(mapillaryImageLayer);
|
|
}
|
|
this.map.on('style.load', this.addBinded);
|
|
this.map.on('mouseenter', 'mapillary-image', this.onMouseEnterBinded);
|
|
this.map.on('mouseleave', 'mapillary-image', this.onMouseLeaveBinded);
|
|
}
|
|
|
|
remove() {
|
|
this.map.off('style.load', this.addBinded);
|
|
this.map.off('mouseenter', 'mapillary-image', this.onMouseEnterBinded);
|
|
this.map.off('mouseleave', 'mapillary-image', this.onMouseLeaveBinded);
|
|
|
|
if (this.map.getLayer('mapillary-image')) {
|
|
this.map.removeLayer('mapillary-image');
|
|
}
|
|
if (this.map.getLayer('mapillary-sequence')) {
|
|
this.map.removeLayer('mapillary-sequence');
|
|
}
|
|
if (this.map.getSource('mapillary')) {
|
|
this.map.removeSource('mapillary');
|
|
}
|
|
|
|
this.marker.remove();
|
|
this.popupOpen.set(false);
|
|
}
|
|
|
|
closePopup() {
|
|
this.active = false;
|
|
this.marker.remove();
|
|
this.popupOpen.set(false);
|
|
}
|
|
|
|
onMouseEnter(e: mapboxgl.MapMouseEvent) {
|
|
this.active = true;
|
|
|
|
this.viewer.resize();
|
|
this.viewer.moveTo(e.features[0].properties.id);
|
|
|
|
setPointerCursor();
|
|
}
|
|
|
|
onMouseLeave() {
|
|
resetCursor();
|
|
}
|
|
} |