1// Copyright for the additional Leaflet ExtraMarkers by coryasilva 2// 3// The MIT License (MIT) 4// 5// Copyright (c) 2014 coryasilva 6// 7// Permission is hereby granted, free of charge, to any person obtaining a copy 8// of this software and associated documentation files (the "Software"), to deal 9// in the Software without restriction, including without limitation the rights 10// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11// copies of the Software, and to permit persons to whom the Software is 12// furnished to do so, subject to the following conditions: 13// 14// The above copyright notice and this permission notice shall be included in all 15// copies or substantial portions of the Software. 16// 17// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23// SOFTWARE. 24 25/* Copyright for the additional Leaflet Pan Control - L.control.HwPan 26Copyright (c) 2012, Kartena AB 27All rights reserved. 28 29 Redistribution and use in source and binary forms, with or without 30modification, are permitted provided that the following conditions are met: 31 32 1. Redistributions of source code must retain the above copyright notice, this 33list of conditions and the following disclaimer. 342. Redistributions in binary form must reproduce the above copyright notice, 35 this list of conditions and the following disclaimer in the documentation 36and/or other materials provided with the distribution. 37 38 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 39ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 40WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 41DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 42ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 43(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 44LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 45ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 46(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 47SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.*/ 48 49// The rest of the code is provided by Hirsch & Wölfl GmbH, to be used inside its web-projects. 50// Copyright (c) 2022 Hirsch & Wölfl GmbH [email protected], [email protected] 51 52if (document.readyState === 'complete') { 53 hwLocationmap(); 54} else { 55 document.addEventListener('readystatechange', () => { 56 if (document.readyState === 'complete') { 57 hwLocationmap(); 58 } 59 }); 60} 61 62 63function hwLocationmap() { 64 65 // find all HWLocationmap maps 66 const hwLocationmapElements = document.getElementsByClassName('hw_location_map'); 67 68 // for every found map... 69 for (const mapElement of hwLocationmapElements) { 70 runLocationMap(mapElement).then(map => { 71 addResizeObserver(mapElement, map); 72 }); 73 } 74 75 // Start of the Leaflet ExtraMarkers 76 var ExtraMarker = L.Icon.extend({ 77 options: { 78 iconSize: [ 35, 45 ], 79 iconAnchor: [ 17, 42 ], 80 popupAnchor: [ 1, -32 ], 81 shadowAnchor: [ 10, 12 ], 82 shadowSize: [ 36, 16 ], 83 className: "", 84 prefix: "", 85 extraClasses: "", 86 shape: "circle", 87 icon: "", 88 innerHTML: "", 89 markerColor: "red", 90 svgBorderColor: "#fff", 91 svgOpacity: 1, 92 iconColor: "#fff", 93 iconRotate: 0, 94 number: "", 95 svg: false, 96 name: "" 97 }, 98 initialize: function(options) { 99 options = L.Util.setOptions(this, options); 100 }, 101 createIcon: function() { 102 var div = document.createElement("div"), options = this.options; 103 if (options.icon) { 104 div.innerHTML = this._createInner(); 105 } 106 if (options.innerHTML) { 107 div.innerHTML = options.innerHTML; 108 } 109 if (options.bgPos) { 110 div.style.backgroundPosition = -options.bgPos.x + "px " + -options.bgPos.y + "px"; 111 } 112 if (!options.svg) { 113 this._setIconStyles(div, options.shape + "-" + options.markerColor); 114 } else { 115 this._setIconStyles(div, "svg"); 116 } 117 return div; 118 }, 119 _getColorHex: function (color) { 120 var colorMap = { 121 red: "#a23337", 122 "orange-dark": "#d73e29", 123 orange: "#ef9227", 124 yellow: "#f5bb39", 125 "blue-dark": "#276273", 126 cyan: "#32a9dd", 127 purple: "#440444", 128 violet: "#90278d", 129 pink: "#c057a0", 130 green: "#006838", 131 white: "#e8e8e8", 132 black: "#211c1d" 133 }; 134 return colorMap[color] || color; 135 }, 136 _createSvg: function (shape, markerColor) { 137 var svgMap = { 138 circle: '<svg class="extra-markers" width="32" height="44" viewBox="0 0 35 45" xmlns="http://www.w3.org/2000/svg"><path d="M17.5 2.746c-8.284 0-15 6.853-15 15.307 0 .963.098 1.902.265 2.816a15.413 15.413 0 002.262 5.684l.134.193 12.295 17.785 12.439-17.863.056-.08a15.422 15.422 0 002.343-6.112c.123-.791.206-1.597.206-2.423 0-8.454-6.716-15.307-15-15.307" fill="' + markerColor + '" /><path d="M17.488 2.748c-8.284 0-15 6.853-15 15.307 0 .963.098 1.902.265 2.816a15.413 15.413 0 002.262 5.684l.134.193 12.295 17.785 12.44-17.863.055-.08a15.422 15.422 0 002.343-6.112c.124-.791.206-1.597.206-2.423 0-8.454-6.716-15.307-15-15.307m0 1.071c7.68 0 13.929 6.386 13.929 14.236 0 .685-.064 1.423-.193 2.258-.325 2.075-1.059 3.99-2.164 5.667l-.055.078-11.557 16.595L6.032 26.14l-.12-.174a14.256 14.256 0 01-2.105-5.29 14.698 14.698 0 01-.247-2.62c0-7.851 6.249-14.237 13.928-14.237" fill="#231f20" opacity=".15" /></svg>', 139 square: '<svg class="extra-markers" width="33" height="44" viewBox="0 0 35 45" xmlns="http://www.w3.org/2000/svg"><path d="M28.205 3.217H6.777c-2.367 0-4.286 1.87-4.286 4.179v19.847c0 2.308 1.919 4.179 4.286 4.179h5.357l5.337 13.58 5.377-13.58h5.357c2.366 0 4.285-1.87 4.285-4.179V7.396c0-2.308-1.919-4.179-4.285-4.179" fill="' + markerColor + '" /><g opacity=".15" transform="matrix(1.0714 0 0 -1.0714 -233.22 146.783)"><path d="M244 134h-20c-2.209 0-4-1.746-4-3.9v-18.525c0-2.154 1.791-3.9 4-3.9h5L233.982 95 239 107.675h5c2.209 0 4 1.746 4 3.9V130.1c0 2.154-1.791 3.9-4 3.9m0-1c1.654 0 3-1.301 3-2.9v-18.525c0-1.599-1.346-2.9-3-2.9h-5.68l-.25-.632-4.084-10.318-4.055 10.316-.249.634H224c-1.654 0-3 1.301-3 2.9V130.1c0 1.599 1.346 2.9 3 2.9h20" fill="#231f20" /></g></svg>', 140 star: '<svg class="extra-markers" width="34" height="44" viewBox="0 0 35 45" xmlns="http://www.w3.org/2000/svg"><path d="M32.92 16.93l-3.525-3.525V8.419a1.983 1.983 0 00-1.983-1.982h-4.985L18.9 2.91a1.984 1.984 0 00-2.803 0l-3.524 3.526H7.588a1.983 1.983 0 00-1.982
1401.982v4.986L2.081 16.93a1.982 1.982 0 000 2.803l3.525 3.526v4.984c0 1.096.888 1.983 1.982 1.983h4.986L17.457 45l4.97-14.773h4.985a1.983 1.983 0 001.983-1.983V23.26l3.525-3.526a1.982 1.982 0 000-2.803" fill="' + markerColor + '" /><g opacity=".15" transform="matrix(1.0667 0 0 -1.0667 -347.3 97.26)"><path d="M342 89c-.476 0-.951-.181-1.314-.544l-3.305-3.305h-4.673a1.858 1.858 0 01-1.859-1.858v-4.674l-3.305-3.305a1.857 1.857 0 010-2.627l3.305-3.305v-4.674a1.86 1.86 0 011.859-1.859h4.673L341.959 49l4.659 13.849h4.674a1.86 1.86 0 011.859 1.859v4.674l3.305 3.305a1.858 1.858 0 010 2.627l-3.305 3.305v4.674a1.859 1.859 0 01-1.859 1.858h-4.674l-3.304 3.305A1.851 1.851 0 01342 89m0-1a.853.853 0 00.607-.251l3.304-3.305.293-.293h5.088a.86.86 0 00.859-.858v-5.088l3.598-3.598A.852.852 0 00356 74a.85.85 0 00-.251-.606l-3.598-3.598v-5.088a.86.86 0 00-.859-.859h-5.393l-.229-.681-3.702-11.006-3.637 11.001-.227.686h-5.396a.86.86 0 00-.859.859v5.088l-3.598 3.598c-.162.162-.251.377-.251.606s.089.445.251.607l3.598 3.598v5.088a.86.86 0 00.859.858h5.087l3.598 3.598A.853.853 0 00342 88" fill="#231f20" /></g></svg>', 141 penta: '<svg class="extra-markers" width="33" height="44" viewBox="0 0 35 45" xmlns="http://www.w3.org/2000/svg"><path d="M1.872 17.35L9.679 2.993h15.615L33.1 17.35 17.486 44.992z" fill="' + markerColor + '" /><g opacity=".15" transform="matrix(1.0769 0 0 -1.0769 -272.731 48.23)"><path d="M276.75 42h-14.5L255 28.668 269.5 3 284 28.668zm-.595-1l6.701-12.323L269.5 5.033l-13.356 23.644L262.845 41z" fill="#231f20" /></g></svg>' 142 }; 143 return svgMap[shape]; 144 }, 145 _createInner: function() { 146 var iconStyle = "", iconNumber = "", iconClass = "", result = "", options = this.options; 147 if (options.iconColor) { 148 iconStyle = "color: " + options.iconColor + ";"; 149 } 150 if (options.iconRotate !== 0) { 151 iconStyle += "-webkit-transform: rotate(" + options.iconRotate + "deg);"; 152 iconStyle += "-moz-transform: rotate(" + options.iconRotate + "deg);"; 153 iconStyle += "-o-transform: rotate(" + options.iconRotate + "deg);"; 154 iconStyle += "-ms-transform: rotate(" + options.iconRotate + "deg);"; 155 iconStyle += "transform: rotate(" + options.iconRotate + "deg);"; 156 } 157 if (options.number) { 158 iconNumber = 'number="' + options.number + '" '; 159 } 160 if (options.extraClasses.length) { 161 iconClass += options.extraClasses + " "; 162 } 163 if (options.prefix.length) { 164 iconClass += options.prefix + " "; 165 } 166 if (options.icon.length) { 167 iconClass += options.icon + " "; 168 } 169 if (options.svg) { 170 result += this._createSvg(options.shape, this._getColorHex(options.markerColor)); 171 } 172 173 result += '<i ' + iconNumber + 'style="' + iconStyle + '" class="' + iconClass + '"></i>'; 174 175 if (options.name.length) { 176 result += '<div class="' + (options.nameClasses !== undefined ? options.nameClasses : '') + '">' + options.name + '</div>'; 177 } 178 179 return result; 180 }, 181 _setIconStyles: function(img, name) { 182 var options = this.options, size = L.point(options[name === "shadow" ? "shadowSize" : "iconSize"]), anchor, leafletName; 183 if (name === "shadow") { 184 anchor = L.point(options.shadowAnchor || options.iconAnchor); 185 leafletName = "shadow"; 186 } else { 187 anchor = L.point(options.iconAnchor); 188 leafletName = "icon"; 189 } 190 if (!anchor && size) { 191 anchor = size.divideBy(2, true); 192 } 193 img.className = "leaflet-marker-" + leafletName + " extra-marker extra-marker-" + name + " " + options.className; 194 if (anchor) { 195 img.style.marginLeft = -anchor.x + "px"; 196 img.style.marginTop = -anchor.y + "px"; 197 } 198 if (size) { 199 img.style.width = size.x + "px"; 200 img.style.height = size.y + "px"; 201 } 202 }, 203 createShadow: function() { 204 var div = document.createElement("div"); 205 this._setIconStyles(div, "shadow"); 206 return div; 207 } 208 }); 209 // End of the Leaflet ExtraMarkers 210 211 // create the leaflet map 212 async function runLocationMap(mapElement) { 213 214 // Map settings 215 const { 216 minZoom = 4, 217 maxZoom = 18, 218 defaultZoom = null, 219 } = mapElement.dataset; 220 221 // Get language attributes for zoom, pan, fullscreen from a div container, which is filled with from a language file 222 let languageAttributes = document.querySelector('.hw_map_location__js_attributes'); 223 224 // initialize map 225 let leafletMap = L.map(mapElement.getAttribute('id'), { 226 minZoom: minZoom, 227 maxZoom: maxZoom, 228 keyboard: true, 229 zoomControl: false, 230 scrollWheelZoom: false, 231 dragging: true, 232 touchZoom: true, 233 zoomAnimation: true, 234 gestureHandling: true, 235 markerSet: false, 236 }
236).setView([mapElement.getAttribute('data-start-lat'), mapElement.getAttribute('data-start-lng')], 15); 237 238 // map layer 239 let osmLayer = L.tileLayer('/index.php?eID=tx_hwlib_osmTile&s={s}&x={x}&y={y}&z={z}', { 240 minZoom: minZoom, 241 maxZoom: maxZoom, 242 noWrap: true, 243 attribution: '© <a href="https://www.openstreetmap.org/copyright" target="_blank">OpenStreetMap-Mitwirkende</a>' 244 }).addTo(leafletMap) 245 246 // scale 247 L.control.scale( 248 { 249 position: 'bottomleft', 250 imperial: false 251 } 252 ).addTo(leafletMap); 253 254 L.control.HwPan = L.Control.extend({ 255 options: { 256 position: 'topleft', 257 panOffset: 500 258 }, 259 onAdd: function (map) { 260 let className = 'hw_map_location__control__pan_map', 261 container = L.DomUtil.create('div', className), 262 off = this.options.panOffset; 263 264 this._panButton(languageAttributes.dataset.languageUparrow, className + '--up', 265 container, map, new L.Point( 0 , -off)); 266 this._panButton(languageAttributes.dataset.languageLeftarrow, className + '--left', 267 container, map, new L.Point( -off , 0)); 268 this._panButton(languageAttributes.dataset.languageRightarrow, className + '--right', 269 container, map, new L.Point( off , 0)); 270 this._panButton(languageAttributes.dataset.languageDownarrow, className + '--down', 271 container, map, new L.Point( 0 , off)); 272 let controlContainer; 273 // Add pan control class to the control container 274 if (this.options.position === 'topleft') { 275 controlContainer = L.DomUtil.get(map._controlCorners.topleft); 276 } else if (this.options.position === 'topright') { 277 controlContainer = L.DomUtil.get(map._controlCorners.topright); 278 } else if (this.options.position === 'bottomleft') { 279 controlContainer = L.DomUtil.get(map._controlCorners.bottomleft); 280 } else { 281 controlContainer = L.DomUtil.get(map._controlCorners.bottomright); 282 } 283 if(!L.DomUtil.hasClass(controlContainer, 'has-hw-leaflet-pan-control')) { 284 L.DomUtil.addClass(controlContainer, 'has-hw-leaflet-pan-control'); 285 } 286 287 return container; 288 }, 289 _panButton: function (title, className, container, map, offset) { 290 var wrapper = L.DomUtil.create('div', className + '__wrap', container); 291 var button = L.DomUtil.create('button', className, wrapper); 292 button.type = 'button'; 293 button.title = title; 294 L.DomEvent 295 .on(button, 'click', L.DomEvent.stopPropagation) 296 .on(button, 'click', L.DomEvent.preventDefault) 297 .on(button, 'click', function(){ map.panBy(offset); }, map) 298 .on(button, 'dblclick', L.DomEvent.stopPropagation); 299 300 return button; 301 } 302 }); 303 304 L.control.hwPan = function(options) { 305 return new L.control.HwPan(options); 306 }; 307 308 L.control.hwPan().addTo(leafletMap); 309 310 if(!mapElement.hasAttribute("data-config-zoom") || (mapElement.hasAttribute("data-config-zoom") && mapElement.getAttribute("data-config-zoom") === "true")) { 311 L.control.zoom( 312 { 313 position: 'topright', 314 zoomInText: '', 315 zoomInTitle: languageAttributes.dataset.languageZoomIn, 316 zoomOutText: '', 317 zoomOutTitle: languageAttributes.dataset.languageZoomOut 318 } 319 ).addTo(leafletMap); 320 } 321 322 if (parseInt(mapElement.dataset.allowFullscreen) === 1) { 323 // Fullscreen 324 L.control.fullscreen( 325 { 326 position: 'topright', 327 title: languageAttributes.dataset.languageEnableFullscreen, 328 titleCancel: languageAttributes.dataset.languageDisableFullscreen, 329 forceSeparateButton: true, 330 } 331 ).addTo(leafletMap); 332 333 // Add or remove fullscreen class to document.body 334 const fullScreenApiAvailable = document.fullscreenEnabled || document.mozFullscreenEnabled || document.webkitFullscreenEnabled || document.msFullscreenEnabled; 335 336 // device apple touch 337 const deviceAppleTouch = navigator.platform === 'iPad' || navigator.platform === 'iPhone' || navigator.platform === 'iPod'; 338 339 // on fullscreen open 340 leafletMap.on('enterFullscreen', () => { 341 document.body.classList.add('hw_locationmap__fullscreen'); 342 343 if(deviceAppleTouch) { 344 document.body.classList.add('hwgeomap3_fullscreen_apple_touch'); 345 } 346 347 if (!fullScreenApiAvailable) { 348 document.body.classList.add('hw_locationmap__pseudo_fullscreen'); 349 } 350 351 }); 352 353 // on fullscreen close 354 leafletMap.on('exitFullscreen', () => { 355 document.body.classList.remove('hw_locationmap__fullscreen'); 356 357 if(deviceAppleTouch) { 358 document.body.classList.remove('hwgeomap3_fullscreen_apple_touch'); 359 } 360 361 if (!fullScreenApiAvailable) { 362 document.body.classList.remove('hw_locationmap__pseudo_fullscreen'); 363 } 364 }); 365 } 366 367 let markerGroup; 368 // create a new group container for markers 369 if (mapElement.dataset.disableClustering === '1') { 370 markerGroup = L.featureGroup(); 371 } else { 372 markerGroup = L.markerClusterGroup({showCoverageOnHover: false}); 373 } 374 375 markerGroup.addTo(leafletMap); 376 377 378 // get markers per AJAX request 379 getMarkers(mapElement, leafletMap, markerGroup); 380 381 382 // Events 383 leafletMap.on('popupopen', (e) => { 384 // Set Popup maxWidth to viewport size 385 if (leafletMap._container.getBoundingClientRect().width < e.popup.options.maxWidth && leafletMap._container.getBoundingClientRect().width < e.popup._containerWidth) { 386 e.popup.options.maxWidth = leafletMap._container.getBoundingClientRect().width - (40 * 2); 387 e.popup.update(); 388 } 389 390 document.body.classList.add('hw_locationmap__popup'); 391 392 // Center Popup 393 let px = leafletMap.project(e.target._popup._latlng); 394 px.y -= (e.target._popup._container.clientHeight / 2); 395 leafletMap.panTo(leafletMap.unproject(px), {animate: true}); 396 }); 397 398 leafletMap.on('popupclose', (e) => { 399 document.body.classList.remove('hw_locationmap__popup'); 400 }); 401 402 return leafletMap; 403 404 405 // AJAX-Call for markers 406 function getMarkers(mapElement, leafletMap, markerGroup) { 407 408 let ajaxCall = new XMLHttpRequest(); 409 ajaxCall.onreadystatechange = function() { 410 if (this.readyState === XMLHttpRequest.DONE && this.status === 200) { 411 412 // add markers form AJAX request to map 413 addMarkersToMap(leafletMap, markerGroup, JSON.parse(this.responseText)); 414 } 415 }; 416 ajaxCall.open("GET", mapElement.getAttribute('data-webservice-url')); 417 ajaxCall.send(); 418 } 419 420 421 // draw markers on map 422 function addMarkersToMap(leafletMap, markerGroup, ajaxData) { 423 424 // remove old markers 425 markerGroup.clearLayers(); 426 427 // add new markers 428 if (ajaxData.length > 0) { 429 for (let i = 0; i < ajaxData.length; i++) { 430 431 // create new marker 432 L.marker([ajaxData[i].lat, ajaxData[i].lng], { 433 icon: new ExtraMarker(ajaxData[i]['iconConfig']) 434 }) 435 .bindPopup(ajaxData[i].popupContent, ajaxData[i].popupConfig) 436 .addTo(markerGroup); 437 } 438 439 // invalidate map size 440 leafletMap.invalidateSize(true); 441 442 if (defaultZoom !== null && defaultZoom !== '') { 443 // Set map view to bounds center and default zoom level
444 leafletMap.setView(markerGroup.getBounds().getCenter()).setZoom(defaultZoom); 445 } else { 446 // Set map view to fit bounds with padding 447 leafletMap.fitBounds(markerGroup.getBounds().pad(0.4)); 448 } 449 } 450 } 451 } 452} 453 454 455// Function to observe resize changes 456function addResizeObserver(element, map) { 457 const resizeObserver = new ResizeObserver(entries => { 458 for (let entry of entries) { 459 if (entry.target === element) { 460 map.invalidateSize(); 461 } 462 } 463 }); 464 resizeObserver.observe(element); 465}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.