westraPassesMarkers.js (11061B)
1 import L from 'leaflet'; 2 import '~/lib/leaflet.layer.canvasMarkers'; 3 import {openPopupWindow} from '~/lib/popup-window'; 4 import escapeHtml from 'escape-html'; 5 import {saveAs} from '~/vendored/github.com/eligrey/FileSaver'; 6 import iconFromBackgroundImage from '~/lib/iconFromBackgroundImage'; 7 import {fetch} from '~/lib/xhr-promise'; 8 import {notify} from '~/lib/notifications'; 9 import * as logging from '~/lib/logging'; 10 11 const WestraPassesMarkers = L.Layer.CanvasMarkers.extend({ 12 options: { 13 filePasses: 'westra_passes2.json', 14 scaleDependent: true 15 }, 16 17 initialize: function(baseUrl, options) { 18 L.Layer.CanvasMarkers.prototype.initialize.call(this, null, options); 19 this.on('markerclick', this.showPassDescription, this); 20 this._baseUrl = baseUrl; 21 this.url = baseUrl + this.options.filePasses; 22 }, 23 24 loadData: async function() { 25 if (this._downloadStarted) { 26 return; 27 } 28 this._downloadStarted = true; 29 let xhr; 30 try { 31 xhr = await fetch(this.url); 32 } catch (e) { 33 this._downloadStarted = false; 34 logging.captureException(e, 'failed to get westra passes'); 35 notify('Failed to get Westra passes data'); 36 } 37 38 const {passes, regions} = JSON.parse(xhr.response); 39 this.regions = regions; 40 this._createMarkers(passes); 41 }, 42 43 _createMarkers: function(passes) { 44 const markers = []; 45 for (const pass of passes) { 46 const marker = { 47 latlng: { 48 lat: pass.latlon[0], 49 lng: pass.latlon[1] 50 }, 51 label: pass.name || "", 52 icon: this._makeIcon, 53 tooltip: this._makeTooltip.bind(this), 54 properties: pass 55 }; 56 markers.push(marker); 57 } 58 this.addMarkers(markers); 59 this._dataLoaded = true; 60 this.fire('data-loaded'); 61 }, 62 63 onAdd: function(map) { 64 L.Layer.CanvasMarkers.prototype.onAdd.call(this, map); 65 this.loadData(); 66 }, 67 68 _makeTooltip: function(marker) { 69 var properties = marker.properties, 70 toolTip = properties.grade || ''; 71 if (toolTip && properties.elevation) { 72 toolTip += ', '; 73 } 74 toolTip += properties.elevation || ''; 75 if (toolTip) { 76 toolTip = ' (' + toolTip + ')'; 77 } 78 toolTip = (properties.name || 'без названия') + toolTip; 79 toolTip = (properties.is_summit ? 'Вершина ' : 'Перевал ') + toolTip; 80 return toolTip; 81 }, 82 83 _passToGpx: function(marker) { 84 let label = marker.tooltip; 85 if (typeof label === 'function') { 86 label = label(marker); 87 } 88 label = escapeHtml(label); 89 const gpx = `<?xml version="1.0" encoding="UTF-8" standalone="no" ?> 90 <gpx xmlns="http://www.topografix.com/GPX/1/1" 91 creator="http://nakarte.me" 92 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 93 xsi:schemaLocation="http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd" 94 version="1.1"> 95 <wpt lat="${marker.latlng.lat.toFixed(6)}" lon="${marker.latlng.lng.toFixed(6)}"> 96 <name>${label}</name> 97 </wpt> 98 </gpx> 99 `; 100 var filename = marker.properties.name || 'Без названия'; 101 saveAs(new Blob([gpx], {type: 'application/gpx+xml'}), filename + '.gpx', true); 102 }, 103 104 _passToKml: function(marker) { 105 let label = marker.tooltip; 106 if (typeof label === 'function') { 107 label = label(marker); 108 } 109 label = escapeHtml(label); 110 const kml = `<?xml version="1.0" encoding="UTF-8"?> 111 <kml xmlns="http://www.opengis.net/kml/2.2"> 112 <Placemark> 113 <name>${label}</name> 114 <Point> 115 <coordinates> 116 ${marker.latlng.lng.toFixed(6)},${marker.latlng.lat.toFixed(6)},0 117 </coordinates> 118 </Point> 119 </Placemark> 120 </kml> 121 `; 122 var filename = marker.properties.name || 'Без названия'; 123 saveAs(new Blob([kml], {type: 'application/vnd.google-earth.kml+xml'}), filename + '.kml', true); 124 }, 125 126 _makeIcon: function(marker) { 127 var className; 128 className = 'westra-pass-marker '; 129 if (marker.properties.is_summit) { 130 className += 'westra-pass-marker-summit'; 131 } else { 132 className += 'westra-pass-marker-' + marker.properties.grade_eng; 133 } 134 return iconFromBackgroundImage(className); 135 }, 136 137 showPassDescription: function(e) { 138 if (!this._map) { 139 return; 140 } 141 const properties = e.marker.properties, 142 latLng = e.marker.latlng, 143 catalogueUrlBase = 'https://westra.ru/passes', 144 passUrl = `${catalogueUrlBase}/Passes/${properties.id}`, 145 regionUrlBase = `${catalogueUrlBase}/Places`; 146 let altnames = '', 147 connects = '', 148 comments = ''; 149 if (properties.altnames) { 150 altnames = ` 151 <tr> 152 <td>Другие названия</td> 153 <td>${escapeHtml(properties.altnames)}</td> 154 </tr>`; 155 } 156 157 if (!properties.is_summit) { 158 connects = ` 159 <tr> 160 <td>Соединяет</td> 161 <td>${properties.connects ? escapeHtml(properties.connects) : "неизвестнo"}</td> 162 </tr>`; 163 } 164 165 if (properties.comments) { 166 for (let comment of properties.comments) { 167 let user = ''; 168 if (comment.user) { 169 user = ( 170 `<span class="westra-passes-description-comment-author">${escapeHtml(comment.user)}:</span>` 171 ); 172 } 173 comments += ( 174 `<p class="westra-passes-description-comment">${user}${escapeHtml(comment.content)}</p>` 175 ); 176 } 177 comments = ` 178 <tr> 179 <td>Комментарии</td> 180 <td>${comments}</td> 181 </tr>`; 182 } 183 let reports; 184 if (properties.reports_total) { 185 reports = 186 `<br>Отчетов: ${properties.reports_total}, ` + 187 `с фото: ${properties.reports_photo || 0}, ` + 188 `с описанием: ${properties.reports_tech || 0}`; 189 } else { 190 reports = '<br>Отчетов нет'; 191 } 192 const region = properties.regions.map((regionId) => { 193 const name = escapeHtml(this.regions[regionId].name); 194 const id = escapeHtml(regionId); 195 return `<a href="${regionUrlBase}/${id}">${name}</a>`; 196 }).join(' / '); 197 198 let description = ` 199 <table class="pass-details"> 200 <tr> 201 <td>${properties.is_summit ? 'Вершина ' : 'Перевал '}</td> 202 <td>${properties.name ? escapeHtml(properties.name) : 'название неизвестно'}</td> 203 </tr> 204 ${altnames} 205 <tr> 206 <td>Категория</td> 207 <td>${properties.grade ? escapeHtml(properties.grade) : "неизвестная"}</td> 208 </tr> 209 <tr> 210 <td>Высота</td> 211 <td>${properties.elevation ? (escapeHtml(properties.elevation) + ' м') : 'неизвестная'}</td> 212 </tr> 213 ${connects} 214 <tr> 215 <td>Характеристика склонов</td> 216 <td>${properties.slopes ? escapeHtml(properties.slopes) : "неизвестная"}</td> 217 </tr> 218 <tr> 219 <td>Координаты</td> 220 <td> 221 <table class="coords"> 222 <tr class="header"> 223 <td>Широта</td> 224 <td>Долгота</td> 225 </tr> 226 <tr> 227 <td>${latLng.lat.toFixed(5)}</td> 228 <td>${latLng.lng.toFixed(5)}</td> 229 <td><a id="westra-pass-gpx" title="Сохранить">gpx</a></td> 230 <td><a id="westra-pass-kml" title="Сохранить">kml</a></td> 231 </tr> 232 </table> 233 </td> 234 </tr> 235 <tr> 236 <td>На сайте Вестры</td> 237 <td><a id="westra-pass-link" href="${passUrl}">${passUrl}</a>${reports}</td></tr> 238 <tr> 239 <td>Добавил</td> 240 <td>${properties.author ? escapeHtml(properties.author) : "неизвестно"}</td> 241 </tr> 242 ${comments} 243 <tr> 244 <td>Район</td> 245 <td>${region}</td> 246 </tr> 247 248 </table>`; 249 this._map.openPopup(description, latLng, {maxWidth: 500}); 250 document.getElementById('westra-pass-link').onclick = function() { 251 openPopupWindow(passUrl, 780, 'westra-details'); 252 return false; 253 }; 254 document.getElementById('westra-pass-gpx').onclick = function() { 255 this._passToGpx(e.marker); 256 return false; 257 }.bind(this); 258 document.getElementById('westra-pass-kml').onclick = function() { 259 this._passToKml(e.marker); 260 return false; 261 }.bind(this); 262 } 263 } 264 ); 265 266 export {WestraPassesMarkers};