leaflet-city-mapper 0.0.9 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -46
- package/dist/README.md +18 -0
- package/dist/leaflet-city-mapper-src.js +279 -110
- package/dist/leaflet-city-mapper-src.js.map +4 -4
- package/dist/leaflet-city-mapper-worker-src.js.map +2 -2
- package/dist/leaflet-city-mapper-worker.js.map +2 -2
- package/dist/leaflet-city-mapper.js +5 -5
- package/dist/leaflet-city-mapper.js.map +4 -4
- package/libs/README.md +18 -0
- package/libs/leaflet-lens.js +151 -151
- package/libs/leaflet.js +3 -3
- package/libs/openlayers-bindings.js +1129 -1129
- package/libs/openlayers-bindings.min.js.map +1 -1
- package/package.json +2 -4
- package/src/README.md +148 -0
- package/src/animations/README.md +30 -0
- package/src/animations/cancelCameraAnimation.js +13 -11
- package/src/animations/cancelGridFade.js +5 -3
- package/src/animations/endZoom.js +0 -5
- package/src/animations/mapAnimateCamera.js +13 -3
- package/src/animations/mapStopPitchBearingAnimation.js +8 -1
- package/src/animations/onZoomAnim.js +5 -4
- package/src/animations/renderPendingZoomAnimation.js +1 -4
- package/src/animations/runCameraAnimations.js +7 -4
- package/src/animations/runGridFades.js +1 -4
- package/src/animations/runMarkerPanFrame.js +1 -1
- package/src/animations/scheduleCameraAnimation.js +10 -8
- package/src/animations/scheduleGridFade.js +5 -4
- package/src/animations/scheduleMarkerPan.js +10 -6
- package/src/animations/startZoom.js +0 -3
- package/src/animations/synchronizeZoomView.js +6 -1
- package/src/animations/updateZoomCamera.js +21 -17
- package/src/archives/README.md +28 -0
- package/src/archives/decodeDirectory.js +13 -2
- package/src/archives/decodeHeader.js +9 -2
- package/src/archives/decompress.js +10 -0
- package/src/archives/findDirectoryEntry.js +17 -9
- package/src/archives/findTile.js +45 -31
- package/src/archives/getDirectoryEntries.js +28 -17
- package/src/archives/getHeader.js +7 -2
- package/src/archives/getTileData.js +26 -13
- package/src/archives/getZxy.js +11 -3
- package/src/archives/loadDirectory.js +10 -0
- package/src/archives/loadSource.js +12 -3
- package/src/archives/readArchiveRange.js +45 -31
- package/src/archives/readVarint.js +11 -2
- package/src/archives/tileId.js +11 -2
- package/src/astronomy/README.md +25 -0
- package/src/astronomy/horizontalPosition.js +11 -0
- package/src/astronomy/moonPosition.js +9 -2
- package/src/astronomy/solarPosition.js +9 -2
- package/src/astronomy/solarTime.js +21 -11
- package/src/camera/README.md +30 -0
- package/src/camera/cameraMapReady.js +6 -8
- package/src/camera/cleanupCameraMap.js +8 -10
- package/src/camera/constrainCameraToBounds.js +3 -2
- package/src/camera/createSceneCamera.js +25 -21
- package/src/camera/fitCameraBounds.js +9 -1
- package/src/camera/getBearing.js +10 -5
- package/src/camera/getPitch.js +10 -5
- package/src/camera/initializeCameraMap.js +1 -3
- package/src/camera/mapCamera.js +0 -2
- package/src/camera/mapContainerPointToLayerPoint.js +7 -2
- package/src/camera/mapGetBearing.js +7 -2
- package/src/camera/mapGetBounds.js +5 -2
- package/src/camera/mapGetBoundsCenterZoom.js +9 -2
- package/src/camera/mapGetBoundsZoom.js +9 -2
- package/src/camera/mapGetCenterLayerPoint.js +5 -1
- package/src/camera/mapGetPitch.js +7 -2
- package/src/camera/mapLayerPointToContainerPoint.js +7 -1
- package/src/camera/mapLimitCenter.js +9 -2
- package/src/camera/mapLimitOffset.js +12 -6
- package/src/camera/mapPanBy.js +10 -3
- package/src/camera/mapPanInside.js +8 -2
- package/src/camera/mapResetNorth.js +8 -0
- package/src/camera/mapResetNorthPitch.js +8 -0
- package/src/camera/mapSetBearing.js +10 -0
- package/src/camera/mapSetPitch.js +10 -0
- package/src/camera/mapSetPitchAndBearing.js +12 -3
- package/src/camera/mapSetZoomAround.js +9 -1
- package/src/camera/mapTryAnimatedPan.js +8 -1
- package/src/camera/mapUpdateCameraOverlays.js +6 -0
- package/src/camera/setBearing.js +13 -5
- package/src/camera/setPitch.js +13 -5
- package/src/camera/updateMapCamera.js +6 -4
- package/src/camera/updateSceneCamera.js +7 -1
- package/src/camera/updateSky.js +1 -3
- package/src/cog/README.md +29 -0
- package/src/cog/decodeCogTile.js +37 -24
- package/src/cog/finiteCogValues.js +12 -5
- package/src/cog/getCogAssetEntry.js +26 -15
- package/src/cog/getCogBase.js +22 -10
- package/src/cog/getCogHeader.js +10 -3
- package/src/cog/getCogProfile.js +25 -16
- package/src/cog/getCogTile.js +25 -12
- package/src/cog/getColorTile.js +38 -25
- package/src/cog/getElevationTile.js +29 -16
- package/src/cog/hasCogProjection.js +16 -9
- package/src/cog/initCog.js +13 -7
- package/src/cog/invalidCogFullResponse.js +10 -3
- package/src/cog/openCog.js +40 -30
- package/src/cog/openCogAsset.js +22 -14
- package/src/cog/readCog.js +39 -25
- package/src/cog/readCogBlock.js +19 -8
- package/src/cog/readCogBody.js +30 -20
- package/src/cog/readCogDirectories.js +32 -20
- package/src/cog/readCogDirectory.js +34 -21
- package/src/cog/readCogLevel.js +36 -27
- package/src/cog/readCogTag.js +28 -15
- package/src/cog/validCogDimensions.js +15 -6
- package/src/cog/validCogEncoding.js +18 -5
- package/src/cog/validCogGeoArrays.js +17 -8
- package/src/cog/validCogGrid.js +22 -9
- package/src/cog/validCogTileCoordinates.js +13 -4
- package/src/cog/validateCogContainer.js +17 -9
- package/src/cog/validateCogContentRange.js +18 -8
- package/src/cog/validateCogOffsets.js +19 -10
- package/src/cog/validateCogRange.js +16 -7
- package/src/cog/validateCogResponse.js +26 -15
- package/src/collision/README.md +28 -0
- package/src/collision/advanceFeature.js +13 -0
- package/src/collision/boxNormal.js +29 -0
- package/src/collision/cachedCollider.js +18 -0
- package/src/collision/collectIntersections.js +41 -16
- package/src/collision/collectMeshes.js +6 -0
- package/src/collision/collideTrip.js +56 -0
- package/src/collision/collider.js +28 -18
- package/src/collision/countCrossings.js +35 -15
- package/src/collision/enclosesOrigin.js +13 -0
- package/src/collision/flipsNormal.js +15 -0
- package/src/collision/hiddenLightHit.js +19 -8
- package/src/collision/horizontalRay.js +13 -1
- package/src/collision/indexTriangle.js +18 -11
- package/src/collision/insideMesh.js +47 -33
- package/src/collision/insideWalker.js +52 -46
- package/src/collision/intersectMeshes.js +40 -32
- package/src/collision/localRay.js +31 -21
- package/src/collision/mergeHits.js +19 -11
- package/src/collision/missesBox.js +13 -0
- package/src/collision/rayBounds.js +28 -19
- package/src/collision/readTriangle.js +32 -23
- package/src/collision/slabDistance.js +14 -0
- package/src/collision/slabMiss.js +14 -0
- package/src/collision/sortCrossings.js +17 -0
- package/src/collision/sortHits.js +9 -1
- package/src/collision/trafficBounds.js +24 -0
- package/src/collision/trafficCollision.js +30 -55
- package/src/collision/trafficRay.js +21 -0
- package/src/collision/transformTriangle.js +18 -9
- package/src/collision/transformVertices.js +18 -0
- package/src/collision/triangleDistance.js +34 -21
- package/src/collision/vertexCount.js +11 -3
- package/src/collision/worldHit.js +30 -18
- package/src/colors/README.md +25 -0
- package/src/colors/formatRGB.js +7 -0
- package/src/colors/hslChannel.js +10 -0
- package/src/colors/mixColor.js +10 -0
- package/src/colors/parseColor.js +4 -1
- package/src/colors/toSRGB.js +7 -0
- package/src/controls/README.md +26 -0
- package/src/controls/acceptPitchDrag.js +10 -3
- package/src/controls/acceptRotateDrag.js +9 -2
- package/src/controls/addCameraHandler.js +18 -11
- package/src/controls/adjustCameraDrag.js +8 -10
- package/src/controls/cameraControls.js +5 -4
- package/src/controls/cameraDragClick.js +5 -1
- package/src/controls/cameraDragContextMenu.js +10 -6
- package/src/controls/cameraDragDown.js +5 -2
- package/src/controls/cameraDragEnd.js +7 -3
- package/src/controls/cameraDragMove.js +24 -20
- package/src/controls/changeCameraTouch.js +12 -14
- package/src/controls/cleanupCameraTouch.js +1 -4
- package/src/controls/compassAddHooks.js +1 -0
- package/src/controls/compassOrientation.js +11 -5
- package/src/controls/compassRemoveHooks.js +3 -2
- package/src/controls/containerResizeAddHooks.js +1 -0
- package/src/controls/containerResizeRemoveHooks.js +3 -2
- package/src/controls/dragCamera.js +11 -2
- package/src/controls/endAllCameraDrags.js +1 -2
- package/src/controls/endAllCameraTouches.js +1 -2
- package/src/controls/endCameraTouch.js +18 -12
- package/src/controls/endCameraTouchEvent.js +5 -2
- package/src/controls/failCompassPermission.js +10 -4
- package/src/controls/finishCameraDrag.js +14 -8
- package/src/controls/finishCompassPermission.js +24 -17
- package/src/controls/isEditableTarget.js +9 -2
- package/src/controls/loadCameraControls.js +18 -9
- package/src/controls/moveCameraTouch.js +30 -27
- package/src/controls/notifyCameraTouchChange.js +1 -0
- package/src/controls/pitchDragAddHooks.js +1 -1
- package/src/controls/pitchDragRemoveHooks.js +1 -0
- package/src/controls/refreshRotateControl.js +2 -0
- package/src/controls/refreshRotateFocus.js +3 -2
- package/src/controls/removeCameraDrag.js +18 -15
- package/src/controls/resizeMap.js +7 -2
- package/src/controls/rotateButtonClick.js +15 -10
- package/src/controls/rotateButtonKeydown.js +16 -10
- package/src/controls/rotateControl.js +11 -3
- package/src/controls/rotateOnAdd.js +7 -1
- package/src/controls/rotateOnRemove.js +5 -0
- package/src/controls/shiftRotateAddHooks.js +1 -1
- package/src/controls/shiftRotateRemoveHooks.js +3 -2
- package/src/controls/shiftRotateWheel.js +11 -6
- package/src/controls/startCameraTouch.js +5 -2
- package/src/core/README.md +28 -0
- package/src/core/adjustCameraMarkerPan.js +7 -2
- package/src/core/cameraCircleBounds.js +5 -1
- package/src/core/cameraMarkerDrag.js +1 -2
- package/src/core/cameraMarkerOnDrag.js +13 -10
- package/src/core/closestCameraLayerPoint.js +7 -1
- package/src/core/constructLayer.js +16 -9
- package/src/core/extendLeafletClass.js +12 -5
- package/src/core/extendTerrainPixelBounds.js +41 -31
- package/src/core/fireRasterLoad.js +1 -1
- package/src/core/gridlayerGetEvents.js +5 -2
- package/src/core/gridlayerGetTiledPixelBounds.js +7 -1
- package/src/core/initializeGridContainer.js +1 -1
- package/src/core/initializeNativeLayer.js +1 -4
- package/src/core/layerAddInitHook.js +12 -7
- package/src/core/layerCallInitHooks.js +1 -2
- package/src/core/layerMergeOptions.js +14 -7
- package/src/core/markerGetEvents.js +5 -2
- package/src/core/markerInitInteraction.js +7 -4
- package/src/core/markerSetIcon.js +10 -5
- package/src/core/markerSetPos.js +5 -2
- package/src/core/markerSetRotation.js +19 -9
- package/src/core/markerUpdateZIndex.js +6 -4
- package/src/core/popupAdjustPan.js +5 -2
- package/src/core/popupGetEvents.js +5 -1
- package/src/core/popupUpdatePosition.js +1 -2
- package/src/core/projectNativePath.js +30 -23
- package/src/core/redrawPath.js +11 -6
- package/src/core/removeLayer.js +23 -20
- package/src/core/setRotation.js +12 -5
- package/src/core/tooltipGetEvents.js +5 -1
- package/src/core/tooltipSetPosition.js +5 -2
- package/src/core/updateGridOpacity.js +2 -1
- package/src/core/whenReady.js +11 -8
- package/src/geometry/README.md +29 -0
- package/src/geometry/addBridges.js +30 -28
- package/src/geometry/addGeneratedTriangle.js +7 -3
- package/src/geometry/appendAreaTriangle.js +32 -17
- package/src/geometry/appendNativeTriangle.js +17 -3
- package/src/geometry/appendRouteDash.js +33 -15
- package/src/geometry/appendRouteSegment.js +28 -15
- package/src/geometry/assembleAreaGeometry.js +48 -41
- package/src/geometry/boundsQuad.js +8 -0
- package/src/geometry/box.js +10 -0
- package/src/geometry/bridgeEdge.js +18 -11
- package/src/geometry/bridgeElevation.js +8 -1
- package/src/geometry/bridgeFaces.js +22 -15
- package/src/geometry/bridgePaths.js +19 -11
- package/src/geometry/bridgePolygon.js +37 -31
- package/src/geometry/bridgeSides.js +18 -11
- package/src/geometry/buildGeometryParts.js +7 -0
- package/src/geometry/buildProjectedPoint.js +32 -21
- package/src/geometry/buildProjectedPolygon.js +34 -25
- package/src/geometry/circleAt.js +18 -5
- package/src/geometry/circleGeometry.js +41 -35
- package/src/geometry/clipLine.js +8 -1
- package/src/geometry/clipSegment.js +9 -0
- package/src/geometry/computeBounds.js +5 -2
- package/src/geometry/conformModelToTerrain.js +6 -3
- package/src/geometry/createLampRing.js +8 -0
- package/src/geometry/createModelGeometry.js +44 -34
- package/src/geometry/createRasterQuadGeometry.js +7 -1
- package/src/geometry/createTreeRing.js +8 -1
- package/src/geometry/crossVector.js +15 -7
- package/src/geometry/dashValues.js +23 -14
- package/src/geometry/dashedSegment.js +33 -21
- package/src/geometry/disk.js +9 -0
- package/src/geometry/diskAt.js +16 -4
- package/src/geometry/emitter.js +18 -8
- package/src/geometry/fillNativePolygon.js +28 -20
- package/src/geometry/generateTreeGeometry.js +15 -9
- package/src/geometry/indexBridge.js +34 -28
- package/src/geometry/instanceAreaGeometry.js +37 -31
- package/src/geometry/interpolateRoute.js +10 -2
- package/src/geometry/lampPostGeometry.js +9 -2
- package/src/geometry/lightGeometry.js +9 -2
- package/src/geometry/line.js +28 -21
- package/src/geometry/lineJoin.js +35 -26
- package/src/geometry/markerImageBounds.js +20 -11
- package/src/geometry/markerQuadCorners.js +9 -3
- package/src/geometry/meshShadowBounds.js +33 -24
- package/src/geometry/nativeGeometry.js +9 -1
- package/src/geometry/offsetBelowGround.js +10 -3
- package/src/geometry/polygon.js +7 -0
- package/src/geometry/quad.js +23 -9
- package/src/geometry/restoreGeometry.js +29 -23
- package/src/geometry/roofCoverage.js +29 -22
- package/src/geometry/roofFootprint.js +36 -28
- package/src/geometry/routeGeometry.js +7 -2
- package/src/geometry/samePoint.js +11 -3
- package/src/geometry/segment.js +32 -23
- package/src/geometry/setVertexColor.js +1 -1
- package/src/geometry/shadowBounds.js +8 -0
- package/src/geometry/subtractRoofTile.js +28 -19
- package/src/geometry/subtractVector.js +8 -0
- package/src/geometry/surface.js +11 -1
- package/src/geometry/terrainBuffers.js +33 -26
- package/src/geometry/terrainGrid.js +7 -2
- package/src/geometry/terrainTileGeometry.js +24 -15
- package/src/geometry/treeGeometry.js +7 -4
- package/src/geometry/triangle.js +11 -0
- package/src/geometry/validateTree.js +19 -7
- package/src/geometry/vertexNormals.js +8 -2
- package/src/geometry/visitNativeCoordinates.js +7 -0
- package/src/globals/CELL.js +6 -2
- package/src/globals/Compass.js +5 -0
- package/src/globals/ContainerResize.js +5 -0
- package/src/globals/HEIGHT.js +5 -0
- package/src/globals/L.js +6 -1
- package/src/globals/PitchDrag.js +5 -0
- package/src/globals/README.md +28 -0
- package/src/globals/ShiftRotate.js +5 -0
- package/src/globals/TILE_RADIUS.js +5 -0
- package/src/globals/TILE_SIZE.js +5 -0
- package/src/globals/TouchMode.js +5 -0
- package/src/globals/alphaBlend.js +5 -0
- package/src/globals/archiveDecoder.js +5 -0
- package/src/globals/archiveNorthWest.js +5 -0
- package/src/globals/archiveSouthEast.js +5 -0
- package/src/globals/atmosphereColor.js +5 -0
- package/src/globals/atmosphereStops.js +5 -0
- package/src/globals/blobParts.js +5 -0
- package/src/globals/cameraAngles.js +5 -0
- package/src/globals/cameraAnimatedOptions.js +5 -0
- package/src/globals/cameraAnimationFrame.js +5 -0
- package/src/globals/cameraAnimations.js +5 -0
- package/src/globals/cameraBearingSensitivity.js +5 -0
- package/src/globals/cameraDragSensitivity.js +5 -0
- package/src/globals/cameraDrags.js +5 -0
- package/src/globals/cameraEmptyOptions.js +5 -0
- package/src/globals/cameraFocusOptions.js +5 -0
- package/src/globals/cameraFov.js +8 -3
- package/src/globals/cameraListenerOptions.js +5 -0
- package/src/globals/cameraTouchStates.js +5 -0
- package/src/globals/cameraZeroPadding.js +5 -0
- package/src/globals/cogTags.js +6 -1
- package/src/globals/colorLayout.js +5 -0
- package/src/globals/colorTexture.js +11 -6
- package/src/globals/coreEventTypes.js +5 -0
- package/src/globals/coreMatrixKeys.js +5 -0
- package/src/globals/coreQuadIndices.js +5 -0
- package/src/globals/coreQuadUV.js +5 -0
- package/src/globals/coreSampler.js +5 -0
- package/src/globals/coreWhite.js +5 -0
- package/src/globals/cosObliquity.js +8 -3
- package/src/globals/coverageTiles.js +5 -0
- package/src/globals/dark.js +5 -0
- package/src/globals/defaultMaterial.js +5 -0
- package/src/globals/degrees.js +6 -1
- package/src/globals/demBuffer.js +5 -0
- package/src/globals/demLayout.js +5 -0
- package/src/globals/demSize.js +5 -0
- package/src/globals/demTarget.js +5 -0
- package/src/globals/demTexture.js +5 -0
- package/src/globals/depthBindGroup.js +5 -0
- package/src/globals/depthTexture.js +5 -0
- package/src/globals/directoryReader.js +5 -0
- package/src/globals/disabledShadow.js +5 -0
- package/src/globals/drawEntries.js +5 -0
- package/src/globals/drawFrameEntry.js +5 -0
- package/src/globals/drawMeshEntry.js +5 -0
- package/src/globals/drawSamplerEntries.js +5 -0
- package/src/globals/drawTerrainEntry.js +5 -0
- package/src/globals/drawTextureEntries.js +5 -0
- package/src/globals/earthCirc.js +6 -1
- package/src/globals/elevationWGSL.js +2 -0
- package/src/globals/fragmentShader.js +5 -0
- package/src/globals/frameBuffer.js +5 -0
- package/src/globals/frameCommands.js +5 -0
- package/src/globals/frameLayoutEntry.js +5 -0
- package/src/globals/geometryDecoder.js +5 -0
- package/src/globals/geometryEmpty.js +5 -0
- package/src/globals/geometryImageOptions.js +5 -0
- package/src/globals/geometryPixelStates.js +5 -0
- package/src/globals/geometryQuaternion.js +5 -0
- package/src/globals/geometryScale.js +5 -0
- package/src/globals/geometrySemantics.js +5 -0
- package/src/globals/geometryTranslation.js +5 -0
- package/src/globals/geometryWorkerUrl.js +8 -3
- package/src/globals/glass.js +5 -0
- package/src/globals/gridEvents.js +5 -0
- package/src/globals/gridFadeFrame.js +5 -0
- package/src/globals/halfRadians.js +6 -1
- package/src/globals/headerBounds.js +5 -0
- package/src/globals/headerFlags.js +5 -0
- package/src/globals/headerOffsets.js +5 -0
- package/src/globals/headlight.js +5 -0
- package/src/globals/hull.js +5 -0
- package/src/globals/instanceLayout.js +5 -0
- package/src/globals/lampDirections.js +13 -8
- package/src/globals/layerControlAddItem.js +8 -3
- package/src/globals/layerProto.js +5 -0
- package/src/globals/leafletLayer.js +8 -3
- package/src/globals/lightScale.js +6 -1
- package/src/globals/limbs.js +5 -1
- package/src/globals/loading.js +5 -0
- package/src/globals/mapMethods.js +5 -0
- package/src/globals/markerMethods.js +5 -0
- package/src/globals/markerPanFrame.js +5 -0
- package/src/globals/meshBindGroup.js +5 -0
- package/src/globals/meshBuffer.js +5 -0
- package/src/globals/meshCopySize.js +5 -0
- package/src/globals/meshImage.js +5 -0
- package/src/globals/meshLayoutEntry.js +5 -0
- package/src/globals/meshOffsets.js +5 -0
- package/src/globals/meshPipeline.js +5 -0
- package/src/globals/meshStack.js +5 -0
- package/src/globals/meshTarget.js +5 -0
- package/src/globals/moves.js +5 -1
- package/src/globals/mvtTextDecoder.js +6 -1
- package/src/globals/nativeMethodHandlers.js +5 -0
- package/src/globals/nativeScalableStyleKeys.js +6 -1
- package/src/globals/nextId.js +5 -0
- package/src/globals/normalLayout.js +5 -0
- package/src/globals/paints.js +5 -0
- package/src/globals/parts.js +5 -0
- package/src/globals/pendingGridFades.js +5 -0
- package/src/globals/pendingInitializations.js +5 -0
- package/src/globals/pendingMapChanges.js +5 -0
- package/src/globals/pendingMarkerPan.js +5 -0
- package/src/globals/pendingPlacements.js +5 -0
- package/src/globals/pendingRasterLoads.js +5 -0
- package/src/globals/pendingUpdates.js +5 -0
- package/src/globals/pendingZoomAnimations.js +5 -0
- package/src/globals/pipelineLayout.js +5 -0
- package/src/globals/popupEvents.js +5 -0
- package/src/globals/popupPan.js +5 -0
- package/src/globals/popupPosition.js +5 -0
- package/src/globals/positionLayout.js +5 -0
- package/src/globals/programEntries.js +5 -0
- package/src/globals/programLayout.js +5 -0
- package/src/globals/radians.js +5 -0
- package/src/globals/rasterBuffer.js +5 -0
- package/src/globals/rasterIndices.js +5 -0
- package/src/globals/rasterNormals.js +5 -0
- package/src/globals/rasterPoint.js +5 -0
- package/src/globals/rasterPositions.js +5 -0
- package/src/globals/rasterSampler.js +5 -0
- package/src/globals/rasterTexture.js +5 -0
- package/src/globals/rasterUVs.js +5 -0
- package/src/globals/removeLayer.js +5 -0
- package/src/globals/renderEmpty.js +5 -0
- package/src/globals/ringDirections.js +5 -0
- package/src/globals/roofBindGroup.js +5 -0
- package/src/globals/roofBlitSampler.js +5 -0
- package/src/globals/roofBuffer.js +5 -0
- package/src/globals/roofCommands.js +5 -0
- package/src/globals/roofCopySize.js +5 -0
- package/src/globals/roofImage.js +5 -0
- package/src/globals/roofMin.js +5 -0
- package/src/globals/roofOpacities.js +5 -0
- package/src/globals/roofPass.js +5 -0
- package/src/globals/roofPipeline.js +5 -0
- package/src/globals/roofSampler.js +5 -0
- package/src/globals/roofShader.js +5 -0
- package/src/globals/roofSignatures.js +5 -0
- package/src/globals/roofSize.js +5 -0
- package/src/globals/roofTarget.js +5 -0
- package/src/globals/roofTexture.js +5 -0
- package/src/globals/roofTiles.js +5 -0
- package/src/globals/roundProfile.js +5 -0
- package/src/globals/samplerLayoutEntries.js +5 -0
- package/src/globals/sceneCleanupFields.js +5 -0
- package/src/globals/sceneEmptyOptions.js +5 -0
- package/src/globals/scenePass.js +5 -0
- package/src/globals/sceneSunlightUniforms.js +5 -0
- package/src/globals/sceneTransferFields.js +5 -0
- package/src/globals/sceneWalkHandlers.js +5 -0
- package/src/globals/shadowBindGroup.js +5 -0
- package/src/globals/shadowBounds.js +5 -0
- package/src/globals/shadowCamera.js +5 -0
- package/src/globals/shadowDepthLayout.js +5 -0
- package/src/globals/shadowHigh.js +5 -0
- package/src/globals/shadowInstanceLayouts.js +5 -0
- package/src/globals/shadowLayouts.js +5 -0
- package/src/globals/shadowLow.js +5 -0
- package/src/globals/shadowMeshLayout.js +5 -0
- package/src/globals/shadowOffsets.js +5 -0
- package/src/globals/shadowPass.js +5 -0
- package/src/globals/shadowPipeline.js +5 -0
- package/src/globals/shadowPipelineLayout.js +5 -0
- package/src/globals/shadowShader.js +5 -0
- package/src/globals/shadowTexture.js +5 -0
- package/src/globals/shadowValues.js +5 -0
- package/src/globals/shirt.js +5 -0
- package/src/globals/sinObliquity.js +8 -3
- package/src/globals/sizes.js +5 -0
- package/src/globals/skin.js +5 -0
- package/src/globals/speed.js +5 -1
- package/src/globals/sunBindGroup.js +5 -0
- package/src/globals/taillight.js +5 -0
- package/src/globals/tau.js +6 -1
- package/src/globals/terrainLayoutEntry.js +5 -0
- package/src/globals/textureLayoutEntries.js +5 -0
- package/src/globals/tiledBounds.js +5 -0
- package/src/globals/tooltipEvents.js +5 -0
- package/src/globals/tooltipPosition.js +5 -0
- package/src/globals/trafficClocks.js +5 -0
- package/src/globals/trafficEmptyList.js +5 -0
- package/src/globals/trafficEmptyOptions.js +5 -0
- package/src/globals/trafficRouteMaterial.js +5 -0
- package/src/globals/trafficShader.js +5 -1
- package/src/globals/triangleContexts.js +5 -0
- package/src/globals/trousers.js +5 -0
- package/src/globals/types.js +5 -0
- package/src/globals/tyre.js +5 -0
- package/src/globals/uVLayout.js +5 -0
- package/src/globals/vectorStyleNamedColors.js +13 -8
- package/src/globals/vectorTileEvents.js +6 -1
- package/src/globals/vehicles.js +2 -0
- package/src/globals/vertexShader.js +5 -0
- package/src/globals/wantedTiles.js +5 -0
- package/src/globals/white.js +5 -0
- package/src/globals/workerCogSource.js +6 -1
- package/src/gpu/README.md +29 -0
- package/src/gpu/initializeRendererResources.js +39 -34
- package/src/gpu/initializeSharedRenderer.js +51 -44
- package/src/gpu/mountRenderer.js +25 -19
- package/src/gpu/releaseRenderer.js +8 -0
- package/src/gpu/rendererDeviceError.js +5 -3
- package/src/gpu/rendererDeviceLost.js +5 -3
- package/src/gpu/reportShaderCompilation.js +8 -0
- package/src/gpu/requestAdapter.js +8 -0
- package/src/gpu/requestDevice.js +9 -0
- package/src/gpu/showWebGPUWarning.js +5 -0
- package/src/index.js +0 -2
- package/src/layer-controls/README.md +25 -0
- package/src/layer-controls/layerControlInputId.js +18 -11
- package/src/layer-controls/layerCountTitle.js +16 -6
- package/src/layer-controls/placeEntry.js +9 -0
- package/src/layer-controls/placeEntryElement.js +29 -22
- package/src/layer-controls/placeUnderEntry.js +7 -0
- package/src/layer-controls/removeEntry.js +1 -0
- package/src/layer-controls/renderLayerCount.js +28 -20
- package/src/layer-controls/replaceEntry.js +1 -2
- package/src/layer-controls/runPlacements.js +1 -2
- package/src/layer-controls/underEntry.js +6 -2
- package/src/layer-controls/updateLayerCount.js +5 -1
- package/src/lighting/README.md +28 -0
- package/src/lighting/cacheLightGrid.js +9 -1
- package/src/lighting/collectLightMeshes.js +7 -1
- package/src/lighting/lightGrid.js +10 -1
- package/src/lighting/updatePointLights.js +7 -3
- package/src/lighting/visitLightCells.js +26 -13
- package/src/lighting/visitLightGridCells.js +11 -0
- package/src/lighting/worldLights.js +8 -1
- package/src/lighting/writeLightCell.js +14 -5
- package/src/materials/README.md +28 -0
- package/src/materials/createProgram.js +8 -4
- package/src/materials/createProgramLayout.js +44 -36
- package/src/materials/createProgramUniforms.js +25 -18
- package/src/materials/modelMaterialFor.js +29 -21
- package/src/materials/prepareMeshCutout.js +21 -12
- package/src/materials/terrainRasterProgram.js +57 -50
- package/src/materials/validateRoofMaterial.js +17 -10
- package/src/models/README.md +27 -0
- package/src/models/applyModelTransform.js +16 -12
- package/src/models/buildModelNodes.js +24 -14
- package/src/models/createModelContext.js +24 -15
- package/src/models/decodeModel.js +13 -2
- package/src/models/hasUnsupportedPrimitives.js +7 -0
- package/src/models/loadBuffer.js +16 -6
- package/src/models/loadModel.js +10 -7
- package/src/models/loadModelResources.js +22 -14
- package/src/models/modelNode.js +11 -1
- package/src/models/normalizeAccessor.js +21 -11
- package/src/models/prepareModel.js +29 -19
- package/src/models/prepareModelGeometry.js +35 -25
- package/src/models/prepareModelPrimitive.js +25 -17
- package/src/models/readAccessor.js +10 -4
- package/src/models/readAccessorValue.js +16 -7
- package/src/models/readAccessorValues.js +17 -0
- package/src/models/readModelAttributes.js +32 -20
- package/src/models/readModelIndices.js +28 -16
- package/src/models/readSparseAccessor.js +31 -19
- package/src/models/releaseModelResources.js +15 -10
- package/src/mvt/README.md +28 -0
- package/src/mvt/addMvtCrossings.js +23 -17
- package/src/mvt/appendMvtBandTriangles.js +42 -31
- package/src/mvt/appendMvtCoordinates.js +20 -11
- package/src/mvt/appendMvtPolygonTriangles.js +29 -19
- package/src/mvt/beginMvtPath.js +19 -9
- package/src/mvt/closeMvtPath.js +16 -7
- package/src/mvt/collectMvtEdges.js +29 -19
- package/src/mvt/createMvtReader.js +14 -7
- package/src/mvt/decodeVectorTile.js +39 -32
- package/src/mvt/expectMvtWire.js +11 -3
- package/src/mvt/finishMvtPath.js +14 -5
- package/src/mvt/finiteMvtCoordinate.js +14 -7
- package/src/mvt/groupMvtPolygons.js +35 -25
- package/src/mvt/isMvtFallbackError.js +13 -6
- package/src/mvt/mergeMvtActiveEdges.js +18 -9
- package/src/mvt/mvtEdgeX.js +12 -4
- package/src/mvt/mvtPathsVertices.js +15 -8
- package/src/mvt/mvtPolygonPaths.js +19 -12
- package/src/mvt/numericMvtValue.js +11 -4
- package/src/mvt/readMvtFeature.js +46 -34
- package/src/mvt/readMvtField.js +17 -8
- package/src/mvt/readMvtGeometry.js +42 -29
- package/src/mvt/readMvtInteger.js +22 -12
- package/src/mvt/readMvtKnownValue.js +30 -21
- package/src/mvt/readMvtLayer.js +40 -31
- package/src/mvt/readMvtMessage.js +18 -10
- package/src/mvt/readMvtNumber.js +18 -9
- package/src/mvt/readMvtNumbers.js +18 -11
- package/src/mvt/readMvtString.js +14 -6
- package/src/mvt/readMvtValue.js +29 -19
- package/src/mvt/skipMvtField.js +22 -14
- package/src/mvt/sortMvtActiveEdges.js +20 -15
- package/src/mvt/sortedMvtLevels.js +29 -22
- package/src/mvt/takeMvtBytes.js +18 -8
- package/src/mvt/tessellateVectorRings.js +26 -19
- package/src/mvt/triangulateVectorRings.js +23 -19
- package/src/native/README.md +27 -0
- package/src/native/beforeNativeRender.js +21 -16
- package/src/native/bypassNativeEvent.js +21 -11
- package/src/native/canScaleNativeStyle.js +26 -17
- package/src/native/compareNativeHits.js +10 -2
- package/src/native/createNativeMesh.js +46 -31
- package/src/native/disposeNativeLayer.js +3 -2
- package/src/native/forwardNativeError.js +8 -3
- package/src/native/getGridTerrainTile.js +47 -34
- package/src/native/gridTerrainElevation.js +34 -26
- package/src/native/handleNativeMapEvent.js +9 -4
- package/src/native/hideTargets.js +6 -0
- package/src/native/initNativeGPU.js +6 -3
- package/src/native/isCurrentNativeLayer.js +9 -4
- package/src/native/loadGridTerrain.js +36 -26
- package/src/native/nativeAddLatLng.js +7 -0
- package/src/native/nativeBringToBack.js +7 -0
- package/src/native/nativeBringToFront.js +7 -0
- package/src/native/nativeEventSource.js +27 -18
- package/src/native/nativeEvents.js +5 -4
- package/src/native/nativeLayer.js +10 -6
- package/src/native/nativeLayerMethod.js +9 -2
- package/src/native/nativeProgram.js +28 -20
- package/src/native/nativeRedraw.js +7 -0
- package/src/native/nativeSetBounds.js +7 -0
- package/src/native/nativeSetIcon.js +7 -0
- package/src/native/nativeSetLatLng.js +7 -0
- package/src/native/nativeSetLatLngs.js +7 -0
- package/src/native/nativeSetOpacity.js +7 -0
- package/src/native/nativeSetRadius.js +7 -0
- package/src/native/nativeSetStyle.js +7 -0
- package/src/native/nativeSetUrl.js +7 -0
- package/src/native/nativeSetZIndex.js +7 -0
- package/src/native/nativeSetZIndexOffset.js +7 -0
- package/src/native/nativeTerrainElevation.js +27 -16
- package/src/native/nativeVectorGeometry.js +30 -23
- package/src/native/orderNativeGridLayer.js +20 -14
- package/src/native/prepareGridTerrainRequests.js +23 -16
- package/src/native/pruneNativeResources.js +25 -20
- package/src/native/putNativeMesh.js +14 -0
- package/src/native/quadNativeMesh.js +11 -1
- package/src/native/readyNativeGPU.js +10 -6
- package/src/native/refreshNativeEvent.js +5 -0
- package/src/native/refreshNativeLayer.js +5 -3
- package/src/native/refreshNativeLayerContract.js +5 -2
- package/src/native/rejectNativeReady.js +7 -2
- package/src/native/removeNativeEvents.js +18 -14
- package/src/native/removeTargets.js +5 -2
- package/src/native/reorderNativeLayer.js +5 -3
- package/src/native/resolveNativeReady.js +5 -2
- package/src/native/restoreNativeEvents.js +8 -5
- package/src/native/retainGridTerrain.js +15 -10
- package/src/native/styleNativeMesh.js +17 -11
- package/src/native/syncGridLayer.js +5 -1
- package/src/native/syncGridTile.js +28 -18
- package/src/native/syncImageOverlay.js +10 -5
- package/src/native/syncMarker.js +5 -0
- package/src/native/syncNativeStrokeAnchors.js +18 -12
- package/src/native/syncNativeStrokeZoom.js +34 -29
- package/src/native/syncTerrainGridTile.js +38 -28
- package/src/native/syncVectorLayer.js +5 -0
- package/src/native/synchronizeNativeLayer.js +5 -3
- package/src/native/terrainGridMesh.js +47 -34
- package/src/native/updateNativeHover.js +15 -7
- package/src/native/updateNativeLayerView.js +3 -3
- package/src/native/updateNativeStrokeRadius.js +14 -9
- package/src/picking/README.md +29 -0
- package/src/picking/collectVisibleMesh.js +8 -0
- package/src/picking/findFeature.js +4 -4
- package/src/picking/hit.js +14 -7
- package/src/picking/hitColliderCell.js +29 -19
- package/src/picking/hitMesh.js +8 -2
- package/src/picking/onClick.js +6 -5
- package/src/picking/onPointerLeave.js +5 -5
- package/src/picking/onPointerMove.js +6 -5
- package/src/picking/pointerClick.js +5 -0
- package/src/picking/pointerLeave.js +1 -0
- package/src/picking/pointerMove.js +5 -0
- package/src/picking/raycast.js +2 -4
- package/src/picking/setHighlight.js +6 -5
- package/src/picking/shouldSkipOther.js +8 -2
- package/src/picking/showFeature.js +7 -4
- package/src/picking/validateCameraInverse.js +15 -8
- package/src/projections/README.md +28 -0
- package/src/projections/cameraAngles.js +8 -1
- package/src/projections/displayContainerPoint.js +32 -23
- package/src/projections/groundBounds.js +9 -1
- package/src/projections/localPixel.js +8 -0
- package/src/projections/localPixelForGeometry.js +8 -1
- package/src/projections/localPosition.js +8 -2
- package/src/projections/markerCameraIconPoint.js +9 -1
- package/src/projections/projectBridgePoint.js +16 -4
- package/src/projections/projectCameraPoint.js +11 -1
- package/src/projections/projectCelestialBody.js +11 -2
- package/src/projections/projectRing.js +11 -1
- package/src/projections/projectTreePoint.js +9 -1
- package/src/projections/toPoint.js +12 -4
- package/src/projections/transformZoomAnimationPoint.js +16 -9
- package/src/projections/verticalGroundY.js +14 -3
- package/src/projections/walkerLocalPosition.js +7 -0
- package/src/raster/README.md +28 -0
- package/src/raster/addRasterTile.js +10 -2
- package/src/raster/comparePendingTiles.js +8 -0
- package/src/raster/createRasterMesh.js +6 -5
- package/src/raster/finishRasterAttachment.js +9 -4
- package/src/raster/finishRasterTile.js +11 -2
- package/src/raster/getRasterEvents.js +7 -0
- package/src/raster/getRasterTileSize.js +5 -1
- package/src/raster/initRaster.js +6 -3
- package/src/raster/isRasterLoading.js +7 -3
- package/src/raster/loadRasterTile.js +8 -3
- package/src/raster/onPMTileAdd.js +6 -3
- package/src/raster/onPMTileRemove.js +6 -3
- package/src/raster/pruneRasterTiles.js +7 -3
- package/src/raster/pumpRasterTiles.js +5 -4
- package/src/raster/rasterTileRange.js +32 -23
- package/src/raster/readyRaster.js +8 -3
- package/src/raster/registerTerrainTile.js +9 -3
- package/src/raster/releaseRasterTile.js +6 -3
- package/src/raster/releaseRasterTiles.js +5 -3
- package/src/raster/removeRasterTile.js +6 -3
- package/src/raster/reportRasterError.js +8 -0
- package/src/raster/retainRasterTiles.js +19 -14
- package/src/raster/setPMTileOpacity.js +8 -0
- package/src/raster/setPMTileZIndex.js +8 -0
- package/src/raster/setRasterOpacity.js +6 -3
- package/src/raster/setRasterTerrain.js +6 -3
- package/src/raster/setRasterZIndex.js +6 -3
- package/src/raster/updateAttachedTiles.js +9 -3
- package/src/raster/updateRasterTiles.js +5 -5
- package/src/rendering/README.md +32 -0
- package/src/rendering/collectFrameMeshes.js +7 -3
- package/src/rendering/collectMeshes.js +11 -0
- package/src/rendering/collectVisibleMesh.js +48 -39
- package/src/rendering/compareMeshDepth.js +14 -6
- package/src/rendering/compareMeshes.js +10 -1
- package/src/rendering/createMesh.js +8 -5
- package/src/rendering/disposeMesh.js +6 -0
- package/src/rendering/drawGeometry.js +9 -2
- package/src/rendering/drawPipeline.js +44 -34
- package/src/rendering/drawSceneMeshes.js +9 -3
- package/src/rendering/nativeStrokeExpansion.js +11 -4
- package/src/rendering/prepareFrameBuffer.js +22 -16
- package/src/rendering/prepareFrameMeshes.js +10 -3
- package/src/rendering/prepareFrameUniforms.js +8 -3
- package/src/rendering/prepareMeshUniforms.js +36 -27
- package/src/rendering/render.js +2 -5
- package/src/rendering/resizeRenderer.js +6 -3
- package/src/rendering/revealRoofMesh.js +43 -34
- package/src/scene/README.md +36 -0
- package/src/scene/addRegisteredLayer.js +5 -4
- package/src/scene/addSceneLayer.js +22 -16
- package/src/scene/attachLayer.js +8 -3
- package/src/scene/attachSharedScene.js +6 -1
- package/src/scene/callLayer.js +31 -25
- package/src/scene/cancelUpdate.js +5 -3
- package/src/scene/createLayer.js +12 -6
- package/src/scene/createSceneNode.js +5 -1
- package/src/scene/emptyEvents.js +5 -0
- package/src/scene/failAttachment.js +9 -3
- package/src/scene/get3DEvents.js +7 -3
- package/src/scene/getLocation.js +10 -6
- package/src/scene/init3D.js +6 -3
- package/src/scene/initializeLayer.js +9 -2
- package/src/scene/initializerFor.js +8 -0
- package/src/scene/isNativeLayer.js +17 -11
- package/src/scene/layerInitialize.js +7 -4
- package/src/scene/onAdd3DLayer.js +6 -4
- package/src/scene/onMapChange.js +0 -5
- package/src/scene/onRemove3DLayer.js +6 -5
- package/src/scene/ready3D.js +9 -3
- package/src/scene/releaseSharedScene.js +6 -2
- package/src/scene/removeLayerEvents.js +1 -3
- package/src/scene/removeSceneLayer.js +20 -14
- package/src/scene/renderPendingMapChange.js +1 -4
- package/src/scene/renderPendingUpdates.js +5 -4
- package/src/scene/reportLayerError.js +9 -3
- package/src/scene/resolveNextInitialization.js +5 -2
- package/src/scene/restoreObject.js +6 -3
- package/src/scene/scheduleSceneUpdate.js +7 -6
- package/src/scene/setParent.js +6 -2
- package/src/scene/traverse.js +7 -2
- package/src/shaders/README.md +29 -0
- package/src/shaders/materialBaseShader.js +26 -17
- package/src/shaders/materialShaders.js +9 -1
- package/src/shaders/materialSurfaceShader.js +60 -47
- package/src/shaders/materialVertexShader.js +89 -77
- package/src/shaders/nativeStrokeShader.js +13 -6
- package/src/shaders/roofVertexShader.js +16 -9
- package/src/shadows/README.md +28 -0
- package/src/shadows/bindSunlight.js +5 -3
- package/src/shadows/drawShadowMeshes.js +7 -2
- package/src/shadows/ensureShadowPipeline.js +7 -0
- package/src/shadows/renderSunlight.js +8 -4
- package/src/shadows/resizeSunlight.js +6 -3
- package/src/shadows/shadowCacheMatches.js +11 -1
- package/src/shadows/shadowMatrix.js +8 -1
- package/src/shadows/shadowMeshMatches.js +19 -11
- package/src/sources/README.md +33 -0
- package/src/sources/attachAreaMesh.js +5 -4
- package/src/sources/buildArea.js +13 -2
- package/src/sources/buildAreaFeature.js +7 -1
- package/src/sources/buildAreaFeatures.js +23 -14
- package/src/sources/compareAreaDistance.js +8 -0
- package/src/sources/extrusionStyle.js +21 -10
- package/src/sources/featureAnchor.js +21 -9
- package/src/sources/groundOffset.js +9 -2
- package/src/sources/initVectorTiles.js +21 -15
- package/src/sources/initializeGeoJSON.js +6 -3
- package/src/sources/isVectorTileSource.js +11 -4
- package/src/sources/matchesAreaTile.js +17 -7
- package/src/sources/pendingSourceAreas.js +26 -19
- package/src/sources/prepareAreaGeometryJob.js +34 -24
- package/src/sources/projectAreaPolygons.js +25 -15
- package/src/sources/pumpSourceAreas.js +6 -6
- package/src/sources/readyVectorTiles.js +17 -10
- package/src/sources/releaseArea.js +6 -4
- package/src/sources/setGeoJSONData.js +8 -3
- package/src/sources/setGeoJSONLayerData.js +7 -0
- package/src/sources/sourceAreaContext.js +9 -2
- package/src/sources/updateArea.js +5 -5
- package/src/sources/updateSourceStatus.js +6 -3
- package/src/sunlight/README.md +28 -0
- package/src/sunlight/addTimeControlToMap.js +17 -10
- package/src/sunlight/addTimeLayer.js +10 -5
- package/src/sunlight/atmosphere.js +9 -2
- package/src/sunlight/createSun.js +7 -0
- package/src/sunlight/initSunlight.js +5 -0
- package/src/sunlight/initializeTimeControl.js +15 -13
- package/src/sunlight/onAddSun.js +35 -26
- package/src/sunlight/onAddTimeControl.js +12 -5
- package/src/sunlight/onRemoveSun.js +10 -10
- package/src/sunlight/removeSun.js +22 -20
- package/src/sunlight/removeTimeControl.js +13 -7
- package/src/sunlight/removeTimeLayer.js +8 -5
- package/src/sunlight/requestSunlightRender.js +10 -7
- package/src/sunlight/styleTimeControl.js +13 -7
- package/src/sunlight/tickSun.js +10 -5
- package/src/sunlight/updateCelestialDisc.js +23 -12
- package/src/sunlight/updateSky.js +5 -3
- package/src/sunlight/updateSun.js +42 -40
- package/src/sunlight/useLiveTime.js +11 -6
- package/src/sunlight/useSelectedTime.js +24 -22
- package/src/terrain/README.md +30 -0
- package/src/terrain/applyTerrain.js +26 -20
- package/src/terrain/clearLayerTerrain.js +5 -3
- package/src/terrain/copyTerrainTile.js +20 -12
- package/src/terrain/getElevation.js +8 -5
- package/src/terrain/initTerrain.js +5 -3
- package/src/terrain/loadReadyTerrain.js +6 -5
- package/src/terrain/loadTerrain.js +10 -2
- package/src/terrain/loadTerrainTiles.js +10 -3
- package/src/terrain/mapElevationOf.js +19 -11
- package/src/terrain/onTerrainAdd.js +8 -4
- package/src/terrain/onTerrainChange.js +5 -5
- package/src/terrain/onTerrainRemove.js +6 -3
- package/src/terrain/readBridges.js +13 -4
- package/src/terrain/readyTerrainOf.js +14 -7
- package/src/terrain/sampleTerrainTile.js +16 -7
- package/src/terrain/setLayerTerrain.js +5 -3
- package/src/terrain/setTerrainHeight.js +5 -4
- package/src/terrain/terrainAtlas.js +8 -2
- package/src/terrain/terrainElevation.js +8 -2
- package/src/terrain/terrainTileQueue.js +31 -24
- package/src/textures/README.md +29 -0
- package/src/textures/addImageState.js +12 -7
- package/src/textures/attachRasterImage.js +1 -2
- package/src/textures/bindMeshTextures.js +57 -50
- package/src/textures/collectRoofTiles.js +21 -14
- package/src/textures/compareRoofTiles.js +8 -0
- package/src/textures/composeRoofAtlas.js +11 -3
- package/src/textures/destroyTexture.js +6 -4
- package/src/textures/destroyTextureAfterSubmission.js +9 -0
- package/src/textures/ensureRoofBlit.js +5 -0
- package/src/textures/loadModelImage.js +28 -18
- package/src/textures/modelTextureFor.js +45 -37
- package/src/textures/modelTextureSampler.js +7 -2
- package/src/textures/nativeImageError.js +5 -1
- package/src/textures/nativeImageRefresh.js +5 -2
- package/src/textures/nativeTextureFor.js +11 -3
- package/src/textures/prepareMeshTextures.js +31 -23
- package/src/textures/rebuildRoofAtlas.js +8 -3
- package/src/textures/removeImageState.js +11 -6
- package/src/textures/resizeRoofTexture.js +30 -23
- package/src/textures/restoreMaterialTextures.js +22 -16
- package/src/textures/textureBinding.js +9 -0
- package/src/textures/updateRoofAtlas.js +25 -19
- package/src/textures/updateRoofRaster.js +8 -0
- package/src/textures/uploadCanvasTexture.js +15 -0
- package/src/textures/uploadMeshTexture.js +32 -26
- package/src/textures/uploadNativeImage.js +26 -13
- package/src/textures/uploadRoofTile.js +29 -23
- package/src/traffic/README.md +30 -0
- package/src/traffic/addTraffic.js +5 -2
- package/src/traffic/clockMinutes.js +7 -0
- package/src/traffic/compareDepartures.js +8 -0
- package/src/traffic/createTrafficMesh.js +15 -4
- package/src/traffic/destroyTrafficGpu.js +5 -0
- package/src/traffic/disposeTrafficObject.js +14 -11
- package/src/traffic/drawTrafficRoute.js +5 -1
- package/src/traffic/failTraffic.js +12 -6
- package/src/traffic/failedTrafficLoad.js +9 -2
- package/src/traffic/featuresToTrafficLanes.js +8 -0
- package/src/traffic/fetchTrafficLanes.js +21 -10
- package/src/traffic/groundTraffic.js +5 -1
- package/src/traffic/initTraffic.js +17 -15
- package/src/traffic/loadTraffic.js +5 -0
- package/src/traffic/loadedTrafficLanes.js +19 -12
- package/src/traffic/locateTraffic.js +20 -11
- package/src/traffic/moveTraffic.js +21 -15
- package/src/traffic/placeTraffic.js +5 -0
- package/src/traffic/prepareTraffic.js +5 -3
- package/src/traffic/readyTraffic.js +8 -3
- package/src/traffic/rebaseTraffic.js +5 -3
- package/src/traffic/rebuildTrafficMesh.js +5 -1
- package/src/traffic/refreshTrafficTrips.js +42 -32
- package/src/traffic/removeTraffic.js +5 -2
- package/src/traffic/routeColor.js +13 -6
- package/src/traffic/scheduledTrips.js +5 -2
- package/src/traffic/startTraffic.js +10 -5
- package/src/traffic/tickTraffic.js +5 -3
- package/src/traffic/trafficBounds.js +5 -0
- package/src/traffic/trafficNow.js +14 -9
- package/src/traffic/trafficStatusText.js +13 -5
- package/src/traffic/trafficStorage.js +13 -5
- package/src/traffic/trafficTooltip.js +7 -0
- package/src/traffic/tripsAt.js +9 -2
- package/src/traffic/updateTraffic.js +11 -8
- package/src/traffic/updateTrafficLights.js +23 -18
- package/src/traffic/updateTrafficPose.js +15 -8
- package/src/traffic/updateTrafficTerrain.js +12 -7
- package/src/traffic/uploadTrafficLanes.js +27 -21
- package/src/traffic/vehicleOffsets.js +9 -3
- package/src/transforms/README.md +27 -0
- package/src/transforms/composeLocalTransform.js +23 -16
- package/src/transforms/modelNodeMatrix.js +7 -2
- package/src/transforms/transformNativePoint.js +19 -7
- package/src/transforms/updateWorldMatrix.js +5 -2
- package/src/transforms/worldMatrixChanged.js +26 -18
- package/src/triangulation/README.md +26 -0
- package/src/triangulation/area.js +7 -0
- package/src/triangulation/clean.js +9 -0
- package/src/triangulation/clipEars.js +32 -23
- package/src/triangulation/connectHole.js +30 -18
- package/src/triangulation/containsVertex.js +10 -0
- package/src/triangulation/cross.js +12 -3
- package/src/triangulation/crossesBoundary.js +10 -0
- package/src/triangulation/crossesRing.js +9 -0
- package/src/triangulation/equal.js +11 -3
- package/src/triangulation/inside.js +8 -0
- package/src/triangulation/insideHole.js +8 -0
- package/src/triangulation/intersects.js +21 -11
- package/src/triangulation/isClockWise.js +4 -1
- package/src/triangulation/mergeHoles.js +19 -11
- package/src/triangulation/minimumX.js +7 -0
- package/src/triangulation/on.js +13 -4
- package/src/triangulation/polygonRings.js +22 -14
- package/src/triangulation/sortHoles.js +7 -0
- package/src/triangulation/triangulate.js +3 -2
- package/src/triangulation/validateArea.js +19 -10
- package/src/utils/README.md +16 -0
- package/src/utils/compareDistance.js +11 -3
- package/src/utils/noOperation.js +1 -0
- package/src/utils/wrap.js +7 -0
- package/src/utils/yieldTask.js +12 -5
- package/src/vector-style/README.md +27 -0
- package/src/vector-style/appendQuotedStyleCharacter.js +30 -22
- package/src/vector-style/arrayContainsRange.js +18 -8
- package/src/vector-style/evaluateBoolean.js +31 -18
- package/src/vector-style/evaluateCoalesceOrCase.js +34 -21
- package/src/vector-style/evaluateComparison.js +29 -16
- package/src/vector-style/evaluateIExpression.js +21 -8
- package/src/vector-style/evaluateInput.js +16 -6
- package/src/vector-style/evaluateInterpolate.js +36 -27
- package/src/vector-style/evaluateMatch.js +21 -12
- package/src/vector-style/evaluateMath.js +26 -14
- package/src/vector-style/evaluateMembership.js +29 -18
- package/src/vector-style/evaluateNegation.js +26 -13
- package/src/vector-style/evaluatePrimitive.js +21 -9
- package/src/vector-style/evaluateStep.js +20 -11
- package/src/vector-style/evaluateStyle.js +43 -33
- package/src/vector-style/evaluateToExpression.js +27 -14
- package/src/vector-style/fillVectorPaint.js +26 -17
- package/src/vector-style/lineVectorPaint.js +31 -21
- package/src/vector-style/parseFunctionalColor.js +23 -14
- package/src/vector-style/parseHexColor.js +20 -13
- package/src/vector-style/parseVectorStyle.js +20 -13
- package/src/vector-style/readPaintValue.js +17 -6
- package/src/vector-style/removeTrailingCommas.js +19 -12
- package/src/vector-style/scaleDashArray.js +25 -13
- package/src/vector-style/skipStyleComment.js +20 -9
- package/src/vector-style/stripStyleComments.js +28 -21
- package/src/vector-style/styleColor.js +18 -11
- package/src/vector-style/validateVectorLayers.js +18 -10
- package/src/vector-style/vectorPaint.js +17 -8
- package/src/vector-style/visibleStyle.js +16 -7
- package/src/vector-tiles/README.md +30 -0
- package/src/vector-tiles/appendVectorBatch.js +34 -22
- package/src/vector-tiles/attachVectorTileBatch.js +25 -17
- package/src/vector-tiles/attachVectorTileBatches.js +26 -15
- package/src/vector-tiles/compareVectorLabelPriority.js +11 -3
- package/src/vector-tiles/compareVectorTileDistance.js +11 -3
- package/src/vector-tiles/configureVectorTileLayer.js +8 -0
- package/src/vector-tiles/createVectorLabel.js +37 -22
- package/src/vector-tiles/forwardVectorTileError.js +10 -5
- package/src/vector-tiles/loadVectorSprite.js +14 -5
- package/src/vector-tiles/loadVectorTile.js +45 -36
- package/src/vector-tiles/onVectorTileAdd.js +44 -39
- package/src/vector-tiles/onVectorTileMessage.js +15 -10
- package/src/vector-tiles/onVectorTileRemove.js +25 -20
- package/src/vector-tiles/onVectorTileWorkerError.js +16 -11
- package/src/vector-tiles/paintVectorTileBatch.js +18 -12
- package/src/vector-tiles/prepareVectorLabel.js +34 -25
- package/src/vector-tiles/prepareVectorStyleLayer.js +38 -30
- package/src/vector-tiles/prepareVectorTile.js +29 -16
- package/src/vector-tiles/projectVectorPaths.js +25 -15
- package/src/vector-tiles/projectVectorPoint.js +15 -6
- package/src/vector-tiles/projectVectorTriangles.js +28 -18
- package/src/vector-tiles/pruneVectorTiles.js +14 -11
- package/src/vector-tiles/pumpVectorTiles.js +21 -18
- package/src/vector-tiles/readTileJSON.js +27 -17
- package/src/vector-tiles/readVectorStyle.js +28 -17
- package/src/vector-tiles/refreshVectorTiles.js +8 -5
- package/src/vector-tiles/reserveVectorLabelCells.js +14 -6
- package/src/vector-tiles/retireVectorTileGroup.js +20 -13
- package/src/vector-tiles/revokeVectorWorkerUrl.js +14 -9
- package/src/vector-tiles/rotateVectorLabel.js +19 -12
- package/src/vector-tiles/rotateVectorLabels.js +9 -6
- package/src/vector-tiles/simplifyVectorPath.js +29 -21
- package/src/vector-tiles/updateVectorLabelMarker.js +36 -27
- package/src/vector-tiles/updateVectorLabelStyle.js +14 -8
- package/src/vector-tiles/updateVectorTileLabels.js +33 -28
- package/src/vector-tiles/updateVectorTilePaint.js +25 -20
- package/src/vector-tiles/updateVectorTiles.js +32 -29
- package/src/vector-tiles/validateVectorTileZooms.js +15 -6
- package/src/vector-tiles/vectorFeaturePaint.js +25 -15
- package/src/vector-tiles/vectorFeaturePaths.js +26 -16
- package/src/vector-tiles/vectorFeatureZoom.js +18 -8
- package/src/vector-tiles/vectorLabelAnchors.js +31 -24
- package/src/vector-tiles/vectorLabelCandidates.js +18 -11
- package/src/vector-tiles/vectorLabelCells.js +32 -23
- package/src/vector-tiles/vectorLabelIcon.js +38 -30
- package/src/vector-tiles/vectorLabelProperty.js +12 -3
- package/src/vector-tiles/vectorLabelText.js +19 -10
- package/src/vector-tiles/vectorSpriteIcon.js +19 -11
- package/src/vector-tiles/vectorStraightRun.js +23 -14
- package/src/vector-tiles/vectorStyleDependencies.js +22 -15
- package/src/vector-tiles/vectorStyleValue.js +16 -5
- package/src/vector-tiles/vectorStyleZoom.js +12 -6
- package/src/vector-tiles/vectorTileAwaited.js +17 -9
- package/src/vector-tiles/vectorTileOverlaps.js +12 -4
- package/src/vector-tiles/vectorTilePaint.js +18 -10
- package/src/vector-tiles/vectorTileSettings.js +27 -17
- package/src/vector-tiles/vectorTilesIdle.js +11 -3
- package/src/vector-tiles/vectorTolerance.js +11 -4
- package/src/vector-tiles/wrapVectorLabel.js +17 -11
- package/src/vehicles/README.md +27 -0
- package/src/vehicles/bicycleModel.js +7 -1
- package/src/vehicles/boatBenches.js +5 -0
- package/src/vehicles/boatModel.js +32 -32
- package/src/vehicles/buildCarriage.js +9 -1
- package/src/vehicles/busModel.js +10 -2
- package/src/vehicles/carModel.js +34 -33
- package/src/vehicles/metroModel.js +8 -0
- package/src/vehicles/mirrorVehiclePart.js +11 -0
- package/src/vehicles/pedestrianModel.js +7 -1
- package/src/vehicles/tramModel.js +8 -0
- package/src/walk/README.md +30 -0
- package/src/walk/animateWalker.js +5 -4
- package/src/walk/createWalk.js +6 -3
- package/src/walk/initWalk.js +5 -0
- package/src/walk/initializeWalkControl.js +11 -6
- package/src/walk/isWalkBlocked.js +15 -6
- package/src/walk/landWalker.js +35 -31
- package/src/walk/moveWalker.js +35 -22
- package/src/walk/onAddWalkControl.js +40 -31
- package/src/walk/onRemoveWalkControl.js +17 -12
- package/src/walk/onWalkBlur.js +3 -2
- package/src/walk/onWalkKey.js +5 -2
- package/src/walk/onWalkPointer.js +6 -0
- package/src/walk/onWalkTerrain.js +3 -2
- package/src/walk/placeWalker.js +1 -2
- package/src/walk/resolveWalkerPosition.js +33 -28
- package/src/walk/startWalking.js +1 -1
- package/src/walk/stepWalkerHeight.js +18 -11
- package/src/walk/stopWalking.js +1 -0
- package/src/walk/toggleWalking.js +3 -2
- package/src/walk/updateWalkerFrame.js +29 -19
- package/src/walk/updateWalkerView.js +31 -22
- package/src/weakmaps/README.md +33 -0
- package/src/weakmaps/addedByLayer.js +5 -0
- package/src/weakmaps/archiveHeaderByLayer.js +5 -0
- package/src/weakmaps/areasByLayer.js +5 -0
- package/src/weakmaps/boundsMethods.js +5 -0
- package/src/weakmaps/bridgeMeshByLayer.js +5 -0
- package/src/weakmaps/bridgesByLayer.js +5 -0
- package/src/weakmaps/cameraAnimationByMap.js +5 -0
- package/src/weakmaps/cameraBearingByMap.js +5 -0
- package/src/weakmaps/cameraByLayer.js +5 -0
- package/src/weakmaps/cameraDraggableByMap.js +5 -0
- package/src/weakmaps/cameraFields.js +5 -0
- package/src/weakmaps/cameraFrameByMap.js +5 -0
- package/src/weakmaps/cameraHandlersByMap.js +6 -1
- package/src/weakmaps/cameraMaps.js +5 -0
- package/src/weakmaps/cameraPitchByMap.js +5 -0
- package/src/weakmaps/cameraReadyByMap.js +5 -0
- package/src/weakmaps/cameraTouchStateByMap.js +5 -0
- package/src/weakmaps/cameraViewByMap.js +5 -0
- package/src/weakmaps/cameraZIndexOffsetByLayer.js +5 -0
- package/src/weakmaps/closestMethods.js +5 -0
- package/src/weakmaps/colliders.js +5 -0
- package/src/weakmaps/containerByLayer.js +5 -0
- package/src/weakmaps/controlByLayer.js +5 -0
- package/src/weakmaps/countStatusByLayer.js +5 -0
- package/src/weakmaps/cursorByLayer.js +5 -0
- package/src/weakmaps/demByLayer.js +5 -0
- package/src/weakmaps/directoriesByLayer.js +5 -0
- package/src/weakmaps/dragByHandler.js +5 -0
- package/src/weakmaps/dragStates.js +5 -0
- package/src/weakmaps/etagByLayer.js +5 -0
- package/src/weakmaps/eventMapByLayer.js +5 -0
- package/src/weakmaps/eventsByLayer.js +5 -0
- package/src/weakmaps/fadeFrameByLayer.js +5 -0
- package/src/weakmaps/fadeVersionByLayer.js +5 -0
- package/src/weakmaps/frameByLayer.js +5 -0
- package/src/weakmaps/geojsonByLayer.js +5 -0
- package/src/weakmaps/geometryWorkersByMap.js +6 -1
- package/src/weakmaps/gridInitializers.js +5 -0
- package/src/weakmaps/groupByLayer.js +5 -0
- package/src/weakmaps/headerByLayer.js +5 -0
- package/src/weakmaps/highlightedFeatureByLayer.js +5 -0
- package/src/weakmaps/hoveredFeatureByLayer.js +5 -0
- package/src/weakmaps/imageStates.js +5 -0
- package/src/weakmaps/inflightByLayer.js +5 -0
- package/src/weakmaps/kindByLayer.js +5 -0
- package/src/weakmaps/layersByLayer.js +5 -0
- package/src/weakmaps/loadingTilesByLayer.js +5 -0
- package/src/weakmaps/locationByLayer.js +5 -0
- package/src/weakmaps/modelByLayer.js +5 -0
- package/src/weakmaps/modelUrlByLayer.js +5 -0
- package/src/weakmaps/nativeEventMaps.js +5 -0
- package/src/weakmaps/nativeGPUBackByMap.js +5 -0
- package/src/weakmaps/nativeGPUByLayer.js +5 -0
- package/src/weakmaps/nativeGPUOrderByMap.js +5 -0
- package/src/weakmaps/nativeProgramsByRenderer.js +6 -1
- package/src/weakmaps/nativeRenderByLayer.js +5 -0
- package/src/weakmaps/pathProjectionByMap.js +6 -1
- package/src/weakmaps/pitchSkyByMap.js +5 -0
- package/src/weakmaps/pointerEventsByLayer.js +5 -0
- package/src/weakmaps/pruneAfterByLayer.js +5 -0
- package/src/weakmaps/pruneVersionByLayer.js +5 -0
- package/src/weakmaps/pruneWantedByLayer.js +5 -0
- package/src/weakmaps/queuedByLayer.js +5 -0
- package/src/weakmaps/rasterGeometryByLayer.js +5 -0
- package/src/weakmaps/rasterProgramByLayer.js +5 -0
- package/src/weakmaps/rasterTilesByLayer.js +5 -0
- package/src/weakmaps/rasterVersionByLayer.js +5 -0
- package/src/weakmaps/raycasterByLayer.js +5 -0
- package/src/weakmaps/readyByLayer.js +5 -0
- package/src/weakmaps/rendererByLayer.js +5 -0
- package/src/weakmaps/rendererDevices.js +5 -0
- package/src/weakmaps/rendererReadyByLayer.js +5 -0
- package/src/weakmaps/renderers.js +5 -0
- package/src/weakmaps/roofRasterByLayer.js +5 -0
- package/src/weakmaps/roofRastersByLayer.js +5 -0
- package/src/weakmaps/rootByLayer.js +5 -0
- package/src/weakmaps/rotateControlByMap.js +5 -0
- package/src/weakmaps/sceneByLayer.js +5 -0
- package/src/weakmaps/sceneFields.js +5 -0
- package/src/weakmaps/sceneLayers.js +5 -0
- package/src/weakmaps/sceneOriginByLayer.js +5 -0
- package/src/weakmaps/shadowMeshesByLayer.js +5 -0
- package/src/weakmaps/sharedByLayer.js +5 -0
- package/src/weakmaps/sizeByLayer.js +5 -0
- package/src/weakmaps/state3dByLayer.js +5 -0
- package/src/weakmaps/streamTerrainByLayer.js +6 -1
- package/src/weakmaps/streamTerrainByMap.js +6 -1
- package/src/weakmaps/sunByMap.js +6 -1
- package/src/weakmaps/sunlightByControl.js +5 -0
- package/src/weakmaps/sunlightByMap.js +5 -0
- package/src/weakmaps/terrain3DByLayer.js +5 -0
- package/src/weakmaps/terrain3DByMap.js +5 -0
- package/src/weakmaps/terrainArchiveByLayer.js +5 -0
- package/src/weakmaps/terrainBaseYByLayer.js +5 -0
- package/src/weakmaps/terrainBoundsByLayer.js +5 -0
- package/src/weakmaps/terrainControllerByLayer.js +5 -0
- package/src/weakmaps/terrainGridsByLayer.js +5 -0
- package/src/weakmaps/terrainLoadingByLayer.js +5 -0
- package/src/weakmaps/terrainOriginElevationByLayer.js +5 -0
- package/src/weakmaps/terrainPromiseByLayer.js +5 -0
- package/src/weakmaps/terrainReadyByLayer.js +5 -0
- package/src/weakmaps/terrainRequestByLayer.js +5 -0
- package/src/weakmaps/terrainSourceByLayer.js +5 -0
- package/src/weakmaps/terrainTilesByLayer.js +5 -0
- package/src/weakmaps/terrainZoomByLayer.js +5 -0
- package/src/weakmaps/tileZoomByLayer.js +5 -0
- package/src/weakmaps/timeControlByMap.js +5 -0
- package/src/weakmaps/tooltipByLayer.js +5 -0
- package/src/weakmaps/touchByContainer.js +5 -0
- package/src/weakmaps/touchPitchByMap.js +5 -0
- package/src/weakmaps/touchRotateByMap.js +5 -0
- package/src/weakmaps/trafficByLayer.js +5 -0
- package/src/weakmaps/typeByLayer.js +5 -0
- package/src/weakmaps/urlByLayer.js +5 -0
- package/src/weakmaps/vectorTileOptionsByLayer.js +6 -1
- package/src/weakmaps/vectorWorkerByLayer.js +6 -1
- package/src/weakmaps/visibleMeshesByLayer.js +5 -0
- package/src/weakmaps/walkByMap.js +6 -1
- package/src/weakmaps/walkerByLayer.js +5 -0
- package/src/weakmaps/wantedRasterTilesByLayer.js +5 -0
- package/src/weakmaps/workerMapByLayer.js +6 -1
- package/src/weakmaps/zoomLevelByLayer.js +5 -0
- package/src/weakmaps/zoomTransitionsByLayer.js +5 -0
- package/src/weakmaps/zoomViewByLayer.js +5 -0
- package/src/workers/README.md +33 -0
- package/src/workers/acquireGeometryWorker.js +39 -29
- package/src/workers/buildAreaInWorker.js +24 -16
- package/src/workers/closeGeometryWorkers.js +16 -11
- package/src/workers/cogWorker.js +27 -20
- package/src/workers/createGeometryWorker.js +30 -20
- package/src/workers/geometryWorker.js +34 -29
- package/src/workers/getCogInWorker.js +18 -7
- package/src/workers/modelWorker.js +17 -10
- package/src/workers/openCogInWorker.js +22 -14
- package/src/workers/runSourceWorker.js +44 -32
- package/src/workers/settleGeometryWorker.js +16 -10
- package/src/workers/startGeometryWorker.js +23 -16
- package/src/workers/vectorTileWorker.js +15 -10
- package/src/collision/setTrafficNormal.js +0 -9
|
@@ -1,1129 +1,1129 @@
|
|
|
1
|
-
// Leaflet-compatible classes backed by OpenLayers. Load after ol.js and before the plugin.
|
|
2
|
-
(() => {
|
|
3
|
-
if (!window.ol) throw new Error('Unable to load OpenLayers');
|
|
4
|
-
|
|
5
|
-
const style = document.createElement('style');
|
|
6
|
-
style.dataset.openlayersBindings = '';
|
|
7
|
-
style.textContent = `
|
|
8
|
-
.openlayers-city-mapper {
|
|
9
|
-
position: relative;
|
|
10
|
-
overflow: hidden;
|
|
11
|
-
touch-action: none;
|
|
12
|
-
}
|
|
13
|
-
.ol-viewport {
|
|
14
|
-
position: absolute !important;
|
|
15
|
-
inset: 0;
|
|
16
|
-
}
|
|
17
|
-
.ol-overlaycontainer-stopevent { z-index: 1000 !important; }
|
|
18
|
-
.ol-city-corner {
|
|
19
|
-
position: absolute;
|
|
20
|
-
display: flex;
|
|
21
|
-
flex-direction: column;
|
|
22
|
-
gap: .5em;
|
|
23
|
-
pointer-events: none;
|
|
24
|
-
}
|
|
25
|
-
.ol-city-topleft { top: 5em; left: .5em; }
|
|
26
|
-
.ol-city-topright { top: 10px; right: 10px; }
|
|
27
|
-
.ol-city-bottomleft { bottom: .5em; left: .5em; }
|
|
28
|
-
.ol-city-bottomright { bottom: 4em; right: .5em; }
|
|
29
|
-
.ol-attribution {
|
|
30
|
-
text-align: justify;
|
|
31
|
-
border-radius: 0 !important;
|
|
32
|
-
left: 0;
|
|
33
|
-
right: 0 !important;
|
|
34
|
-
max-width: unset;
|
|
35
|
-
font-family: "Helvetica Neue", Arial, Helvetica, sans-serif;
|
|
36
|
-
font-size: .75rem;
|
|
37
|
-
line-height: 1.5;
|
|
38
|
-
}
|
|
39
|
-
.ol-attribution a { color: #0078A8; }
|
|
40
|
-
.ol-attribution * { text-shadow: none !important; }
|
|
41
|
-
.ol-city-control {
|
|
42
|
-
position: static;
|
|
43
|
-
pointer-events: auto;
|
|
44
|
-
font: 13px/1.5 sans-serif;
|
|
45
|
-
}
|
|
46
|
-
.ol-city-rotate {
|
|
47
|
-
padding: 0;
|
|
48
|
-
border: 1px solid #0003;
|
|
49
|
-
border-radius: 4px;
|
|
50
|
-
background: #fff;
|
|
51
|
-
background-clip: padding-box;
|
|
52
|
-
}
|
|
53
|
-
.ol-city-rotate a {
|
|
54
|
-
display: block;
|
|
55
|
-
width: 30px;
|
|
56
|
-
height: 30px;
|
|
57
|
-
border-radius: 2px;
|
|
58
|
-
color: #000;
|
|
59
|
-
text-decoration: none;
|
|
60
|
-
}
|
|
61
|
-
.ol-city-rotate a:hover { background: #f4f4f4; }
|
|
62
|
-
.ol-city-rotate a:focus-visible { outline: 2px solid #2675c9; }
|
|
63
|
-
.ol-city-layers {
|
|
64
|
-
max-height: calc(100vh - 5em);
|
|
65
|
-
overflow: auto;
|
|
66
|
-
border-radius: 4px;
|
|
67
|
-
}
|
|
68
|
-
.ol-city-layers section { padding: .5em; background: var(--ol-background-color); }
|
|
69
|
-
.ol-city-layers label { display: block; cursor: pointer; white-space: nowrap; }
|
|
70
|
-
.ol-city-layers input { vertical-align: middle; }
|
|
71
|
-
.ol-city-layers hr { border: 0; border-top: 1px solid #ccc; }
|
|
72
|
-
.ol-city-layers .ol-control { background: transparent; }
|
|
73
|
-
.ol-city-layers .sunlight-time button { width: auto; padding: 0 .4em; flex-shrink: 0; }
|
|
74
|
-
.openlayers-city-mapper .leaflet-pane {
|
|
75
|
-
position: absolute;
|
|
76
|
-
inset: 0;
|
|
77
|
-
pointer-events: none;
|
|
78
|
-
}
|
|
79
|
-
.ol-zoom button { width: 30px; height: 30px; }
|
|
80
|
-
.openlayers-city-mapper .leaflet-marker-icon,
|
|
81
|
-
.openlayers-city-mapper .leaflet-marker-shadow {
|
|
82
|
-
position: absolute;
|
|
83
|
-
top: 0;
|
|
84
|
-
left: 0;
|
|
85
|
-
}
|
|
86
|
-
.openlayers-city-mapper .leaflet-marker-icon { pointer-events: auto; cursor: pointer; }
|
|
87
|
-
.openlayers-city-mapper .leaflet-div-icon { background: #fff; border: 1px solid #666; }
|
|
88
|
-
.ol-city-popup {
|
|
89
|
-
padding: 10px;
|
|
90
|
-
background: white;
|
|
91
|
-
border: 1px solid #888;
|
|
92
|
-
border-radius: 4px;
|
|
93
|
-
font: 14px sans-serif;
|
|
94
|
-
}
|
|
95
|
-
.ol-city-popup button { float: right; margin-left: 12px; }
|
|
96
|
-
.ol-city-tooltip {
|
|
97
|
-
position: absolute;
|
|
98
|
-
z-index: 1100;
|
|
99
|
-
padding: 4px 8px;
|
|
100
|
-
background: white;
|
|
101
|
-
border: 1px solid #888;
|
|
102
|
-
pointer-events: none;
|
|
103
|
-
}
|
|
104
|
-
`;
|
|
105
|
-
document.head.appendChild(style);
|
|
106
|
-
|
|
107
|
-
const L = window.L = { version: '1.9.4-openlayers', control: {} };
|
|
108
|
-
let lastId = 0;
|
|
109
|
-
const stamp = object => object._leaflet_id ||= ++lastId;
|
|
110
|
-
const setOptions = (object, options) => object.options = { ...object.options, ...options };
|
|
111
|
-
const zoomTiming = new Animation(new KeyframeEffect(null, [], {
|
|
112
|
-
duration: 1, fill: 'both', easing: 'cubic-bezier(0,0,0.25,1)',
|
|
113
|
-
}));
|
|
114
|
-
|
|
115
|
-
function Class(...args) {
|
|
116
|
-
this.initialize?.(...args);
|
|
117
|
-
this.callInitHooks();
|
|
118
|
-
}
|
|
119
|
-
Class.extend = function (properties) {
|
|
120
|
-
function Child(...args) {
|
|
121
|
-
this.initialize?.(...args);
|
|
122
|
-
this.callInitHooks();
|
|
123
|
-
}
|
|
124
|
-
Object.setPrototypeOf(Child, this);
|
|
125
|
-
Child.prototype = Object.create(this.prototype);
|
|
126
|
-
Object.assign(Child.prototype, properties, { constructor: Child });
|
|
127
|
-
Child.prototype.options = { ...this.prototype.options, ...properties.options };
|
|
128
|
-
Child.prototype._initHooks = [];
|
|
129
|
-
return Child;
|
|
130
|
-
};
|
|
131
|
-
Class.include = function (properties) { Object.assign(this.prototype, properties); return this; };
|
|
132
|
-
Class.mergeOptions = function (options) {
|
|
133
|
-
this.prototype.options = { ...this.prototype.options, ...options };
|
|
134
|
-
return this;
|
|
135
|
-
};
|
|
136
|
-
Class.addInitHook = function (hook, ...args) {
|
|
137
|
-
if (!Object.hasOwn(this.prototype, '_initHooks')) this.prototype._initHooks = [];
|
|
138
|
-
this.prototype._initHooks.push(typeof hook === 'function' ? hook : function () { this[hook](...args); });
|
|
139
|
-
return this;
|
|
140
|
-
};
|
|
141
|
-
Class.prototype.callInitHooks = function () {
|
|
142
|
-
if (this._initHooksCalled) return;
|
|
143
|
-
this._initHooksCalled = true;
|
|
144
|
-
const prototypes = [];
|
|
145
|
-
for (let proto = Object.getPrototypeOf(this); proto; proto = Object.getPrototypeOf(proto)) prototypes.unshift(proto);
|
|
146
|
-
for (const proto of prototypes) {
|
|
147
|
-
if (Object.hasOwn(proto, '_initHooks')) for (const hook of proto._initHooks) hook.call(this);
|
|
148
|
-
}
|
|
149
|
-
};
|
|
150
|
-
L.Evented = Class.extend({
|
|
151
|
-
on(types, fn, context) {
|
|
152
|
-
if (typeof types === 'object') {
|
|
153
|
-
for (const [type, handler] of Object.entries(types)) this.on(type, handler, fn);
|
|
154
|
-
} else {
|
|
155
|
-
this._events ||= {};
|
|
156
|
-
for (const type of types.split(/\s+/)) {
|
|
157
|
-
const events = this._events[type] ||= [];
|
|
158
|
-
if (!events.some(event => event.fn === fn && event.context === context)) events.push({ fn, context });
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
return this;
|
|
162
|
-
},
|
|
163
|
-
off(types, fn, context) {
|
|
164
|
-
if (!types) this._events = {};
|
|
165
|
-
else if (typeof types === 'object') {
|
|
166
|
-
for (const [type, handler] of Object.entries(types)) this.off(type, handler, fn);
|
|
167
|
-
} else {
|
|
168
|
-
for (const type of types.split(/\s+/)) {
|
|
169
|
-
if (this._events?.[type]) this._events[type] = fn
|
|
170
|
-
? this._events[type].filter(event => event.fn !== fn || event.context !== context) : [];
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
return this;
|
|
174
|
-
},
|
|
175
|
-
once(types, fn, context) {
|
|
176
|
-
const handler = event => { this.off(types, handler); fn.call(context || this, event); };
|
|
177
|
-
return this.on(types, handler);
|
|
178
|
-
},
|
|
179
|
-
fire(type, data) {
|
|
180
|
-
for (const event of [...this._events?.[type] || []]) {
|
|
181
|
-
event.fn.call(event.context || this, { ...data, type, target: this, sourceTarget: this });
|
|
182
|
-
}
|
|
183
|
-
return this;
|
|
184
|
-
},
|
|
185
|
-
listens(type) { return Boolean(this._events?.[type]?.length); },
|
|
186
|
-
});
|
|
187
|
-
L.Util = {
|
|
188
|
-
stamp, setOptions,
|
|
189
|
-
throttle(fn, interval, context) {
|
|
190
|
-
let timer, pending;
|
|
191
|
-
const run = (...args) => {
|
|
192
|
-
if (timer) { pending = args; return; }
|
|
193
|
-
fn.apply(context, args);
|
|
194
|
-
timer = setTimeout(() => {
|
|
195
|
-
timer = null;
|
|
196
|
-
if (pending) { const args = pending; pending = null; run(...args); }
|
|
197
|
-
}, interval);
|
|
198
|
-
};
|
|
199
|
-
return run;
|
|
200
|
-
},
|
|
201
|
-
};
|
|
202
|
-
|
|
203
|
-
L.Point = function (x, y, round) {
|
|
204
|
-
this.x = round ? Math.round(x) : x;
|
|
205
|
-
this.y = round ? Math.round(y) : y;
|
|
206
|
-
};
|
|
207
|
-
const point = value => value instanceof L.Point ? value
|
|
208
|
-
: Array.isArray(value) ? new L.Point(...value) : new L.Point(value.x, value.y);
|
|
209
|
-
L.Point.prototype = {
|
|
210
|
-
clone() { return new L.Point(this.x, this.y); },
|
|
211
|
-
add(value) { return this.clone()._add(point(value)); },
|
|
212
|
-
_add(value) { this.x += value.x; this.y += value.y; return this; },
|
|
213
|
-
subtract(value) { return this.clone()._subtract(point(value)); },
|
|
214
|
-
_subtract(value) { this.x -= value.x; this.y -= value.y; return this; },
|
|
215
|
-
multiplyBy(value) { return new L.Point(this.x * value, this.y * value); },
|
|
216
|
-
divideBy(value) { return new L.Point(this.x / value, this.y / value); },
|
|
217
|
-
scaleBy(value) { return new L.Point(this.x * value.x, this.y * value.y); },
|
|
218
|
-
unscaleBy(value) { return new L.Point(this.x / value.x, this.y / value.y); },
|
|
219
|
-
round() { return new L.Point(Math.round(this.x), Math.round(this.y)); },
|
|
220
|
-
floor() { return new L.Point(Math.floor(this.x), Math.floor(this.y)); },
|
|
221
|
-
ceil() { return new L.Point(Math.ceil(this.x), Math.ceil(this.y)); },
|
|
222
|
-
distanceTo(value) { value = point(value); return Math.hypot(this.x - value.x, this.y - value.y); },
|
|
223
|
-
equals(value) { value = point(value); return this.x === value.x && this.y === value.y; },
|
|
224
|
-
contains(value) { value = point(value); return Math.abs(value.x) <= Math.abs(this.x) && Math.abs(value.y) <= Math.abs(this.y); },
|
|
225
|
-
};
|
|
226
|
-
L.LatLng = function (lat, lng, alt) {
|
|
227
|
-
if (!Number.isFinite(Number(lat)) || !Number.isFinite(Number(lng))) throw new Error('Invalid LatLng');
|
|
228
|
-
this.lat = Number(lat); this.lng = Number(lng);
|
|
229
|
-
if (alt !== undefined) this.alt = alt;
|
|
230
|
-
};
|
|
231
|
-
const latLng = value => value instanceof L.LatLng ? value
|
|
232
|
-
: Array.isArray(value) ? new L.LatLng(...value) : new L.LatLng(value.lat, value.lng);
|
|
233
|
-
L.LatLng.prototype = {
|
|
234
|
-
equals(value, margin = 1e-9) {
|
|
235
|
-
value = latLng(value);
|
|
236
|
-
return Math.max(Math.abs(this.lat - value.lat), Math.abs(this.lng - value.lng)) <= margin;
|
|
237
|
-
},
|
|
238
|
-
distanceTo(value) { value = latLng(value); return ol.sphere.getDistance([this.lng, this.lat], [value.lng, value.lat]); },
|
|
239
|
-
wrap() { return new L.LatLng(this.lat, ((this.lng + 180) % 360 + 360) % 360 - 180, this.alt); },
|
|
240
|
-
};
|
|
241
|
-
L.Bounds = function (a, b) {
|
|
242
|
-
if (a) for (const value of b ? [a, b] : Array.isArray(a) ? a : [a]) this.extend(value);
|
|
243
|
-
};
|
|
244
|
-
L.Bounds.prototype = {
|
|
245
|
-
extend(value) {
|
|
246
|
-
if (value instanceof L.Bounds) { this.extend(value.min); this.extend(value.max); return this; }
|
|
247
|
-
value = point(value);
|
|
248
|
-
if (!this.min) { this.min = value.clone(); this.max = value.clone(); }
|
|
249
|
-
else {
|
|
250
|
-
this.min.x = Math.min(this.min.x, value.x); this.min.y = Math.min(this.min.y, value.y);
|
|
251
|
-
this.max.x = Math.max(this.max.x, value.x); this.max.y = Math.max(this.max.y, value.y);
|
|
252
|
-
}
|
|
253
|
-
return this;
|
|
254
|
-
},
|
|
255
|
-
getCenter() { return this.min.add(this.max).divideBy(2); },
|
|
256
|
-
getSize() { return this.max.subtract(this.min); },
|
|
257
|
-
contains(value) {
|
|
258
|
-
const min = value.min || point(value), max = value.max || min;
|
|
259
|
-
return min.x >= this.min.x && max.x <= this.max.x && min.y >= this.min.y && max.y <= this.max.y;
|
|
260
|
-
},
|
|
261
|
-
intersects(value) {
|
|
262
|
-
return value.max.x >= this.min.x && value.min.x <= this.max.x && value.max.y >= this.min.y && value.min.y <= this.max.y;
|
|
263
|
-
},
|
|
264
|
-
};
|
|
265
|
-
L.LatLngBounds = function (a, b) {
|
|
266
|
-
if (a) for (const value of b ? [a, b] : a) this.extend(value);
|
|
267
|
-
};
|
|
268
|
-
L.LatLngBounds.prototype = {
|
|
269
|
-
extend(value) {
|
|
270
|
-
if (value instanceof L.LatLngBounds) { this.extend(value._southWest); this.extend(value._northEast); return this; }
|
|
271
|
-
value = latLng(value);
|
|
272
|
-
if (!this._southWest) {
|
|
273
|
-
this._southWest = new L.LatLng(value.lat, value.lng);
|
|
274
|
-
this._northEast = new L.LatLng(value.lat, value.lng);
|
|
275
|
-
} else {
|
|
276
|
-
this._southWest.lat = Math.min(this._southWest.lat, value.lat);
|
|
277
|
-
this._southWest.lng = Math.min(this._southWest.lng, value.lng);
|
|
278
|
-
this._northEast.lat = Math.max(this._northEast.lat, value.lat);
|
|
279
|
-
this._northEast.lng = Math.max(this._northEast.lng, value.lng);
|
|
280
|
-
}
|
|
281
|
-
return this;
|
|
282
|
-
},
|
|
283
|
-
getSouthWest() { return this._southWest; },
|
|
284
|
-
getNorthEast() { return this._northEast; },
|
|
285
|
-
getNorthWest() { return new L.LatLng(this.getNorth(), this.getWest()); },
|
|
286
|
-
getSouthEast() { return new L.LatLng(this.getSouth(), this.getEast()); },
|
|
287
|
-
getNorth() { return this._northEast.lat; },
|
|
288
|
-
getSouth() { return this._southWest.lat; },
|
|
289
|
-
getEast() { return this._northEast.lng; },
|
|
290
|
-
getWest() { return this._southWest.lng; },
|
|
291
|
-
getCenter() { return new L.LatLng((this.getNorth() + this.getSouth()) / 2, (this.getEast() + this.getWest()) / 2); },
|
|
292
|
-
contains(value) {
|
|
293
|
-
value = latLng(value);
|
|
294
|
-
return value.lat >= this.getSouth() && value.lat <= this.getNorth() && value.lng >= this.getWest() && value.lng <= this.getEast();
|
|
295
|
-
},
|
|
296
|
-
isValid() { return Boolean(this._southWest && this._northEast); },
|
|
297
|
-
};
|
|
298
|
-
|
|
299
|
-
const radius = 6378137, circumference = 2 * Math.PI * radius;
|
|
300
|
-
const crs = {
|
|
301
|
-
scale: zoom => 256 * 2 ** zoom,
|
|
302
|
-
zoom: scale => Math.log2(scale / 256),
|
|
303
|
-
project(value) { value = latLng(value); return point(ol.proj.fromLonLat([value.lng, Math.max(-85.0511287798, Math.min(85.0511287798, value.lat))])); },
|
|
304
|
-
unproject(value) { const [lng, lat] = ol.proj.toLonLat([value.x, value.y]); return new L.LatLng(lat, lng); },
|
|
305
|
-
transformation: {
|
|
306
|
-
transform(value, scale) { return new L.Point((value.x / circumference + 0.5) * scale, (0.5 - value.y / circumference) * scale); },
|
|
307
|
-
untransform(value, scale) { return new L.Point((value.x / scale - 0.5) * circumference, (0.5 - value.y / scale) * circumference); },
|
|
308
|
-
},
|
|
309
|
-
};
|
|
310
|
-
|
|
311
|
-
L.DomUtil = {
|
|
312
|
-
create(tag, className = '', parent) {
|
|
313
|
-
const element = document.createElement(tag);
|
|
314
|
-
element.className = className; parent?.append(element); return element;
|
|
315
|
-
},
|
|
316
|
-
setPosition(element, value) { element._leaflet_pos = point(value); element.style.transform = `translate(${value.x}px,${value.y}px)`; },
|
|
317
|
-
getPosition(element) { return element._leaflet_pos || new L.Point(0, 0); },
|
|
318
|
-
};
|
|
319
|
-
const domListeners = new WeakMap();
|
|
320
|
-
function domEvent(add, element, types, fn, context) {
|
|
321
|
-
if (typeof types === 'object') {
|
|
322
|
-
for (const [type, handler] of Object.entries(types)) domEvent(add, element, type, handler, fn);
|
|
323
|
-
return L.DomEvent;
|
|
324
|
-
}
|
|
325
|
-
let listeners = domListeners.get(element);
|
|
326
|
-
if (!listeners) domListeners.set(element, listeners = []);
|
|
327
|
-
for (const type of types.split(/\s+/)) {
|
|
328
|
-
const existing = listeners.find(item => item.type === type && item.fn === fn && item.context === context);
|
|
329
|
-
if (add && !existing) {
|
|
330
|
-
const handler = context ? fn.bind(context) : fn;
|
|
331
|
-
listeners.push({ type, fn, context, handler });
|
|
332
|
-
element.addEventListener(type, handler, { passive: false });
|
|
333
|
-
} else if (!add && existing) {
|
|
334
|
-
element.removeEventListener(type, existing.handler);
|
|
335
|
-
listeners.splice(listeners.indexOf(existing), 1);
|
|
336
|
-
}
|
|
337
|
-
}
|
|
338
|
-
return L.DomEvent;
|
|
339
|
-
}
|
|
340
|
-
const stopPropagation = event => event.stopPropagation();
|
|
341
|
-
L.DomEvent = {
|
|
342
|
-
on: (...args) => domEvent(true, ...args),
|
|
343
|
-
off: (...args) => domEvent(false, ...args),
|
|
344
|
-
stop(event) { event.preventDefault(); event.stopPropagation(); },
|
|
345
|
-
disableClickPropagation(element) {
|
|
346
|
-
element.classList.add('leaflet-control');
|
|
347
|
-
L.DomEvent.on(element, 'click dblclick pointerdown mousedown touchstart contextmenu', stopPropagation);
|
|
348
|
-
return this;
|
|
349
|
-
},
|
|
350
|
-
disableScrollPropagation(element) { return this.on(element, 'wheel', stopPropagation); },
|
|
351
|
-
};
|
|
352
|
-
L.Handler = Class.extend({
|
|
353
|
-
initialize(map) { this._map = map; },
|
|
354
|
-
enable() { if (!this._enabled) { this._enabled = true; this.addHooks?.(); } return this; },
|
|
355
|
-
disable() { if (this._enabled) { this._enabled = false; this.removeHooks?.(); } return this; },
|
|
356
|
-
enabled() { return Boolean(this._enabled); },
|
|
357
|
-
moving() { return Boolean(this._moving); },
|
|
358
|
-
});
|
|
359
|
-
L.Layer = L.Evented.extend({
|
|
360
|
-
initialize(options) { setOptions(this, options); },
|
|
361
|
-
addTo(map) { map.addLayer(this); return this; },
|
|
362
|
-
remove() { return this.removeFrom(this._map || this._mapToAdd); },
|
|
363
|
-
removeFrom(map) { map?.removeLayer(this); return this; },
|
|
364
|
-
getAttribution() { return this.options.attribution; },
|
|
365
|
-
getPane(name) { return this._map.getPane(name || this.options.pane); },
|
|
366
|
-
_layerAdd({ target: map }) {
|
|
367
|
-
if (!map.hasLayer(this)) return;
|
|
368
|
-
this._map = map;
|
|
369
|
-
if (this.getEvents) { this._mapEvents = this.getEvents(); map.on(this._mapEvents, this); }
|
|
370
|
-
this.onAdd?.(map);
|
|
371
|
-
this.fire('add'); map.fire('layeradd', { layer: this });
|
|
372
|
-
},
|
|
373
|
-
});
|
|
374
|
-
L.LayerGroup = L.Layer.extend({
|
|
375
|
-
initialize(layers = [], options) {
|
|
376
|
-
setOptions(this, options); this._layers = {};
|
|
377
|
-
for (const layer of layers) this.addLayer(layer);
|
|
378
|
-
},
|
|
379
|
-
addLayer(layer) { this._layers[stamp(layer)] = layer; this._map?.addLayer(layer); return this; },
|
|
380
|
-
removeLayer(layer) { delete this._layers[stamp(layer)]; this._map?.removeLayer(layer); return this; },
|
|
381
|
-
hasLayer(layer) { return stamp(layer) in this._layers; },
|
|
382
|
-
eachLayer(fn, context) { for (const layer of Object.values(this._layers)) fn.call(context || this, layer); return this; },
|
|
383
|
-
onAdd(map) { this.eachLayer(map.addLayer, map); },
|
|
384
|
-
onRemove(map) { this.eachLayer(map.removeLayer, map); },
|
|
385
|
-
});
|
|
386
|
-
// Declare the hierarchy before the plugin installs its instanceof checks and hooks.
|
|
387
|
-
for (const [name, parent] of [
|
|
388
|
-
['GridLayer', L.Layer], ['Marker', L.Layer], ['Path', L.Layer],
|
|
389
|
-
['Polyline', null], ['Polygon', null], ['CircleMarker', null], ['Circle', null],
|
|
390
|
-
['ImageOverlay', L.Layer], ['VideoOverlay', null], ['SVGOverlay', null],
|
|
391
|
-
['Popup', L.Layer], ['Tooltip', L.Layer], ['DivIcon', Class],
|
|
392
|
-
]) {
|
|
393
|
-
const base = parent || ({ Polyline: L.Path, Polygon: L.Polyline, CircleMarker: L.Path,
|
|
394
|
-
Circle: L.CircleMarker, VideoOverlay: L.ImageOverlay, SVGOverlay: L.ImageOverlay })[name];
|
|
395
|
-
L[name] = base.extend({
|
|
396
|
-
initialize() { throw new Error(`L.${name} is not supported by the OpenLayers bindings; use L.Layer with a source`); },
|
|
397
|
-
getEvents() { return {}; },
|
|
398
|
-
});
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
L.Map = L.Evented.extend({
|
|
402
|
-
options: { crs, minZoom: 0, maxZoom: 24, zoomSnap: 1, touchZoom: true,
|
|
403
|
-
scrollWheelZoom: true, keyboard: true, doubleClickZoom: true,
|
|
404
|
-
wheelDebounceTime: 40, wheelPxPerZoomLevel: 60 },
|
|
405
|
-
initialize(target, options) {
|
|
406
|
-
setOptions(this, options);
|
|
407
|
-
this._container = typeof target === 'string' ? document.getElementById(target) : target;
|
|
408
|
-
if (!this._container) throw new Error('Map container not found');
|
|
409
|
-
stamp(this._container);
|
|
410
|
-
this._container.classList.add('openlayers-city-mapper');
|
|
411
|
-
this._layers = {}; this._panes = {}; this._handlers = []; this._controls = new Set();
|
|
412
|
-
const center = crs.project(this.options.center || [0, 0]);
|
|
413
|
-
this.ol = new ol.Map({
|
|
414
|
-
target: this._container, controls: [new ol.control.Zoom(), new ol.control.Attribution({collapsible: false })],
|
|
415
|
-
interactions: [],
|
|
416
|
-
view: new ol.View({ center: [center.x, center.y], zoom: this.options.zoom || 0,
|
|
417
|
-
minZoom: this.getMinZoom(), maxZoom: this.getMaxZoom() }),
|
|
418
|
-
});
|
|
419
|
-
for (const control of this.ol.getControls().getArray()) {
|
|
420
|
-
control.element.classList.add('leaflet-control');
|
|
421
|
-
for (const button of control.element.querySelectorAll('button[title]')) button.setAttribute('aria-label', button.title);
|
|
422
|
-
if (control instanceof ol.control.Zoom) {
|
|
423
|
-
for (const [selector, delta] of [['.ol-zoom-in', 1], ['.ol-zoom-out', -1]]) {
|
|
424
|
-
control.element.querySelector(selector).addEventListener('click', event => {
|
|
425
|
-
L.DomEvent.stop(event);
|
|
426
|
-
event.stopImmediatePropagation();
|
|
427
|
-
this._zoomBy(delta * (event.shiftKey ? 3 : 1));
|
|
428
|
-
}, true);
|
|
429
|
-
}
|
|
430
|
-
}
|
|
431
|
-
}
|
|
432
|
-
this._loaded = true;
|
|
433
|
-
this._zoomAnimated = false;
|
|
434
|
-
this.dragging = new L.Handler(this).enable();
|
|
435
|
-
this.touchZoom = new L.Handler(this);
|
|
436
|
-
if (this.options.touchZoom) this.touchZoom.enable();
|
|
437
|
-
this._handlers.push(this.dragging, this.touchZoom);
|
|
438
|
-
for (const name of ['scrollWheelZoom', 'keyboard', 'doubleClickZoom']) this.addHandler(name, L.Handler);
|
|
439
|
-
if (!this._container.hasAttribute('tabindex')) this._container.tabIndex = 0;
|
|
440
|
-
const view = this.ol.getView();
|
|
441
|
-
this._viewZoom = view.getZoom();
|
|
442
|
-
view.on(['change:center', 'change:resolution'], () => {
|
|
443
|
-
if (this._settingView) return;
|
|
444
|
-
const zoomChanged = view.getZoom() !== this._viewZoom;
|
|
445
|
-
if (!this._viewMoving) { this._viewMoving = true; this.fire('movestart'); }
|
|
446
|
-
if (zoomChanged && !this._viewZooming) { this._viewZooming = true; this.fire('zoomstart'); }
|
|
447
|
-
this.fire('move');
|
|
448
|
-
if (zoomChanged) this.fire('zoom');
|
|
449
|
-
this._viewZoom = view.getZoom();
|
|
450
|
-
if (!view.getAnimating() && !view.getInteracting()) this._endViewChange();
|
|
451
|
-
});
|
|
452
|
-
this.ol.on('moveend', () => this._endViewChange());
|
|
453
|
-
// OpenLayers interactions need the pitched ground coordinate, not the flat viewport.
|
|
454
|
-
this.ol.getCoordinateFromPixel = pixel => {
|
|
455
|
-
const coordinate = crs.project(this.containerPointToLatLng(point(pixel)));
|
|
456
|
-
return [coordinate.x, coordinate.y];
|
|
457
|
-
};
|
|
458
|
-
this._wheelDelta = 0;
|
|
459
|
-
this.ol.addInteraction(new ol.interaction.Interaction({
|
|
460
|
-
handleEvent: event => {
|
|
461
|
-
const original = event.originalEvent;
|
|
462
|
-
if (original.target.closest('.ol-control')) return true;
|
|
463
|
-
if (event.type === 'dblclick' && this.doubleClickZoom.enabled()) {
|
|
464
|
-
this._zoomBy(original.shiftKey ? -1 : 1, point(event.pixel));
|
|
465
|
-
} else if (event.type === 'wheel' && this.scrollWheelZoom.enabled() && !original.shiftKey) {
|
|
466
|
-
const ratio = window.devicePixelRatio || 1;
|
|
467
|
-
const factor = /Linux/.test(navigator.platform) && /Chrome/.test(navigator.userAgent) ? ratio
|
|
468
|
-
: /Mac/.test(navigator.platform) ? 3 * ratio : 2 * ratio;
|
|
469
|
-
this._wheelDelta -= original.deltaY * (original.deltaMode === 1 ? 20
|
|
470
|
-
: original.deltaMode === 2 ? 60 : 1 / factor);
|
|
471
|
-
this._wheelPixel = point(event.pixel);
|
|
472
|
-
this._wheelStart ??= performance.now();
|
|
473
|
-
clearTimeout(this._wheelTimer);
|
|
474
|
-
this._wheelTimer = setTimeout(() => {
|
|
475
|
-
const magnitude = 4 * Math.log2(2 / (1 + Math.exp(-Math.abs(this._wheelDelta /
|
|
476
|
-
(this.options.wheelPxPerZoomLevel * 4)))));
|
|
477
|
-
const snap = this.options.zoomSnap;
|
|
478
|
-
const delta = Math.sign(this._wheelDelta) * (snap ? Math.ceil(magnitude / snap) * snap : magnitude);
|
|
479
|
-
this._wheelDelta = 0;
|
|
480
|
-
this._wheelStart = null;
|
|
481
|
-
if (this._loaded && this.scrollWheelZoom.enabled()) this._zoomBy(delta,
|
|
482
|
-
this.options.scrollWheelZoom === 'center' ? undefined : this._wheelPixel);
|
|
483
|
-
}, Math.max(0, this.options.wheelDebounceTime - (performance.now() - this._wheelStart)));
|
|
484
|
-
} else return true;
|
|
485
|
-
original.preventDefault();
|
|
486
|
-
return false;
|
|
487
|
-
},
|
|
488
|
-
}));
|
|
489
|
-
this._controlCorners = {};
|
|
490
|
-
for (const position of ['topleft', 'topright', 'bottomleft', 'bottomright']) {
|
|
491
|
-
this._controlCorners[position] = L.DomUtil.create('div',
|
|
492
|
-
`ol-city-corner ol-city-${position}`, this.ol.getOverlayContainerStopEvent());
|
|
493
|
-
}
|
|
494
|
-
const attributionSource = new ol.source.Vector();
|
|
495
|
-
this.ol.addLayer(new ol.layer.Vector({ source: attributionSource }));
|
|
496
|
-
const updateAttribution = () => {
|
|
497
|
-
const values = new Set(['<a href="https://openlayers.org/">OpenLayers</a>']);
|
|
498
|
-
this.eachLayer(layer => { if (layer.getAttribution?.()) values.add(layer.getAttribution()); });
|
|
499
|
-
attributionSource.setAttributions([...values]);
|
|
500
|
-
};
|
|
501
|
-
this.on('layeradd layerremove', updateAttribution);
|
|
502
|
-
updateAttribution();
|
|
503
|
-
let anchor, pointerId;
|
|
504
|
-
const pixel = event => {
|
|
505
|
-
const rect = this._container.getBoundingClientRect();
|
|
506
|
-
return new L.Point(event.clientX - rect.left, event.clientY - rect.top);
|
|
507
|
-
};
|
|
508
|
-
this._onPointer = event => {
|
|
509
|
-
if (event.type === 'pointerdown') {
|
|
510
|
-
if (!this.dragging.enabled() || event.button !== 0 || !event.isPrimary || event.target.closest('.ol-control')) return;
|
|
511
|
-
anchor = this.containerPointToLatLng(pixel(event)); pointerId = event.pointerId;
|
|
512
|
-
this._moved = this.dragging._moving = false;
|
|
513
|
-
this._container.focus({ preventScroll: true });
|
|
514
|
-
this._container.setPointerCapture(pointerId);
|
|
515
|
-
} else if (event.pointerId === pointerId && event.type === 'pointermove' && this.dragging.enabled()) {
|
|
516
|
-
const delta = this.project(anchor).subtract(this.project(this.containerPointToLatLng(pixel(event))));
|
|
517
|
-
if (Math.hypot(delta.x, delta.y) > 1) this._moved = this.dragging._moving = true;
|
|
518
|
-
this.setView(this.unproject(this.project(this.getCenter()).add(delta)), this.getZoom());
|
|
519
|
-
} else if (event.pointerId === pointerId && event.type !== 'pointermove') {
|
|
520
|
-
if (this._container.hasPointerCapture(pointerId)) this._container.releasePointerCapture(pointerId);
|
|
521
|
-
anchor = null; pointerId = null;
|
|
522
|
-
this.dragging._moving = false;
|
|
523
|
-
}
|
|
524
|
-
};
|
|
525
|
-
this._onKey = event => {
|
|
526
|
-
if (!this.keyboard.enabled() || event.target !== this._container || event.altKey || event.ctrlKey || event.metaKey) return;
|
|
527
|
-
const offsets = { ArrowLeft: [-80, 0], ArrowRight: [80, 0], ArrowUp: [0, -80], ArrowDown: [0, 80] };
|
|
528
|
-
if (offsets[event.key]) this.panBy(offsets[event.key]);
|
|
529
|
-
else if (['+', '=', '-', '_'].includes(event.key)) this._zoomBy(
|
|
530
|
-
(['-', '_'].includes(event.key) ? -1 : 1) * (event.shiftKey ? 3 : 1));
|
|
531
|
-
else return;
|
|
532
|
-
event.preventDefault();
|
|
533
|
-
};
|
|
534
|
-
L.DomEvent.on(this._container, 'pointerdown pointermove pointerup pointercancel', this._onPointer);
|
|
535
|
-
L.DomEvent.on(this._container, 'keydown', this._onKey);
|
|
536
|
-
this.ol.on('change:size', () => this.fire('resize', { newSize: this.getSize() }));
|
|
537
|
-
this.ol.updateSize();
|
|
538
|
-
},
|
|
539
|
-
getContainer() { return this._container; },
|
|
540
|
-
getSize() { return point(this.ol.getSize() || [this._container.clientWidth, this._container.clientHeight]); },
|
|
541
|
-
getCenter() { return crs.unproject(point(this.ol.getView().getCenter())); },
|
|
542
|
-
getZoom() { return this.ol.getView().getZoom(); },
|
|
543
|
-
getMinZoom() { return this.options.minZoom; },
|
|
544
|
-
getMaxZoom() { return this.options.maxZoom; },
|
|
545
|
-
getZoomScale(to, from = this.getZoom()) { return 2 ** (to - from); },
|
|
546
|
-
getScaleZoom(scale, from = this.getZoom()) { return from + Math.log2(scale); },
|
|
547
|
-
_limitZoom(zoom) { return Math.max(this.getMinZoom(), Math.min(this.getMaxZoom(), zoom)); },
|
|
548
|
-
project(value, zoom = this.getZoom()) { return crs.transformation.transform(crs.project(value), crs.scale(zoom)); },
|
|
549
|
-
unproject(value, zoom = this.getZoom()) { return crs.unproject(crs.transformation.untransform(point(value), crs.scale(zoom))); },
|
|
550
|
-
getPixelOrigin() { return this.project(this.getCenter()).subtract(this.getSize().divideBy(2)); },
|
|
551
|
-
_getMapPanePos() { return new L.Point(0, 0); },
|
|
552
|
-
latLngToLayerPoint(value) { return this.project(value).subtract(this.getPixelOrigin()); },
|
|
553
|
-
layerPointToLatLng(value) { return this.unproject(point(value).add(this.getPixelOrigin())); },
|
|
554
|
-
layerPointToContainerPoint(value) { return point(value).clone(); },
|
|
555
|
-
containerPointToLayerPoint(value) { return point(value).clone(); },
|
|
556
|
-
latLngToContainerPoint(value) { return this.layerPointToContainerPoint(this.latLngToLayerPoint(value)); },
|
|
557
|
-
containerPointToLatLng(value) { return this.layerPointToLatLng(this.containerPointToLayerPoint(value)); },
|
|
558
|
-
getBounds() { return new L.LatLngBounds(this.containerPointToLatLng([0, 0]), this.containerPointToLatLng(this.getSize())); },
|
|
559
|
-
_endViewChange() {
|
|
560
|
-
if (!this._viewMoving) return;
|
|
561
|
-
const zooming = this._viewZooming;
|
|
562
|
-
this._viewMoving = this._viewZooming = false;
|
|
563
|
-
if (zooming) this.fire('zoomend');
|
|
564
|
-
this.fire('moveend');
|
|
565
|
-
},
|
|
566
|
-
_zoomBy(delta, pixel) {
|
|
567
|
-
if (!delta || this.ol.getView().getAnimating()) return this;
|
|
568
|
-
const zoom = this._limitZoom(this.getZoom() + delta);
|
|
569
|
-
return pixel ? this.setZoomAround(pixel, zoom, { animate: true })
|
|
570
|
-
: this.setZoom(zoom, { animate: true });
|
|
571
|
-
},
|
|
572
|
-
setView(center, zoom = this.getZoom(), options = {}) {
|
|
573
|
-
center = latLng(center); zoom = this._limitZoom(zoom);
|
|
574
|
-
if ((options.animate === true || options.zoom?.animate === true) && zoom !== this.getZoom()) {
|
|
575
|
-
const scale = this.getZoomScale(zoom), projected = crs.project(center);
|
|
576
|
-
// Leaflet animates CSS scale, not resolution; convert the same native CSS easing.
|
|
577
|
-
this.ol.getView().animate({
|
|
578
|
-
center: [projected.x, projected.y], zoom, duration: 250,
|
|
579
|
-
easing: time => {
|
|
580
|
-
zoomTiming.currentTime = time;
|
|
581
|
-
const progress = zoomTiming.effect.getComputedTiming().progress;
|
|
582
|
-
return (1 - 1 / (1 + (scale - 1) * progress)) / (1 - 1 / scale);
|
|
583
|
-
},
|
|
584
|
-
});
|
|
585
|
-
return this;
|
|
586
|
-
}
|
|
587
|
-
this.ol.getView().cancelAnimations();
|
|
588
|
-
this._endViewChange();
|
|
589
|
-
const zoomChanged = zoom !== this.getZoom(), moved = !center.equals(this.getCenter());
|
|
590
|
-
if (!zoomChanged && !moved) return this;
|
|
591
|
-
this.fire('movestart');
|
|
592
|
-
if (zoomChanged) this.fire('zoomstart');
|
|
593
|
-
this._settingView = true;
|
|
594
|
-
const projected = crs.project(center);
|
|
595
|
-
this.ol.getView().setCenter([projected.x, projected.y]);
|
|
596
|
-
this.ol.getView().setZoom(zoom);
|
|
597
|
-
this._viewZoom = this.getZoom();
|
|
598
|
-
this._settingView = false;
|
|
599
|
-
if (zoomChanged) this.fire('zoom');
|
|
600
|
-
this.fire('move').fire('viewreset');
|
|
601
|
-
if (zoomChanged) this.fire('zoomend');
|
|
602
|
-
return this.fire('moveend');
|
|
603
|
-
},
|
|
604
|
-
setZoom(zoom, options) { return this.setView(this.getCenter(), zoom, options); },
|
|
605
|
-
panTo(center) { return this.setView(center); },
|
|
606
|
-
panBy(offset) { return this.panTo(this.unproject(this.project(this.getCenter()).add(point(offset)))); },
|
|
607
|
-
setZoomAround(value, zoom, options) {
|
|
608
|
-
const anchor = value instanceof L.Point ? value : this.latLngToContainerPoint(value);
|
|
609
|
-
const half = this.getSize().divideBy(2), scale = this.getZoomScale(zoom);
|
|
610
|
-
return this.setView(this.unproject(this.project(this.getCenter()).add(anchor.subtract(half).multiplyBy(1 - 1 / scale))), zoom, options);
|
|
611
|
-
},
|
|
612
|
-
getBoundsZoom(bounds, inside, padding = [0, 0]) {
|
|
613
|
-
const size = this.project(bounds.getSouthEast()).subtract(this.project(bounds.getNorthWest()));
|
|
614
|
-
const available = this.getSize().subtract(point(padding));
|
|
615
|
-
const scale = Math[inside ? 'max' : 'min'](available.x / size.x, available.y / size.y);
|
|
616
|
-
return this._limitZoom(this.getScaleZoom(scale));
|
|
617
|
-
},
|
|
618
|
-
_getBoundsCenterZoom(bounds, options = {}) { return { center: bounds.getCenter(), zoom: this.getBoundsZoom(bounds, false, options.padding) }; },
|
|
619
|
-
fitBounds(bounds, options) { const view = this._getBoundsCenterZoom(bounds, options); return this.setView(view.center, view.zoom); },
|
|
620
|
-
_limitCenter(center) { return center; },
|
|
621
|
-
_limitOffset(offset) { return offset; },
|
|
622
|
-
_tryAnimatedPan() { return false; },
|
|
623
|
-
panInside(value) { if (!this.getBounds().contains(value)) this.panTo(value); return this; },
|
|
624
|
-
whenReady(fn, context) { if (this._loaded) fn.call(context || this, { target: this }); else this.once('load', fn, context); return this; },
|
|
625
|
-
addLayer(layer) {
|
|
626
|
-
const id = stamp(layer);
|
|
627
|
-
if (this._layers[id]) return this;
|
|
628
|
-
this._layers[id] = layer; layer._mapToAdd = this;
|
|
629
|
-
layer.beforeAdd?.(this);
|
|
630
|
-
this.whenReady(layer._layerAdd, layer);
|
|
631
|
-
return this;
|
|
632
|
-
},
|
|
633
|
-
removeLayer(layer) {
|
|
634
|
-
if (!this.hasLayer(layer)) return this;
|
|
635
|
-
layer.onRemove?.(this);
|
|
636
|
-
if (layer._mapEvents) this.off(layer._mapEvents, layer);
|
|
637
|
-
delete this._layers[stamp(layer)];
|
|
638
|
-
this.fire('layerremove', { layer }); layer.fire('remove');
|
|
639
|
-
layer._map = layer._mapToAdd = null;
|
|
640
|
-
return this;
|
|
641
|
-
},
|
|
642
|
-
hasLayer(layer) { return Boolean(this._layers[stamp(layer)]); },
|
|
643
|
-
eachLayer(fn, context) { for (const layer of Object.values(this._layers)) fn.call(context || this, layer); return this; },
|
|
644
|
-
createPane(name, parent = this._container) { return this._panes[name] = L.DomUtil.create('div', `leaflet-pane leaflet-${name}`, parent); },
|
|
645
|
-
getPane(name = 'overlayPane') { return this._panes[name]; },
|
|
646
|
-
addHandler(name, Handler) { this[name] = new Handler(this); this._handlers.push(this[name]); if (this.options[name]) this[name].enable(); return this; },
|
|
647
|
-
invalidateSize() { this.ol.updateSize(); return this; },
|
|
648
|
-
_draggableMoved() { return Boolean(this._moved); },
|
|
649
|
-
remove() {
|
|
650
|
-
clearTimeout(this._wheelTimer);
|
|
651
|
-
this.ol.getView().cancelAnimations();
|
|
652
|
-
this.fire('unload');
|
|
653
|
-
for (const control of [...this._controls]) control.remove();
|
|
654
|
-
this.eachLayer(this.removeLayer, this);
|
|
655
|
-
for (const handler of this._handlers) handler.disable();
|
|
656
|
-
L.DomEvent.off(this._container, 'pointerdown pointermove pointerup pointercancel', this._onPointer);
|
|
657
|
-
L.DomEvent.off(this._container, 'keydown', this._onKey);
|
|
658
|
-
this.ol.setTarget(undefined); this.ol.dispose();
|
|
659
|
-
for (const corner of Object.values(this._controlCorners)) corner.remove();
|
|
660
|
-
for (const pane of Object.values(this._panes)) pane.remove();
|
|
661
|
-
this._loaded = false;
|
|
662
|
-
delete this._container._leaflet_id;
|
|
663
|
-
return this.off();
|
|
664
|
-
},
|
|
665
|
-
});
|
|
666
|
-
|
|
667
|
-
L.Control = Class.extend({
|
|
668
|
-
options: { position: 'topright' },
|
|
669
|
-
initialize(options) { setOptions(this, options); },
|
|
670
|
-
getPosition() { return this.options.position; },
|
|
671
|
-
getContainer() { return this._container; },
|
|
672
|
-
addTo(map) {
|
|
673
|
-
this.remove(); this._map = map;
|
|
674
|
-
this._container = this.onAdd(map);
|
|
675
|
-
if (L.Control.Rotate && this instanceof L.Control.Rotate) {
|
|
676
|
-
this._container.classList.add('ol-city-rotate');
|
|
677
|
-
}
|
|
678
|
-
this._container.classList.add('leaflet-control', 'ol-control', 'ol-city-control');
|
|
679
|
-
this._olControl = new ol.control.Control({
|
|
680
|
-
element: this._container, target: map._controlCorners[this.getPosition()],
|
|
681
|
-
});
|
|
682
|
-
map.ol.addControl(this._olControl);
|
|
683
|
-
map._controls.add(this);
|
|
684
|
-
return this;
|
|
685
|
-
},
|
|
686
|
-
remove() {
|
|
687
|
-
if (!this._map) return this;
|
|
688
|
-
const map = this._map;
|
|
689
|
-
this.onRemove?.(map); this._container?.remove();
|
|
690
|
-
map.ol.removeControl(this._olControl);
|
|
691
|
-
map._controls.delete(this); this._map = null;
|
|
692
|
-
return this;
|
|
693
|
-
},
|
|
694
|
-
});
|
|
695
|
-
L.Control.Layers = L.Control.extend({
|
|
696
|
-
options: { collapsed: true },
|
|
697
|
-
initialize(base = {}, overlays = {}, options) {
|
|
698
|
-
setOptions(this, options); this._layers = [];
|
|
699
|
-
for (const [name, layer] of Object.entries(base)) this._layers.push({ name, layer, overlay: false });
|
|
700
|
-
for (const [name, layer] of Object.entries(overlays)) this._layers.push({ name, layer, overlay: true });
|
|
701
|
-
},
|
|
702
|
-
onAdd(map) {
|
|
703
|
-
const container = L.DomUtil.create('div', 'ol-city-layers');
|
|
704
|
-
L.DomEvent.disableClickPropagation(container); L.DomEvent.disableScrollPropagation(container);
|
|
705
|
-
const list = L.DomUtil.create('section', '', container);
|
|
706
|
-
list.setAttribute('aria-label', 'Map layers');
|
|
707
|
-
const base = L.DomUtil.create('div', '', list);
|
|
708
|
-
L.DomUtil.create('hr', '', list);
|
|
709
|
-
const overlays = L.DomUtil.create('div', '', list);
|
|
710
|
-
this._inputs = [];
|
|
711
|
-
for (const entry of this._layers) {
|
|
712
|
-
const label = L.DomUtil.create('label', '', entry.overlay ? overlays : base);
|
|
713
|
-
const input = L.DomUtil.create('input', 'leaflet-control-layers-selector', label);
|
|
714
|
-
input.type = entry.overlay ? 'checkbox' : 'radio';
|
|
715
|
-
input.name = `base-${stamp(this)}`; input.layerId = stamp(entry.layer);
|
|
716
|
-
input.checked = map.hasLayer(entry.layer);
|
|
717
|
-
label.append(document.createTextNode(` ${entry.name}`));
|
|
718
|
-
this._inputs.push(input);
|
|
719
|
-
input.onchange = () => {
|
|
720
|
-
const checked = input.checked;
|
|
721
|
-
if (!entry.overlay) for (const other of this._layers) {
|
|
722
|
-
if (!other.overlay && other !== entry) map.removeLayer(other.layer);
|
|
723
|
-
}
|
|
724
|
-
if (checked) map.addLayer(entry.layer); else map.removeLayer(entry.layer);
|
|
725
|
-
};
|
|
726
|
-
}
|
|
727
|
-
map.on('layeradd layerremove', this._update, this);
|
|
728
|
-
return container;
|
|
729
|
-
},
|
|
730
|
-
_update() { for (const input of this._inputs) input.checked = Boolean(this._map._layers[input.layerId]); },
|
|
731
|
-
onRemove(map) { map.off('layeradd layerremove', this._update, this); },
|
|
732
|
-
});
|
|
733
|
-
|
|
734
|
-
// Native layer contracts consumed by the plugin's WebGPU renderer.
|
|
735
|
-
const bounds = value => value instanceof L.LatLngBounds ? value : new L.LatLngBounds(value);
|
|
736
|
-
const coordinates = values => values.map(value => Array.isArray(value) && typeof value[0] !== 'number'
|
|
737
|
-
? coordinates(value) : latLng(value));
|
|
738
|
-
const image = (url, options, className) => {
|
|
739
|
-
const element = document.createElement('img');
|
|
740
|
-
element.className = className;
|
|
741
|
-
if (options.crossOrigin) element.crossOrigin = options.crossOrigin === true ? '' : options.crossOrigin;
|
|
742
|
-
element.src = url;
|
|
743
|
-
element.draggable = false;
|
|
744
|
-
return element;
|
|
745
|
-
};
|
|
746
|
-
|
|
747
|
-
L.Layer.include({
|
|
748
|
-
bindPopup(content) {
|
|
749
|
-
this._popupContent = content;
|
|
750
|
-
this.off('click', this.openPopup, this).on('click', this.openPopup, this);
|
|
751
|
-
this.once('remove', this.closePopup, this);
|
|
752
|
-
if (this instanceof L.LayerGroup) this.eachLayer(layer => layer.bindPopup(content));
|
|
753
|
-
return this;
|
|
754
|
-
},
|
|
755
|
-
openPopup(event) {
|
|
756
|
-
if (!this._map) return this;
|
|
757
|
-
this.closePopup();
|
|
758
|
-
const location = event?.latlng || this.getLatLng?.() || this.getBounds?.().getCenter();
|
|
759
|
-
if (!location) throw new Error('Popup requires a location');
|
|
760
|
-
const element = L.DomUtil.create('div', 'ol-city-popup leaflet-popup');
|
|
761
|
-
element.setAttribute('role', 'dialog');
|
|
762
|
-
const close = L.DomUtil.create('button', '', element);
|
|
763
|
-
close.type = 'button'; close.textContent = '\u00d7'; close.setAttribute('aria-label', 'Close popup');
|
|
764
|
-
close.onclick = () => this.closePopup();
|
|
765
|
-
const content = L.DomUtil.create('div', '', element);
|
|
766
|
-
const value = typeof this._popupContent === 'function' ? this._popupContent(this) : this._popupContent;
|
|
767
|
-
if (value instanceof Node) content.append(value); else content.innerHTML = value;
|
|
768
|
-
L.DomEvent.disableClickPropagation(element);
|
|
769
|
-
this._popupOverlay = new ol.Overlay({ element, positioning: 'bottom-center', offset: [0, -12] });
|
|
770
|
-
this._map.ol.addOverlay(this._popupOverlay);
|
|
771
|
-
this._popupLocation = latLng(location);
|
|
772
|
-
this._map.on('move zoom rotate pitch', this._positionPopup, this);
|
|
773
|
-
this._positionPopup();
|
|
774
|
-
return this;
|
|
775
|
-
},
|
|
776
|
-
_positionPopup() {
|
|
777
|
-
const screen = this._map.latLngToContainerPoint(this._popupLocation);
|
|
778
|
-
this._popupOverlay.setPosition(this._map.ol.getCoordinateFromPixelInternal([screen.x, screen.y]));
|
|
779
|
-
},
|
|
780
|
-
closePopup() {
|
|
781
|
-
if (this._popupOverlay) {
|
|
782
|
-
this._map?.off('move zoom rotate pitch', this._positionPopup, this);
|
|
783
|
-
this._map?.ol.removeOverlay(this._popupOverlay);
|
|
784
|
-
this._popupOverlay = null;
|
|
785
|
-
}
|
|
786
|
-
return this;
|
|
787
|
-
},
|
|
788
|
-
bindTooltip(content) {
|
|
789
|
-
this._tooltipContent = content;
|
|
790
|
-
this.on('mouseover', this._showTooltip, this).on('mouseout remove', this._hideTooltip, this);
|
|
791
|
-
if (this instanceof L.LayerGroup) this.eachLayer(layer => layer.bindTooltip(content));
|
|
792
|
-
return this;
|
|
793
|
-
},
|
|
794
|
-
_showTooltip(event) {
|
|
795
|
-
this._hideTooltip();
|
|
796
|
-
if (!this._map || !event.latlng) return;
|
|
797
|
-
const element = this._tooltipElement = L.DomUtil.create('div', 'ol-city-tooltip leaflet-tooltip', this._map.getContainer());
|
|
798
|
-
element.setAttribute('role', 'tooltip');
|
|
799
|
-
const value = typeof this._tooltipContent === 'function' ? this._tooltipContent(this) : this._tooltipContent;
|
|
800
|
-
if (value instanceof Node) element.append(value); else element.innerHTML = value;
|
|
801
|
-
const pixel = this._map.latLngToContainerPoint(event.latlng);
|
|
802
|
-
element.style.left = `${pixel.x + 12}px`; element.style.top = `${pixel.y + 12}px`;
|
|
803
|
-
},
|
|
804
|
-
_hideTooltip() { this._tooltipElement?.remove(); this._tooltipElement = null; },
|
|
805
|
-
});
|
|
806
|
-
L.LayerGroup.include({
|
|
807
|
-
getLayers() { return Object.values(this._layers); },
|
|
808
|
-
getBounds() {
|
|
809
|
-
const result = new L.LatLngBounds();
|
|
810
|
-
this.eachLayer(layer => result.extend(layer.getBounds?.() || layer.getLatLng()));
|
|
811
|
-
return result;
|
|
812
|
-
},
|
|
813
|
-
});
|
|
814
|
-
L.FeatureGroup = L.LayerGroup.extend({});
|
|
815
|
-
|
|
816
|
-
L.Path.include({
|
|
817
|
-
options: { pane: 'overlayPane', interactive: true, stroke: true, color: '#3388ff',
|
|
818
|
-
weight: 3, opacity: 1, lineCap: 'round', lineJoin: 'round', fill: false, fillOpacity: 0.2 },
|
|
819
|
-
initialize(options) { L.Util.setOptions(this, options); },
|
|
820
|
-
setStyle(options) { L.Util.setOptions(this, options); return this.redraw(); },
|
|
821
|
-
redraw() { return this; },
|
|
822
|
-
bringToFront() { return this; },
|
|
823
|
-
bringToBack() { return this; },
|
|
824
|
-
});
|
|
825
|
-
L.Polyline.include({
|
|
826
|
-
initialize(values, options) { L.Util.setOptions(this, options); this.setLatLngs(values); },
|
|
827
|
-
getLatLngs() { return this._latlngs; },
|
|
828
|
-
setLatLngs(values) { this._latlngs = coordinates(values); return this.redraw(); },
|
|
829
|
-
addLatLng(value) { this._latlngs.push(latLng(value)); return this.redraw(); },
|
|
830
|
-
getBounds() {
|
|
831
|
-
const result = new L.LatLngBounds();
|
|
832
|
-
const visit = values => { for (const value of values) Array.isArray(value) ? visit(value) : result.extend(value); };
|
|
833
|
-
visit(this._latlngs);
|
|
834
|
-
return result;
|
|
835
|
-
},
|
|
836
|
-
_project() {
|
|
837
|
-
this._rings = [];
|
|
838
|
-
const visit = values => {
|
|
839
|
-
if (!values.length) return;
|
|
840
|
-
if (Array.isArray(values[0])) values.forEach(visit);
|
|
841
|
-
else this._rings.push(values.map(value => this._map.latLngToLayerPoint(value)));
|
|
842
|
-
};
|
|
843
|
-
visit(this._latlngs);
|
|
844
|
-
},
|
|
845
|
-
closestLayerPoint(value) {
|
|
846
|
-
this._project();
|
|
847
|
-
const paths = this._rings.map(ring => ring.map(value => [value.x, value.y]));
|
|
848
|
-
const closest = new ol.geom.MultiLineString(paths).getClosestPoint([value.x, value.y]);
|
|
849
|
-
return point(closest);
|
|
850
|
-
},
|
|
851
|
-
});
|
|
852
|
-
L.Polyline.mergeOptions(L.Path.prototype.options);
|
|
853
|
-
L.Polygon.include({ initialize: L.Polyline.prototype.initialize });
|
|
854
|
-
L.Polygon.mergeOptions(L.Path.prototype.options);
|
|
855
|
-
L.Polygon.mergeOptions({ fill: true });
|
|
856
|
-
L.Rectangle = L.Polygon.extend({
|
|
857
|
-
initialize(value, options) { L.Util.setOptions(this, options); this.setBounds(value); },
|
|
858
|
-
setBounds(value) {
|
|
859
|
-
value = bounds(value);
|
|
860
|
-
return this.setLatLngs([value.getSouthWest(), value.getNorthWest(), value.getNorthEast(), value.getSouthEast()]);
|
|
861
|
-
},
|
|
862
|
-
});
|
|
863
|
-
L.CircleMarker.include({
|
|
864
|
-
options: { ...L.Path.prototype.options, fill: true, radius: 10 },
|
|
865
|
-
initialize(value, options) { L.Util.setOptions(this, options); this._latlng = latLng(value); },
|
|
866
|
-
getLatLng() { return this._latlng; },
|
|
867
|
-
setLatLng(value) { this._latlng = latLng(value); this.fire('move', { latlng: this._latlng }); return this.redraw(); },
|
|
868
|
-
getRadius() { return this.options.radius; },
|
|
869
|
-
setRadius(radius) { this.options.radius = radius; return this.redraw(); },
|
|
870
|
-
});
|
|
871
|
-
L.Circle.include({
|
|
872
|
-
initialize: L.CircleMarker.prototype.initialize,
|
|
873
|
-
_project() {
|
|
874
|
-
this._point = this._map.latLngToLayerPoint(this._latlng);
|
|
875
|
-
this._radius = this._radiusY = this.getRadius() * this._map.options.crs.scale(this._map.getZoom()) /
|
|
876
|
-
(2 * Math.PI * 6378137 * Math.cos(this._latlng.lat * Math.PI / 180));
|
|
877
|
-
},
|
|
878
|
-
getBounds() {
|
|
879
|
-
const north = this.getRadius() / 6378137 * 180 / Math.PI;
|
|
880
|
-
const east = north / Math.cos(this._latlng.lat * Math.PI / 180);
|
|
881
|
-
return new L.LatLngBounds([this._latlng.lat - north, this._latlng.lng - east],
|
|
882
|
-
[this._latlng.lat + north, this._latlng.lng + east]);
|
|
883
|
-
},
|
|
884
|
-
});
|
|
885
|
-
L.Circle.mergeOptions(L.CircleMarker.prototype.options);
|
|
886
|
-
L.GeoJSON = L.FeatureGroup.extend({
|
|
887
|
-
initialize(data, options) {
|
|
888
|
-
L.LayerGroup.prototype.initialize.call(this, [], options);
|
|
889
|
-
if (data) this.addData(data);
|
|
890
|
-
},
|
|
891
|
-
addData(data) {
|
|
892
|
-
const features = new ol.format.GeoJSON().readFeatures(data);
|
|
893
|
-
const convert = (geometry, feature) => {
|
|
894
|
-
const values = geometry.getCoordinates();
|
|
895
|
-
const locations = value => typeof value[0] === 'number' ? [value[1], value[0]] : value.map(locations);
|
|
896
|
-
switch (geometry.getType()) {
|
|
897
|
-
case 'Point': return this.options.pointToLayer
|
|
898
|
-
? this.options.pointToLayer(feature, latLng(locations(values))) : new L.Marker(locations(values));
|
|
899
|
-
case 'MultiPoint': return new L.FeatureGroup(values.map(value => convert(new ol.geom.Point(value), feature)));
|
|
900
|
-
case 'LineString': case 'MultiLineString': return new L.Polyline(locations(values), this.options);
|
|
901
|
-
case 'Polygon': case 'MultiPolygon': return new L.Polygon(locations(values), this.options);
|
|
902
|
-
default: throw new Error(`Unsupported GeoJSON geometry: ${geometry.getType()}`);
|
|
903
|
-
}
|
|
904
|
-
};
|
|
905
|
-
for (const feature of features) {
|
|
906
|
-
const layer = convert(feature.getGeometry(), new ol.format.GeoJSON().writeFeatureObject(feature));
|
|
907
|
-
this.addLayer(layer);
|
|
908
|
-
}
|
|
909
|
-
return this;
|
|
910
|
-
},
|
|
911
|
-
});
|
|
912
|
-
|
|
913
|
-
L.GridLayer.include({
|
|
914
|
-
options: { pane: 'tilePane', tileSize: 256, opacity: 1, minZoom: 0, maxZoom: 24, updateInterval: 200 },
|
|
915
|
-
initialize(options) { L.Util.setOptions(this, options); this._tiles = {}; },
|
|
916
|
-
getTileSize() { return typeof this.options.tileSize === 'number'
|
|
917
|
-
? new L.Point(this.options.tileSize, this.options.tileSize) : point(this.options.tileSize); },
|
|
918
|
-
getEvents() { return { moveend: this._onMoveEnd, zoomend: this._onMoveEnd, resize: this._onMoveEnd }; },
|
|
919
|
-
_initContainer() { this._container = L.DomUtil.create('div', '', this.getPane()); },
|
|
920
|
-
onAdd() { this._initContainer(); this._onMoveEnd(); },
|
|
921
|
-
onRemove() {
|
|
922
|
-
for (const tile of Object.values(this._tiles)) this.fire('tileunload', { tile: tile.el, coords: tile.coords });
|
|
923
|
-
this._tiles = {}; this._container?.remove();
|
|
924
|
-
},
|
|
925
|
-
_getTiledPixelBounds() {
|
|
926
|
-
return new L.Bounds(this._map.project(this._map.getBounds().getNorthWest(), this._tileZoom),
|
|
927
|
-
this._map.project(this._map.getBounds().getSouthEast(), this._tileZoom));
|
|
928
|
-
},
|
|
929
|
-
_onMoveEnd() {
|
|
930
|
-
if (!this._map) return;
|
|
931
|
-
this._tileZoom = Math.max(this.options.minZoom, Math.min(this.options.maxZoom, Math.round(this._map.getZoom())));
|
|
932
|
-
const size = this.getTileSize(), extent = this._getTiledPixelBounds(this._map.getCenter());
|
|
933
|
-
const min = extent.min.unscaleBy(size).floor(), max = extent.max.unscaleBy(size).floor();
|
|
934
|
-
const retained = new Set(), limit = 2 ** this._tileZoom;
|
|
935
|
-
for (let x = min.x; x <= max.x; x++) for (let y = min.y; y <= max.y; y++) {
|
|
936
|
-
if (y < 0 || y >= limit) continue;
|
|
937
|
-
const key = `${this._tileZoom}:${x}:${y}`;
|
|
938
|
-
retained.add(key);
|
|
939
|
-
if (this._tiles[key]) continue;
|
|
940
|
-
const coords = new L.Point(x, y); coords.z = this._tileZoom;
|
|
941
|
-
const tile = this._tiles[key] = { coords, current: true, loaded: 0 };
|
|
942
|
-
const done = (error, element) => {
|
|
943
|
-
if (this._tiles[key] !== tile) return;
|
|
944
|
-
tile.el = element;
|
|
945
|
-
if (error) { this.fire('tileerror', { error, tile: element, coords }); return; }
|
|
946
|
-
tile.loaded = Date.now();
|
|
947
|
-
this.fire('tileload', { tile: element, coords });
|
|
948
|
-
this.fire('load');
|
|
949
|
-
};
|
|
950
|
-
tile.el = this.createTile(coords, done);
|
|
951
|
-
if (this.createTile.length < 2) done(null, tile.el);
|
|
952
|
-
}
|
|
953
|
-
for (const [key, tile] of Object.entries(this._tiles)) {
|
|
954
|
-
if (retained.has(key)) continue;
|
|
955
|
-
delete this._tiles[key];
|
|
956
|
-
this.fire('tileunload', { tile: tile.el, coords: tile.coords });
|
|
957
|
-
}
|
|
958
|
-
},
|
|
959
|
-
_tileCoordsToNwSe(coords) {
|
|
960
|
-
const size = this.getTileSize(), nw = new L.Point(coords.x * size.x, coords.y * size.y);
|
|
961
|
-
return [this._map.unproject(nw, coords.z), this._map.unproject(nw.add(size), coords.z)];
|
|
962
|
-
},
|
|
963
|
-
setOpacity(opacity) { this.options.opacity = opacity; return this; },
|
|
964
|
-
setZIndex(zIndex) { this.options.zIndex = zIndex; return this; },
|
|
965
|
-
redraw() { if (this._map) { this.onRemove(); this._onMoveEnd(); } return this; },
|
|
966
|
-
});
|
|
967
|
-
L.TileLayer = L.GridLayer.extend({
|
|
968
|
-
initialize(url, options) {
|
|
969
|
-
L.GridLayer.prototype.initialize.call(this, options); this.setUrl(url);
|
|
970
|
-
},
|
|
971
|
-
setUrl(url) { this._url = url; this._source = new ol.source.XYZ({ url, crossOrigin: 'anonymous' }); return this.redraw(); },
|
|
972
|
-
createTile(coords, done) {
|
|
973
|
-
const url = this._source.getTileUrlFunction()([coords.z, coords.x, coords.y], 1, ol.proj.get('EPSG:3857'));
|
|
974
|
-
const tile = image(url, this.options, '');
|
|
975
|
-
tile.onload = () => done(null, tile);
|
|
976
|
-
tile.onerror = () => done(new Error(`Unable to load tile: ${url}`), tile);
|
|
977
|
-
return tile;
|
|
978
|
-
},
|
|
979
|
-
});
|
|
980
|
-
L.TileLayer.WMS = L.TileLayer.extend({
|
|
981
|
-
setUrl(url) {
|
|
982
|
-
this._url = url;
|
|
983
|
-
this._source = new ol.source.TileWMS({ url, crossOrigin: 'anonymous', params: {
|
|
984
|
-
LAYERS: this.options.layers, FORMAT: this.options.format || 'image/png',
|
|
985
|
-
TRANSPARENT: this.options.transparent || false,
|
|
986
|
-
} });
|
|
987
|
-
return this.redraw();
|
|
988
|
-
},
|
|
989
|
-
});
|
|
990
|
-
L.ImageOverlay.include({
|
|
991
|
-
options: { pane: 'overlayPane', opacity: 1, interactive: false },
|
|
992
|
-
initialize(url, value, options) { L.Util.setOptions(this, options); this._url = url; this._bounds = bounds(value); },
|
|
993
|
-
_initImage() {
|
|
994
|
-
this._image = image(this._url, this.options, '');
|
|
995
|
-
this._image.onload = () => this.fire('load');
|
|
996
|
-
this._image.onerror = () => this.fire('error', { error: new Error(`Unable to load image: ${this._url}`) });
|
|
997
|
-
},
|
|
998
|
-
getBounds() { return this._bounds; },
|
|
999
|
-
setBounds(value) { this._bounds = bounds(value); return this; },
|
|
1000
|
-
setUrl(url) { this._url = url; if (this._image) this._image.src = url; return this; },
|
|
1001
|
-
setOpacity(opacity) { this.options.opacity = opacity; return this; },
|
|
1002
|
-
setZIndex(zIndex) { this.options.zIndex = zIndex; return this; },
|
|
1003
|
-
});
|
|
1004
|
-
|
|
1005
|
-
L.Icon = L.Evented.extend({
|
|
1006
|
-
initialize(options) { L.Util.setOptions(this, options); },
|
|
1007
|
-
createIcon() { return this._create('icon'); },
|
|
1008
|
-
createShadow() { return this.options.shadowUrl ? this._create('shadow') : null; },
|
|
1009
|
-
_create(kind) {
|
|
1010
|
-
const element = image(this.options[`${kind}Url`], this.options, `leaflet-marker-${kind}`);
|
|
1011
|
-
const size = this.options[`${kind}Size`], anchor = this.options[`${kind}Anchor`] || this.options.iconAnchor;
|
|
1012
|
-
if (size) { element.style.width = `${size[0]}px`; element.style.height = `${size[1]}px`; }
|
|
1013
|
-
if (anchor) { element.style.marginLeft = `${-anchor[0]}px`; element.style.marginTop = `${-anchor[1]}px`; }
|
|
1014
|
-
return element;
|
|
1015
|
-
},
|
|
1016
|
-
});
|
|
1017
|
-
L.Icon.Default = L.Icon.extend({
|
|
1018
|
-
options: {
|
|
1019
|
-
iconUrl: 'https://unpkg.com/leaflet@1.9/dist/images/marker-icon.png',
|
|
1020
|
-
shadowUrl: 'https://unpkg.com/leaflet@1.9/dist/images/marker-shadow.png',
|
|
1021
|
-
iconSize: [25, 41], iconAnchor: [12, 41], shadowSize: [41, 41], shadowAnchor: [12, 41],
|
|
1022
|
-
},
|
|
1023
|
-
});
|
|
1024
|
-
L.DivIcon = L.Icon.extend({
|
|
1025
|
-
createIcon() {
|
|
1026
|
-
const element = L.DomUtil.create('div', `leaflet-marker-icon ${this.options.className || ''}`);
|
|
1027
|
-
if (this.options.html instanceof Node) element.append(this.options.html); else element.innerHTML = this.options.html || '';
|
|
1028
|
-
const size = this.options.iconSize || [12, 12], anchor = this.options.iconAnchor || size.map(value => value / 2);
|
|
1029
|
-
element.style.cssText = `width:${size[0]}px;height:${size[1]}px;margin-left:${-anchor[0]}px;margin-top:${-anchor[1]}px`;
|
|
1030
|
-
return element;
|
|
1031
|
-
},
|
|
1032
|
-
createShadow() { return null; },
|
|
1033
|
-
});
|
|
1034
|
-
L.Marker.include({
|
|
1035
|
-
options: { pane: 'markerPane', icon: new L.Icon.Default(), opacity: 1, interactive: true, zIndexOffset: 0 },
|
|
1036
|
-
initialize(value, options) { L.Util.setOptions(this, options); this._latlng = latLng(value); },
|
|
1037
|
-
getLatLng() { return this._latlng; },
|
|
1038
|
-
setLatLng(value) { this._latlng = latLng(value); this.update(); return this.fire('move', { latlng: this._latlng }); },
|
|
1039
|
-
setIcon(icon) { this.options.icon = icon; if (this._map) { this.onRemove(); this.onAdd(); } return this; },
|
|
1040
|
-
getEvents() { return { zoom: this.update, viewreset: this.update }; },
|
|
1041
|
-
onAdd() {
|
|
1042
|
-
this._icon = this.options.icon.createIcon(); this._shadow = this.options.icon.createShadow();
|
|
1043
|
-
this._icon.tabIndex = 0; this._icon.setAttribute('role', 'button');
|
|
1044
|
-
this._icon.setAttribute('aria-label', this.options.title || 'Marker');
|
|
1045
|
-
this._icon.title = this.options.title || '';
|
|
1046
|
-
for (const element of [this._shadow, this._icon]) if (element) this.getPane().append(element);
|
|
1047
|
-
this._initInteraction(); this.update();
|
|
1048
|
-
},
|
|
1049
|
-
onRemove() { this.dragging?.disable(); this._icon?.remove(); this._shadow?.remove(); },
|
|
1050
|
-
update() { if (this._map && this._icon) this._setPos(this._map.latLngToLayerPoint(this._latlng)); return this; },
|
|
1051
|
-
_setPos(value) {
|
|
1052
|
-
for (const element of [this._icon, this._shadow]) if (element) L.DomUtil.setPosition(element, value);
|
|
1053
|
-
this._zIndex = value.y + this.options.zIndexOffset; this._updateZIndex(0);
|
|
1054
|
-
},
|
|
1055
|
-
_updateZIndex(offset) { if (this._icon) this._icon.style.zIndex = this._zIndex + offset; },
|
|
1056
|
-
setOpacity(opacity) { this.options.opacity = opacity; return this; },
|
|
1057
|
-
setZIndexOffset(value) { this.options.zIndexOffset = value; return this.update(); },
|
|
1058
|
-
_initInteraction() {
|
|
1059
|
-
this._icon._cityLayer = this;
|
|
1060
|
-
const drag = this.dragging = new L.Handler(this._map);
|
|
1061
|
-
const icon = this._icon;
|
|
1062
|
-
L.DomEvent.on(icon, 'pointerdown', event => {
|
|
1063
|
-
this._map._moved = false;
|
|
1064
|
-
event.stopPropagation();
|
|
1065
|
-
});
|
|
1066
|
-
L.DomEvent.on(icon, 'keydown', event => {
|
|
1067
|
-
if (event.key !== 'Enter' && event.key !== ' ') return;
|
|
1068
|
-
L.DomEvent.stop(event);
|
|
1069
|
-
this.fire('click', { latlng: this._latlng, originalEvent: event });
|
|
1070
|
-
});
|
|
1071
|
-
drag._marker = this;
|
|
1072
|
-
drag._draggable = new L.Evented();
|
|
1073
|
-
drag._onDrag = function () {
|
|
1074
|
-
const marker = this._marker;
|
|
1075
|
-
marker._latlng = marker._map.layerPointToLatLng(L.DomUtil.getPosition(marker._icon));
|
|
1076
|
-
marker.fire('move', { latlng: marker._latlng }).fire('drag', { latlng: marker._latlng });
|
|
1077
|
-
};
|
|
1078
|
-
drag._adjustPan = function () {};
|
|
1079
|
-
drag._draggable.on('drag', drag._onDrag, drag);
|
|
1080
|
-
let pointer, anchor, origin, moved;
|
|
1081
|
-
const handle = event => {
|
|
1082
|
-
if (!drag.enabled()) return;
|
|
1083
|
-
if (event.type === 'pointerdown') {
|
|
1084
|
-
if (event.button !== 0) return;
|
|
1085
|
-
event.preventDefault(); event.stopPropagation();
|
|
1086
|
-
pointer = event.pointerId; anchor = [event.clientX, event.clientY];
|
|
1087
|
-
origin = this._map.latLngToContainerPoint(this._latlng); moved = false;
|
|
1088
|
-
icon.setPointerCapture(pointer);
|
|
1089
|
-
this.fire('dragstart');
|
|
1090
|
-
} else if (event.pointerId === pointer && event.type === 'pointermove') {
|
|
1091
|
-
const value = new L.Point(origin.x + event.clientX - anchor[0], origin.y + event.clientY - anchor[1]);
|
|
1092
|
-
L.DomUtil.setPosition(icon, value);
|
|
1093
|
-
drag._draggable._newPos = value;
|
|
1094
|
-
drag._draggable.fire('drag', { originalEvent: event });
|
|
1095
|
-
moved = true;
|
|
1096
|
-
} else if (event.pointerId === pointer) {
|
|
1097
|
-
if (icon.hasPointerCapture(pointer)) icon.releasePointerCapture(pointer);
|
|
1098
|
-
pointer = null; this.fire('dragend'); this._map._moved = moved;
|
|
1099
|
-
}
|
|
1100
|
-
};
|
|
1101
|
-
drag.addHooks = () => L.DomEvent.on(icon, 'pointerdown pointermove pointerup pointercancel', handle);
|
|
1102
|
-
drag.removeHooks = () => L.DomEvent.off(icon, 'pointerdown pointermove pointerup pointercancel', handle);
|
|
1103
|
-
if (this.options.draggable) drag.enable();
|
|
1104
|
-
},
|
|
1105
|
-
});
|
|
1106
|
-
|
|
1107
|
-
L.Map.include({
|
|
1108
|
-
_fireDOMEvent(event, type = event.type, targets) {
|
|
1109
|
-
const rect = this.getContainer().getBoundingClientRect();
|
|
1110
|
-
const pixel = new L.Point(event.clientX - rect.left, event.clientY - rect.top);
|
|
1111
|
-
const location = this.containerPointToLatLng(pixel);
|
|
1112
|
-
const layer = event.target.closest?.('.leaflet-marker-icon')?._cityLayer;
|
|
1113
|
-
if (type === 'click' && this._draggableMoved(layer)) return;
|
|
1114
|
-
for (const target of targets || (layer ? [layer] : [this])) {
|
|
1115
|
-
target.fire(type, { originalEvent: event, latlng: location, containerPoint: pixel,
|
|
1116
|
-
layerPoint: this.containerPointToLayerPoint(pixel) });
|
|
1117
|
-
}
|
|
1118
|
-
},
|
|
1119
|
-
});
|
|
1120
|
-
L.Map.addInitHook(function () {
|
|
1121
|
-
const mapPane = this.createPane('mapPane');
|
|
1122
|
-
for (const [name, order] of [['tilePane', 200], ['overlayPane', 400], ['markerPane', 600]]) {
|
|
1123
|
-
this.createPane(name, mapPane).style.zIndex = order;
|
|
1124
|
-
}
|
|
1125
|
-
const handler = event => this._fireDOMEvent(event);
|
|
1126
|
-
L.DomEvent.on(this.getContainer(), 'click mousemove mouseout mouseover', handler);
|
|
1127
|
-
this.once('unload', () => L.DomEvent.off(this.getContainer(), 'click mousemove mouseout mouseover', handler));
|
|
1128
|
-
});
|
|
1129
|
-
})();
|
|
1
|
+
// Leaflet-compatible classes backed by OpenLayers. Load after ol.js and before the plugin.
|
|
2
|
+
(() => {
|
|
3
|
+
if (!window.ol) throw new Error('Unable to load OpenLayers');
|
|
4
|
+
|
|
5
|
+
const style = document.createElement('style');
|
|
6
|
+
style.dataset.openlayersBindings = '';
|
|
7
|
+
style.textContent = `
|
|
8
|
+
.openlayers-city-mapper {
|
|
9
|
+
position: relative;
|
|
10
|
+
overflow: hidden;
|
|
11
|
+
touch-action: none;
|
|
12
|
+
}
|
|
13
|
+
.ol-viewport {
|
|
14
|
+
position: absolute !important;
|
|
15
|
+
inset: 0;
|
|
16
|
+
}
|
|
17
|
+
.ol-overlaycontainer-stopevent { z-index: 1000 !important; }
|
|
18
|
+
.ol-city-corner {
|
|
19
|
+
position: absolute;
|
|
20
|
+
display: flex;
|
|
21
|
+
flex-direction: column;
|
|
22
|
+
gap: .5em;
|
|
23
|
+
pointer-events: none;
|
|
24
|
+
}
|
|
25
|
+
.ol-city-topleft { top: 5em; left: .5em; }
|
|
26
|
+
.ol-city-topright { top: 10px; right: 10px; }
|
|
27
|
+
.ol-city-bottomleft { bottom: .5em; left: .5em; }
|
|
28
|
+
.ol-city-bottomright { bottom: 4em; right: .5em; }
|
|
29
|
+
.ol-attribution {
|
|
30
|
+
text-align: justify;
|
|
31
|
+
border-radius: 0 !important;
|
|
32
|
+
left: 0;
|
|
33
|
+
right: 0 !important;
|
|
34
|
+
max-width: unset;
|
|
35
|
+
font-family: "Helvetica Neue", Arial, Helvetica, sans-serif;
|
|
36
|
+
font-size: .75rem;
|
|
37
|
+
line-height: 1.5;
|
|
38
|
+
}
|
|
39
|
+
.ol-attribution a { color: #0078A8; }
|
|
40
|
+
.ol-attribution * { text-shadow: none !important; }
|
|
41
|
+
.ol-city-control {
|
|
42
|
+
position: static;
|
|
43
|
+
pointer-events: auto;
|
|
44
|
+
font: 13px/1.5 sans-serif;
|
|
45
|
+
}
|
|
46
|
+
.ol-city-rotate {
|
|
47
|
+
padding: 0;
|
|
48
|
+
border: 1px solid #0003;
|
|
49
|
+
border-radius: 4px;
|
|
50
|
+
background: #fff;
|
|
51
|
+
background-clip: padding-box;
|
|
52
|
+
}
|
|
53
|
+
.ol-city-rotate a {
|
|
54
|
+
display: block;
|
|
55
|
+
width: 30px;
|
|
56
|
+
height: 30px;
|
|
57
|
+
border-radius: 2px;
|
|
58
|
+
color: #000;
|
|
59
|
+
text-decoration: none;
|
|
60
|
+
}
|
|
61
|
+
.ol-city-rotate a:hover { background: #f4f4f4; }
|
|
62
|
+
.ol-city-rotate a:focus-visible { outline: 2px solid #2675c9; }
|
|
63
|
+
.ol-city-layers {
|
|
64
|
+
max-height: calc(100vh - 5em);
|
|
65
|
+
overflow: auto;
|
|
66
|
+
border-radius: 4px;
|
|
67
|
+
}
|
|
68
|
+
.ol-city-layers section { padding: .5em; background: var(--ol-background-color); }
|
|
69
|
+
.ol-city-layers label { display: block; cursor: pointer; white-space: nowrap; }
|
|
70
|
+
.ol-city-layers input { vertical-align: middle; }
|
|
71
|
+
.ol-city-layers hr { border: 0; border-top: 1px solid #ccc; }
|
|
72
|
+
.ol-city-layers .ol-control { background: transparent; }
|
|
73
|
+
.ol-city-layers .sunlight-time button { width: auto; padding: 0 .4em; flex-shrink: 0; }
|
|
74
|
+
.openlayers-city-mapper .leaflet-pane {
|
|
75
|
+
position: absolute;
|
|
76
|
+
inset: 0;
|
|
77
|
+
pointer-events: none;
|
|
78
|
+
}
|
|
79
|
+
.ol-zoom button { width: 30px; height: 30px; }
|
|
80
|
+
.openlayers-city-mapper .leaflet-marker-icon,
|
|
81
|
+
.openlayers-city-mapper .leaflet-marker-shadow {
|
|
82
|
+
position: absolute;
|
|
83
|
+
top: 0;
|
|
84
|
+
left: 0;
|
|
85
|
+
}
|
|
86
|
+
.openlayers-city-mapper .leaflet-marker-icon { pointer-events: auto; cursor: pointer; }
|
|
87
|
+
.openlayers-city-mapper .leaflet-div-icon { background: #fff; border: 1px solid #666; }
|
|
88
|
+
.ol-city-popup {
|
|
89
|
+
padding: 10px;
|
|
90
|
+
background: white;
|
|
91
|
+
border: 1px solid #888;
|
|
92
|
+
border-radius: 4px;
|
|
93
|
+
font: 14px sans-serif;
|
|
94
|
+
}
|
|
95
|
+
.ol-city-popup button { float: right; margin-left: 12px; }
|
|
96
|
+
.ol-city-tooltip {
|
|
97
|
+
position: absolute;
|
|
98
|
+
z-index: 1100;
|
|
99
|
+
padding: 4px 8px;
|
|
100
|
+
background: white;
|
|
101
|
+
border: 1px solid #888;
|
|
102
|
+
pointer-events: none;
|
|
103
|
+
}
|
|
104
|
+
`;
|
|
105
|
+
document.head.appendChild(style);
|
|
106
|
+
|
|
107
|
+
const L = window.L = { version: '1.9.4-openlayers', control: {} };
|
|
108
|
+
let lastId = 0;
|
|
109
|
+
const stamp = object => object._leaflet_id ||= ++lastId;
|
|
110
|
+
const setOptions = (object, options) => object.options = { ...object.options, ...options };
|
|
111
|
+
const zoomTiming = new Animation(new KeyframeEffect(null, [], {
|
|
112
|
+
duration: 1, fill: 'both', easing: 'cubic-bezier(0,0,0.25,1)',
|
|
113
|
+
}));
|
|
114
|
+
|
|
115
|
+
function Class(...args) {
|
|
116
|
+
this.initialize?.(...args);
|
|
117
|
+
this.callInitHooks();
|
|
118
|
+
}
|
|
119
|
+
Class.extend = function (properties) {
|
|
120
|
+
function Child(...args) {
|
|
121
|
+
this.initialize?.(...args);
|
|
122
|
+
this.callInitHooks();
|
|
123
|
+
}
|
|
124
|
+
Object.setPrototypeOf(Child, this);
|
|
125
|
+
Child.prototype = Object.create(this.prototype);
|
|
126
|
+
Object.assign(Child.prototype, properties, { constructor: Child });
|
|
127
|
+
Child.prototype.options = { ...this.prototype.options, ...properties.options };
|
|
128
|
+
Child.prototype._initHooks = [];
|
|
129
|
+
return Child;
|
|
130
|
+
};
|
|
131
|
+
Class.include = function (properties) { Object.assign(this.prototype, properties); return this; };
|
|
132
|
+
Class.mergeOptions = function (options) {
|
|
133
|
+
this.prototype.options = { ...this.prototype.options, ...options };
|
|
134
|
+
return this;
|
|
135
|
+
};
|
|
136
|
+
Class.addInitHook = function (hook, ...args) {
|
|
137
|
+
if (!Object.hasOwn(this.prototype, '_initHooks')) this.prototype._initHooks = [];
|
|
138
|
+
this.prototype._initHooks.push(typeof hook === 'function' ? hook : function () { this[hook](...args); });
|
|
139
|
+
return this;
|
|
140
|
+
};
|
|
141
|
+
Class.prototype.callInitHooks = function () {
|
|
142
|
+
if (this._initHooksCalled) return;
|
|
143
|
+
this._initHooksCalled = true;
|
|
144
|
+
const prototypes = [];
|
|
145
|
+
for (let proto = Object.getPrototypeOf(this); proto; proto = Object.getPrototypeOf(proto)) prototypes.unshift(proto);
|
|
146
|
+
for (const proto of prototypes) {
|
|
147
|
+
if (Object.hasOwn(proto, '_initHooks')) for (const hook of proto._initHooks) hook.call(this);
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
L.Evented = Class.extend({
|
|
151
|
+
on(types, fn, context) {
|
|
152
|
+
if (typeof types === 'object') {
|
|
153
|
+
for (const [type, handler] of Object.entries(types)) this.on(type, handler, fn);
|
|
154
|
+
} else {
|
|
155
|
+
this._events ||= {};
|
|
156
|
+
for (const type of types.split(/\s+/)) {
|
|
157
|
+
const events = this._events[type] ||= [];
|
|
158
|
+
if (!events.some(event => event.fn === fn && event.context === context)) events.push({ fn, context });
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
return this;
|
|
162
|
+
},
|
|
163
|
+
off(types, fn, context) {
|
|
164
|
+
if (!types) this._events = {};
|
|
165
|
+
else if (typeof types === 'object') {
|
|
166
|
+
for (const [type, handler] of Object.entries(types)) this.off(type, handler, fn);
|
|
167
|
+
} else {
|
|
168
|
+
for (const type of types.split(/\s+/)) {
|
|
169
|
+
if (this._events?.[type]) this._events[type] = fn
|
|
170
|
+
? this._events[type].filter(event => event.fn !== fn || event.context !== context) : [];
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
return this;
|
|
174
|
+
},
|
|
175
|
+
once(types, fn, context) {
|
|
176
|
+
const handler = event => { this.off(types, handler); fn.call(context || this, event); };
|
|
177
|
+
return this.on(types, handler);
|
|
178
|
+
},
|
|
179
|
+
fire(type, data) {
|
|
180
|
+
for (const event of [...this._events?.[type] || []]) {
|
|
181
|
+
event.fn.call(event.context || this, { ...data, type, target: this, sourceTarget: this });
|
|
182
|
+
}
|
|
183
|
+
return this;
|
|
184
|
+
},
|
|
185
|
+
listens(type) { return Boolean(this._events?.[type]?.length); },
|
|
186
|
+
});
|
|
187
|
+
L.Util = {
|
|
188
|
+
stamp, setOptions,
|
|
189
|
+
throttle(fn, interval, context) {
|
|
190
|
+
let timer, pending;
|
|
191
|
+
const run = (...args) => {
|
|
192
|
+
if (timer) { pending = args; return; }
|
|
193
|
+
fn.apply(context, args);
|
|
194
|
+
timer = setTimeout(() => {
|
|
195
|
+
timer = null;
|
|
196
|
+
if (pending) { const args = pending; pending = null; run(...args); }
|
|
197
|
+
}, interval);
|
|
198
|
+
};
|
|
199
|
+
return run;
|
|
200
|
+
},
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
L.Point = function (x, y, round) {
|
|
204
|
+
this.x = round ? Math.round(x) : x;
|
|
205
|
+
this.y = round ? Math.round(y) : y;
|
|
206
|
+
};
|
|
207
|
+
const point = value => value instanceof L.Point ? value
|
|
208
|
+
: Array.isArray(value) ? new L.Point(...value) : new L.Point(value.x, value.y);
|
|
209
|
+
L.Point.prototype = {
|
|
210
|
+
clone() { return new L.Point(this.x, this.y); },
|
|
211
|
+
add(value) { return this.clone()._add(point(value)); },
|
|
212
|
+
_add(value) { this.x += value.x; this.y += value.y; return this; },
|
|
213
|
+
subtract(value) { return this.clone()._subtract(point(value)); },
|
|
214
|
+
_subtract(value) { this.x -= value.x; this.y -= value.y; return this; },
|
|
215
|
+
multiplyBy(value) { return new L.Point(this.x * value, this.y * value); },
|
|
216
|
+
divideBy(value) { return new L.Point(this.x / value, this.y / value); },
|
|
217
|
+
scaleBy(value) { return new L.Point(this.x * value.x, this.y * value.y); },
|
|
218
|
+
unscaleBy(value) { return new L.Point(this.x / value.x, this.y / value.y); },
|
|
219
|
+
round() { return new L.Point(Math.round(this.x), Math.round(this.y)); },
|
|
220
|
+
floor() { return new L.Point(Math.floor(this.x), Math.floor(this.y)); },
|
|
221
|
+
ceil() { return new L.Point(Math.ceil(this.x), Math.ceil(this.y)); },
|
|
222
|
+
distanceTo(value) { value = point(value); return Math.hypot(this.x - value.x, this.y - value.y); },
|
|
223
|
+
equals(value) { value = point(value); return this.x === value.x && this.y === value.y; },
|
|
224
|
+
contains(value) { value = point(value); return Math.abs(value.x) <= Math.abs(this.x) && Math.abs(value.y) <= Math.abs(this.y); },
|
|
225
|
+
};
|
|
226
|
+
L.LatLng = function (lat, lng, alt) {
|
|
227
|
+
if (!Number.isFinite(Number(lat)) || !Number.isFinite(Number(lng))) throw new Error('Invalid LatLng');
|
|
228
|
+
this.lat = Number(lat); this.lng = Number(lng);
|
|
229
|
+
if (alt !== undefined) this.alt = alt;
|
|
230
|
+
};
|
|
231
|
+
const latLng = value => value instanceof L.LatLng ? value
|
|
232
|
+
: Array.isArray(value) ? new L.LatLng(...value) : new L.LatLng(value.lat, value.lng);
|
|
233
|
+
L.LatLng.prototype = {
|
|
234
|
+
equals(value, margin = 1e-9) {
|
|
235
|
+
value = latLng(value);
|
|
236
|
+
return Math.max(Math.abs(this.lat - value.lat), Math.abs(this.lng - value.lng)) <= margin;
|
|
237
|
+
},
|
|
238
|
+
distanceTo(value) { value = latLng(value); return ol.sphere.getDistance([this.lng, this.lat], [value.lng, value.lat]); },
|
|
239
|
+
wrap() { return new L.LatLng(this.lat, ((this.lng + 180) % 360 + 360) % 360 - 180, this.alt); },
|
|
240
|
+
};
|
|
241
|
+
L.Bounds = function (a, b) {
|
|
242
|
+
if (a) for (const value of b ? [a, b] : Array.isArray(a) ? a : [a]) this.extend(value);
|
|
243
|
+
};
|
|
244
|
+
L.Bounds.prototype = {
|
|
245
|
+
extend(value) {
|
|
246
|
+
if (value instanceof L.Bounds) { this.extend(value.min); this.extend(value.max); return this; }
|
|
247
|
+
value = point(value);
|
|
248
|
+
if (!this.min) { this.min = value.clone(); this.max = value.clone(); }
|
|
249
|
+
else {
|
|
250
|
+
this.min.x = Math.min(this.min.x, value.x); this.min.y = Math.min(this.min.y, value.y);
|
|
251
|
+
this.max.x = Math.max(this.max.x, value.x); this.max.y = Math.max(this.max.y, value.y);
|
|
252
|
+
}
|
|
253
|
+
return this;
|
|
254
|
+
},
|
|
255
|
+
getCenter() { return this.min.add(this.max).divideBy(2); },
|
|
256
|
+
getSize() { return this.max.subtract(this.min); },
|
|
257
|
+
contains(value) {
|
|
258
|
+
const min = value.min || point(value), max = value.max || min;
|
|
259
|
+
return min.x >= this.min.x && max.x <= this.max.x && min.y >= this.min.y && max.y <= this.max.y;
|
|
260
|
+
},
|
|
261
|
+
intersects(value) {
|
|
262
|
+
return value.max.x >= this.min.x && value.min.x <= this.max.x && value.max.y >= this.min.y && value.min.y <= this.max.y;
|
|
263
|
+
},
|
|
264
|
+
};
|
|
265
|
+
L.LatLngBounds = function (a, b) {
|
|
266
|
+
if (a) for (const value of b ? [a, b] : a) this.extend(value);
|
|
267
|
+
};
|
|
268
|
+
L.LatLngBounds.prototype = {
|
|
269
|
+
extend(value) {
|
|
270
|
+
if (value instanceof L.LatLngBounds) { this.extend(value._southWest); this.extend(value._northEast); return this; }
|
|
271
|
+
value = latLng(value);
|
|
272
|
+
if (!this._southWest) {
|
|
273
|
+
this._southWest = new L.LatLng(value.lat, value.lng);
|
|
274
|
+
this._northEast = new L.LatLng(value.lat, value.lng);
|
|
275
|
+
} else {
|
|
276
|
+
this._southWest.lat = Math.min(this._southWest.lat, value.lat);
|
|
277
|
+
this._southWest.lng = Math.min(this._southWest.lng, value.lng);
|
|
278
|
+
this._northEast.lat = Math.max(this._northEast.lat, value.lat);
|
|
279
|
+
this._northEast.lng = Math.max(this._northEast.lng, value.lng);
|
|
280
|
+
}
|
|
281
|
+
return this;
|
|
282
|
+
},
|
|
283
|
+
getSouthWest() { return this._southWest; },
|
|
284
|
+
getNorthEast() { return this._northEast; },
|
|
285
|
+
getNorthWest() { return new L.LatLng(this.getNorth(), this.getWest()); },
|
|
286
|
+
getSouthEast() { return new L.LatLng(this.getSouth(), this.getEast()); },
|
|
287
|
+
getNorth() { return this._northEast.lat; },
|
|
288
|
+
getSouth() { return this._southWest.lat; },
|
|
289
|
+
getEast() { return this._northEast.lng; },
|
|
290
|
+
getWest() { return this._southWest.lng; },
|
|
291
|
+
getCenter() { return new L.LatLng((this.getNorth() + this.getSouth()) / 2, (this.getEast() + this.getWest()) / 2); },
|
|
292
|
+
contains(value) {
|
|
293
|
+
value = latLng(value);
|
|
294
|
+
return value.lat >= this.getSouth() && value.lat <= this.getNorth() && value.lng >= this.getWest() && value.lng <= this.getEast();
|
|
295
|
+
},
|
|
296
|
+
isValid() { return Boolean(this._southWest && this._northEast); },
|
|
297
|
+
};
|
|
298
|
+
|
|
299
|
+
const radius = 6378137, circumference = 2 * Math.PI * radius;
|
|
300
|
+
const crs = {
|
|
301
|
+
scale: zoom => 256 * 2 ** zoom,
|
|
302
|
+
zoom: scale => Math.log2(scale / 256),
|
|
303
|
+
project(value) { value = latLng(value); return point(ol.proj.fromLonLat([value.lng, Math.max(-85.0511287798, Math.min(85.0511287798, value.lat))])); },
|
|
304
|
+
unproject(value) { const [lng, lat] = ol.proj.toLonLat([value.x, value.y]); return new L.LatLng(lat, lng); },
|
|
305
|
+
transformation: {
|
|
306
|
+
transform(value, scale) { return new L.Point((value.x / circumference + 0.5) * scale, (0.5 - value.y / circumference) * scale); },
|
|
307
|
+
untransform(value, scale) { return new L.Point((value.x / scale - 0.5) * circumference, (0.5 - value.y / scale) * circumference); },
|
|
308
|
+
},
|
|
309
|
+
};
|
|
310
|
+
|
|
311
|
+
L.DomUtil = {
|
|
312
|
+
create(tag, className = '', parent) {
|
|
313
|
+
const element = document.createElement(tag);
|
|
314
|
+
element.className = className; parent?.append(element); return element;
|
|
315
|
+
},
|
|
316
|
+
setPosition(element, value) { element._leaflet_pos = point(value); element.style.transform = `translate(${value.x}px,${value.y}px)`; },
|
|
317
|
+
getPosition(element) { return element._leaflet_pos || new L.Point(0, 0); },
|
|
318
|
+
};
|
|
319
|
+
const domListeners = new WeakMap();
|
|
320
|
+
function domEvent(add, element, types, fn, context) {
|
|
321
|
+
if (typeof types === 'object') {
|
|
322
|
+
for (const [type, handler] of Object.entries(types)) domEvent(add, element, type, handler, fn);
|
|
323
|
+
return L.DomEvent;
|
|
324
|
+
}
|
|
325
|
+
let listeners = domListeners.get(element);
|
|
326
|
+
if (!listeners) domListeners.set(element, listeners = []);
|
|
327
|
+
for (const type of types.split(/\s+/)) {
|
|
328
|
+
const existing = listeners.find(item => item.type === type && item.fn === fn && item.context === context);
|
|
329
|
+
if (add && !existing) {
|
|
330
|
+
const handler = context ? fn.bind(context) : fn;
|
|
331
|
+
listeners.push({ type, fn, context, handler });
|
|
332
|
+
element.addEventListener(type, handler, { passive: false });
|
|
333
|
+
} else if (!add && existing) {
|
|
334
|
+
element.removeEventListener(type, existing.handler);
|
|
335
|
+
listeners.splice(listeners.indexOf(existing), 1);
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
return L.DomEvent;
|
|
339
|
+
}
|
|
340
|
+
const stopPropagation = event => event.stopPropagation();
|
|
341
|
+
L.DomEvent = {
|
|
342
|
+
on: (...args) => domEvent(true, ...args),
|
|
343
|
+
off: (...args) => domEvent(false, ...args),
|
|
344
|
+
stop(event) { event.preventDefault(); event.stopPropagation(); },
|
|
345
|
+
disableClickPropagation(element) {
|
|
346
|
+
element.classList.add('leaflet-control');
|
|
347
|
+
L.DomEvent.on(element, 'click dblclick pointerdown mousedown touchstart contextmenu', stopPropagation);
|
|
348
|
+
return this;
|
|
349
|
+
},
|
|
350
|
+
disableScrollPropagation(element) { return this.on(element, 'wheel', stopPropagation); },
|
|
351
|
+
};
|
|
352
|
+
L.Handler = Class.extend({
|
|
353
|
+
initialize(map) { this._map = map; },
|
|
354
|
+
enable() { if (!this._enabled) { this._enabled = true; this.addHooks?.(); } return this; },
|
|
355
|
+
disable() { if (this._enabled) { this._enabled = false; this.removeHooks?.(); } return this; },
|
|
356
|
+
enabled() { return Boolean(this._enabled); },
|
|
357
|
+
moving() { return Boolean(this._moving); },
|
|
358
|
+
});
|
|
359
|
+
L.Layer = L.Evented.extend({
|
|
360
|
+
initialize(options) { setOptions(this, options); },
|
|
361
|
+
addTo(map) { map.addLayer(this); return this; },
|
|
362
|
+
remove() { return this.removeFrom(this._map || this._mapToAdd); },
|
|
363
|
+
removeFrom(map) { map?.removeLayer(this); return this; },
|
|
364
|
+
getAttribution() { return this.options.attribution; },
|
|
365
|
+
getPane(name) { return this._map.getPane(name || this.options.pane); },
|
|
366
|
+
_layerAdd({ target: map }) {
|
|
367
|
+
if (!map.hasLayer(this)) return;
|
|
368
|
+
this._map = map;
|
|
369
|
+
if (this.getEvents) { this._mapEvents = this.getEvents(); map.on(this._mapEvents, this); }
|
|
370
|
+
this.onAdd?.(map);
|
|
371
|
+
this.fire('add'); map.fire('layeradd', { layer: this });
|
|
372
|
+
},
|
|
373
|
+
});
|
|
374
|
+
L.LayerGroup = L.Layer.extend({
|
|
375
|
+
initialize(layers = [], options) {
|
|
376
|
+
setOptions(this, options); this._layers = {};
|
|
377
|
+
for (const layer of layers) this.addLayer(layer);
|
|
378
|
+
},
|
|
379
|
+
addLayer(layer) { this._layers[stamp(layer)] = layer; this._map?.addLayer(layer); return this; },
|
|
380
|
+
removeLayer(layer) { delete this._layers[stamp(layer)]; this._map?.removeLayer(layer); return this; },
|
|
381
|
+
hasLayer(layer) { return stamp(layer) in this._layers; },
|
|
382
|
+
eachLayer(fn, context) { for (const layer of Object.values(this._layers)) fn.call(context || this, layer); return this; },
|
|
383
|
+
onAdd(map) { this.eachLayer(map.addLayer, map); },
|
|
384
|
+
onRemove(map) { this.eachLayer(map.removeLayer, map); },
|
|
385
|
+
});
|
|
386
|
+
// Declare the hierarchy before the plugin installs its instanceof checks and hooks.
|
|
387
|
+
for (const [name, parent] of [
|
|
388
|
+
['GridLayer', L.Layer], ['Marker', L.Layer], ['Path', L.Layer],
|
|
389
|
+
['Polyline', null], ['Polygon', null], ['CircleMarker', null], ['Circle', null],
|
|
390
|
+
['ImageOverlay', L.Layer], ['VideoOverlay', null], ['SVGOverlay', null],
|
|
391
|
+
['Popup', L.Layer], ['Tooltip', L.Layer], ['DivIcon', Class],
|
|
392
|
+
]) {
|
|
393
|
+
const base = parent || ({ Polyline: L.Path, Polygon: L.Polyline, CircleMarker: L.Path,
|
|
394
|
+
Circle: L.CircleMarker, VideoOverlay: L.ImageOverlay, SVGOverlay: L.ImageOverlay })[name];
|
|
395
|
+
L[name] = base.extend({
|
|
396
|
+
initialize() { throw new Error(`L.${name} is not supported by the OpenLayers bindings; use L.Layer with a source`); },
|
|
397
|
+
getEvents() { return {}; },
|
|
398
|
+
});
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
L.Map = L.Evented.extend({
|
|
402
|
+
options: { crs, minZoom: 0, maxZoom: 24, zoomSnap: 1, touchZoom: true,
|
|
403
|
+
scrollWheelZoom: true, keyboard: true, doubleClickZoom: true,
|
|
404
|
+
wheelDebounceTime: 40, wheelPxPerZoomLevel: 60 },
|
|
405
|
+
initialize(target, options) {
|
|
406
|
+
setOptions(this, options);
|
|
407
|
+
this._container = typeof target === 'string' ? document.getElementById(target) : target;
|
|
408
|
+
if (!this._container) throw new Error('Map container not found');
|
|
409
|
+
stamp(this._container);
|
|
410
|
+
this._container.classList.add('openlayers-city-mapper');
|
|
411
|
+
this._layers = {}; this._panes = {}; this._handlers = []; this._controls = new Set();
|
|
412
|
+
const center = crs.project(this.options.center || [0, 0]);
|
|
413
|
+
this.ol = new ol.Map({
|
|
414
|
+
target: this._container, controls: [new ol.control.Zoom(), new ol.control.Attribution({collapsible: false })],
|
|
415
|
+
interactions: [],
|
|
416
|
+
view: new ol.View({ center: [center.x, center.y], zoom: this.options.zoom || 0,
|
|
417
|
+
minZoom: this.getMinZoom(), maxZoom: this.getMaxZoom() }),
|
|
418
|
+
});
|
|
419
|
+
for (const control of this.ol.getControls().getArray()) {
|
|
420
|
+
control.element.classList.add('leaflet-control');
|
|
421
|
+
for (const button of control.element.querySelectorAll('button[title]')) button.setAttribute('aria-label', button.title);
|
|
422
|
+
if (control instanceof ol.control.Zoom) {
|
|
423
|
+
for (const [selector, delta] of [['.ol-zoom-in', 1], ['.ol-zoom-out', -1]]) {
|
|
424
|
+
control.element.querySelector(selector).addEventListener('click', event => {
|
|
425
|
+
L.DomEvent.stop(event);
|
|
426
|
+
event.stopImmediatePropagation();
|
|
427
|
+
this._zoomBy(delta * (event.shiftKey ? 3 : 1));
|
|
428
|
+
}, true);
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
this._loaded = true;
|
|
433
|
+
this._zoomAnimated = false;
|
|
434
|
+
this.dragging = new L.Handler(this).enable();
|
|
435
|
+
this.touchZoom = new L.Handler(this);
|
|
436
|
+
if (this.options.touchZoom) this.touchZoom.enable();
|
|
437
|
+
this._handlers.push(this.dragging, this.touchZoom);
|
|
438
|
+
for (const name of ['scrollWheelZoom', 'keyboard', 'doubleClickZoom']) this.addHandler(name, L.Handler);
|
|
439
|
+
if (!this._container.hasAttribute('tabindex')) this._container.tabIndex = 0;
|
|
440
|
+
const view = this.ol.getView();
|
|
441
|
+
this._viewZoom = view.getZoom();
|
|
442
|
+
view.on(['change:center', 'change:resolution'], () => {
|
|
443
|
+
if (this._settingView) return;
|
|
444
|
+
const zoomChanged = view.getZoom() !== this._viewZoom;
|
|
445
|
+
if (!this._viewMoving) { this._viewMoving = true; this.fire('movestart'); }
|
|
446
|
+
if (zoomChanged && !this._viewZooming) { this._viewZooming = true; this.fire('zoomstart'); }
|
|
447
|
+
this.fire('move');
|
|
448
|
+
if (zoomChanged) this.fire('zoom');
|
|
449
|
+
this._viewZoom = view.getZoom();
|
|
450
|
+
if (!view.getAnimating() && !view.getInteracting()) this._endViewChange();
|
|
451
|
+
});
|
|
452
|
+
this.ol.on('moveend', () => this._endViewChange());
|
|
453
|
+
// OpenLayers interactions need the pitched ground coordinate, not the flat viewport.
|
|
454
|
+
this.ol.getCoordinateFromPixel = pixel => {
|
|
455
|
+
const coordinate = crs.project(this.containerPointToLatLng(point(pixel)));
|
|
456
|
+
return [coordinate.x, coordinate.y];
|
|
457
|
+
};
|
|
458
|
+
this._wheelDelta = 0;
|
|
459
|
+
this.ol.addInteraction(new ol.interaction.Interaction({
|
|
460
|
+
handleEvent: event => {
|
|
461
|
+
const original = event.originalEvent;
|
|
462
|
+
if (original.target.closest('.ol-control')) return true;
|
|
463
|
+
if (event.type === 'dblclick' && this.doubleClickZoom.enabled()) {
|
|
464
|
+
this._zoomBy(original.shiftKey ? -1 : 1, point(event.pixel));
|
|
465
|
+
} else if (event.type === 'wheel' && this.scrollWheelZoom.enabled() && !original.shiftKey) {
|
|
466
|
+
const ratio = window.devicePixelRatio || 1;
|
|
467
|
+
const factor = /Linux/.test(navigator.platform) && /Chrome/.test(navigator.userAgent) ? ratio
|
|
468
|
+
: /Mac/.test(navigator.platform) ? 3 * ratio : 2 * ratio;
|
|
469
|
+
this._wheelDelta -= original.deltaY * (original.deltaMode === 1 ? 20
|
|
470
|
+
: original.deltaMode === 2 ? 60 : 1 / factor);
|
|
471
|
+
this._wheelPixel = point(event.pixel);
|
|
472
|
+
this._wheelStart ??= performance.now();
|
|
473
|
+
clearTimeout(this._wheelTimer);
|
|
474
|
+
this._wheelTimer = setTimeout(() => {
|
|
475
|
+
const magnitude = 4 * Math.log2(2 / (1 + Math.exp(-Math.abs(this._wheelDelta /
|
|
476
|
+
(this.options.wheelPxPerZoomLevel * 4)))));
|
|
477
|
+
const snap = this.options.zoomSnap;
|
|
478
|
+
const delta = Math.sign(this._wheelDelta) * (snap ? Math.ceil(magnitude / snap) * snap : magnitude);
|
|
479
|
+
this._wheelDelta = 0;
|
|
480
|
+
this._wheelStart = null;
|
|
481
|
+
if (this._loaded && this.scrollWheelZoom.enabled()) this._zoomBy(delta,
|
|
482
|
+
this.options.scrollWheelZoom === 'center' ? undefined : this._wheelPixel);
|
|
483
|
+
}, Math.max(0, this.options.wheelDebounceTime - (performance.now() - this._wheelStart)));
|
|
484
|
+
} else return true;
|
|
485
|
+
original.preventDefault();
|
|
486
|
+
return false;
|
|
487
|
+
},
|
|
488
|
+
}));
|
|
489
|
+
this._controlCorners = {};
|
|
490
|
+
for (const position of ['topleft', 'topright', 'bottomleft', 'bottomright']) {
|
|
491
|
+
this._controlCorners[position] = L.DomUtil.create('div',
|
|
492
|
+
`ol-city-corner ol-city-${position}`, this.ol.getOverlayContainerStopEvent());
|
|
493
|
+
}
|
|
494
|
+
const attributionSource = new ol.source.Vector();
|
|
495
|
+
this.ol.addLayer(new ol.layer.Vector({ source: attributionSource }));
|
|
496
|
+
const updateAttribution = () => {
|
|
497
|
+
const values = new Set(['<a href="https://openlayers.org/">OpenLayers</a>']);
|
|
498
|
+
this.eachLayer(layer => { if (layer.getAttribution?.()) values.add(layer.getAttribution()); });
|
|
499
|
+
attributionSource.setAttributions([...values]);
|
|
500
|
+
};
|
|
501
|
+
this.on('layeradd layerremove', updateAttribution);
|
|
502
|
+
updateAttribution();
|
|
503
|
+
let anchor, pointerId;
|
|
504
|
+
const pixel = event => {
|
|
505
|
+
const rect = this._container.getBoundingClientRect();
|
|
506
|
+
return new L.Point(event.clientX - rect.left, event.clientY - rect.top);
|
|
507
|
+
};
|
|
508
|
+
this._onPointer = event => {
|
|
509
|
+
if (event.type === 'pointerdown') {
|
|
510
|
+
if (!this.dragging.enabled() || event.button !== 0 || !event.isPrimary || event.target.closest('.ol-control')) return;
|
|
511
|
+
anchor = this.containerPointToLatLng(pixel(event)); pointerId = event.pointerId;
|
|
512
|
+
this._moved = this.dragging._moving = false;
|
|
513
|
+
this._container.focus({ preventScroll: true });
|
|
514
|
+
this._container.setPointerCapture(pointerId);
|
|
515
|
+
} else if (event.pointerId === pointerId && event.type === 'pointermove' && this.dragging.enabled()) {
|
|
516
|
+
const delta = this.project(anchor).subtract(this.project(this.containerPointToLatLng(pixel(event))));
|
|
517
|
+
if (Math.hypot(delta.x, delta.y) > 1) this._moved = this.dragging._moving = true;
|
|
518
|
+
this.setView(this.unproject(this.project(this.getCenter()).add(delta)), this.getZoom());
|
|
519
|
+
} else if (event.pointerId === pointerId && event.type !== 'pointermove') {
|
|
520
|
+
if (this._container.hasPointerCapture(pointerId)) this._container.releasePointerCapture(pointerId);
|
|
521
|
+
anchor = null; pointerId = null;
|
|
522
|
+
this.dragging._moving = false;
|
|
523
|
+
}
|
|
524
|
+
};
|
|
525
|
+
this._onKey = event => {
|
|
526
|
+
if (!this.keyboard.enabled() || event.target !== this._container || event.altKey || event.ctrlKey || event.metaKey) return;
|
|
527
|
+
const offsets = { ArrowLeft: [-80, 0], ArrowRight: [80, 0], ArrowUp: [0, -80], ArrowDown: [0, 80] };
|
|
528
|
+
if (offsets[event.key]) this.panBy(offsets[event.key]);
|
|
529
|
+
else if (['+', '=', '-', '_'].includes(event.key)) this._zoomBy(
|
|
530
|
+
(['-', '_'].includes(event.key) ? -1 : 1) * (event.shiftKey ? 3 : 1));
|
|
531
|
+
else return;
|
|
532
|
+
event.preventDefault();
|
|
533
|
+
};
|
|
534
|
+
L.DomEvent.on(this._container, 'pointerdown pointermove pointerup pointercancel', this._onPointer);
|
|
535
|
+
L.DomEvent.on(this._container, 'keydown', this._onKey);
|
|
536
|
+
this.ol.on('change:size', () => this.fire('resize', { newSize: this.getSize() }));
|
|
537
|
+
this.ol.updateSize();
|
|
538
|
+
},
|
|
539
|
+
getContainer() { return this._container; },
|
|
540
|
+
getSize() { return point(this.ol.getSize() || [this._container.clientWidth, this._container.clientHeight]); },
|
|
541
|
+
getCenter() { return crs.unproject(point(this.ol.getView().getCenter())); },
|
|
542
|
+
getZoom() { return this.ol.getView().getZoom(); },
|
|
543
|
+
getMinZoom() { return this.options.minZoom; },
|
|
544
|
+
getMaxZoom() { return this.options.maxZoom; },
|
|
545
|
+
getZoomScale(to, from = this.getZoom()) { return 2 ** (to - from); },
|
|
546
|
+
getScaleZoom(scale, from = this.getZoom()) { return from + Math.log2(scale); },
|
|
547
|
+
_limitZoom(zoom) { return Math.max(this.getMinZoom(), Math.min(this.getMaxZoom(), zoom)); },
|
|
548
|
+
project(value, zoom = this.getZoom()) { return crs.transformation.transform(crs.project(value), crs.scale(zoom)); },
|
|
549
|
+
unproject(value, zoom = this.getZoom()) { return crs.unproject(crs.transformation.untransform(point(value), crs.scale(zoom))); },
|
|
550
|
+
getPixelOrigin() { return this.project(this.getCenter()).subtract(this.getSize().divideBy(2)); },
|
|
551
|
+
_getMapPanePos() { return new L.Point(0, 0); },
|
|
552
|
+
latLngToLayerPoint(value) { return this.project(value).subtract(this.getPixelOrigin()); },
|
|
553
|
+
layerPointToLatLng(value) { return this.unproject(point(value).add(this.getPixelOrigin())); },
|
|
554
|
+
layerPointToContainerPoint(value) { return point(value).clone(); },
|
|
555
|
+
containerPointToLayerPoint(value) { return point(value).clone(); },
|
|
556
|
+
latLngToContainerPoint(value) { return this.layerPointToContainerPoint(this.latLngToLayerPoint(value)); },
|
|
557
|
+
containerPointToLatLng(value) { return this.layerPointToLatLng(this.containerPointToLayerPoint(value)); },
|
|
558
|
+
getBounds() { return new L.LatLngBounds(this.containerPointToLatLng([0, 0]), this.containerPointToLatLng(this.getSize())); },
|
|
559
|
+
_endViewChange() {
|
|
560
|
+
if (!this._viewMoving) return;
|
|
561
|
+
const zooming = this._viewZooming;
|
|
562
|
+
this._viewMoving = this._viewZooming = false;
|
|
563
|
+
if (zooming) this.fire('zoomend');
|
|
564
|
+
this.fire('moveend');
|
|
565
|
+
},
|
|
566
|
+
_zoomBy(delta, pixel) {
|
|
567
|
+
if (!delta || this.ol.getView().getAnimating()) return this;
|
|
568
|
+
const zoom = this._limitZoom(this.getZoom() + delta);
|
|
569
|
+
return pixel ? this.setZoomAround(pixel, zoom, { animate: true })
|
|
570
|
+
: this.setZoom(zoom, { animate: true });
|
|
571
|
+
},
|
|
572
|
+
setView(center, zoom = this.getZoom(), options = {}) {
|
|
573
|
+
center = latLng(center); zoom = this._limitZoom(zoom);
|
|
574
|
+
if ((options.animate === true || options.zoom?.animate === true) && zoom !== this.getZoom()) {
|
|
575
|
+
const scale = this.getZoomScale(zoom), projected = crs.project(center);
|
|
576
|
+
// Leaflet animates CSS scale, not resolution; convert the same native CSS easing.
|
|
577
|
+
this.ol.getView().animate({
|
|
578
|
+
center: [projected.x, projected.y], zoom, duration: 250,
|
|
579
|
+
easing: time => {
|
|
580
|
+
zoomTiming.currentTime = time;
|
|
581
|
+
const progress = zoomTiming.effect.getComputedTiming().progress;
|
|
582
|
+
return (1 - 1 / (1 + (scale - 1) * progress)) / (1 - 1 / scale);
|
|
583
|
+
},
|
|
584
|
+
});
|
|
585
|
+
return this;
|
|
586
|
+
}
|
|
587
|
+
this.ol.getView().cancelAnimations();
|
|
588
|
+
this._endViewChange();
|
|
589
|
+
const zoomChanged = zoom !== this.getZoom(), moved = !center.equals(this.getCenter());
|
|
590
|
+
if (!zoomChanged && !moved) return this;
|
|
591
|
+
this.fire('movestart');
|
|
592
|
+
if (zoomChanged) this.fire('zoomstart');
|
|
593
|
+
this._settingView = true;
|
|
594
|
+
const projected = crs.project(center);
|
|
595
|
+
this.ol.getView().setCenter([projected.x, projected.y]);
|
|
596
|
+
this.ol.getView().setZoom(zoom);
|
|
597
|
+
this._viewZoom = this.getZoom();
|
|
598
|
+
this._settingView = false;
|
|
599
|
+
if (zoomChanged) this.fire('zoom');
|
|
600
|
+
this.fire('move').fire('viewreset');
|
|
601
|
+
if (zoomChanged) this.fire('zoomend');
|
|
602
|
+
return this.fire('moveend');
|
|
603
|
+
},
|
|
604
|
+
setZoom(zoom, options) { return this.setView(this.getCenter(), zoom, options); },
|
|
605
|
+
panTo(center) { return this.setView(center); },
|
|
606
|
+
panBy(offset) { return this.panTo(this.unproject(this.project(this.getCenter()).add(point(offset)))); },
|
|
607
|
+
setZoomAround(value, zoom, options) {
|
|
608
|
+
const anchor = value instanceof L.Point ? value : this.latLngToContainerPoint(value);
|
|
609
|
+
const half = this.getSize().divideBy(2), scale = this.getZoomScale(zoom);
|
|
610
|
+
return this.setView(this.unproject(this.project(this.getCenter()).add(anchor.subtract(half).multiplyBy(1 - 1 / scale))), zoom, options);
|
|
611
|
+
},
|
|
612
|
+
getBoundsZoom(bounds, inside, padding = [0, 0]) {
|
|
613
|
+
const size = this.project(bounds.getSouthEast()).subtract(this.project(bounds.getNorthWest()));
|
|
614
|
+
const available = this.getSize().subtract(point(padding));
|
|
615
|
+
const scale = Math[inside ? 'max' : 'min'](available.x / size.x, available.y / size.y);
|
|
616
|
+
return this._limitZoom(this.getScaleZoom(scale));
|
|
617
|
+
},
|
|
618
|
+
_getBoundsCenterZoom(bounds, options = {}) { return { center: bounds.getCenter(), zoom: this.getBoundsZoom(bounds, false, options.padding) }; },
|
|
619
|
+
fitBounds(bounds, options) { const view = this._getBoundsCenterZoom(bounds, options); return this.setView(view.center, view.zoom); },
|
|
620
|
+
_limitCenter(center) { return center; },
|
|
621
|
+
_limitOffset(offset) { return offset; },
|
|
622
|
+
_tryAnimatedPan() { return false; },
|
|
623
|
+
panInside(value) { if (!this.getBounds().contains(value)) this.panTo(value); return this; },
|
|
624
|
+
whenReady(fn, context) { if (this._loaded) fn.call(context || this, { target: this }); else this.once('load', fn, context); return this; },
|
|
625
|
+
addLayer(layer) {
|
|
626
|
+
const id = stamp(layer);
|
|
627
|
+
if (this._layers[id]) return this;
|
|
628
|
+
this._layers[id] = layer; layer._mapToAdd = this;
|
|
629
|
+
layer.beforeAdd?.(this);
|
|
630
|
+
this.whenReady(layer._layerAdd, layer);
|
|
631
|
+
return this;
|
|
632
|
+
},
|
|
633
|
+
removeLayer(layer) {
|
|
634
|
+
if (!this.hasLayer(layer)) return this;
|
|
635
|
+
layer.onRemove?.(this);
|
|
636
|
+
if (layer._mapEvents) this.off(layer._mapEvents, layer);
|
|
637
|
+
delete this._layers[stamp(layer)];
|
|
638
|
+
this.fire('layerremove', { layer }); layer.fire('remove');
|
|
639
|
+
layer._map = layer._mapToAdd = null;
|
|
640
|
+
return this;
|
|
641
|
+
},
|
|
642
|
+
hasLayer(layer) { return Boolean(this._layers[stamp(layer)]); },
|
|
643
|
+
eachLayer(fn, context) { for (const layer of Object.values(this._layers)) fn.call(context || this, layer); return this; },
|
|
644
|
+
createPane(name, parent = this._container) { return this._panes[name] = L.DomUtil.create('div', `leaflet-pane leaflet-${name}`, parent); },
|
|
645
|
+
getPane(name = 'overlayPane') { return this._panes[name]; },
|
|
646
|
+
addHandler(name, Handler) { this[name] = new Handler(this); this._handlers.push(this[name]); if (this.options[name]) this[name].enable(); return this; },
|
|
647
|
+
invalidateSize() { this.ol.updateSize(); return this; },
|
|
648
|
+
_draggableMoved() { return Boolean(this._moved); },
|
|
649
|
+
remove() {
|
|
650
|
+
clearTimeout(this._wheelTimer);
|
|
651
|
+
this.ol.getView().cancelAnimations();
|
|
652
|
+
this.fire('unload');
|
|
653
|
+
for (const control of [...this._controls]) control.remove();
|
|
654
|
+
this.eachLayer(this.removeLayer, this);
|
|
655
|
+
for (const handler of this._handlers) handler.disable();
|
|
656
|
+
L.DomEvent.off(this._container, 'pointerdown pointermove pointerup pointercancel', this._onPointer);
|
|
657
|
+
L.DomEvent.off(this._container, 'keydown', this._onKey);
|
|
658
|
+
this.ol.setTarget(undefined); this.ol.dispose();
|
|
659
|
+
for (const corner of Object.values(this._controlCorners)) corner.remove();
|
|
660
|
+
for (const pane of Object.values(this._panes)) pane.remove();
|
|
661
|
+
this._loaded = false;
|
|
662
|
+
delete this._container._leaflet_id;
|
|
663
|
+
return this.off();
|
|
664
|
+
},
|
|
665
|
+
});
|
|
666
|
+
|
|
667
|
+
L.Control = Class.extend({
|
|
668
|
+
options: { position: 'topright' },
|
|
669
|
+
initialize(options) { setOptions(this, options); },
|
|
670
|
+
getPosition() { return this.options.position; },
|
|
671
|
+
getContainer() { return this._container; },
|
|
672
|
+
addTo(map) {
|
|
673
|
+
this.remove(); this._map = map;
|
|
674
|
+
this._container = this.onAdd(map);
|
|
675
|
+
if (L.Control.Rotate && this instanceof L.Control.Rotate) {
|
|
676
|
+
this._container.classList.add('ol-city-rotate');
|
|
677
|
+
}
|
|
678
|
+
this._container.classList.add('leaflet-control', 'ol-control', 'ol-city-control');
|
|
679
|
+
this._olControl = new ol.control.Control({
|
|
680
|
+
element: this._container, target: map._controlCorners[this.getPosition()],
|
|
681
|
+
});
|
|
682
|
+
map.ol.addControl(this._olControl);
|
|
683
|
+
map._controls.add(this);
|
|
684
|
+
return this;
|
|
685
|
+
},
|
|
686
|
+
remove() {
|
|
687
|
+
if (!this._map) return this;
|
|
688
|
+
const map = this._map;
|
|
689
|
+
this.onRemove?.(map); this._container?.remove();
|
|
690
|
+
map.ol.removeControl(this._olControl);
|
|
691
|
+
map._controls.delete(this); this._map = null;
|
|
692
|
+
return this;
|
|
693
|
+
},
|
|
694
|
+
});
|
|
695
|
+
L.Control.Layers = L.Control.extend({
|
|
696
|
+
options: { collapsed: true },
|
|
697
|
+
initialize(base = {}, overlays = {}, options) {
|
|
698
|
+
setOptions(this, options); this._layers = [];
|
|
699
|
+
for (const [name, layer] of Object.entries(base)) this._layers.push({ name, layer, overlay: false });
|
|
700
|
+
for (const [name, layer] of Object.entries(overlays)) this._layers.push({ name, layer, overlay: true });
|
|
701
|
+
},
|
|
702
|
+
onAdd(map) {
|
|
703
|
+
const container = L.DomUtil.create('div', 'ol-city-layers');
|
|
704
|
+
L.DomEvent.disableClickPropagation(container); L.DomEvent.disableScrollPropagation(container);
|
|
705
|
+
const list = L.DomUtil.create('section', '', container);
|
|
706
|
+
list.setAttribute('aria-label', 'Map layers');
|
|
707
|
+
const base = L.DomUtil.create('div', '', list);
|
|
708
|
+
L.DomUtil.create('hr', '', list);
|
|
709
|
+
const overlays = L.DomUtil.create('div', '', list);
|
|
710
|
+
this._inputs = [];
|
|
711
|
+
for (const entry of this._layers) {
|
|
712
|
+
const label = L.DomUtil.create('label', '', entry.overlay ? overlays : base);
|
|
713
|
+
const input = L.DomUtil.create('input', 'leaflet-control-layers-selector', label);
|
|
714
|
+
input.type = entry.overlay ? 'checkbox' : 'radio';
|
|
715
|
+
input.name = `base-${stamp(this)}`; input.layerId = stamp(entry.layer);
|
|
716
|
+
input.checked = map.hasLayer(entry.layer);
|
|
717
|
+
label.append(document.createTextNode(` ${entry.name}`));
|
|
718
|
+
this._inputs.push(input);
|
|
719
|
+
input.onchange = () => {
|
|
720
|
+
const checked = input.checked;
|
|
721
|
+
if (!entry.overlay) for (const other of this._layers) {
|
|
722
|
+
if (!other.overlay && other !== entry) map.removeLayer(other.layer);
|
|
723
|
+
}
|
|
724
|
+
if (checked) map.addLayer(entry.layer); else map.removeLayer(entry.layer);
|
|
725
|
+
};
|
|
726
|
+
}
|
|
727
|
+
map.on('layeradd layerremove', this._update, this);
|
|
728
|
+
return container;
|
|
729
|
+
},
|
|
730
|
+
_update() { for (const input of this._inputs) input.checked = Boolean(this._map._layers[input.layerId]); },
|
|
731
|
+
onRemove(map) { map.off('layeradd layerremove', this._update, this); },
|
|
732
|
+
});
|
|
733
|
+
|
|
734
|
+
// Native layer contracts consumed by the plugin's WebGPU renderer.
|
|
735
|
+
const bounds = value => value instanceof L.LatLngBounds ? value : new L.LatLngBounds(value);
|
|
736
|
+
const coordinates = values => values.map(value => Array.isArray(value) && typeof value[0] !== 'number'
|
|
737
|
+
? coordinates(value) : latLng(value));
|
|
738
|
+
const image = (url, options, className) => {
|
|
739
|
+
const element = document.createElement('img');
|
|
740
|
+
element.className = className;
|
|
741
|
+
if (options.crossOrigin) element.crossOrigin = options.crossOrigin === true ? '' : options.crossOrigin;
|
|
742
|
+
element.src = url;
|
|
743
|
+
element.draggable = false;
|
|
744
|
+
return element;
|
|
745
|
+
};
|
|
746
|
+
|
|
747
|
+
L.Layer.include({
|
|
748
|
+
bindPopup(content) {
|
|
749
|
+
this._popupContent = content;
|
|
750
|
+
this.off('click', this.openPopup, this).on('click', this.openPopup, this);
|
|
751
|
+
this.once('remove', this.closePopup, this);
|
|
752
|
+
if (this instanceof L.LayerGroup) this.eachLayer(layer => layer.bindPopup(content));
|
|
753
|
+
return this;
|
|
754
|
+
},
|
|
755
|
+
openPopup(event) {
|
|
756
|
+
if (!this._map) return this;
|
|
757
|
+
this.closePopup();
|
|
758
|
+
const location = event?.latlng || this.getLatLng?.() || this.getBounds?.().getCenter();
|
|
759
|
+
if (!location) throw new Error('Popup requires a location');
|
|
760
|
+
const element = L.DomUtil.create('div', 'ol-city-popup leaflet-popup');
|
|
761
|
+
element.setAttribute('role', 'dialog');
|
|
762
|
+
const close = L.DomUtil.create('button', '', element);
|
|
763
|
+
close.type = 'button'; close.textContent = '\u00d7'; close.setAttribute('aria-label', 'Close popup');
|
|
764
|
+
close.onclick = () => this.closePopup();
|
|
765
|
+
const content = L.DomUtil.create('div', '', element);
|
|
766
|
+
const value = typeof this._popupContent === 'function' ? this._popupContent(this) : this._popupContent;
|
|
767
|
+
if (value instanceof Node) content.append(value); else content.innerHTML = value;
|
|
768
|
+
L.DomEvent.disableClickPropagation(element);
|
|
769
|
+
this._popupOverlay = new ol.Overlay({ element, positioning: 'bottom-center', offset: [0, -12] });
|
|
770
|
+
this._map.ol.addOverlay(this._popupOverlay);
|
|
771
|
+
this._popupLocation = latLng(location);
|
|
772
|
+
this._map.on('move zoom rotate pitch', this._positionPopup, this);
|
|
773
|
+
this._positionPopup();
|
|
774
|
+
return this;
|
|
775
|
+
},
|
|
776
|
+
_positionPopup() {
|
|
777
|
+
const screen = this._map.latLngToContainerPoint(this._popupLocation);
|
|
778
|
+
this._popupOverlay.setPosition(this._map.ol.getCoordinateFromPixelInternal([screen.x, screen.y]));
|
|
779
|
+
},
|
|
780
|
+
closePopup() {
|
|
781
|
+
if (this._popupOverlay) {
|
|
782
|
+
this._map?.off('move zoom rotate pitch', this._positionPopup, this);
|
|
783
|
+
this._map?.ol.removeOverlay(this._popupOverlay);
|
|
784
|
+
this._popupOverlay = null;
|
|
785
|
+
}
|
|
786
|
+
return this;
|
|
787
|
+
},
|
|
788
|
+
bindTooltip(content) {
|
|
789
|
+
this._tooltipContent = content;
|
|
790
|
+
this.on('mouseover', this._showTooltip, this).on('mouseout remove', this._hideTooltip, this);
|
|
791
|
+
if (this instanceof L.LayerGroup) this.eachLayer(layer => layer.bindTooltip(content));
|
|
792
|
+
return this;
|
|
793
|
+
},
|
|
794
|
+
_showTooltip(event) {
|
|
795
|
+
this._hideTooltip();
|
|
796
|
+
if (!this._map || !event.latlng) return;
|
|
797
|
+
const element = this._tooltipElement = L.DomUtil.create('div', 'ol-city-tooltip leaflet-tooltip', this._map.getContainer());
|
|
798
|
+
element.setAttribute('role', 'tooltip');
|
|
799
|
+
const value = typeof this._tooltipContent === 'function' ? this._tooltipContent(this) : this._tooltipContent;
|
|
800
|
+
if (value instanceof Node) element.append(value); else element.innerHTML = value;
|
|
801
|
+
const pixel = this._map.latLngToContainerPoint(event.latlng);
|
|
802
|
+
element.style.left = `${pixel.x + 12}px`; element.style.top = `${pixel.y + 12}px`;
|
|
803
|
+
},
|
|
804
|
+
_hideTooltip() { this._tooltipElement?.remove(); this._tooltipElement = null; },
|
|
805
|
+
});
|
|
806
|
+
L.LayerGroup.include({
|
|
807
|
+
getLayers() { return Object.values(this._layers); },
|
|
808
|
+
getBounds() {
|
|
809
|
+
const result = new L.LatLngBounds();
|
|
810
|
+
this.eachLayer(layer => result.extend(layer.getBounds?.() || layer.getLatLng()));
|
|
811
|
+
return result;
|
|
812
|
+
},
|
|
813
|
+
});
|
|
814
|
+
L.FeatureGroup = L.LayerGroup.extend({});
|
|
815
|
+
|
|
816
|
+
L.Path.include({
|
|
817
|
+
options: { pane: 'overlayPane', interactive: true, stroke: true, color: '#3388ff',
|
|
818
|
+
weight: 3, opacity: 1, lineCap: 'round', lineJoin: 'round', fill: false, fillOpacity: 0.2 },
|
|
819
|
+
initialize(options) { L.Util.setOptions(this, options); },
|
|
820
|
+
setStyle(options) { L.Util.setOptions(this, options); return this.redraw(); },
|
|
821
|
+
redraw() { return this; },
|
|
822
|
+
bringToFront() { return this; },
|
|
823
|
+
bringToBack() { return this; },
|
|
824
|
+
});
|
|
825
|
+
L.Polyline.include({
|
|
826
|
+
initialize(values, options) { L.Util.setOptions(this, options); this.setLatLngs(values); },
|
|
827
|
+
getLatLngs() { return this._latlngs; },
|
|
828
|
+
setLatLngs(values) { this._latlngs = coordinates(values); return this.redraw(); },
|
|
829
|
+
addLatLng(value) { this._latlngs.push(latLng(value)); return this.redraw(); },
|
|
830
|
+
getBounds() {
|
|
831
|
+
const result = new L.LatLngBounds();
|
|
832
|
+
const visit = values => { for (const value of values) Array.isArray(value) ? visit(value) : result.extend(value); };
|
|
833
|
+
visit(this._latlngs);
|
|
834
|
+
return result;
|
|
835
|
+
},
|
|
836
|
+
_project() {
|
|
837
|
+
this._rings = [];
|
|
838
|
+
const visit = values => {
|
|
839
|
+
if (!values.length) return;
|
|
840
|
+
if (Array.isArray(values[0])) values.forEach(visit);
|
|
841
|
+
else this._rings.push(values.map(value => this._map.latLngToLayerPoint(value)));
|
|
842
|
+
};
|
|
843
|
+
visit(this._latlngs);
|
|
844
|
+
},
|
|
845
|
+
closestLayerPoint(value) {
|
|
846
|
+
this._project();
|
|
847
|
+
const paths = this._rings.map(ring => ring.map(value => [value.x, value.y]));
|
|
848
|
+
const closest = new ol.geom.MultiLineString(paths).getClosestPoint([value.x, value.y]);
|
|
849
|
+
return point(closest);
|
|
850
|
+
},
|
|
851
|
+
});
|
|
852
|
+
L.Polyline.mergeOptions(L.Path.prototype.options);
|
|
853
|
+
L.Polygon.include({ initialize: L.Polyline.prototype.initialize });
|
|
854
|
+
L.Polygon.mergeOptions(L.Path.prototype.options);
|
|
855
|
+
L.Polygon.mergeOptions({ fill: true });
|
|
856
|
+
L.Rectangle = L.Polygon.extend({
|
|
857
|
+
initialize(value, options) { L.Util.setOptions(this, options); this.setBounds(value); },
|
|
858
|
+
setBounds(value) {
|
|
859
|
+
value = bounds(value);
|
|
860
|
+
return this.setLatLngs([value.getSouthWest(), value.getNorthWest(), value.getNorthEast(), value.getSouthEast()]);
|
|
861
|
+
},
|
|
862
|
+
});
|
|
863
|
+
L.CircleMarker.include({
|
|
864
|
+
options: { ...L.Path.prototype.options, fill: true, radius: 10 },
|
|
865
|
+
initialize(value, options) { L.Util.setOptions(this, options); this._latlng = latLng(value); },
|
|
866
|
+
getLatLng() { return this._latlng; },
|
|
867
|
+
setLatLng(value) { this._latlng = latLng(value); this.fire('move', { latlng: this._latlng }); return this.redraw(); },
|
|
868
|
+
getRadius() { return this.options.radius; },
|
|
869
|
+
setRadius(radius) { this.options.radius = radius; return this.redraw(); },
|
|
870
|
+
});
|
|
871
|
+
L.Circle.include({
|
|
872
|
+
initialize: L.CircleMarker.prototype.initialize,
|
|
873
|
+
_project() {
|
|
874
|
+
this._point = this._map.latLngToLayerPoint(this._latlng);
|
|
875
|
+
this._radius = this._radiusY = this.getRadius() * this._map.options.crs.scale(this._map.getZoom()) /
|
|
876
|
+
(2 * Math.PI * 6378137 * Math.cos(this._latlng.lat * Math.PI / 180));
|
|
877
|
+
},
|
|
878
|
+
getBounds() {
|
|
879
|
+
const north = this.getRadius() / 6378137 * 180 / Math.PI;
|
|
880
|
+
const east = north / Math.cos(this._latlng.lat * Math.PI / 180);
|
|
881
|
+
return new L.LatLngBounds([this._latlng.lat - north, this._latlng.lng - east],
|
|
882
|
+
[this._latlng.lat + north, this._latlng.lng + east]);
|
|
883
|
+
},
|
|
884
|
+
});
|
|
885
|
+
L.Circle.mergeOptions(L.CircleMarker.prototype.options);
|
|
886
|
+
L.GeoJSON = L.FeatureGroup.extend({
|
|
887
|
+
initialize(data, options) {
|
|
888
|
+
L.LayerGroup.prototype.initialize.call(this, [], options);
|
|
889
|
+
if (data) this.addData(data);
|
|
890
|
+
},
|
|
891
|
+
addData(data) {
|
|
892
|
+
const features = new ol.format.GeoJSON().readFeatures(data);
|
|
893
|
+
const convert = (geometry, feature) => {
|
|
894
|
+
const values = geometry.getCoordinates();
|
|
895
|
+
const locations = value => typeof value[0] === 'number' ? [value[1], value[0]] : value.map(locations);
|
|
896
|
+
switch (geometry.getType()) {
|
|
897
|
+
case 'Point': return this.options.pointToLayer
|
|
898
|
+
? this.options.pointToLayer(feature, latLng(locations(values))) : new L.Marker(locations(values));
|
|
899
|
+
case 'MultiPoint': return new L.FeatureGroup(values.map(value => convert(new ol.geom.Point(value), feature)));
|
|
900
|
+
case 'LineString': case 'MultiLineString': return new L.Polyline(locations(values), this.options);
|
|
901
|
+
case 'Polygon': case 'MultiPolygon': return new L.Polygon(locations(values), this.options);
|
|
902
|
+
default: throw new Error(`Unsupported GeoJSON geometry: ${geometry.getType()}`);
|
|
903
|
+
}
|
|
904
|
+
};
|
|
905
|
+
for (const feature of features) {
|
|
906
|
+
const layer = convert(feature.getGeometry(), new ol.format.GeoJSON().writeFeatureObject(feature));
|
|
907
|
+
this.addLayer(layer);
|
|
908
|
+
}
|
|
909
|
+
return this;
|
|
910
|
+
},
|
|
911
|
+
});
|
|
912
|
+
|
|
913
|
+
L.GridLayer.include({
|
|
914
|
+
options: { pane: 'tilePane', tileSize: 256, opacity: 1, minZoom: 0, maxZoom: 24, updateInterval: 200 },
|
|
915
|
+
initialize(options) { L.Util.setOptions(this, options); this._tiles = {}; },
|
|
916
|
+
getTileSize() { return typeof this.options.tileSize === 'number'
|
|
917
|
+
? new L.Point(this.options.tileSize, this.options.tileSize) : point(this.options.tileSize); },
|
|
918
|
+
getEvents() { return { moveend: this._onMoveEnd, zoomend: this._onMoveEnd, resize: this._onMoveEnd }; },
|
|
919
|
+
_initContainer() { this._container = L.DomUtil.create('div', '', this.getPane()); },
|
|
920
|
+
onAdd() { this._initContainer(); this._onMoveEnd(); },
|
|
921
|
+
onRemove() {
|
|
922
|
+
for (const tile of Object.values(this._tiles)) this.fire('tileunload', { tile: tile.el, coords: tile.coords });
|
|
923
|
+
this._tiles = {}; this._container?.remove();
|
|
924
|
+
},
|
|
925
|
+
_getTiledPixelBounds() {
|
|
926
|
+
return new L.Bounds(this._map.project(this._map.getBounds().getNorthWest(), this._tileZoom),
|
|
927
|
+
this._map.project(this._map.getBounds().getSouthEast(), this._tileZoom));
|
|
928
|
+
},
|
|
929
|
+
_onMoveEnd() {
|
|
930
|
+
if (!this._map) return;
|
|
931
|
+
this._tileZoom = Math.max(this.options.minZoom, Math.min(this.options.maxZoom, Math.round(this._map.getZoom())));
|
|
932
|
+
const size = this.getTileSize(), extent = this._getTiledPixelBounds(this._map.getCenter());
|
|
933
|
+
const min = extent.min.unscaleBy(size).floor(), max = extent.max.unscaleBy(size).floor();
|
|
934
|
+
const retained = new Set(), limit = 2 ** this._tileZoom;
|
|
935
|
+
for (let x = min.x; x <= max.x; x++) for (let y = min.y; y <= max.y; y++) {
|
|
936
|
+
if (y < 0 || y >= limit) continue;
|
|
937
|
+
const key = `${this._tileZoom}:${x}:${y}`;
|
|
938
|
+
retained.add(key);
|
|
939
|
+
if (this._tiles[key]) continue;
|
|
940
|
+
const coords = new L.Point(x, y); coords.z = this._tileZoom;
|
|
941
|
+
const tile = this._tiles[key] = { coords, current: true, loaded: 0 };
|
|
942
|
+
const done = (error, element) => {
|
|
943
|
+
if (this._tiles[key] !== tile) return;
|
|
944
|
+
tile.el = element;
|
|
945
|
+
if (error) { this.fire('tileerror', { error, tile: element, coords }); return; }
|
|
946
|
+
tile.loaded = Date.now();
|
|
947
|
+
this.fire('tileload', { tile: element, coords });
|
|
948
|
+
this.fire('load');
|
|
949
|
+
};
|
|
950
|
+
tile.el = this.createTile(coords, done);
|
|
951
|
+
if (this.createTile.length < 2) done(null, tile.el);
|
|
952
|
+
}
|
|
953
|
+
for (const [key, tile] of Object.entries(this._tiles)) {
|
|
954
|
+
if (retained.has(key)) continue;
|
|
955
|
+
delete this._tiles[key];
|
|
956
|
+
this.fire('tileunload', { tile: tile.el, coords: tile.coords });
|
|
957
|
+
}
|
|
958
|
+
},
|
|
959
|
+
_tileCoordsToNwSe(coords) {
|
|
960
|
+
const size = this.getTileSize(), nw = new L.Point(coords.x * size.x, coords.y * size.y);
|
|
961
|
+
return [this._map.unproject(nw, coords.z), this._map.unproject(nw.add(size), coords.z)];
|
|
962
|
+
},
|
|
963
|
+
setOpacity(opacity) { this.options.opacity = opacity; return this; },
|
|
964
|
+
setZIndex(zIndex) { this.options.zIndex = zIndex; return this; },
|
|
965
|
+
redraw() { if (this._map) { this.onRemove(); this._onMoveEnd(); } return this; },
|
|
966
|
+
});
|
|
967
|
+
L.TileLayer = L.GridLayer.extend({
|
|
968
|
+
initialize(url, options) {
|
|
969
|
+
L.GridLayer.prototype.initialize.call(this, options); this.setUrl(url);
|
|
970
|
+
},
|
|
971
|
+
setUrl(url) { this._url = url; this._source = new ol.source.XYZ({ url, crossOrigin: 'anonymous' }); return this.redraw(); },
|
|
972
|
+
createTile(coords, done) {
|
|
973
|
+
const url = this._source.getTileUrlFunction()([coords.z, coords.x, coords.y], 1, ol.proj.get('EPSG:3857'));
|
|
974
|
+
const tile = image(url, this.options, '');
|
|
975
|
+
tile.onload = () => done(null, tile);
|
|
976
|
+
tile.onerror = () => done(new Error(`Unable to load tile: ${url}`), tile);
|
|
977
|
+
return tile;
|
|
978
|
+
},
|
|
979
|
+
});
|
|
980
|
+
L.TileLayer.WMS = L.TileLayer.extend({
|
|
981
|
+
setUrl(url) {
|
|
982
|
+
this._url = url;
|
|
983
|
+
this._source = new ol.source.TileWMS({ url, crossOrigin: 'anonymous', params: {
|
|
984
|
+
LAYERS: this.options.layers, FORMAT: this.options.format || 'image/png',
|
|
985
|
+
TRANSPARENT: this.options.transparent || false,
|
|
986
|
+
} });
|
|
987
|
+
return this.redraw();
|
|
988
|
+
},
|
|
989
|
+
});
|
|
990
|
+
L.ImageOverlay.include({
|
|
991
|
+
options: { pane: 'overlayPane', opacity: 1, interactive: false },
|
|
992
|
+
initialize(url, value, options) { L.Util.setOptions(this, options); this._url = url; this._bounds = bounds(value); },
|
|
993
|
+
_initImage() {
|
|
994
|
+
this._image = image(this._url, this.options, '');
|
|
995
|
+
this._image.onload = () => this.fire('load');
|
|
996
|
+
this._image.onerror = () => this.fire('error', { error: new Error(`Unable to load image: ${this._url}`) });
|
|
997
|
+
},
|
|
998
|
+
getBounds() { return this._bounds; },
|
|
999
|
+
setBounds(value) { this._bounds = bounds(value); return this; },
|
|
1000
|
+
setUrl(url) { this._url = url; if (this._image) this._image.src = url; return this; },
|
|
1001
|
+
setOpacity(opacity) { this.options.opacity = opacity; return this; },
|
|
1002
|
+
setZIndex(zIndex) { this.options.zIndex = zIndex; return this; },
|
|
1003
|
+
});
|
|
1004
|
+
|
|
1005
|
+
L.Icon = L.Evented.extend({
|
|
1006
|
+
initialize(options) { L.Util.setOptions(this, options); },
|
|
1007
|
+
createIcon() { return this._create('icon'); },
|
|
1008
|
+
createShadow() { return this.options.shadowUrl ? this._create('shadow') : null; },
|
|
1009
|
+
_create(kind) {
|
|
1010
|
+
const element = image(this.options[`${kind}Url`], this.options, `leaflet-marker-${kind}`);
|
|
1011
|
+
const size = this.options[`${kind}Size`], anchor = this.options[`${kind}Anchor`] || this.options.iconAnchor;
|
|
1012
|
+
if (size) { element.style.width = `${size[0]}px`; element.style.height = `${size[1]}px`; }
|
|
1013
|
+
if (anchor) { element.style.marginLeft = `${-anchor[0]}px`; element.style.marginTop = `${-anchor[1]}px`; }
|
|
1014
|
+
return element;
|
|
1015
|
+
},
|
|
1016
|
+
});
|
|
1017
|
+
L.Icon.Default = L.Icon.extend({
|
|
1018
|
+
options: {
|
|
1019
|
+
iconUrl: 'https://unpkg.com/leaflet@1.9/dist/images/marker-icon.png',
|
|
1020
|
+
shadowUrl: 'https://unpkg.com/leaflet@1.9/dist/images/marker-shadow.png',
|
|
1021
|
+
iconSize: [25, 41], iconAnchor: [12, 41], shadowSize: [41, 41], shadowAnchor: [12, 41],
|
|
1022
|
+
},
|
|
1023
|
+
});
|
|
1024
|
+
L.DivIcon = L.Icon.extend({
|
|
1025
|
+
createIcon() {
|
|
1026
|
+
const element = L.DomUtil.create('div', `leaflet-marker-icon ${this.options.className || ''}`);
|
|
1027
|
+
if (this.options.html instanceof Node) element.append(this.options.html); else element.innerHTML = this.options.html || '';
|
|
1028
|
+
const size = this.options.iconSize || [12, 12], anchor = this.options.iconAnchor || size.map(value => value / 2);
|
|
1029
|
+
element.style.cssText = `width:${size[0]}px;height:${size[1]}px;margin-left:${-anchor[0]}px;margin-top:${-anchor[1]}px`;
|
|
1030
|
+
return element;
|
|
1031
|
+
},
|
|
1032
|
+
createShadow() { return null; },
|
|
1033
|
+
});
|
|
1034
|
+
L.Marker.include({
|
|
1035
|
+
options: { pane: 'markerPane', icon: new L.Icon.Default(), opacity: 1, interactive: true, zIndexOffset: 0 },
|
|
1036
|
+
initialize(value, options) { L.Util.setOptions(this, options); this._latlng = latLng(value); },
|
|
1037
|
+
getLatLng() { return this._latlng; },
|
|
1038
|
+
setLatLng(value) { this._latlng = latLng(value); this.update(); return this.fire('move', { latlng: this._latlng }); },
|
|
1039
|
+
setIcon(icon) { this.options.icon = icon; if (this._map) { this.onRemove(); this.onAdd(); } return this; },
|
|
1040
|
+
getEvents() { return { zoom: this.update, viewreset: this.update }; },
|
|
1041
|
+
onAdd() {
|
|
1042
|
+
this._icon = this.options.icon.createIcon(); this._shadow = this.options.icon.createShadow();
|
|
1043
|
+
this._icon.tabIndex = 0; this._icon.setAttribute('role', 'button');
|
|
1044
|
+
this._icon.setAttribute('aria-label', this.options.title || 'Marker');
|
|
1045
|
+
this._icon.title = this.options.title || '';
|
|
1046
|
+
for (const element of [this._shadow, this._icon]) if (element) this.getPane().append(element);
|
|
1047
|
+
this._initInteraction(); this.update();
|
|
1048
|
+
},
|
|
1049
|
+
onRemove() { this.dragging?.disable(); this._icon?.remove(); this._shadow?.remove(); },
|
|
1050
|
+
update() { if (this._map && this._icon) this._setPos(this._map.latLngToLayerPoint(this._latlng)); return this; },
|
|
1051
|
+
_setPos(value) {
|
|
1052
|
+
for (const element of [this._icon, this._shadow]) if (element) L.DomUtil.setPosition(element, value);
|
|
1053
|
+
this._zIndex = value.y + this.options.zIndexOffset; this._updateZIndex(0);
|
|
1054
|
+
},
|
|
1055
|
+
_updateZIndex(offset) { if (this._icon) this._icon.style.zIndex = this._zIndex + offset; },
|
|
1056
|
+
setOpacity(opacity) { this.options.opacity = opacity; return this; },
|
|
1057
|
+
setZIndexOffset(value) { this.options.zIndexOffset = value; return this.update(); },
|
|
1058
|
+
_initInteraction() {
|
|
1059
|
+
this._icon._cityLayer = this;
|
|
1060
|
+
const drag = this.dragging = new L.Handler(this._map);
|
|
1061
|
+
const icon = this._icon;
|
|
1062
|
+
L.DomEvent.on(icon, 'pointerdown', event => {
|
|
1063
|
+
this._map._moved = false;
|
|
1064
|
+
event.stopPropagation();
|
|
1065
|
+
});
|
|
1066
|
+
L.DomEvent.on(icon, 'keydown', event => {
|
|
1067
|
+
if (event.key !== 'Enter' && event.key !== ' ') return;
|
|
1068
|
+
L.DomEvent.stop(event);
|
|
1069
|
+
this.fire('click', { latlng: this._latlng, originalEvent: event });
|
|
1070
|
+
});
|
|
1071
|
+
drag._marker = this;
|
|
1072
|
+
drag._draggable = new L.Evented();
|
|
1073
|
+
drag._onDrag = function () {
|
|
1074
|
+
const marker = this._marker;
|
|
1075
|
+
marker._latlng = marker._map.layerPointToLatLng(L.DomUtil.getPosition(marker._icon));
|
|
1076
|
+
marker.fire('move', { latlng: marker._latlng }).fire('drag', { latlng: marker._latlng });
|
|
1077
|
+
};
|
|
1078
|
+
drag._adjustPan = function () {};
|
|
1079
|
+
drag._draggable.on('drag', drag._onDrag, drag);
|
|
1080
|
+
let pointer, anchor, origin, moved;
|
|
1081
|
+
const handle = event => {
|
|
1082
|
+
if (!drag.enabled()) return;
|
|
1083
|
+
if (event.type === 'pointerdown') {
|
|
1084
|
+
if (event.button !== 0) return;
|
|
1085
|
+
event.preventDefault(); event.stopPropagation();
|
|
1086
|
+
pointer = event.pointerId; anchor = [event.clientX, event.clientY];
|
|
1087
|
+
origin = this._map.latLngToContainerPoint(this._latlng); moved = false;
|
|
1088
|
+
icon.setPointerCapture(pointer);
|
|
1089
|
+
this.fire('dragstart');
|
|
1090
|
+
} else if (event.pointerId === pointer && event.type === 'pointermove') {
|
|
1091
|
+
const value = new L.Point(origin.x + event.clientX - anchor[0], origin.y + event.clientY - anchor[1]);
|
|
1092
|
+
L.DomUtil.setPosition(icon, value);
|
|
1093
|
+
drag._draggable._newPos = value;
|
|
1094
|
+
drag._draggable.fire('drag', { originalEvent: event });
|
|
1095
|
+
moved = true;
|
|
1096
|
+
} else if (event.pointerId === pointer) {
|
|
1097
|
+
if (icon.hasPointerCapture(pointer)) icon.releasePointerCapture(pointer);
|
|
1098
|
+
pointer = null; this.fire('dragend'); this._map._moved = moved;
|
|
1099
|
+
}
|
|
1100
|
+
};
|
|
1101
|
+
drag.addHooks = () => L.DomEvent.on(icon, 'pointerdown pointermove pointerup pointercancel', handle);
|
|
1102
|
+
drag.removeHooks = () => L.DomEvent.off(icon, 'pointerdown pointermove pointerup pointercancel', handle);
|
|
1103
|
+
if (this.options.draggable) drag.enable();
|
|
1104
|
+
},
|
|
1105
|
+
});
|
|
1106
|
+
|
|
1107
|
+
L.Map.include({
|
|
1108
|
+
_fireDOMEvent(event, type = event.type, targets) {
|
|
1109
|
+
const rect = this.getContainer().getBoundingClientRect();
|
|
1110
|
+
const pixel = new L.Point(event.clientX - rect.left, event.clientY - rect.top);
|
|
1111
|
+
const location = this.containerPointToLatLng(pixel);
|
|
1112
|
+
const layer = event.target.closest?.('.leaflet-marker-icon')?._cityLayer;
|
|
1113
|
+
if (type === 'click' && this._draggableMoved(layer)) return;
|
|
1114
|
+
for (const target of targets || (layer ? [layer] : [this])) {
|
|
1115
|
+
target.fire(type, { originalEvent: event, latlng: location, containerPoint: pixel,
|
|
1116
|
+
layerPoint: this.containerPointToLayerPoint(pixel) });
|
|
1117
|
+
}
|
|
1118
|
+
},
|
|
1119
|
+
});
|
|
1120
|
+
L.Map.addInitHook(function () {
|
|
1121
|
+
const mapPane = this.createPane('mapPane');
|
|
1122
|
+
for (const [name, order] of [['tilePane', 200], ['overlayPane', 400], ['markerPane', 600]]) {
|
|
1123
|
+
this.createPane(name, mapPane).style.zIndex = order;
|
|
1124
|
+
}
|
|
1125
|
+
const handler = event => this._fireDOMEvent(event);
|
|
1126
|
+
L.DomEvent.on(this.getContainer(), 'click mousemove mouseout mouseover', handler);
|
|
1127
|
+
this.once('unload', () => L.DomEvent.off(this.getContainer(), 'click mousemove mouseout mouseover', handler));
|
|
1128
|
+
});
|
|
1129
|
+
})();
|