nakarte

Source code of https://map.sikmir.ru (fork)
git clone git://git.sikmir.ru/nakarte
Log | Files | Refs | LICENSE

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:
Msrc/lib/leaflet.control.panoramas/index.js | 10++++++++++
Asrc/lib/leaflet.control.panoramas/lib/mapycz/apiLoader.js | 38++++++++++++++++++++++++++++++++++++++
Asrc/lib/leaflet.control.panoramas/lib/mapycz/index.js | 116+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
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};