mirror of
				https://github.com/gpxstudio/gpx.studio.git
				synced 2025-11-04 05:21:09 +00:00 
			
		
		
		
	improve mapillary integration, closes #127
This commit is contained in:
		@@ -1,16 +1,17 @@
 | 
			
		||||
import mapboxgl from "mapbox-gl";
 | 
			
		||||
import { Viewer } from 'mapillary-js/dist/mapillary.module';
 | 
			
		||||
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 = {
 | 
			
		||||
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 = {
 | 
			
		||||
const mapillarySequenceLayer: LayerSpecification = {
 | 
			
		||||
    id: 'mapillary-sequence',
 | 
			
		||||
    type: 'line',
 | 
			
		||||
    source: 'mapillary',
 | 
			
		||||
@@ -26,7 +27,7 @@ const mapillarySequenceLayer = {
 | 
			
		||||
    },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const mapillaryImageLayer = {
 | 
			
		||||
const mapillaryImageLayer: LayerSpecification = {
 | 
			
		||||
    id: 'mapillary-image',
 | 
			
		||||
    type: 'circle',
 | 
			
		||||
    source: 'mapillary',
 | 
			
		||||
@@ -40,35 +41,56 @@ const mapillaryImageLayer = {
 | 
			
		||||
 | 
			
		||||
export class MapillaryLayer {
 | 
			
		||||
    map: mapboxgl.Map;
 | 
			
		||||
    popup: mapboxgl.Popup;
 | 
			
		||||
    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) {
 | 
			
		||||
    constructor(map: mapboxgl.Map, container: HTMLElement, popupOpen: Writable<boolean>) {
 | 
			
		||||
        this.map = map;
 | 
			
		||||
 | 
			
		||||
        this.viewer = new Viewer({
 | 
			
		||||
            accessToken: 'MLY|4381405525255083|3204871ec181638c3c31320490f03011',
 | 
			
		||||
            container,
 | 
			
		||||
        });
 | 
			
		||||
        container.classList.remove('hidden');
 | 
			
		||||
 | 
			
		||||
        this.popup = new mapboxgl.Popup({
 | 
			
		||||
            closeButton: false,
 | 
			
		||||
            maxWidth: container.style.width,
 | 
			
		||||
        }).setDOMContent(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.popup.isOpen()) {
 | 
			
		||||
            if (this.active) {
 | 
			
		||||
                popupOpen.set(true);
 | 
			
		||||
                let latLng = await this.viewer.getPosition();
 | 
			
		||||
                this.popup.setLngLat(latLng);
 | 
			
		||||
                if (!this.map.getBounds().contains(latLng)) {
 | 
			
		||||
                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() {
 | 
			
		||||
@@ -101,15 +123,19 @@ export class MapillaryLayer {
 | 
			
		||||
            this.map.removeSource('mapillary');
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.popup.remove();
 | 
			
		||||
        this.marker.remove();
 | 
			
		||||
        this.popupOpen.set(false);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    closePopup() {
 | 
			
		||||
        this.popup.remove();
 | 
			
		||||
        this.active = false;
 | 
			
		||||
        this.marker.remove();
 | 
			
		||||
        this.popupOpen.set(false);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    onMouseEnter(e: mapboxgl.MapLayerMouseEvent) {
 | 
			
		||||
        this.popup.addTo(this.map).setLngLat(e.lngLat);
 | 
			
		||||
    onMouseEnter(e: mapboxgl.MapMouseEvent) {
 | 
			
		||||
        this.active = true;
 | 
			
		||||
 | 
			
		||||
        this.viewer.resize();
 | 
			
		||||
        this.viewer.moveTo(e.features[0].properties.id);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -8,16 +8,18 @@
 | 
			
		||||
	import { map, streetViewEnabled } from '$lib/stores';
 | 
			
		||||
	import { settings } from '$lib/db';
 | 
			
		||||
	import { _ } from 'svelte-i18n';
 | 
			
		||||
	import { writable } from 'svelte/store';
 | 
			
		||||
 | 
			
		||||
	const { streetViewSource } = settings;
 | 
			
		||||
 | 
			
		||||
	let googleRedirect: GoogleRedirect;
 | 
			
		||||
	let mapillaryLayer: MapillaryLayer;
 | 
			
		||||
	let mapillaryOpen = writable(false);
 | 
			
		||||
	let container: HTMLElement;
 | 
			
		||||
 | 
			
		||||
	$: if ($map) {
 | 
			
		||||
		googleRedirect = new GoogleRedirect($map);
 | 
			
		||||
		mapillaryLayer = new MapillaryLayer($map, container);
 | 
			
		||||
		mapillaryLayer = new MapillaryLayer($map, container, mapillaryOpen);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	$: if (mapillaryLayer) {
 | 
			
		||||
@@ -53,7 +55,9 @@
 | 
			
		||||
 | 
			
		||||
<div
 | 
			
		||||
	bind:this={container}
 | 
			
		||||
	class="hidden relative w-[50vw] h-[40vh] rounded-md border-background border-2"
 | 
			
		||||
	class="{$mapillaryOpen
 | 
			
		||||
		? ''
 | 
			
		||||
		: 'hidden'} !absolute bottom-[44px] right-2.5 z-10 w-[40%] h-[40%] bg-background rounded-md overflow-hidden border-background border-2"
 | 
			
		||||
>
 | 
			
		||||
	<!-- svelte-ignore a11y-click-events-have-key-events -->
 | 
			
		||||
	<!-- svelte-ignore a11y-no-static-element-interactions -->
 | 
			
		||||
 
 | 
			
		||||
@@ -3,7 +3,6 @@ import { TrackPoint, distance } from "gpx";
 | 
			
		||||
import { derived, get, writable } from "svelte/store";
 | 
			
		||||
import { settings } from "$lib/db";
 | 
			
		||||
import { _, isLoading, locale } from "svelte-i18n";
 | 
			
		||||
import { map } from "$lib/stores";
 | 
			
		||||
import { getElevation } from "$lib/utils";
 | 
			
		||||
 | 
			
		||||
const { routing, routingProfile, privateRoads } = settings;
 | 
			
		||||
 
 | 
			
		||||
@@ -2,16 +2,15 @@ import { distance, type Coordinates, TrackPoint, TrackSegment, Track, projectedP
 | 
			
		||||
import { get, writable, type Readable } from "svelte/store";
 | 
			
		||||
import mapboxgl from "mapbox-gl";
 | 
			
		||||
import { route } from "./Routing";
 | 
			
		||||
 | 
			
		||||
import { toast } from "svelte-sonner";
 | 
			
		||||
 | 
			
		||||
import { _ } from "svelte-i18n";
 | 
			
		||||
import { dbUtils, type GPXFileWithStatistics } from "$lib/db";
 | 
			
		||||
import { dbUtils, settings, type GPXFileWithStatistics } from "$lib/db";
 | 
			
		||||
import { getOrderedSelection, selection } from "$lib/components/file-list/Selection";
 | 
			
		||||
import { ListFileItem, ListTrackItem, ListTrackSegmentItem } from "$lib/components/file-list/FileList";
 | 
			
		||||
import { currentTool, streetViewEnabled, Tool } from "$lib/stores";
 | 
			
		||||
import { getClosestLinePoint, resetCursor, setGrabbingCursor } from "$lib/utils";
 | 
			
		||||
 | 
			
		||||
const { streetViewSource } = settings;
 | 
			
		||||
export const canChangeStart = writable(false);
 | 
			
		||||
 | 
			
		||||
function stopPropagation(e: any) {
 | 
			
		||||
@@ -458,7 +457,7 @@ export class RoutingControls {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async appendAnchor(e: mapboxgl.MapMouseEvent) { // Add a new anchor to the end of the last segment
 | 
			
		||||
        if (get(streetViewEnabled)) {
 | 
			
		||||
        if (get(streetViewEnabled) && get(streetViewSource) === 'google') {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user