commit d01e771647e8aab8279b48015017ff1be620a992
parent 542a1adf30f38bb018b88a4aa0eb9ad634a7079e
Author: Sergey Orlov <wladimirych@gmail.com>
Date: Fri, 1 May 2020 22:53:43 +0200
panoramas: add mapy.cz panoramas #379
Diffstat:
3 files changed, 164 insertions(+), 0 deletions(-)
diff --git a/src/lib/leaflet.control.panoramas/index.js b/src/lib/leaflet.control.panoramas/index.js
@@ -10,6 +10,7 @@ import wikimediaProvider from './lib/wikimedia';
import {DragEvents} from '~/lib/leaflet.events.drag';
import {onElementResize} from '~/lib/anyElementResizeEvent';
import safeLocalStorage from '~/lib/safe-localstorage';
+import mapyczProvider from './lib/mapycz';
const PanoMarker = L.Marker.extend({
options: {
@@ -84,6 +85,15 @@ L.Control.Panoramas = L.Control.extend({
selected: ko.observable(false),
mapMarkerType: 'normal'
},
+ {
+ name: 'mapycz',
+ title: 'mapy.cz',
+ provider: mapyczProvider,
+ layerOptions: {opacity: 0.7, zIndex: 8},
+ code: 'c',
+ selected: ko.observable(false),
+ mapMarkerType: 'normal'
+ }
];
},
diff --git a/src/lib/leaflet.control.panoramas/lib/mapycz/apiLoader.js b/src/lib/leaflet.control.panoramas/lib/mapycz/apiLoader.js
@@ -0,0 +1,38 @@
+import loadScript from 'load-script';
+
+let _smap = null;
+let _pending = null;
+
+function getLoader() {
+ const loaderUrl = 'https://api.mapy.cz/loader.js';
+ return new Promise((resolve, reject) => {
+ loadScript(loaderUrl, (error) => {
+ if (error) {
+ reject(error);
+ } else {
+ resolve(window.Loader);
+ }
+ });
+ });
+}
+
+function loadApi(loader) {
+ return new Promise((resolve) => {
+ loader.async = true;
+ loader.load(null, {pano: true}, () => {
+ resolve(window.SMap);
+ });
+ });
+}
+
+function getSMap() {
+ if (_smap) {
+ return _smap;
+ }
+ if (!_pending) {
+ _pending = getLoader().then((loader) => loadApi(loader));
+ }
+ return _pending;
+}
+
+export {getSMap};
diff --git a/src/lib/leaflet.control.panoramas/lib/mapycz/index.js b/src/lib/leaflet.control.panoramas/lib/mapycz/index.js
@@ -0,0 +1,116 @@
+import L from 'leaflet';
+import {getSMap} from './apiLoader';
+import {CloseButtonMixin} from '../common';
+
+function getCoverageLayer(options) {
+ return L.tileLayer('https://mapserver.mapy.cz/panorama_hybrid-m/{z}-{x}-{y}', options);
+}
+
+async function getPanoramaAtPos(latlng, searchRadiusMeters) {
+ const smap = await getSMap();
+ const request = smap.Pano.getBest(smap.Coords.fromWGS84(latlng.lng, latlng.lat), searchRadiusMeters);
+ try {
+ return {
+ found: true,
+ data: await request,
+ };
+ } catch (e) {
+ return {found: false};
+ }
+}
+
+const Viewer = L.Evented.extend({
+ includes: [CloseButtonMixin],
+
+ initialize: function(smap, container) {
+ this.panorama = new smap.Pano.Scene(container);
+ this.createCloseButton(container);
+ window.addEventListener('resize', this.resize.bind(this));
+ },
+
+ showPano: function(data) {
+ const yaw = this.panorama.getCamera().yaw;
+ this.panorama.show(data, {yaw});
+ this.panorama.setCamera({fov: 1.256637061});
+ this.updatePositionAndView();
+ },
+
+ activate: function() {
+ this._active = true;
+ this.resize();
+ if (!this._updateHandler) {
+ this._updateHandler = setInterval(() => this.updatePositionAndView(), 200);
+ }
+ },
+
+ deactivate: function() {
+ this._active = false;
+ if (this._updateHandler) {
+ clearInterval(this._updateHandler);
+ this._updateHandler = null;
+ }
+ },
+
+ getState: function() {
+ const camera = this.panorama.getCamera();
+ const place = this.panorama.getPlace();
+ if (!place) {
+ return null;
+ }
+ const coords = place.getCoords().toWGS84();
+ return [
+ coords[1].toFixed(6),
+ coords[0].toFixed(6),
+ camera.yaw.toFixed(4),
+ camera.pitch.toFixed(4),
+ camera.fov.toFixed(4),
+ ];
+ },
+
+ setState: function(state) {
+ const lat = parseFloat(state[0]);
+ const lng = parseFloat(state[1]);
+ const yaw = parseFloat(state[2]);
+ const pitch = parseFloat(state[3]);
+ const fov = parseFloat(state[4]);
+ if (!isNaN(lat) && !isNaN(lng) && !isNaN(yaw) && !isNaN(pitch) && !isNaN(fov)) {
+ getPanoramaAtPos({lat, lng}, 0).then(({data, found}) => {
+ if (found) {
+ this.panorama.show(data, {yaw, pitch, fov});
+ this.panorama.setCamera({yaw, pitch, fov});
+ }
+ });
+ return true;
+ }
+ return false;
+ },
+
+ resize: function() {
+ this.panorama.syncPort();
+ },
+
+ updatePositionAndView: function() {
+ const place = this.panorama.getPlace();
+ if (!place) {
+ return;
+ }
+ const coords = place.getCoords().toWGS84();
+ const oldPosition = this._position;
+ const oldHeading = this._heading;
+ this._position = L.latLng(coords[1], coords[0]);
+ this._heading = this.panorama.getCamera().yaw;
+ if (!oldPosition || !this._position.equals(oldPosition) || this._heading !== oldHeading) {
+ this.fire('change', {
+ latlng: this._position,
+ heading: (this._heading * 180) / Math.PI,
+ });
+ }
+ },
+});
+
+async function getViewer(container) {
+ const smap = await getSMap();
+ return new Viewer(smap, container);
+}
+
+export default {getCoverageLayer, getPanoramaAtPos, getViewer};