1(function (window, document) { 2 'use strict'; 3 4 if (!window || !document || window.PPMapRuntime) return; 5 6 var STORAGE_MODE_KEY = 'pp_gpu_mode'; 7 var STORAGE_REASON_KEY = 'pp_gpu_reason'; 8 var VERSION = '20260519-gpu-capability-v1'; 9 var DEFAULT_SATELLITE_TILE = 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}'; 10 11 function hasForcedLegacyFlag() { 12 try { 13 return /(?:\?|&)pp_force_legacy_map=1(?:&|$)/.test(window.location.search || ''); 14 } catch (_) { 15 return false; 16 } 17 } 18 19 function getCompatState() { 20 var state = { 21 legacy: false, 22 minimal: false, 23 mode: 'full_gpu', 24 reason: '', 25 provider: 'mapbox', 26 supports3D: true, 27 supportsDrawing: true, 28 supportsMeasurement: true 29 }; 30 try { 31 if (window.PPWebGLCompat && typeof window.PPWebGLCompat.getMode === 'function') { 32 state.mode = window.PPWebGLCompat.getMode(); 33 state.reason = (window.PPWebGLCompat.getState && window.PPWebGLCompat.getState().reason) || ''; 34 state.legacy = state.mode === 'no_gpu'; 35 state.minimal = state.mode === 'minimal_gpu'; 36 state.provider = window.PPWebGLCompat.getProvider ? window.PPWebGLCompat.getProvider() : (state.legacy ? 'leaflet' : 'mapbox'); 37 state.supports3D = window.PPWebGLCompat.supports ? window.PPWebGLCompat.supports('3d_mode') : !state.legacy; 38 return state; 39 } 40 } catch (_) {} 41 try { 42 if (hasForcedLegacyFlag()) { 43 state.legacy = true; 44 state.mode = 'no_gpu'; 45 state.reason = 'forced_query'; 46 } 47 } catch (_) {} 48 try { 49 var sessionMode = window.sessionStorage && window.sessionStorage.getItem(STORAGE_MODE_KEY); 50 var localMode = window.localStorage && window.localStorage.getItem(STORAGE_MODE_KEY); 51 var mode = sessionMode || localMode; 52 if (!state.legacy && mode) { 53 state.mode = mode; 54 state.legacy = mode === 'no_gpu'; 55 state.minimal = mode === 'minimal_gpu'; 56 state.reason = (window.sessionStorage && window.sessionStorage.getItem(STORAGE_REASON_KEY)) || 57 (window.localStorage && window.localStorage.getItem(STORAGE_REASON_KEY)) || 'persisted'; 58 } 59 } catch (_) {} 60 if (state.legacy) { 61 state.provider = 'leaflet'; 62 state.supports3D = false; 63 } else if (state.minimal) { 64 state.provider = 'mapbox'; 65 state.supports3D = false; 66 } 67 return state; 68 } 69 70 function markLegacy(reason) { 71 try { 72 if (window.PPWebGLCompat && typeof window.PPWebGLCompat.getMode === 'function') { 73 if (window.PPWebGLCompat.getMode() !== 'no_gpu') { 74 if (typeof window.PPWebGLCompat.mark3DDisabled === 'function') { 75 window.PPWebGLCompat.mark3DDisabled(reason || 'leaflet_visual_fallback'); 76 } 77 state.legacy = false; 78 state.provider = 'mapbox'; 79 return; 80 } 81 } 82 } catch (_) {} 83 markNoGpu(reason); 84 } 85 86 function markNoGpu(reason) { 87 try { 88 if (window.PPWebGLCompat && typeof window.PPWebGLCompat.markNoGpu === 'function') { 89 window.PPWebGLCompat.markNoGpu(reason || 'map_runtime'); 90 return; 91 } 92 } catch (_) {} 93 try { 94 if (window.sessionStorage) { 95 window.sessionStorage.setItem(STORAGE_MODE_KEY, 'no_gpu'); 96 window.sessionStorage.setItem(STORAGE_REASON_KEY, reason || 'map_runtime'); 97 } 98 if (window.localStorage) { 99 window.localStorage.setItem(STORAGE_MODE_KEY, 'no_gpu'); 100 window.localStorage.setItem(STORAGE_REASON_KEY, reason || 'map_runtime'); 101 } 102 } catch (_) {} 103 } 104 105 function toFeatureCollection(input) { 106 if (!input) return { type: 'FeatureCollection', features: [] }; 107 if (input.type === 'FeatureCollection') return input; 108 if (input.type === 'Feature') return { type: 'FeatureCollection', features: [input] }; 109 if (input.type && input.coordinates) { 110 return { type: 'FeatureCollection', features: [{ type: 'Feature', geometry: input, properties: {} }] }; 111 } 112 if (Array.isArray(input)) return { type: 'FeatureCollection', features:
112input.filter(Boolean) }; 113 return { type: 'FeatureCollection', features: [] }; 114 } 115 116 function firstPaintValue(paint, keys, fallback) { 117 paint = paint || {}; 118 for (var i = 0; i < keys.length; i += 1) { 119 var value = paint[keys[i]]; 120 if (value == null) continue; 121 if (Array.isArray(value)) continue; 122 return value; 123 } 124 return fallback; 125 } 126 127 function styleFromMapboxLayer(layer, fallback) { 128 layer = layer || {}; 129 fallback = fallback || {}; 130 var paint = layer.paint || {}; 131 return { 132 color: firstPaintValue(paint, ['line-color', 'fill-outline-color', 'circle-color'], fallback.color || '#2563eb'), 133 weight: Number(firstPaintValue(paint, ['line-width'], fallback.weight || 3)) || fallback.weight || 3, 134 opacity: Number(firstPaintValue(paint, ['line-opacity', 'circle-opacity'], fallback.opacity == null ? 0.9 : fallback.opacity)), 135 fillColor: firstPaintValue(paint, ['fill-color', 'circle-color', 'line-color'], fallback.fillColor || fallback.color || '#2563eb'), 136 fillOpacity: Number(firstPaintValue(paint, ['fill-opacity'], fallback.fillOpacity == null ? 0.18 : fallback.fillOpacity)), 137 radius: Number(firstPaintValue(paint, ['circle-radius'], fallback.radius || 7)) || fallback.radius || 7 138 }; 139 } 140 141 function evaluateMapboxExpression(value, feature, fallback) { 142 if (!Array.isArray(value)) return value == null ? fallback : value; 143 var props = (feature && feature.properties) || {}; 144 if (value[0] === 'match') { 145 var keyExpr = value[1]; 146 var key = Array.isArray(keyExpr) && keyExpr[0] === 'get' ? props[keyExpr[1]] : null; 147 for (var i = 2; i < value.length - 1; i += 2) { 148 if (value[i] === key) return value[i + 1]; 149 } 150 return value[value.length - 1] || fallback; 151 } 152 if (value[0] === 'case') { 153 for (var j = 1; j < value.length - 1; j += 2) { 154 var cond = value[j]; 155 if (Array.isArray(cond) && cond.length >= 3) { 156 var op = cond[0]; 157 var left = cond[1]; 158 var right = cond[2]; 159 var leftValue = Array.isArray(left) && left[0] === 'get' ? Number(props[left[1]]) : Number(left); 160 var rightValue = Number(right); 161 if ((op === '<=' && leftValue <= rightValue) || (op === '==' && leftValue === rightValue)) return value[j + 1]; 162 } 163 } 164 return value[value.length - 1] || fallback; 165 } 166 return fallback; 167 } 168 169 function createLeafletRuntime(map, options) { 170 options = options || {}; 171 var layers = {}; 172 var visibility = {}; 173 174 function removeLayer(key) { 175 var layer = layers[key]; 176 if (!layer) return; 177 try { map.removeLayer(layer); } catch (_) {} 178 delete layers[key]; 179 delete visibility[key]; 180 } 181 182 function drawGeoJson(key, data, opts) { 183 if (!map || !window.L || !key) return null; 184 opts = opts || {}; 185 if (layers[key]) removeLayer(key); 186 var fc = toFeatureCollection(data); 187 var style = opts.style || {}; 188 var layer = window.L.geoJSON(fc, { 189 pointToLayer: function (feature, latlng) { 190 var radius = opts.radius || style.radius || 7; 191 return window.L.circleMarker(latlng, { 192 radius: radius, 193 color: style.color || opts.color || '#2563eb', 194 weight: style.weight || opts.weight || 2, 195 opacity: style.opacity == null ? 0.95 : style.opacity, 196 fillColor: style.fillColor || opts.fillColor || style.color || '#2563eb', 197 fillOpacity: style.fillOpacity == null ? 0.75 : style.fillOpacity 198 }); 199 }, 200 style: function (feature) { 201 var featureColor = feature && feature.properties && feature.properties.color; 202 return { 203 color: featureColor || style.color || opts.color || '#2563eb', 204 weight: style.weight || opts.weight || 3, 205 opacity: style.opacity == null ? (opts.opacity == null ? 0.95 : opts.opacity) : style.opacity, 206 fillColor: style.fillColor || opts.fillColor || featureColor || style.color || opts.color || '#2563eb', 207 fillOpacity: style.fillOpacity == null ? (opts.fillOpacity == null ? 0.18 : opts.fillOpacity) : style.fillOpacity 208 }; 209 }, 210 onEachFeature: function (feature, leafletLayer) { 211 var label = feature && feature.properties && (feature.properties.adaParsel || feature.properties.AdaParsel || feature.properties.label || feature.properties.label_text || feature.properties.text); 212 if (label && leafletLayer && leafletLayer.getBounds) { 213 try { 214 window.L.marker(leafletLayer.getBounds().getCenter(), { 215 icon: window.L.divIcon({ 216 html: '<div style="background:rgba(255,255,255,.94);border:1px solid rgba(37,99,235,.55);border-radius:5px;padding:2px 6px;font-weight:700;color:#1e3a8a;white-space:nowrap;">' + String(label) + '</div>', 217 className: 'pp-leaflet-label-icon' 218 }) 219 }).addTo(map); 220 } catch (_) {} 221 } 222 } 223 }).addTo(map); 224 layers[key] = layer; 225 visibility[key] = true; 226 if (opts.fit !== false) { 227 try { map.fitBounds(layer.getBounds(), { padding: opts.padding || [40, 40] }); } catch (_) {} 228 } 229 return layer; 230 } 231 232 return { 233 provider: 'leaflet', 234 map: map, 235 isLegacy: true, 236 drawGeoJson: drawGeoJson, 237 drawPolygon: function (key, coords, opts) { 238 var geometry = { type: 'Polygon', coordinates: coords }; 239 return drawGeoJson(key, { type: 'Feature', geometry: geometry, properties: (opts && opts.properties) || {} }, opts); 240 },
241 drawLine: function (key, coords, opts) { 242 var geometry = { type: 'LineString', coordinates: coords }; 243 return drawGeoJson(key, { type: 'Feature', geometry: geometry, properties: (opts && opts.properties) || {} }, opts); 244 }, 245 drawMarker: function (key, lngLat, opts) { 246 if (!window.L || !Array.isArray(lngLat)) return null; 247 removeLayer(key); 248 var marker = window.L.marker([lngLat[1], lngLat[0]], opts || {}).addTo(map); 249 layers[key] = marker; 250 return marker; 251 }, 252 drawParcel: function (feature, opts) { 253 opts = opts || {}; 254 opts.style = opts.style || { 255 color: '#D32F2F', 256 weight: 3, 257 fillColor: '#D32F2F', 258 fillOpacity: 0.14 259 }; 260 if (opts.fit == null) opts.fit = true; 261 return drawGeoJson('parcel_polygon', feature, opts); 262 }, 263 clearLayer: removeLayer, 264 setLayerVisibility: function (key, visible) { 265 var layer = layers[key]; 266 if (!layer) return; 267 visibility[key] = !!visible; 268 try { 269 if (visible && !map.hasLayer(layer)) layer.addTo(map); 270 if (!visible && map.hasLayer(layer)) map.removeLayer(layer); 271 } catch (_) {} 272 }, 273 fitGeoJson: function (data, opts) { 274 try { 275 var temp = window.L.geoJSON(toFeatureCollection(data)); 276 map.fitBounds(temp.getBounds(), opts || { padding: [40, 40] }); 277 return true; 278 } catch (_) { 279 return false; 280 } 281 }, 282 onClick: function (handler) { 283 if (!handler) return; 284 var wrapped = function (event) { 285 handler(normalizeClick(event)); 286 }; 287 map.on('click', wrapped); 288 return wrapped; 289 }, 290 offClick: function (wrapped) { 291 try { map.off('click', wrapped); } catch (_) {} 292 }, 293 resize: function () { 294 try { map.invalidateSize(); } catch (_) {} 295 }, 296 project: function (lngLat) { 297 var p = map.latLngToContainerPoint([lngLat[1], lngLat[0]]); 298 return { x: p.x, y: p.y }; 299 }, 300 unproject: function (point) { 301 var ll = map.containerPointToLatLng(point); 302 return { lng: ll.lng, lat: ll.lat }; 303 }, 304 _layers: layers, 305 _visibility: visibility 306 }; 307 } 308 309 function createMapboxRuntime(map) { 310 function defaultPaintForLayer(key, type, opts) { 311 var paint = opts.paint || {}; 312 if (key === 'parcel_polygon' || (typeof key === 'string' && /^parcel_polygon(_|$|-)/.test(key))) { 313 paint = Object.assign({ 314 'fill-color': '#ff0000', 315 'fill-opacity': 0.25, 316 'fill-outline-color': '#ff0000', 317 'line-color': '#ff0000', 318 'line-width': 4, 319 'line-opacity': 0.95 320 }, paint); 321 } 322 return paint; 323 } 324 325 return { 326 provider: 'mapbox', 327 map: map, 328 isLegacy: false, 329 drawGeoJson: function (key, data, opts) { 330 opts = opts || {}; 331 var fc = toFeatureCollection(data); 332 var style = opts.style || {}; 333 var isParcelKey = key === 'parcel_polygon' || (typeof key === 'string' && /^parcel_polygon(_|$)/.test(key)); 334 try { 335 if (map.getSource(key)) map.getSource(key).setData(fc); 336 else map.addSource(key, { type: 'geojson', data: fc }); 337 338 if (isParcelKey) { 339 var fillId = key + '_fill'; 340 var lineWidth = Number(style.weight) || 3; 341 var fillOpacity = style.fillOpacity == null ? 0.2 : Number(style.fillOpacity); 342 var visibility = opts.visible === false ? 'none' : 'visible'; 343 if (!map.getLayer(fillId)) { 344 map.addLayer({ 345 id: fillId, 346 type: 'fill', 347 source: key, 348 paint: { 'fill-color': '#ff0000', 'fill-opacity': fillOpacity }, 349 layout: { visibility: visibility }, 350 }); 351 } else { 352 try { map.setPaintProperty(fillId, 'fill-opacity', fillOpacity); } catch (_) {} 353 try { map.setLayoutProperty(fillId, 'visibility', visibility); } catch (_) {} 354 } 355 if (!map.getLayer(key)) { 356 map.addLayer({ 357 id: key, 358 type: 'line', 359 source: key, 360 paint: { 'line-color': '#ff0000', 'line-width': lineWidth, 'line-opacity': 0.95 }, 361 layout: { visibility: visibility }, 362 }); 363 } else { 364 try { map.setPaintProperty(key, 'line-width', lineWidth); } catch (_) {}
365 try { map.setLayoutProperty(key, 'visibility', visibility); } catch (_) {} 366 } 367 } else if (!map.getLayer(key)) { 368 var geometryType = (fc.features[0] && fc.features[0].geometry && fc.features[0].geometry.type) || 'Polygon'; 369 var type = geometryType.indexOf('Point') !== -1 ? 'circle' : (geometryType.indexOf('Line') !== -1 ? 'line' : 'fill'); 370 map.addLayer({ id: key, type: type, source: key, paint: defaultPaintForLayer(key, type, opts), layout: { visibility: opts.visible === false ? 'none' : 'visible' } }); 371 } 372 if (opts.fit !== false && window.PPMapRuntime) window.PPMapRuntime.fitMapboxToGeoJson(map, fc, opts); 373 return true; 374 } catch (_) { 375 return false; 376 } 377 }, 378 clearLayer: function (key) { 379 try { if (map.getLayer(key)) map.removeLayer(key); } catch (_) {} 380 try { if (map.getSource(key)) map.removeSource(key); } catch (_) {} 381 }, 382 setLayerVisibility: function (key, visible) { 383 try { if (map.getLayer(key)) map.setLayoutProperty(key, 'visibility', visible ? 'visible' : 'none'); } catch (_) {} 384 }, 385 onClick: function (handler) { 386 if (!handler || !map || typeof map.on !== 'function') return null; 387 var wrapped = function (event) { handler(normalizeClick(event)); }; 388 map.on('click', wrapped); 389 return wrapped; 390 }, 391 offClick: function (wrapped) { 392 try { if (wrapped && map && typeof map.off === 'function') map.off('click', wrapped); } catch (_) {} 393 }, 394 drawParcel: function (feature, opts) { 395 opts = opts || {}; 396 opts.fit = opts.fit !== false; 397 opts.paint = Object.assign({ 398 'fill-color': '#D32F2F', 399 'fill-opacity': 0.14, 400 'fill-outline-color': '#D32F2F' 401 }, opts.paint || {}); 402 return this.drawGeoJson('parcel_polygon', feature, opts); 403 }, 404 resize: function () { try { map.resize(); } catch (_) {} } 405 }; 406 } 407 408 function normalizeClick(event) { 409 if (!event) return null; 410 if (event.lngLat) return event; 411 if (event.latlng) { 412 return { 413 lngLat: { lng: Number(event.latlng.lng), lat: Number(event.latlng.lat) }, 414 originalEvent: event.originalEvent || event 415 }; 416 } 417 if (event.lon != null && event.lat != null) { 418 return { lngLat: { lng: Number(event.lon), lat: Number(event.lat) }, originalEvent: event }; 419 } 420 if (event.lng != null && event.lat != null) { 421 return { lngLat: { lng: Number(event.lng), lat: Number(event.lat) }, originalEvent: event }; 422 } 423 return event; 424 } 425 426 function fitMapboxToGeoJson(map, data, opts) { 427 try { 428 var fc = toFeatureCollection(data); 429 var bounds = new mapboxgl.LngLatBounds(); 430 fc.features.forEach(function (feature) { 431 walkCoords(feature && feature.geometry && feature.geometry.coordinates, function (coord) { 432 bounds.extend(coord); 433 }); 434 }); 435 if (!bounds.isEmpty()) map.fitBounds(bounds, { padding: (opts && opts.padding) || 40, maxZoom: (opts && opts.maxZoom) || 18 }); 436 return true; 437 } catch (_) { 438 return false; 439 } 440 } 441 442 function walkCoords(coords, callback) { 443 if (!Array.isArray(coords)) return; 444 if (coords.length >= 2 && typeof coords[0] === 'number' && typeof coords[1] === 'number') { 445 callback([coords[0], coords[1]]); 446 return; 447 } 448 coords.forEach(function (item) { walkCoords(item, callback); }); 449 } 450 451 function createLeafletMapboxFacade(leafletMap) { 452 var runtime = createLeafletRuntime(leafletMap); 453 var sources = {}; 454 var layers = {}; 455 var handlers = {}; 456 function renderLayer(layer) { 457 if (!layer || !layer.id || !layer.source) return; 458 var source = sources[layer.source]; 459 if (!source) return; 460 var style = styleFromMapboxLayer(layer); 461 var paint = layer.paint || {}; 462 style.fillColor = evaluateMapboxExpression(paint['fill-color'], null, style.fillColor); 463 var visible = !(layer.layout && layer.layout.visibility === 'none'); 464 runtime.drawGeoJson(layer.id, source.data, { style: style, fit: false }); 465 runtime.setLayerVisibility(layer.id, visible); 466 } 467 var facade = { 468 __ppLeafletFacade: true, 469 __ppRuntime: runtime, 470 getContainer: function () { return leafletMap.getContainer(); }, 471 getCanvasContainer: function () { return leafletMap.getContainer(); }, 472 getCanvas: function () { return leafletMap.getContainer(); }, 473 loaded: function () { return true; }, 474 isStyleLoaded: function () { return true; }, 475 getZoom: function () { return leafletMap.getZoom(); }, 476 getCenter: function () { 477 var center = leafletMap.getCenter(); 478 return { lng: center.lng, lat: center.lat }; 479 },
480 setZoom: function (zoom) { try { leafletMap.setZoom(zoom); } catch (_) {} }, 481 setCenter: function (lngLat) { 482 try { 483 var lng = Array.isArray(lngLat) ? lngLat[0] : lngLat.lng; 484 var lat = Array.isArray(lngLat) ? lngLat[1] : lngLat.lat; 485 leafletMap.panTo([lat, lng]); 486 } catch (_) {} 487 }, 488 resize: function () { runtime.resize(); }, 489 stop: function () {}, 490 on: function (type, handler) { 491 if (type === 'load' || type === 'style.load') { 492 setTimeout(handler, 0); 493 return this; 494 } 495 handlers[type] = handlers[type] || new window.Map(); 496 var wrapped = function (event) { handler(normalizeClick(event)); }; 497 handlers[type].set(handler, wrapped); 498 leafletMap.on(type, wrapped); 499 return this; 500 }, 501 once: function (type, handler) { 502 if (type === 'load' || type === 'style.load') { 503 setTimeout(handler, 0); 504 return this; 505 } 506 var wrapped = function (event) { handler(normalizeClick(event)); }; 507 leafletMap.once(type, wrapped); 508 return this; 509 }, 510 off: function (type, handler) { 511 try { 512 var wrapped = handlers[type] && handlers[type].get(handler); 513 leafletMap.off(type, wrapped || handler); 514 if (wrapped) handlers[type].delete(handler); 515 } catch (_) {} 516 return this; 517 }, 518 remove: function () { try { leafletMap.remove(); } catch (_) {} }, 519 project: function (lngLat) { return runtime.project(Array.isArray(lngLat) ? lngLat : [lngLat.lng, lngLat.lat]); }, 520 unproject: function (point) { return runtime.unproject(point); }, 521 flyTo: function (opts) { try { leafletMap.setView([opts.center[1], opts.center[0]], opts.zoom || leafletMap.getZoom()); } catch (_) {} }, 522 fitBounds: function (bounds, opts) { 523 try {
524 var sw = bounds.getSouthWest ? bounds.getSouthWest() : bounds[0]; 525 var ne = bounds.getNorthEast ? bounds.getNorthEast() : bounds[1]; 526 leafletMap.fitBounds([[sw.lat || sw[1], sw.lng || sw[0]], [ne.lat || ne[1], ne.lng || ne[0]]], opts || {}); 527 } catch (_) {} 528 }, 529 addSource: function (id, source) { 530 sources[id] = { data: source && source.data }; 531 }, 532 getSource: function (id) { 533 if (!sources[id]) return null; 534 return { 535 _data: sources[id].data, 536 setData: function (data) { 537 sources[id].data = data; 538 Object.keys(layers).forEach(function (layerId) { 539 if (layers[layerId].source === id) renderLayer(layers[layerId]); 540 }); 541 } 542 }; 543 }, 544 removeSource: function (id) { delete sources[id]; }, 545 addLayer: function (layer) { 546 layers[layer.id] = layer; 547 renderLayer(layer); 548 }, 549 getLayer: function (id) { return layers[id] || null; }, 550 removeLayer: function (id) { 551 runtime.clearLayer(id); 552 delete layers[id]; 553 }, 554 setPaintProperty: function (id, prop, value) { 555 if (!layers[id]) return; 556 layers[id].paint = layers[id].paint || {}; 557 layers[id].paint[prop] = value; 558 renderLayer(layers[id]); 559 }, 560 getPaintProperty: function (id, prop) { 561 return layers[id] && layers[id].paint ? layers[id].paint[prop] : undefined; 562 }, 563 setLayoutProperty: function (id, prop, value) { 564 if (prop === 'visibility') runtime.setLayerVisibility(id, value !== 'none'); 565 if (layers[id]) { 566 layers[id].layout = layers[id].layout || {}; 567 layers[id].layout[prop] = value; 568 } 569 }, 570 getLayoutProperty: function (id, prop) { 571 return layers[id] && layers[id].layout ? layers[id].layout[prop] : undefined; 572 }, 573 setFilter: function () {}, 574 moveLayer: function () {}, 575 addControl: function () {}, 576 getStyle: function () { 577 return { layers: Object.keys(layers).map(function (id) { return layers[id]; }) }; 578 }, 579 queryRenderedFeatures: function () { return []; }, 580 doubleClickZoom: { enable: function () {}, disable: function () {} }, 581 dragPan: { enable: function () {}, disable: function () {} } 582 }; 583 return facade; 584 } 585 586 function create(options) { 587 options = options || {}; 588 var container = typeof options.container === 'string' 589 ? document.getElementById(options.container) 590 : options.container; 591 var state = getCompatState(); 592 if (state.legacy || options.provider === 'leaflet') { 593 var leafletMap = createLeafletMap(container, options); 594 var facade = leafletMap ? createLeafletMapboxFacade(leafletMap) : null; 595 return { 596 provider: 'leaflet', 597 map: facade, 598 rawMap: leafletMap, 599 runtime: leafletMap ? createLeafletRuntime(leafletMap) : null 600 }; 601 } 602 return { 603 provider: 'mapbox', 604 map: null, 605 rawMap: null, 606 runtime: null 607 }; 608 } 609 610 function createLeafletMap(container, options) { 611 options = options || {}; 612 if (!window.L || !container) return null; 613 var map = window.L.map(container, { 614 zoomControl: options.zoomControl !== false, 615 attributionControl: options.attributionControl !== false, 616 preferCanvas: true, 617 worldCopyJump: true 618 }).setView(options.centerLatLng || [39.0, 35.0], options.zoom || 6); 619 window.L.tileLayer(options.tileUrl || DEFAULT_SATELLITE_TILE, { 620 maxZoom: options.maxZoom || 19, 621 attribution: options.attribution || 'Tiles © Esri, Maxar, Earthstar Geographics, and the GIS User Community' 622 }).addTo(map); 623 return map; 624 } 625 626 function distanceMeters(a, b) { 627 var R = 6371008.8; 628 var p1 = a[1] * Math.PI / 180; 629 var p2 = b[1] * Math.PI / 180; 630 var dp = (b[1] - a[1]) * Math.PI / 180; 631 var dl = (b[0] - a[0]) * Math.PI / 180; 632 var h = Math.sin(dp / 2) * Math.sin(dp / 2) + Math.cos(p1) * Math.cos(p2) * Math.sin(dl / 2) * Math.sin(dl / 2); 633 return 2 * R * Math.atan2(Math.sqrt(h), Math.sqrt(1 - h)); 634 } 635 636 function polygonAreaM2(points) { 637 if (window.turf && points.length >= 3) {
638 try { 639 var ring = points.concat([points[0]]); 640 return window.turf.area({ type: 'Feature', geometry: { type: 'Polygon', coordinates: [ring] }, properties: {} }); 641 } catch (_) {} 642 } 643 return 0; 644 } 645 646 function formatDistance(meters) { 647 return meters >= 1000 ? (meters / 1000).toFixed(2) + ' km' : Math.round(meters) + ' m'; 648 } 649 650 function formatArea(area) { 651 return area >= 10000 ? (area / 10000).toFixed(2) + ' ha' : Math.round(area) + ' m²'; 652 } 653 654 function createLeafletMeasurementManager(map) { 655 var manager = { 656 map: map, 657 mode: null, 658 isActive: false, 659 points: [], 660 layers: [], 661 drawColorRuler: '#3B82F6', 662 drawColorArea: '#F97316', 663 startRulerMode: function () { start('ruler'); }, 664 startAreaMode: function () { start('area'); }, 665 stopMeasurement: stop, 666 clearMeasurements: clear, 667 setDrawColor: function (color) { 668 if (manager.mode === 'area') manager.drawColorArea = color; 669 else manager.drawColorRuler = color; 670 }, 671 clearMeasureSelection: function () {}, 672 finishActiveMeasurementFromUi: stop, 673 applyColorToSelectedMeasure: function () {} 674 }; 675 676 function start(mode) { 677 stop(); 678 manager.mode = mode; 679 manager.isActive = true; 680 manager.points = [];
681 try { window.enableMapClick = false; } catch (_) {} 682 map.on('click', onClick); 683 map.getContainer().style.cursor = 'crosshair'; 684 } 685 686 function stop() { 687 if (manager.isActive) { 688 try { map.off('click', onClick); } catch (_) {} 689 } 690 manager.mode = null; 691 manager.isActive = false; 692 manager.points = []; 693 try { map.getContainer().style.cursor = ''; } catch (_) {} 694 try { window.enableMapClick = true; } catch (_) {} 695 } 696 697 function clear() { 698 manager.layers.forEach(function (layer) { 699 try { map.removeLayer(layer); } catch (_) {} 700 }); 701 manager.layers = []; 702 stop(); 703 } 704 705 function onClick(event) { 706 if (!event || !event.latlng) return; 707 var point = [event.latlng.lng, event.latlng.lat]; 708 manager.points.push(point); 709 redraw(); 710 if (event.originalEvent) { 711 event.originalEvent.__annotationHandled = true; 712 try { event.originalEvent.preventDefault(); event.originalEvent.stopPropagation(); } catch (_) {} 713 } 714 } 715 716 function addLabel(text, latlng) { 717 var layer = window.L.marker(latlng, { 718 icon: window.L.divIcon({ 719 html: '<div style="background:#0f172a;color:#fff;border-radius:6px;padding:3px 7px;font-weight:700;font-size:12px;white-space:nowrap;">
719' + text + '</div>', 720 className: 'pp-leaflet-label-icon' 721 }) 722 }).addTo(map); 723 manager.layers.push(layer); 724 } 725 726 function redraw() { 727 manager.layers.forEach(function (layer) { 728 if (layer.__ppMeasurePreview) { 729 try { map.removeLayer(layer); } catch (_) {} 730 } 731 }); 732 manager.layers = manager.layers.filter(function (layer) { return !layer.__ppMeasurePreview; }); 733 if (!manager.points.length) return; 734 manager.points.forEach(function (p) { 735 var dot = window.L.circleMarker([p[1], p[0]], { 736 radius: 5, 737 color: manager.mode === 'area' ? manager.drawColorArea : manager.drawColorRuler, 738 fillColor: '#fff', 739 fillOpacity: 1, 740 weight: 2 741 }).addTo(map); 742 dot.__ppMeasurePreview = true; 743 manager.layers.push(dot); 744 }); 745 if (manager.mode === 'ruler' && manager.points.length >= 2) { 746 var line = window.L.polyline(manager.points.map(function (p) { return [p[1], p[0]]; }), { 747 color: manager.drawColorRuler, 748 weight: 3 749 }).addTo(map); 750 line.__ppMeasurePreview = true; 751 manager.layers.push(line); 752 var total = 0; 753 for (var i = 1; i < manager.points.length; i += 1) total += distanceMeters(manager.points[i - 1], manager.points[i]); 754 var last = manager.points[manager.points.length - 1]; 755 addLabel(formatDistance(total), [last[1], last[0]]); 756 } 757 if (manager.mode === 'area' && manager.points.length >= 3) { 758 var poly = window.L.polygon(manager.points.map(function (p) { return [p[1], p[0]]; }), { 759 color: manager.drawColorArea, 760 weight: 3, 761 fillColor: manager.drawColorArea, 762 fillOpacity: 0.22 763 }).addTo(map); 764 poly.__ppMeasurePreview = true; 765 manager.layers.push(poly); 766 var center = poly.getBounds().getCenter(); 767 addLabel(formatArea(polygonAreaM2(manager.points)), center); 768 } 769 } 770 771 return manager; 772 } 773 774 function installLeafletAnnotationFallback(map) { 775 if (!map || !window.L || window.__ppLeafletAnnotationFallbackInstalled) return; 776 window.__ppLeafletAnnotationFallbackInstalled = true; 777 var layers = []; 778 var mode = null; 779 var points = []; 780 var color = '#ef4444'; 781 782 function stop() { 783 mode = null; 784 points = [];
785 try { map.off('click', onClick); } catch (_) {} 786 try { map.getContainer().style.cursor = ''; } catch (_) {} 787 try { window.enableMapClick = true; } catch (_) {} 788 } 789 790 function clear() { 791 layers.forEach(function (layer) { 792 try { map.removeLayer(layer); } catch (_) {} 793 }); 794 layers = []; 795 stop(); 796 } 797 798 function onClick(event) { 799 if (!mode || !event || !event.latlng) return; 800 if (event.originalEvent) { 801 event.originalEvent.__annotationHandled = true; 802 try { event.originalEvent.preventDefault(); event.originalEvent.stopPropagation(); } catch (_) {} 803 } 804 if (mode === 'pin') { 805 layers.push(window.L.marker(event.latlng).addTo(map)); 806 stop(); 807 } else if (mode === 'text') { 808 var text = window.prompt('Haritaya eklenecek metin'); 809 if (text) { 810 layers.push(window.L.marker(event.latlng, { 811 icon: window.L.divIcon({ 812 html: '<div style="background:#fff;border:1px solid #2563eb;border-radius:6px;padding:4px 8px;font-weight:700;color:#1e3a8a;white-space:nowrap;">' + String(text) + '</div>', 813 className: 'pp-leaflet-label-icon' 814 }) 815 }).addTo(map)); 816 } 817 stop(); 818 } else if (mode === 'freepolyline') { 819 points.push([event.latlng.lat, event.latlng.lng]); 820 if (points.length >= 2) { 821 if (layers.__preview) { 822 try { map.removeLayer(layers.__preview); } catch (_) {} 823 } 824 layers.__preview = window.L.polyline(points, { color: color, weight: 4 }).addTo(map); 825 } 826 } 827 } 828 829 document.addEventListener('click', function (event) { 830 var btn = event.target && event.target.closest && event.target.closest('[data-annotation-tool]'); 831 if (!btn || !getCompatState().legacy) return; 832 var tool = btn.getAttribute('data-annotation-tool'); 833 if (!tool) return; 834 event.preventDefault(); 835 event.stopPropagation(); 836 event.stopImmediatePropagation(); 837 if (tool === 'clear') { 838 clear(); 839 return; 840 } 841 if (tool === 'pencil') { 842 mode = 'freepolyline'; 843 } else { 844 mode = tool; 845 } 846 points = [];
847 try { window.enableMapClick = false; } catch (_) {} 848 map.off('click', onClick); 849 map.on('click', onClick); 850 map.getContainer().style.cursor = 'crosshair'; 851 }, true); 852 853 document.addEventListener('keydown', function (event) { 854 if (event.key === 'Escape') stop(); 855 if (event.key === 'Enter' && mode === 'freepolyline') { 856 if (layers.__preview) { 857 layers.push(layers.__preview); 858 layers.__preview = null; 859 } 860 stop(); 861 } 862 }, true); 863 864 window.ppLeafletAnnotationFallback = { clearAll: clear, stop: stop }; 865 } 866 867 function attachToManager(manager, provider, map) { 868 if (!manager || !map) return null; 869 var runtime = provider === 'leaflet' ? createLeafletRuntime(map) : createMapboxRuntime(map); 870 manager.activeMapRuntime = runtime; 871 return runtime; 872 } 873 874 window.PPMapRuntime = { 875 version: VERSION, 876 getCompatState: getCompatState, 877 isLegacy: function () { return getCompatState().legacy; }, 878 isMinimal: function () { return getCompatState().minimal; }, 879 getMode: function () { return getCompatState().mode; }, 880 markLegacy: markLegacy, 881 markNoGpu: markNoGpu, 882 createLeafletMap: createLeafletMap, 883 create: create, 884 createLeafletRuntime: createLeafletRuntime, 885 createMapboxRuntime: createMapboxRuntime, 886 createLeafletMapboxFacade: createLeafletMapboxFacade, 887 createLeafletMeasurementManager: createLeafletMeasurementManager, 888 installLeafletAnnotationFallback: installLeafletAnnotationFallback, 889 attachToManager: attachToManager, 890 normalizeClick: normalizeClick, 891 toFeatureCollection: toFeatureCollection, 892 styleFromMapboxLayer: styleFromMapboxLayer, 893 fitMapboxToGeoJson: fitMapboxToGeoJson 894 }; 895})(window, document);
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.