index.js (5828B)
1 import L from 'leaflet'; 2 3 import config from '~/config'; 4 5 import {getPanorama} from './apiLoader'; 6 import {CloseButtonMixin, Events} from '../common'; 7 8 function getCoverageLayer(options) { 9 return L.tileLayer('https://proxy.nakarte.me/mapy/panorama_ln_hybrid-m/{z}-{x}-{y}', options); 10 } 11 12 async function getPanoramaAtPos(latlng, searchRadiusMeters) { 13 const panoramaClass = await getPanorama(); 14 const res = await panoramaClass.panoramaExists({ 15 lon: latlng.lng, 16 lat: latlng.lat, 17 radius: searchRadiusMeters, 18 apiKey: config.mapyCzKey, 19 }); 20 return { 21 found: res.exists, 22 data: res.info, 23 }; 24 } 25 26 const MapyPanoramaWrapper = L.Evented.extend({ 27 initialize: function (mapyPanorama, container, apiKey) { 28 this.apiKey = apiKey; 29 this.container = L.DomUtil.create('div', null, container); 30 this.container.style.height = '100%'; 31 this.mapyPanorama = mapyPanorama; 32 this.viewerControl = null; 33 this.position = null; 34 this.pov = null; 35 }, 36 37 deactivate: function () { 38 this.reset(); 39 this.position = null; 40 this.pov = null; 41 }, 42 showPano: async function (position, pov) { 43 this.reset(); 44 this.position = null; 45 // Disable keyboard events for panorama as they conflict with other hotkeys. 46 const origWindowAddEventListener = window.addEventListener; 47 window.addEventListener = function (type, ...args) { 48 if (!/^key/u.test(type)) { 49 origWindowAddEventListener(type, ...args); 50 } 51 }; 52 let res; 53 try { 54 res = await this.mapyPanorama.panoramaFromPosition({ 55 parent: this.container, 56 ...position, 57 ...(pov ?? this.pov ?? {yaw: 'auto'}), 58 radius: 0.01, 59 showNavigation: true, 60 apiKey: this.apiKey, 61 lang: 'en', 62 }); 63 } finally { 64 window.addEventListener = origWindowAddEventListener; // eslint-disable-line require-atomic-updates 65 } 66 if (res.error) { 67 return; 68 } 69 this.viewerControl = res; 70 this.onPositionChange(res); 71 const loadedPanoPov = res.getCamera(); 72 this.onPOVChange(loadedPanoPov); 73 this.viewerControl.addListener('pano-view', this.onPOVChange.bind(this)); 74 this.viewerControl.addListener('pano-place', this.onPositionChange.bind(this)); 75 }, 76 77 reset: function () { 78 if (this.viewerControl) { 79 this.viewerControl.destroy(); 80 this.viewerControl = null; 81 } 82 }, 83 84 onPOVChange: function (pov) { 85 this.pov = pov; 86 this.notifyViewChanged(pov); 87 }, 88 89 onPositionChange: function (e) { 90 this.position = e.info; 91 this.notifyPositionChanged(e.info); 92 }, 93 94 notifyPositionChanged: function (position) { 95 this.fire('position-change', position); 96 }, 97 98 notifyViewChanged: function (pov) { 99 this.fire('view-change', pov); 100 }, 101 102 getPanoramaCoords: function () { 103 return this.position; 104 }, 105 106 getPov: function () { 107 if (this.viewerControl === null) { 108 return null; 109 } 110 return this.viewerControl.getCamera(); 111 }, 112 }); 113 114 const Viewer = L.Evented.extend({ 115 includes: [CloseButtonMixin], 116 117 initialize: function (mapyPanorama, container) { 118 this.mapyPanoramaWrapper = new MapyPanoramaWrapper(mapyPanorama, container, config.mapyCzKey); 119 this.createCloseButton(container); 120 this.mapyPanoramaWrapper.on('position-change', this.onPanoramaPositionChanged, this); 121 this.mapyPanoramaWrapper.on('view-change', this.onPanoramaPovChanged, this); 122 this.povChangeTimer = null; 123 }, 124 125 showPano: function (place, pov) { 126 this.mapyPanoramaWrapper.showPano(place, pov); 127 }, 128 129 activate: function () { 130 // no action needed 131 }, 132 133 deactivate: function () { 134 this.mapyPanoramaWrapper.reset(); 135 }, 136 137 getState: function () { 138 const coords = this.mapyPanoramaWrapper.getPanoramaCoords(); 139 const pov = this.mapyPanoramaWrapper.getPov(); 140 if (coords === null || pov === null) { 141 return null; 142 } 143 return [ 144 coords.lat.toFixed(6), 145 coords.lon.toFixed(6), 146 pov.yaw.toFixed(4), 147 pov.pitch.toFixed(4), 148 pov.fov.toFixed(4), 149 ]; 150 }, 151 152 setState: function (state) { 153 const lat = parseFloat(state[0]); 154 const lng = parseFloat(state[1]); 155 const yaw = parseFloat(state[2]); 156 const pitch = parseFloat(state[3]); 157 const fov = parseFloat(state[4]); 158 if (isNaN(lat) || isNaN(lng) || isNaN(yaw) || isNaN(pitch) || isNaN(fov)) { 159 return false; 160 } 161 this.showPano({lat, lon: lng}, {yaw, pitch, fov}); 162 return true; 163 }, 164 165 onPanoramaPositionChanged: function (position) { 166 this.fire(Events.ImageChange, {latlng: L.latLng(position.lat, position.lon)}); 167 }, 168 169 onPanoramaPovChanged: function (pov) { 170 this.fire(Events.BearingChange, {bearing: (pov.yaw * 180) / Math.PI}); 171 if (this.povChangeTimer !== null) { 172 clearTimeout(this.povChangeTimer); 173 this.povChangeTimer = null; 174 } 175 this.povChangeTimer = setTimeout(() => { 176 this.povChangeTimer = null; 177 this.fire(Events.YawPitchZoomChangeEnd); 178 }, 120); 179 }, 180 181 invalidateSize: function () { 182 // no action needed 183 }, 184 }); 185 186 async function getViewer(container) { 187 const mapyPanorama = await getPanorama(); 188 return new Viewer(mapyPanorama, container); 189 } 190 191 const mapyczProvider = {getCoverageLayer, getPanoramaAtPos, getViewer}; 192 export default mapyczProvider;