@collabdt/core 0.0.42 → 0.0.43
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/dist/core/components/Toolbar.d.ts.map +1 -1
- package/dist/core/components/Toolbar.js.map +1 -1
- package/dist/core/components/ToolbarBody.js.map +1 -1
- package/dist/core/components/TopNavigationBar.js.map +1 -1
- package/dist/core/components/authentication/ForgotPassword.js.map +1 -1
- package/dist/core/components/authentication/Signin.js.map +1 -1
- package/dist/core/components/authentication/Signup.js.map +1 -1
- package/dist/core/components/settings/src/OrganizationSkeleton.js.map +1 -1
- package/dist/core/components/settings/src/SettingsSkeleton.js.map +1 -1
- package/dist/core/components/ui/Comments/CollapsibleCommentItem.d.ts.map +1 -1
- package/dist/core/components/ui/Comments/CollapsibleCommentItem.js.map +1 -1
- package/dist/core/components/ui/Comments/CommentsSection.d.ts.map +1 -1
- package/dist/core/components/ui/Comments/CommentsSection.js.map +1 -1
- package/dist/core/components/ui/DataTable.d.ts.map +1 -1
- package/dist/core/components/ui/DataTable.js +7 -0
- package/dist/core/components/ui/DataTable.js.map +1 -1
- package/dist/core/components/ui/FilesManager/src/FileItemComponent.d.ts.map +1 -1
- package/dist/core/components/ui/FilesManager/src/FileItemComponent.js.map +1 -1
- package/dist/core/components/ui/FilesManager/src/FileMarker.d.ts +5 -2
- package/dist/core/components/ui/FilesManager/src/FileMarker.d.ts.map +1 -1
- package/dist/core/components/ui/FilesManager/src/FileMarker.js +84 -21
- package/dist/core/components/ui/FilesManager/src/FileMarker.js.map +1 -1
- package/dist/core/components/ui/FilesManager/src/convertIfcToFragmentsFile.d.ts.map +1 -1
- package/dist/core/components/ui/FilesManager/src/convertIfcToFragmentsFile.js.map +1 -1
- package/dist/core/components/ui/FilesManager/src/useFileUploadHandler.d.ts.map +1 -1
- package/dist/core/components/ui/FilesManager/src/useFileUploadHandler.js.map +1 -1
- package/dist/core/components/ui/Icons/IfcIcon.d.ts.map +1 -1
- package/dist/core/components/ui/Icons/IfcIcon.js.map +1 -1
- package/dist/core/components/ui/InfoSidebar/index.d.ts.map +1 -1
- package/dist/core/components/ui/InfoSidebar/index.js.map +1 -1
- package/dist/core/components/ui/Navbar.d.ts.map +1 -1
- package/dist/core/components/ui/Navbar.js.map +1 -1
- package/dist/core/components/ui/Sensors/CollapsibleSensorItem.d.ts.map +1 -1
- package/dist/core/components/ui/Sensors/CollapsibleSensorItem.js.map +1 -1
- package/dist/core/components/ui/Sensors/SensorTagsSection.d.ts.map +1 -1
- package/dist/core/components/ui/Sensors/SensorTagsSection.js.map +1 -1
- package/dist/core/components/ui/Sensors/SensorsSection.d.ts.map +1 -1
- package/dist/core/components/ui/Sensors/SensorsSection.js.map +1 -1
- package/dist/core/components/ui/ShareFeature/ShareToolSubmenu.d.ts.map +1 -1
- package/dist/core/components/ui/ShareFeature/ShareToolSubmenu.js.map +1 -1
- package/dist/core/components/viewers/Data/buildingDetails/GeocoderInput.js +2 -2
- package/dist/core/components/viewers/Data/buildingDetails/GeocoderInput.js.map +1 -1
- package/dist/core/components/viewers/Data/siteDetails/AssociatedBuildings.js +2 -2
- package/dist/core/components/viewers/Data/siteDetails/AssociatedBuildings.js.map +1 -1
- package/dist/core/components/viewers/Viewer.d.ts.map +1 -1
- package/dist/core/components/viewers/Viewer.js +5 -1
- package/dist/core/components/viewers/Viewer.js.map +1 -1
- package/dist/core/components/viewers/bim/BimToolbar.d.ts.map +1 -1
- package/dist/core/components/viewers/bim/BimToolbar.js.map +1 -1
- package/dist/core/components/viewers/bim/BimViewer.d.ts.map +1 -1
- package/dist/core/components/viewers/bim/BimViewer.js +14 -5
- package/dist/core/components/viewers/bim/BimViewer.js.map +1 -1
- package/dist/core/components/viewers/bim/src/BimLoadingState/index.d.ts.map +1 -1
- package/dist/core/components/viewers/bim/src/BimLoadingState/index.js +6 -0
- package/dist/core/components/viewers/bim/src/BimLoadingState/index.js.map +1 -1
- package/dist/core/components/viewers/bim/src/BimSidebar/src/FileTab/src/FilesSection.d.ts.map +1 -1
- package/dist/core/components/viewers/bim/src/BimSidebar/src/FileTab/src/FilesSection.js +168 -39
- package/dist/core/components/viewers/bim/src/BimSidebar/src/FileTab/src/FilesSection.js.map +1 -1
- package/dist/core/components/viewers/bim/src/BimSidebar/src/FileTab/src/ModelsSection.d.ts.map +1 -1
- package/dist/core/components/viewers/bim/src/BimSidebar/src/FileTab/src/ModelsSection.js.map +1 -1
- package/dist/core/components/viewers/bim/src/BimSidebar/src/LayersTab/src/FloorplanSection.d.ts.map +1 -1
- package/dist/core/components/viewers/bim/src/BimSidebar/src/LayersTab/src/FloorplanSection.js +1 -1
- package/dist/core/components/viewers/bim/src/BimSidebar/src/LayersTab/src/FloorplanSection.js.map +1 -1
- package/dist/core/components/viewers/bim/src/DXFLoader/index.d.ts +14 -37
- package/dist/core/components/viewers/bim/src/DXFLoader/index.d.ts.map +1 -1
- package/dist/core/components/viewers/bim/src/DXFLoader/index.js +31 -318
- package/dist/core/components/viewers/bim/src/DXFLoader/index.js.map +1 -1
- package/dist/core/components/viewers/bim/src/FloorplanTool/index.d.ts +66 -7
- package/dist/core/components/viewers/bim/src/FloorplanTool/index.d.ts.map +1 -1
- package/dist/core/components/viewers/bim/src/FloorplanTool/index.js +253 -21
- package/dist/core/components/viewers/bim/src/FloorplanTool/index.js.map +1 -1
- package/dist/core/components/viewers/bim/src/ModelManager/index.d.ts.map +1 -1
- package/dist/core/components/viewers/bim/src/ModelManager/index.js +9 -0
- package/dist/core/components/viewers/bim/src/ModelManager/index.js.map +1 -1
- package/dist/core/components/viewers/bim/src/SimpleBimViewer.d.ts.map +1 -1
- package/dist/core/components/viewers/bim/src/SimpleBimViewer.js.map +1 -1
- package/dist/core/components/viewers/bim/src/lib/TrueNorthPopover.d.ts +3 -2
- package/dist/core/components/viewers/bim/src/lib/TrueNorthPopover.d.ts.map +1 -1
- package/dist/core/components/viewers/bim/src/lib/TrueNorthPopover.js.map +1 -1
- package/dist/core/components/viewers/bim/src/lib/useFriendlyIfcClassName.d.ts.map +1 -1
- package/dist/core/components/viewers/bim/src/lib/useFriendlyIfcClassName.js +3 -4
- package/dist/core/components/viewers/bim/src/lib/useFriendlyIfcClassName.js.map +1 -1
- package/dist/core/components/viewers/bim/src/tools/AddToBim/index.d.ts.map +1 -1
- package/dist/core/components/viewers/bim/src/tools/AddToBim/index.js +40 -18
- package/dist/core/components/viewers/bim/src/tools/AddToBim/index.js.map +1 -1
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/AddDxf.d.ts +2 -5
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/AddDxf.d.ts.map +1 -1
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/AddDxf.js +45 -59
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/AddDxf.js.map +1 -1
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/BimSensor.js +1 -0
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/BimSensor.js.map +1 -1
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/FileHandler.d.ts +10 -1
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/FileHandler.d.ts.map +1 -1
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/FileHandler.js +25 -73
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/FileHandler.js.map +1 -1
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/FileMarkerUtils.d.ts +7 -3
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/FileMarkerUtils.d.ts.map +1 -1
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/FileMarkerUtils.js +42 -78
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/FileMarkerUtils.js.map +1 -1
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/Position3DCard.d.ts.map +1 -1
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/Position3DCard.js +52 -75
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/Position3DCard.js.map +1 -1
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/useFilePlacement.d.ts +15 -3
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/useFilePlacement.d.ts.map +1 -1
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/useFilePlacement.js +165 -105
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/useFilePlacement.js.map +1 -1
- package/dist/core/components/viewers/index.d.ts.map +1 -1
- package/dist/core/components/viewers/index.js.map +1 -1
- package/dist/core/components/viewers/map/MapViewer.d.ts.map +1 -1
- package/dist/core/components/viewers/map/MapViewer.js +1 -0
- package/dist/core/components/viewers/map/MapViewer.js.map +1 -1
- package/dist/core/components/viewers/map/datasets/DatasetManager/index.d.ts.map +1 -1
- package/dist/core/components/viewers/map/datasets/DatasetManager/index.js +4 -3
- package/dist/core/components/viewers/map/datasets/DatasetManager/index.js.map +1 -1
- package/dist/core/components/viewers/map/datasets/RowActions.d.ts.map +1 -1
- package/dist/core/components/viewers/map/datasets/RowActions.js +148 -0
- package/dist/core/components/viewers/map/datasets/RowActions.js.map +1 -1
- package/dist/core/components/viewers/map/datasets/index.d.ts.map +1 -1
- package/dist/core/components/viewers/map/datasets/index.js +32 -15
- package/dist/core/components/viewers/map/datasets/index.js.map +1 -1
- package/dist/core/components/viewers/map/datasets/src/builtinLiveDatasets.d.ts +4 -0
- package/dist/core/components/viewers/map/datasets/src/builtinLiveDatasets.d.ts.map +1 -0
- package/dist/core/components/viewers/map/datasets/src/builtinLiveDatasets.js +43 -0
- package/dist/core/components/viewers/map/datasets/src/builtinLiveDatasets.js.map +1 -0
- package/dist/core/components/viewers/map/datasets/src/localDatasets.d.ts.map +1 -1
- package/dist/core/components/viewers/map/datasets/src/localDatasets.js +39 -3
- package/dist/core/components/viewers/map/datasets/src/localDatasets.js.map +1 -1
- package/dist/core/components/viewers/map/datasets/src/minioDatasets.d.ts +1 -1
- package/dist/core/components/viewers/map/datasets/src/minioDatasets.d.ts.map +1 -1
- package/dist/core/components/viewers/map/datasets/src/minioDatasets.js +2 -1
- package/dist/core/components/viewers/map/datasets/src/minioDatasets.js.map +1 -1
- package/dist/core/components/viewers/map/datasets/src/publishedTiles.d.ts +47 -0
- package/dist/core/components/viewers/map/datasets/src/publishedTiles.d.ts.map +1 -0
- package/dist/core/components/viewers/map/datasets/src/publishedTiles.js +114 -0
- package/dist/core/components/viewers/map/datasets/src/publishedTiles.js.map +1 -0
- package/dist/core/components/viewers/map/datasets/src/wmsTime.d.ts +49 -0
- package/dist/core/components/viewers/map/datasets/src/wmsTime.d.ts.map +1 -0
- package/dist/core/components/viewers/map/datasets/src/wmsTime.js +100 -0
- package/dist/core/components/viewers/map/datasets/src/wmsTime.js.map +1 -0
- package/dist/core/components/viewers/map/src/Geocoder.d.ts.map +1 -1
- package/dist/core/components/viewers/map/src/Geocoder.js +9 -9
- package/dist/core/components/viewers/map/src/Geocoder.js.map +1 -1
- package/dist/core/components/viewers/map/src/MapFeaturePopoverMenu/src/NonDatabaseBuildingPopover.d.ts.map +1 -1
- package/dist/core/components/viewers/map/src/MapFeaturePopoverMenu/src/NonDatabaseBuildingPopover.js +25 -43
- package/dist/core/components/viewers/map/src/MapFeaturePopoverMenu/src/NonDatabaseBuildingPopover.js.map +1 -1
- package/dist/core/components/viewers/map/src/MapLayers/index.d.ts.map +1 -1
- package/dist/core/components/viewers/map/src/MapLayers/index.js.map +1 -1
- package/dist/core/components/viewers/map/src/MapLayers/src/BimLayer/index.d.ts.map +1 -1
- package/dist/core/components/viewers/map/src/MapLayers/src/BimLayer/index.js +19 -2
- package/dist/core/components/viewers/map/src/MapLayers/src/BimLayer/index.js.map +1 -1
- package/dist/core/components/viewers/map/src/MapLayers/src/CountryLayer/countryLayerUtils.d.ts +9 -0
- package/dist/core/components/viewers/map/src/MapLayers/src/CountryLayer/countryLayerUtils.d.ts.map +1 -0
- package/dist/core/components/viewers/map/src/MapLayers/src/CountryLayer/countryLayerUtils.js +28 -0
- package/dist/core/components/viewers/map/src/MapLayers/src/CountryLayer/countryLayerUtils.js.map +1 -0
- package/dist/core/components/viewers/map/src/MapLayers/src/CountryLayer/index.d.ts.map +1 -1
- package/dist/core/components/viewers/map/src/MapLayers/src/CountryLayer/index.js +1 -16
- package/dist/core/components/viewers/map/src/MapLayers/src/CountryLayer/index.js.map +1 -1
- package/dist/core/components/viewers/map/src/MapLayers/src/FileLayer/FileModelLayer/FileModelLayer.d.ts.map +1 -1
- package/dist/core/components/viewers/map/src/MapLayers/src/FileLayer/FileModelLayer/FileModelLayer.js.map +1 -1
- package/dist/core/components/viewers/map/src/MapLayers/src/FileLayer/utils/CustomModelLayer.d.ts.map +1 -1
- package/dist/core/components/viewers/map/src/MapLayers/src/FileLayer/utils/CustomModelLayer.js +31 -2
- package/dist/core/components/viewers/map/src/MapLayers/src/FileLayer/utils/CustomModelLayer.js.map +1 -1
- package/dist/core/components/viewers/map/src/MapLayers/src/OpenDataLayer/src/WmsTimeControl.d.ts +21 -0
- package/dist/core/components/viewers/map/src/MapLayers/src/OpenDataLayer/src/WmsTimeControl.d.ts.map +1 -0
- package/dist/core/components/viewers/map/src/MapLayers/src/OpenDataLayer/src/WmsTimeControl.js +111 -0
- package/dist/core/components/viewers/map/src/MapLayers/src/OpenDataLayer/src/WmsTimeControl.js.map +1 -0
- package/dist/core/components/viewers/map/src/MapLayers/src/OpenDataLayer/src/index.d.ts.map +1 -1
- package/dist/core/components/viewers/map/src/MapLayers/src/OpenDataLayer/src/index.js +77 -2
- package/dist/core/components/viewers/map/src/MapLayers/src/OpenDataLayer/src/index.js.map +1 -1
- package/dist/core/components/viewers/map/src/MapSidebar/src/FileTab/src/FilesSection.d.ts.map +1 -1
- package/dist/core/components/viewers/map/src/MapSidebar/src/FileTab/src/FilesSection.js.map +1 -1
- package/dist/core/components/viewers/map/src/MapSidebar/src/FileTab/src/ModelsSection.d.ts.map +1 -1
- package/dist/core/components/viewers/map/src/MapSidebar/src/FileTab/src/ModelsSection.js.map +1 -1
- package/dist/core/components/viewers/map/src/MapSidebar/src/SettingsTab/src/TerrainLevel.d.ts.map +1 -1
- package/dist/core/components/viewers/map/src/MapSidebar/src/SettingsTab/src/TerrainLevel.js +10 -3
- package/dist/core/components/viewers/map/src/MapSidebar/src/SettingsTab/src/TerrainLevel.js.map +1 -1
- package/dist/core/components/viewers/map/utils/geocoder.d.ts +6 -2
- package/dist/core/components/viewers/map/utils/geocoder.d.ts.map +1 -1
- package/dist/core/components/viewers/map/utils/geocoder.js +10 -62
- package/dist/core/components/viewers/map/utils/geocoder.js.map +1 -1
- package/dist/core/components/viewers/map/utils/geocoding/adapters.d.ts +5 -0
- package/dist/core/components/viewers/map/utils/geocoding/adapters.d.ts.map +1 -0
- package/dist/core/components/viewers/map/utils/geocoding/adapters.js +192 -0
- package/dist/core/components/viewers/map/utils/geocoding/adapters.js.map +1 -0
- package/dist/core/components/viewers/map/utils/geocoding/config.d.ts +6 -0
- package/dist/core/components/viewers/map/utils/geocoding/config.d.ts.map +1 -0
- package/dist/core/components/viewers/map/utils/geocoding/config.js +14 -0
- package/dist/core/components/viewers/map/utils/geocoding/config.js.map +1 -0
- package/dist/core/components/viewers/map/utils/geocoding/index.d.ts +8 -0
- package/dist/core/components/viewers/map/utils/geocoding/index.d.ts.map +1 -0
- package/dist/core/components/viewers/map/utils/geocoding/index.js +44 -0
- package/dist/core/components/viewers/map/utils/geocoding/index.js.map +1 -0
- package/dist/core/components/viewers/map/utils/geocoding/osm.d.ts +6 -0
- package/dist/core/components/viewers/map/utils/geocoding/osm.d.ts.map +1 -0
- package/dist/core/components/viewers/map/utils/geocoding/osm.js +39 -0
- package/dist/core/components/viewers/map/utils/geocoding/osm.js.map +1 -0
- package/dist/core/components/viewers/map/utils/geocoding/pelias.d.ts +8 -0
- package/dist/core/components/viewers/map/utils/geocoding/pelias.d.ts.map +1 -0
- package/dist/core/components/viewers/map/utils/geocoding/pelias.js +35 -0
- package/dist/core/components/viewers/map/utils/geocoding/pelias.js.map +1 -0
- package/dist/core/components/viewers/pointcloud/PointCloudToolbar.d.ts.map +1 -1
- package/dist/core/components/viewers/pointcloud/PointCloudToolbar.js.map +1 -1
- package/dist/core/components/viewers/pointcloud/PointCloudViewer.js +1 -3
- package/dist/core/components/viewers/pointcloud/PointCloudViewer.js.map +1 -1
- package/dist/core/components/viewers/pointcloud/src/PointCloudSidebar/src/FileTab/index.d.ts.map +1 -1
- package/dist/core/components/viewers/pointcloud/src/PointCloudSidebar/src/FileTab/index.js +2 -3
- package/dist/core/components/viewers/pointcloud/src/PointCloudSidebar/src/FileTab/index.js.map +1 -1
- package/dist/core/components/viewers/pointcloud/src/PointCloudSidebar/src/FileTab/src/FilesSection.d.ts.map +1 -1
- package/dist/core/components/viewers/pointcloud/src/PointCloudSidebar/src/FileTab/src/FilesSection.js +8 -2
- package/dist/core/components/viewers/pointcloud/src/PointCloudSidebar/src/FileTab/src/FilesSection.js.map +1 -1
- package/dist/core/components/viewers/pointcloud/src/PointCloudSidebar/src/FileTab/src/PointCloudSection.d.ts.map +1 -1
- package/dist/core/components/viewers/pointcloud/src/PointCloudSidebar/src/FileTab/src/PointCloudSection.js.map +1 -1
- package/dist/core/components/viewers/pointcloud/src/tools/PerformanceSettingsTools/NodeSizeSelectionTool.js +9 -9
- package/dist/core/components/viewers/pointcloud/src/tools/PerformanceSettingsTools/NodeSizeSelectionTool.js.map +1 -1
- package/dist/core/hooks/provider.js.map +1 -1
- package/dist/core/plugins/host/provider.d.ts.map +1 -1
- package/dist/core/plugins/host/provider.js.map +1 -1
- package/dist/core/store/AppConfig/context.d.ts.map +1 -1
- package/dist/core/store/AppConfig/context.js.map +1 -1
- package/dist/core/store/BIM/context.d.ts.map +1 -1
- package/dist/core/store/BIM/context.js.map +1 -1
- package/dist/core/store/BIM/reducer.d.ts +0 -1
- package/dist/core/store/BIM/reducer.d.ts.map +1 -1
- package/dist/core/store/BIM/reducer.js +0 -4
- package/dist/core/store/BIM/reducer.js.map +1 -1
- package/dist/core/store/Buildings/context.d.ts.map +1 -1
- package/dist/core/store/Buildings/context.js.map +1 -1
- package/dist/core/store/Content/context.d.ts.map +1 -1
- package/dist/core/store/Content/context.js.map +1 -1
- package/dist/core/store/Datasets/context.d.ts.map +1 -1
- package/dist/core/store/Datasets/context.js +2 -1
- package/dist/core/store/Datasets/context.js.map +1 -1
- package/dist/core/store/Datasets/reducer.d.ts +2 -0
- package/dist/core/store/Datasets/reducer.d.ts.map +1 -1
- package/dist/core/store/Datasets/reducer.js +9 -4
- package/dist/core/store/Datasets/reducer.js.map +1 -1
- package/dist/core/store/Files/context.d.ts.map +1 -1
- package/dist/core/store/Files/context.js.map +1 -1
- package/dist/core/store/Map/context.d.ts.map +1 -1
- package/dist/core/store/Map/context.js.map +1 -1
- package/dist/core/store/Menus/context.d.ts.map +1 -1
- package/dist/core/store/Menus/context.js.map +1 -1
- package/dist/core/store/Permissions/context.d.ts.map +1 -1
- package/dist/core/store/Permissions/context.js.map +1 -1
- package/dist/core/store/PointCloud/context.d.ts.map +1 -1
- package/dist/core/store/PointCloud/context.js.map +1 -1
- package/dist/core/store/Tools/context.d.ts.map +1 -1
- package/dist/core/store/Tools/context.js.map +1 -1
- package/dist/core/types/datasetTypes.d.ts +8 -1
- package/dist/core/types/datasetTypes.d.ts.map +1 -1
- package/dist/core/types/dbTypes.d.ts +13 -13
- package/dist/core/types/dbTypes.d.ts.map +1 -1
- package/dist/core/types/dbTypes.js +13 -13
- package/dist/core/types/dbTypes.js.map +1 -1
- package/dist/core/types/index.d.ts +1 -1
- package/dist/core/types/index.d.ts.map +1 -1
- package/dist/core/types/index.js.map +1 -1
- package/dist/core/utils/imageUtils.js +1 -1
- package/dist/core/utils/imageUtils.js.map +1 -1
- package/package.json +4 -3
- package/dist/core/components/viewers/pointcloud/src/PointCloudManagement/PointCloudViewer-old.d.ts +0 -3
- package/dist/core/components/viewers/pointcloud/src/PointCloudManagement/PointCloudViewer-old.d.ts.map +0 -1
- package/dist/core/components/viewers/pointcloud/src/PointCloudManagement/PointCloudViewer-old.js +0 -173
- package/dist/core/components/viewers/pointcloud/src/PointCloudManagement/PointCloudViewer-old.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../../../../src/core/components/viewers/map/src/MapLayers/src/FileLayer/FileModelLayer/FileModelLayer.tsx"],"sourcesContent":["\"use client\"\r\n\r\nimport * as THREE from 'three'\r\nimport { MapContext, FilesContext } from '../../../../../../../../store'\r\n\r\nimport * as React from 'react'\r\nimport { CustomModelLayer } from '../utils/CustomModelLayer'\r\nimport { DbFile } from '../../../../../../../../types/dbTypes'\r\n\r\ntype LoadedModelFiles = {\r\n file: DbFile\r\n cleanUpFunction: () => void\r\n hitTest: (ndcX: number, ndcY: number) => boolean\r\n}\r\n\r\ninterface FileModelLayerProps {\r\n tempPositionsRef?: React.MutableRefObject<Record<string, { lat: number; lng: number }>>\r\n editingFileNameRef?: React.MutableRefObject<string | null>\r\n tempRotationsRef?: React.MutableRefObject<Record<string, number>>\r\n tempElevationsRef?: React.MutableRefObject<Record<string, number>>\r\n /** Called when the user right-clicks on a rendered 3D mesh. */\r\n onContextMenu?: (file: DbFile, clientX: number, clientY: number) => void\r\n}\r\n\r\nexport const FileModelLayer = ({\r\n tempPositionsRef,\r\n editingFileNameRef,\r\n tempRotationsRef,\r\n tempElevationsRef,\r\n onContextMenu,\r\n}: FileModelLayerProps) => {\r\n const { state: mapState } = React.useContext(MapContext)\r\n const { map } = mapState.map\r\n const { state: fileState } = React.useContext(FilesContext)\r\n const { files: globalFileState, mapFileIds } = fileState.files\r\n\r\n const is3DModelFile = (extension?: string | null): boolean => {\r\n if (!extension) return false\r\n const ext = extension.toLowerCase()\r\n return ['glb', 'gltf', 'fbx', 'obj', 'collada'].includes(ext)\r\n }\r\n\r\n const mapFiles = React.useMemo(\r\n () => globalFileState.filter(file => is3DModelFile(file.extension) && mapFileIds.includes(file.id) && !!file.url),\r\n [globalFileState, mapFileIds]\r\n )\r\n\r\n const [loadedModels, setLoadedModels] = React.useState<LoadedModelFiles[]>([])\r\n const rendererRef = React.useRef<THREE.WebGLRenderer | null>(null)\r\n\r\n // Stable refs so the canvas listener never needs to be re-registered\r\n const loadedModelsRef = React.useRef<LoadedModelFiles[]>([])\r\n const onContextMenuRef = React.useRef(onContextMenu)\r\n loadedModelsRef.current = loadedModels\r\n onContextMenuRef.current = onContextMenu\r\n\r\n // ── Layer management ───────────────────────────────────────────────────────\r\n React.useEffect(() => {\r\n if (!map) return\r\n if (!rendererRef.current) {\r\n rendererRef.current = new THREE.WebGLRenderer({\r\n canvas: map.getCanvas(),\r\n context: map.getCanvas().getContext('webgl') as WebGLRenderingContext,\r\n antialias: true,\r\n })\r\n }\r\n const currentModelFiles = mapFiles.filter(file => {\r\n const ext = file.extension?.toLowerCase()\r\n return ext === 'glb' || ext === 'gltf' || ext === 'fbx' || ext === 'obj' || ext === 'collada'\r\n })\r\n const loadedIds = new Set(loadedModels.map(model => model.file.id))\r\n const currentFileIds = new Set(currentModelFiles.map(f => f.id))\r\n\r\n const modelsToRemove = loadedModels.filter(model => !currentFileIds.has(model.file.id))\r\n\r\n const modelsWithChangedCoords = loadedModels.filter(model => {\r\n if (!currentFileIds.has(model.file.id)) return false\r\n const updated = currentModelFiles.find(f => f.id === model.file.id)\r\n return updated && (\r\n updated.lat !== model.file.lat ||\r\n updated.lng !== model.file.lng ||\r\n updated.rotation !== model.file.rotation ||\r\n updated.elevation !== model.file.elevation\r\n )\r\n })\r\n\r\n for (const model of [...modelsToRemove, ...modelsWithChangedCoords]) {\r\n model.cleanUpFunction()\r\n }\r\n\r\n const staleIds = new Set(modelsWithChangedCoords.map(m => m.file.id))\r\n\r\n const filesNotLoaded = currentModelFiles.filter(\r\n file => !loadedIds.has(file.id) || staleIds.has(file.id)\r\n )\r\n\r\n const newLoadedModels = loadedModels\r\n .filter(model => currentFileIds.has(model.file.id) && !staleIds.has(model.file.id))\r\n\r\n for (const file of filesNotLoaded) {\r\n const { cleanup, hitTest } = CustomModelLayer(\r\n file,\r\n map,\r\n rendererRef.current,\r\n tempPositionsRef,\r\n editingFileNameRef,\r\n tempRotationsRef,\r\n tempElevationsRef,\r\n )\r\n newLoadedModels.push({ file, cleanUpFunction: cleanup, hitTest })\r\n }\r\n\r\n setLoadedModels(newLoadedModels)\r\n }, [mapFiles, map])\r\n\r\n // ── Canvas right-click → raycasting ───────────────────────────────────────\r\n React.useEffect(() => {\r\n if (!map) return\r\n const canvas = map.getCanvas()\r\n\r\n const handleContextMenu = (e: MouseEvent) => {\r\n // Only handle clicks that land directly on the WebGL canvas (not on HTML\r\n // marker overlays — those have their own onContextMenu handlers)\r\n if (e.target !== canvas) return\r\n\r\n const models = loadedModelsRef.current\r\n if (models.length === 0) return\r\n\r\n const rect = canvas.getBoundingClientRect()\r\n const ndcX = ((e.clientX - rect.left) / rect.width) * 2 - 1\r\n const ndcY = -((e.clientY - rect.top) / rect.height) * 2 + 1\r\n\r\n for (const model of models) {\r\n if (model.hitTest(ndcX, ndcY)) {\r\n e.preventDefault()\r\n e.stopPropagation()\r\n onContextMenuRef.current?.(model.file, e.clientX, e.clientY)\r\n break\r\n }\r\n }\r\n }\r\n\r\n // Use capture phase so we see the event before MapLibre's own handlers\r\n canvas.addEventListener('contextmenu', handleContextMenu, true)\r\n return () => canvas.removeEventListener('contextmenu', handleContextMenu, true)\r\n }, [map])\r\n\r\n //
|
|
1
|
+
{"version":3,"sources":["../../../../../../../../../../src/core/components/viewers/map/src/MapLayers/src/FileLayer/FileModelLayer/FileModelLayer.tsx"],"sourcesContent":["\"use client\"\r\n\r\nimport * as THREE from 'three'\r\nimport { MapContext, FilesContext } from '../../../../../../../../store'\r\n\r\nimport * as React from 'react'\r\nimport { CustomModelLayer } from '../utils/CustomModelLayer'\r\nimport { DbFile } from '../../../../../../../../types/dbTypes'\r\n\r\ntype LoadedModelFiles = {\r\n file: DbFile\r\n cleanUpFunction: () => void\r\n hitTest: (ndcX: number, ndcY: number) => boolean\r\n}\r\n\r\ninterface FileModelLayerProps {\r\n tempPositionsRef?: React.MutableRefObject<Record<string, { lat: number; lng: number }>>\r\n editingFileNameRef?: React.MutableRefObject<string | null>\r\n tempRotationsRef?: React.MutableRefObject<Record<string, number>>\r\n tempElevationsRef?: React.MutableRefObject<Record<string, number>>\r\n /** Called when the user right-clicks on a rendered 3D mesh. */\r\n onContextMenu?: (file: DbFile, clientX: number, clientY: number) => void\r\n}\r\n\r\nexport const FileModelLayer = ({\r\n tempPositionsRef,\r\n editingFileNameRef,\r\n tempRotationsRef,\r\n tempElevationsRef,\r\n onContextMenu,\r\n}: FileModelLayerProps) => {\r\n const { state: mapState } = React.useContext(MapContext)\r\n const { map } = mapState.map\r\n const { state: fileState } = React.useContext(FilesContext)\r\n const { files: globalFileState, mapFileIds } = fileState.files\r\n\r\n const is3DModelFile = (extension?: string | null): boolean => {\r\n if (!extension) return false\r\n const ext = extension.toLowerCase()\r\n return ['glb', 'gltf', 'fbx', 'obj', 'collada'].includes(ext)\r\n }\r\n\r\n const mapFiles = React.useMemo(\r\n () => globalFileState.filter(file => is3DModelFile(file.extension) && mapFileIds.includes(file.id) && !!file.url),\r\n [globalFileState, mapFileIds]\r\n )\r\n\r\n const [loadedModels, setLoadedModels] = React.useState<LoadedModelFiles[]>([])\r\n const rendererRef = React.useRef<THREE.WebGLRenderer | null>(null)\r\n\r\n // Stable refs so the canvas listener never needs to be re-registered\r\n const loadedModelsRef = React.useRef<LoadedModelFiles[]>([])\r\n const onContextMenuRef = React.useRef(onContextMenu)\r\n loadedModelsRef.current = loadedModels\r\n onContextMenuRef.current = onContextMenu\r\n\r\n // ── Layer management ───────────────────────────────────────────────────────\r\n React.useEffect(() => {\r\n if (!map) return\r\n if (!rendererRef.current) {\r\n rendererRef.current = new THREE.WebGLRenderer({\r\n canvas: map.getCanvas(),\r\n context: map.getCanvas().getContext('webgl') as WebGLRenderingContext,\r\n antialias: true,\r\n })\r\n }\r\n const currentModelFiles = mapFiles.filter(file => {\r\n const ext = file.extension?.toLowerCase()\r\n return ext === 'glb' || ext === 'gltf' || ext === 'fbx' || ext === 'obj' || ext === 'collada'\r\n })\r\n const loadedIds = new Set(loadedModels.map(model => model.file.id))\r\n const currentFileIds = new Set(currentModelFiles.map(f => f.id))\r\n\r\n const modelsToRemove = loadedModels.filter(model => !currentFileIds.has(model.file.id))\r\n\r\n const modelsWithChangedCoords = loadedModels.filter(model => {\r\n if (!currentFileIds.has(model.file.id)) return false\r\n const updated = currentModelFiles.find(f => f.id === model.file.id)\r\n return updated && (\r\n updated.lat !== model.file.lat ||\r\n updated.lng !== model.file.lng ||\r\n updated.rotation !== model.file.rotation ||\r\n updated.elevation !== model.file.elevation\r\n )\r\n })\r\n\r\n for (const model of [...modelsToRemove, ...modelsWithChangedCoords]) {\r\n model.cleanUpFunction()\r\n }\r\n\r\n const staleIds = new Set(modelsWithChangedCoords.map(m => m.file.id))\r\n\r\n const filesNotLoaded = currentModelFiles.filter(\r\n file => !loadedIds.has(file.id) || staleIds.has(file.id)\r\n )\r\n\r\n const newLoadedModels = loadedModels\r\n .filter(model => currentFileIds.has(model.file.id) && !staleIds.has(model.file.id))\r\n\r\n for (const file of filesNotLoaded) {\r\n const { cleanup, hitTest } = CustomModelLayer(\r\n file,\r\n map,\r\n rendererRef.current,\r\n tempPositionsRef,\r\n editingFileNameRef,\r\n tempRotationsRef,\r\n tempElevationsRef,\r\n )\r\n newLoadedModels.push({ file, cleanUpFunction: cleanup, hitTest })\r\n }\r\n\r\n setLoadedModels(newLoadedModels)\r\n }, [mapFiles, map])\r\n\r\n // ── Canvas right-click → raycasting ───────────────────────────────────────\r\n React.useEffect(() => {\r\n if (!map) return\r\n const canvas = map.getCanvas()\r\n\r\n const handleContextMenu = (e: MouseEvent) => {\r\n // Only handle clicks that land directly on the WebGL canvas (not on HTML\r\n // marker overlays — those have their own onContextMenu handlers)\r\n if (e.target !== canvas) return\r\n\r\n const models = loadedModelsRef.current\r\n if (models.length === 0) return\r\n\r\n const rect = canvas.getBoundingClientRect()\r\n const ndcX = ((e.clientX - rect.left) / rect.width) * 2 - 1\r\n const ndcY = -((e.clientY - rect.top) / rect.height) * 2 + 1\r\n\r\n for (const model of models) {\r\n if (model.hitTest(ndcX, ndcY)) {\r\n e.preventDefault()\r\n e.stopPropagation()\r\n onContextMenuRef.current?.(model.file, e.clientX, e.clientY)\r\n break\r\n }\r\n }\r\n }\r\n\r\n // Use capture phase so we see the event before MapLibre's own handlers\r\n canvas.addEventListener('contextmenu', handleContextMenu, true)\r\n return () => canvas.removeEventListener('contextmenu', handleContextMenu, true)\r\n }, [map])\r\n\r\n // Teardown: remove model layers + dispose the shared renderer on unmount / map\r\n // change, else the WebGLRenderer + its scenes leak across viewer switches.\r\n React.useEffect(() => {\r\n return () => {\r\n for (const model of loadedModelsRef.current) {\r\n try { model.cleanUpFunction() } catch { /* layer or map may already be gone */ }\r\n }\r\n if (rendererRef.current) {\r\n rendererRef.current.dispose()\r\n rendererRef.current = null\r\n }\r\n }\r\n }, [map])\r\n\r\n return null\r\n}\r\n"],"mappings":"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","names":[]}
|
package/dist/core/components/viewers/map/src/MapLayers/src/FileLayer/utils/CustomModelLayer.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CustomModelLayer.d.ts","sourceRoot":"","sources":["../../../../../../../../../../src/core/components/viewers/map/src/MapLayers/src/FileLayer/utils/CustomModelLayer.ts"],"names":[],"mappings":"AAAA,OAAO,EAA8C,KAAK,GAAG,EAAE,MAAM,aAAa,CAAA;AAClF,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAE9B,OAAO,EAAE,MAAM,EAAE,MAAM,uCAAuC,CAAA;AAG9D,KAAK,gBAAgB,GAAG,KAAK,CAAC,gBAAgB,CAAC,MAAM,CAAC,MAAM,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC,CAAA;AAC5F,KAAK,gBAAgB,GAAG,KAAK,CAAC,gBAAgB,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;AACtE,KAAK,iBAAiB,GAAG,KAAK,CAAC,gBAAgB,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;AACvE,KAAK,kBAAkB,GAAG,KAAK,CAAC,gBAAgB,CAAC,MAAM,GAAG,IAAI,CAAC,CAAA;AA8B/D,eAAO,MAAM,gBAAgB,GAC3B,WAAW,MAAM,EACjB,KAAK,GAAG,EACR,UAAU,KAAK,CAAC,aAAa,EAC7B,mBAAmB,gBAAgB,EACnC,qBAAqB,kBAAkB,EACvC,mBAAmB,gBAAgB,EACnC,oBAAoB,iBAAiB,KACpC;IAAE,OAAO,EAAE,MAAM,IAAI,CAAC;IAAC,MAAM,EAAE,MAAM,IAAI,CAAC;IAAC,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"CustomModelLayer.d.ts","sourceRoot":"","sources":["../../../../../../../../../../src/core/components/viewers/map/src/MapLayers/src/FileLayer/utils/CustomModelLayer.ts"],"names":[],"mappings":"AAAA,OAAO,EAA8C,KAAK,GAAG,EAAE,MAAM,aAAa,CAAA;AAClF,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAE9B,OAAO,EAAE,MAAM,EAAE,MAAM,uCAAuC,CAAA;AAG9D,KAAK,gBAAgB,GAAG,KAAK,CAAC,gBAAgB,CAAC,MAAM,CAAC,MAAM,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC,CAAA;AAC5F,KAAK,gBAAgB,GAAG,KAAK,CAAC,gBAAgB,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;AACtE,KAAK,iBAAiB,GAAG,KAAK,CAAC,gBAAgB,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;AACvE,KAAK,kBAAkB,GAAG,KAAK,CAAC,gBAAgB,CAAC,MAAM,GAAG,IAAI,CAAC,CAAA;AA8B/D,eAAO,MAAM,gBAAgB,GAC3B,WAAW,MAAM,EACjB,KAAK,GAAG,EACR,UAAU,KAAK,CAAC,aAAa,EAC7B,mBAAmB,gBAAgB,EACnC,qBAAqB,kBAAkB,EACvC,mBAAmB,gBAAgB,EACnC,oBAAoB,iBAAiB,KACpC;IAAE,OAAO,EAAE,MAAM,IAAI,CAAC;IAAC,MAAM,EAAE,MAAM,IAAI,CAAC;IAAC,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,OAAO,CAAA;CAgQ7F,CAAA"}
|
package/dist/core/components/viewers/map/src/MapLayers/src/FileLayer/utils/CustomModelLayer.js
CHANGED
|
@@ -44,6 +44,18 @@ const CustomModelLayer = (modelFile, map, renderer, tempPositionsRef, editingFil
|
|
|
44
44
|
let disposed = false;
|
|
45
45
|
const _m = new THREE.Matrix4();
|
|
46
46
|
const _l = new THREE.Matrix4();
|
|
47
|
+
let cachedTerrainElev = 0;
|
|
48
|
+
let lastMoveTime = performance.now();
|
|
49
|
+
const SETTLE_MS = 1e3;
|
|
50
|
+
let onMapMove;
|
|
51
|
+
let onMapMoveEnd;
|
|
52
|
+
const recomputeTerrainElev = () => {
|
|
53
|
+
const { lng, lat } = resolveModelCoordinates(modelFile);
|
|
54
|
+
if (!(lng === 0 && lat === 0)) {
|
|
55
|
+
const e = map.queryTerrainElevation([lng, lat]);
|
|
56
|
+
if (e !== null && e !== void 0) cachedTerrainElev = e;
|
|
57
|
+
}
|
|
58
|
+
};
|
|
47
59
|
return {
|
|
48
60
|
id: `model-${modelFile.id}`,
|
|
49
61
|
type: "custom",
|
|
@@ -86,12 +98,25 @@ const CustomModelLayer = (modelFile, map, renderer, tempPositionsRef, editingFil
|
|
|
86
98
|
}
|
|
87
99
|
}
|
|
88
100
|
scene.add(gltf.scene);
|
|
101
|
+
lastMoveTime = performance.now();
|
|
102
|
+
recomputeTerrainElev();
|
|
103
|
+
map2.triggerRepaint();
|
|
89
104
|
},
|
|
90
105
|
void 0,
|
|
91
106
|
(error) => {
|
|
92
107
|
console.error("Error loading model:", error);
|
|
93
108
|
}
|
|
94
109
|
);
|
|
110
|
+
onMapMove = () => {
|
|
111
|
+
lastMoveTime = performance.now();
|
|
112
|
+
};
|
|
113
|
+
onMapMoveEnd = () => {
|
|
114
|
+
lastMoveTime = performance.now();
|
|
115
|
+
recomputeTerrainElev();
|
|
116
|
+
map2.triggerRepaint();
|
|
117
|
+
};
|
|
118
|
+
map2.on("move", onMapMove);
|
|
119
|
+
map2.on("moveend", onMapMoveEnd);
|
|
95
120
|
},
|
|
96
121
|
render(gl, args) {
|
|
97
122
|
var _a2, _b, _c;
|
|
@@ -119,7 +144,7 @@ const CustomModelLayer = (modelFile, map, renderer, tempPositionsRef, editingFil
|
|
|
119
144
|
}
|
|
120
145
|
const fileElevation = isEditing && (tempElevationsRef == null ? void 0 : tempElevationsRef.current[modelFile.name]) !== void 0 ? tempElevationsRef.current[modelFile.name] : (_b = modelFile.elevation) != null ? _b : 0;
|
|
121
146
|
const modelOrigin = [lng, lat];
|
|
122
|
-
const terrainAltitude = (_c = map.queryTerrainElevation([lng, lat])) != null ? _c :
|
|
147
|
+
const terrainAltitude = isEditing ? (_c = map.queryTerrainElevation([lng, lat])) != null ? _c : cachedTerrainElev : cachedTerrainElev;
|
|
123
148
|
const altitude = terrainAltitude + fileElevation;
|
|
124
149
|
const modelMatrix = map.transform.getMatrixForModel(modelOrigin, altitude);
|
|
125
150
|
_m.fromArray(args.defaultProjectionData.mainMatrix);
|
|
@@ -130,10 +155,14 @@ const CustomModelLayer = (modelFile, map, renderer, tempPositionsRef, editingFil
|
|
|
130
155
|
}
|
|
131
156
|
this.renderer.resetState();
|
|
132
157
|
this.renderer.render(this.scene, this.camera);
|
|
133
|
-
|
|
158
|
+
if (this.mixer || isEditing || performance.now() - lastMoveTime < SETTLE_MS) {
|
|
159
|
+
map.triggerRepaint();
|
|
160
|
+
}
|
|
134
161
|
},
|
|
135
162
|
onRemove() {
|
|
136
163
|
disposed = true;
|
|
164
|
+
if (onMapMove) map.off("move", onMapMove);
|
|
165
|
+
if (onMapMoveEnd) map.off("moveend", onMapMoveEnd);
|
|
137
166
|
if (this.mixer) {
|
|
138
167
|
;
|
|
139
168
|
this.mixer.stopAllAction();
|
package/dist/core/components/viewers/map/src/MapLayers/src/FileLayer/utils/CustomModelLayer.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../../../../src/core/components/viewers/map/src/MapLayers/src/FileLayer/utils/CustomModelLayer.ts"],"sourcesContent":["import { type CustomLayerInterface, type LngLatLike, type Map } from 'maplibre-gl'\r\nimport * as THREE from 'three'\r\nimport { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js'\r\nimport { DbFile } from '../../../../../../../../types/dbTypes'\r\nimport { disposeThreeScene } from '../../disposeThreeScene'\r\n\r\ntype TempPositionsRef = React.MutableRefObject<Record<string, { lat: number; lng: number }>>\r\ntype TempRotationsRef = React.MutableRefObject<Record<string, number>>\r\ntype TempElevationsRef = React.MutableRefObject<Record<string, number>>\r\ntype EditingFileNameRef = React.MutableRefObject<string | null>\r\n\r\nfunction resolveModelCoordinates(file: DbFile): { lng: number, lat: number } {\r\n if (typeof file.lng === 'number' && typeof file.lat === 'number') {\r\n return { lng: file.lng, lat: file.lat }\r\n }\r\n\r\n const rawPosition = file.position as unknown\r\n if (rawPosition && typeof rawPosition === 'object') {\r\n const pos = rawPosition as { lng?: number, lat?: number }\r\n if (typeof pos.lng === 'number' && typeof pos.lat === 'number') {\r\n return { lng: pos.lng, lat: pos.lat }\r\n }\r\n }\r\n\r\n if (typeof rawPosition === 'string') {\r\n try {\r\n const parsed = JSON.parse(rawPosition) as { lng?: number, lat?: number }\r\n if (typeof parsed.lng === 'number' && typeof parsed.lat === 'number') {\r\n return { lng: parsed.lng, lat: parsed.lat }\r\n }\r\n }\r\n catch {\r\n // Ignore malformed legacy position payloads.\r\n }\r\n }\r\n\r\n return { lng: 0, lat: 0 }\r\n}\r\n\r\nexport const CustomModelLayer = (\r\n modelFile: DbFile,\r\n map: Map,\r\n renderer: THREE.WebGLRenderer,\r\n tempPositionsRef?: TempPositionsRef,\r\n editingFileNameRef?: EditingFileNameRef,\r\n tempRotationsRef?: TempRotationsRef,\r\n tempElevationsRef?: TempElevationsRef,\r\n): { cleanup: () => void, remove: () => void, hitTest: (ndcX: number, ndcY: number) => boolean } => {\r\n let components = null\r\n let customLayer: CustomLayerInterface | null = null\r\n\r\n if (!map || !modelFile) {\r\n return { cleanup: () => {}, remove: () => {}, hitTest: () => false }\r\n }\r\n\r\n // Refs into the layer's camera and scene so raycasting can read the last\r\n // rendered frame's transform without entering the render loop.\r\n let cameraRef: THREE.Camera | null = null\r\n let sceneRef: THREE.Scene | null = null\r\n\r\n // Reused temps for hitTest raycasting — avoid per-call allocation (audit B3).\r\n const _hitInv = new THREE.Matrix4()\r\n const _hitNear = new THREE.Vector3()\r\n const _hitFar = new THREE.Vector3()\r\n const _hitDir = new THREE.Vector3()\r\n const _raycaster = new THREE.Raycaster()\r\n\r\n const createCustomLayer = (): CustomLayerInterface => {\r\n // Track last applied rotation so we can apply delta increments (same as BimLayer)\r\n let lastAppliedRotation = modelFile.rotation ?? 0\r\n // Layer-removed-mid-load guard (audit B4) + reused per-frame matrices (audit B2)\r\n let disposed = false\r\n const _m = new THREE.Matrix4()\r\n const _l = new THREE.Matrix4()\r\n\r\n return {\r\n id: `model-${modelFile.id}`,\r\n type: 'custom',\r\n renderingMode: '3d',\r\n onAdd(map, gl) {\r\n this.camera = new THREE.Camera()\r\n this.scene = new THREE.Scene()\r\n this.renderer = renderer\r\n\r\n // Expose to closure for raycasting\r\n cameraRef = this.camera as THREE.Camera\r\n sceneRef = this.scene as THREE.Scene\r\n\r\n const scene = this.scene as THREE.Scene\r\n\r\n // Apply initial rotation\r\n if (lastAppliedRotation !== 0) {\r\n scene.rotateY(lastAppliedRotation * (Math.PI / 180))\r\n }\r\n\r\n // Lighting to match OBC library setup\r\n scene.background = null\r\n scene.fog = new THREE.Fog(0x20_29_32, 10, 200)\r\n scene.add(new THREE.AmbientLight(0xFF_FF_FF, 1))\r\n scene.add(new THREE.HemisphereLight(0xFF_FF_BB, 0x08_08_20, 0.5))\r\n\r\n const sun = new THREE.DirectionalLight(0xFF_FF_FF, 1.5)\r\n sun.position.set(0, -70, 100).normalize()\r\n sun.castShadow = true\r\n sun.shadow.mapSize.set(2048, 2048)\r\n scene.add(sun)\r\n\r\n const fill = new THREE.DirectionalLight(0xFF_FF_FF, 1)\r\n fill.position.set(0, 70, 100).normalize()\r\n scene.add(fill)\r\n\r\n this.renderer.toneMapping = THREE.ACESFilmicToneMapping\r\n this.renderer.autoClear = false\r\n this.clock = new THREE.Clock()\r\n\r\n const loader = new GLTFLoader()\r\n loader.load(\r\n modelFile.url!,\r\n (gltf) => {\r\n // Layer was removed before the async load resolved — don't attach to a\r\n // dead scene; let the gltf be GC'd (no GPU upload happened yet). (audit B4)\r\n if (disposed) return\r\n gltf.scene.scale.setScalar(1)\r\n\r\n if (gltf.animations && gltf.animations.length > 0) {\r\n this.mixer = new THREE.AnimationMixer(gltf.scene)\r\n for (const clip of gltf.animations) {\r\n this.mixer!.clipAction(clip).play()\r\n }\r\n }\r\n\r\n scene.add(gltf.scene)\r\n },\r\n undefined,\r\n (error) => { console.error('Error loading model:', error) },\r\n )\r\n },\r\n\r\n render(gl, args) {\r\n if (map.getZoom() < 15.5) return\r\n\r\n const isEditing = editingFileNameRef?.current === modelFile.name\r\n\r\n // ── Position ──────────────────────────────────────────────────────────\r\n let lng: number\r\n let lat: number\r\n if (isEditing && tempPositionsRef?.current[modelFile.name]) {\r\n const tp = tempPositionsRef.current[modelFile.name]\r\n lng = tp.lng\r\n lat = tp.lat\r\n } else {\r\n const coords = resolveModelCoordinates(modelFile)\r\n lng = coords.lng\r\n lat = coords.lat\r\n }\r\n\r\n if (lng === 0 && lat === 0) return\r\n\r\n // ── Rotation (delta-increment, same pattern as BimLayer) ──────────────\r\n const targetRotation = (isEditing && tempRotationsRef?.current[modelFile.name] !== undefined)\r\n ? tempRotationsRef.current[modelFile.name]\r\n : (modelFile.rotation ?? 0)\r\n\r\n if (targetRotation !== lastAppliedRotation) {\r\n ;(this.scene as THREE.Scene).rotateY(\r\n (targetRotation - lastAppliedRotation) * (Math.PI / 180)\r\n )\r\n lastAppliedRotation = targetRotation\r\n }\r\n\r\n // ── Elevation ─────────────────────────────────────────────────────────\r\n const fileElevation = (isEditing && tempElevationsRef?.current[modelFile.name] !== undefined)\r\n ? tempElevationsRef.current[modelFile.name]\r\n : (modelFile.elevation ?? 0)\r\n\r\n const modelOrigin = [lng, lat] as LngLatLike\r\n const terrainAltitude = map.queryTerrainElevation([lng, lat]) ?? 0\r\n const altitude = terrainAltitude + fileElevation\r\n\r\n const modelMatrix = map.transform.getMatrixForModel(modelOrigin, altitude)\r\n // Reuse temps and write into the camera's own matrix — no per-frame\r\n // allocation. The previous `.scale(1,1,1)` was an identity no-op. (audit B2)\r\n _m.fromArray(args.defaultProjectionData.mainMatrix)\r\n _l.fromArray(modelMatrix)\r\n this.camera.projectionMatrix.multiplyMatrices(_m, _l)\r\n\r\n if (this.mixer) {\r\n this.mixer.update((this.clock as THREE.Clock).getDelta())\r\n }\r\n\r\n this.renderer.resetState()\r\n this.renderer.render(this.scene, this.camera)\r\n\r\n map.triggerRepaint()\r\n },\r\n\r\n onRemove() {\r\n disposed = true\r\n // Stop + release the animation mixer so it isn't left running/holding the\r\n // scene after removal (audit B5).\r\n if (this.mixer) {\r\n ;(this.mixer as THREE.AnimationMixer).stopAllAction()\r\n this.mixer = null\r\n }\r\n if (this.scene) disposeThreeScene(this.scene as THREE.Scene)\r\n cameraRef = null\r\n sceneRef = null\r\n this.renderer = null\r\n this.camera = null\r\n this.scene = null\r\n },\r\n }\r\n }\r\n\r\n /**\r\n * Raycast against this model using the last rendered frame's camera matrix.\r\n *\r\n * The camera.projectionMatrix = VP * M (view-projection × model-to-world),\r\n * so its inverse transforms clip-space → model-space, which is exactly the\r\n * coordinate system the Three.js scene lives in. We manually unproject near/far\r\n * clip-space points through that inverse to build the ray.\r\n */\r\n const hitTest = (ndcX: number, ndcY: number): boolean => {\r\n if (!cameraRef || !sceneRef) return false\r\n\r\n // Invert the combined VP*M matrix to go clip-space → model-space.\r\n // Reuses module-scope temps + a singleton raycaster (audit B3).\r\n _hitInv.copy(cameraRef.projectionMatrix).invert()\r\n\r\n // Unproject near and far clip-space points into model space\r\n _hitNear.set(ndcX, ndcY, -1).applyMatrix4(_hitInv)\r\n _hitFar.set(ndcX, ndcY, 1).applyMatrix4(_hitInv)\r\n\r\n _hitDir.copy(_hitFar).sub(_hitNear).normalize()\r\n\r\n _raycaster.set(_hitNear, _hitDir)\r\n\r\n const intersects = _raycaster.intersectObjects(sceneRef.children, true)\r\n return intersects.length > 0\r\n }\r\n\r\n customLayer = createCustomLayer()\r\n\r\n if (!map.getLayer(customLayer.id)) {\r\n map.addLayer(customLayer)\r\n }\r\n\r\n const removeLayer = () => {\r\n if (customLayer && map.getLayer(customLayer.id)) {\r\n map.removeLayer(customLayer.id)\r\n }\r\n }\r\n\r\n const cleanup = () => {\r\n removeLayer()\r\n components = null\r\n customLayer = null\r\n }\r\n\r\n return { cleanup, remove: removeLayer, hitTest }\r\n}\r\n"],"mappings":"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","names":["map","_a"]}
|
|
1
|
+
{"version":3,"sources":["../../../../../../../../../../src/core/components/viewers/map/src/MapLayers/src/FileLayer/utils/CustomModelLayer.ts"],"sourcesContent":["import { type CustomLayerInterface, type LngLatLike, type Map } from 'maplibre-gl'\r\nimport * as THREE from 'three'\r\nimport { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js'\r\nimport { DbFile } from '../../../../../../../../types/dbTypes'\r\nimport { disposeThreeScene } from '../../disposeThreeScene'\r\n\r\ntype TempPositionsRef = React.MutableRefObject<Record<string, { lat: number; lng: number }>>\r\ntype TempRotationsRef = React.MutableRefObject<Record<string, number>>\r\ntype TempElevationsRef = React.MutableRefObject<Record<string, number>>\r\ntype EditingFileNameRef = React.MutableRefObject<string | null>\r\n\r\nfunction resolveModelCoordinates(file: DbFile): { lng: number, lat: number } {\r\n if (typeof file.lng === 'number' && typeof file.lat === 'number') {\r\n return { lng: file.lng, lat: file.lat }\r\n }\r\n\r\n const rawPosition = file.position as unknown\r\n if (rawPosition && typeof rawPosition === 'object') {\r\n const pos = rawPosition as { lng?: number, lat?: number }\r\n if (typeof pos.lng === 'number' && typeof pos.lat === 'number') {\r\n return { lng: pos.lng, lat: pos.lat }\r\n }\r\n }\r\n\r\n if (typeof rawPosition === 'string') {\r\n try {\r\n const parsed = JSON.parse(rawPosition) as { lng?: number, lat?: number }\r\n if (typeof parsed.lng === 'number' && typeof parsed.lat === 'number') {\r\n return { lng: parsed.lng, lat: parsed.lat }\r\n }\r\n }\r\n catch {\r\n // Ignore malformed legacy position payloads.\r\n }\r\n }\r\n\r\n return { lng: 0, lat: 0 }\r\n}\r\n\r\nexport const CustomModelLayer = (\r\n modelFile: DbFile,\r\n map: Map,\r\n renderer: THREE.WebGLRenderer,\r\n tempPositionsRef?: TempPositionsRef,\r\n editingFileNameRef?: EditingFileNameRef,\r\n tempRotationsRef?: TempRotationsRef,\r\n tempElevationsRef?: TempElevationsRef,\r\n): { cleanup: () => void, remove: () => void, hitTest: (ndcX: number, ndcY: number) => boolean } => {\r\n let components = null\r\n let customLayer: CustomLayerInterface | null = null\r\n\r\n if (!map || !modelFile) {\r\n return { cleanup: () => {}, remove: () => {}, hitTest: () => false }\r\n }\r\n\r\n // Refs into the layer's camera and scene so raycasting can read the last\r\n // rendered frame's transform without entering the render loop.\r\n let cameraRef: THREE.Camera | null = null\r\n let sceneRef: THREE.Scene | null = null\r\n\r\n // Reused temps for hitTest raycasting — avoid per-call allocation.\r\n const _hitInv = new THREE.Matrix4()\r\n const _hitNear = new THREE.Vector3()\r\n const _hitFar = new THREE.Vector3()\r\n const _hitDir = new THREE.Vector3()\r\n const _raycaster = new THREE.Raycaster()\r\n\r\n const createCustomLayer = (): CustomLayerInterface => {\r\n // Track last applied rotation so we can apply delta increments (same as BimLayer)\r\n let lastAppliedRotation = modelFile.rotation ?? 0\r\n // Layer-removed-mid-load guard + reused per-frame matrices\r\n let disposed = false\r\n const _m = new THREE.Matrix4()\r\n const _l = new THREE.Matrix4()\r\n // Render-on-demand: cache terrain elevation off the per-frame path and only\r\n // keep repainting while the camera recently moved or an animation is playing,\r\n // so an idle map with a placed model stops re-rendering instead of pinning the\r\n // main thread (this was the freeze after a flyTo to high zoom).\r\n let cachedTerrainElev = 0\r\n let lastMoveTime = performance.now()\r\n const SETTLE_MS = 1000\r\n let onMapMove: (() => void) | undefined\r\n let onMapMoveEnd: (() => void) | undefined\r\n const recomputeTerrainElev = () => {\r\n const { lng, lat } = resolveModelCoordinates(modelFile)\r\n if (!(lng === 0 && lat === 0)) {\r\n const e = map.queryTerrainElevation([lng, lat])\r\n if (e !== null && e !== undefined) cachedTerrainElev = e\r\n }\r\n }\r\n\r\n return {\r\n id: `model-${modelFile.id}`,\r\n type: 'custom',\r\n renderingMode: '3d',\r\n onAdd(map, gl) {\r\n this.camera = new THREE.Camera()\r\n this.scene = new THREE.Scene()\r\n this.renderer = renderer\r\n\r\n // Expose to closure for raycasting\r\n cameraRef = this.camera as THREE.Camera\r\n sceneRef = this.scene as THREE.Scene\r\n\r\n const scene = this.scene as THREE.Scene\r\n\r\n // Apply initial rotation\r\n if (lastAppliedRotation !== 0) {\r\n scene.rotateY(lastAppliedRotation * (Math.PI / 180))\r\n }\r\n\r\n // Lighting to match OBC library setup\r\n scene.background = null\r\n scene.fog = new THREE.Fog(0x20_29_32, 10, 200)\r\n scene.add(new THREE.AmbientLight(0xFF_FF_FF, 1))\r\n scene.add(new THREE.HemisphereLight(0xFF_FF_BB, 0x08_08_20, 0.5))\r\n\r\n const sun = new THREE.DirectionalLight(0xFF_FF_FF, 1.5)\r\n sun.position.set(0, -70, 100).normalize()\r\n sun.castShadow = true\r\n sun.shadow.mapSize.set(2048, 2048)\r\n scene.add(sun)\r\n\r\n const fill = new THREE.DirectionalLight(0xFF_FF_FF, 1)\r\n fill.position.set(0, 70, 100).normalize()\r\n scene.add(fill)\r\n\r\n this.renderer.toneMapping = THREE.ACESFilmicToneMapping\r\n this.renderer.autoClear = false\r\n this.clock = new THREE.Clock()\r\n\r\n const loader = new GLTFLoader()\r\n loader.load(\r\n modelFile.url!,\r\n (gltf) => {\r\n // Layer was removed before the async load resolved — don't attach to a\r\n // dead scene; let the gltf be GC'd (no GPU upload happened yet).\r\n if (disposed) return\r\n gltf.scene.scale.setScalar(1)\r\n\r\n if (gltf.animations && gltf.animations.length > 0) {\r\n this.mixer = new THREE.AnimationMixer(gltf.scene)\r\n for (const clip of gltf.animations) {\r\n this.mixer!.clipAction(clip).play()\r\n }\r\n }\r\n\r\n scene.add(gltf.scene)\r\n // Open the settle window so the just-loaded model paints, then idle.\r\n lastMoveTime = performance.now()\r\n recomputeTerrainElev()\r\n map.triggerRepaint()\r\n },\r\n undefined,\r\n (error) => { console.error('Error loading model:', error) },\r\n )\r\n\r\n // Track camera movement for render-on-demand: keep repainting only\r\n // during/just-after movement; refresh cached terrain elevation on settle.\r\n onMapMove = () => { lastMoveTime = performance.now() }\r\n onMapMoveEnd = () => {\r\n lastMoveTime = performance.now()\r\n recomputeTerrainElev()\r\n map.triggerRepaint()\r\n }\r\n map.on('move', onMapMove)\r\n map.on('moveend', onMapMoveEnd)\r\n },\r\n\r\n render(gl, args) {\r\n if (map.getZoom() < 15.5) return\r\n\r\n const isEditing = editingFileNameRef?.current === modelFile.name\r\n\r\n // ── Position ──────────────────────────────────────────────────────────\r\n let lng: number\r\n let lat: number\r\n if (isEditing && tempPositionsRef?.current[modelFile.name]) {\r\n const tp = tempPositionsRef.current[modelFile.name]\r\n lng = tp.lng\r\n lat = tp.lat\r\n } else {\r\n const coords = resolveModelCoordinates(modelFile)\r\n lng = coords.lng\r\n lat = coords.lat\r\n }\r\n\r\n if (lng === 0 && lat === 0) return\r\n\r\n // ── Rotation (delta-increment, same pattern as BimLayer) ──────────────\r\n const targetRotation = (isEditing && tempRotationsRef?.current[modelFile.name] !== undefined)\r\n ? tempRotationsRef.current[modelFile.name]\r\n : (modelFile.rotation ?? 0)\r\n\r\n if (targetRotation !== lastAppliedRotation) {\r\n ;(this.scene as THREE.Scene).rotateY(\r\n (targetRotation - lastAppliedRotation) * (Math.PI / 180)\r\n )\r\n lastAppliedRotation = targetRotation\r\n }\r\n\r\n // ── Elevation ─────────────────────────────────────────────────────────\r\n const fileElevation = (isEditing && tempElevationsRef?.current[modelFile.name] !== undefined)\r\n ? tempElevationsRef.current[modelFile.name]\r\n : (modelFile.elevation ?? 0)\r\n\r\n const modelOrigin = [lng, lat] as LngLatLike\r\n // Cached terrain elevation (refreshed on moveend); query live only while\r\n // editing this model's position. Keeps queryTerrainElevation off the hot\r\n // path — the per-frame query drove the high-zoom freeze.\r\n const terrainAltitude = isEditing\r\n ? (map.queryTerrainElevation([lng, lat]) ?? cachedTerrainElev)\r\n : cachedTerrainElev\r\n const altitude = terrainAltitude + fileElevation\r\n\r\n const modelMatrix = map.transform.getMatrixForModel(modelOrigin, altitude)\r\n // Reuse temps and write into the camera's own matrix — no per-frame\r\n // allocation. The previous `.scale(1,1,1)` was an identity no-op.\r\n _m.fromArray(args.defaultProjectionData.mainMatrix)\r\n _l.fromArray(modelMatrix)\r\n this.camera.projectionMatrix.multiplyMatrices(_m, _l)\r\n\r\n if (this.mixer) {\r\n this.mixer.update((this.clock as THREE.Clock).getDelta())\r\n }\r\n\r\n this.renderer.resetState()\r\n this.renderer.render(this.scene, this.camera)\r\n\r\n // Render-on-demand: keep the frame loop alive only while an animation is\r\n // playing, the camera recently moved (settle window), or this model is\r\n // being edited. Idle static model ⇒ no self-scheduled repaints ⇒ no freeze.\r\n if (this.mixer || isEditing || performance.now() - lastMoveTime < SETTLE_MS) {\r\n map.triggerRepaint()\r\n }\r\n },\r\n\r\n onRemove() {\r\n disposed = true\r\n if (onMapMove) map.off('move', onMapMove)\r\n if (onMapMoveEnd) map.off('moveend', onMapMoveEnd)\r\n // Stop + release the animation mixer so it isn't left running/holding the\r\n // scene after removal.\r\n if (this.mixer) {\r\n ;(this.mixer as THREE.AnimationMixer).stopAllAction()\r\n this.mixer = null\r\n }\r\n if (this.scene) disposeThreeScene(this.scene as THREE.Scene)\r\n cameraRef = null\r\n sceneRef = null\r\n this.renderer = null\r\n this.camera = null\r\n this.scene = null\r\n },\r\n }\r\n }\r\n\r\n /**\r\n * Raycast against this model using the last rendered frame's camera matrix.\r\n *\r\n * The camera.projectionMatrix = VP * M (view-projection × model-to-world),\r\n * so its inverse transforms clip-space → model-space, which is exactly the\r\n * coordinate system the Three.js scene lives in. We manually unproject near/far\r\n * clip-space points through that inverse to build the ray.\r\n */\r\n const hitTest = (ndcX: number, ndcY: number): boolean => {\r\n if (!cameraRef || !sceneRef) return false\r\n\r\n // Invert the combined VP*M matrix to go clip-space → model-space.\r\n // Reuses module-scope temps + a singleton raycaster.\r\n _hitInv.copy(cameraRef.projectionMatrix).invert()\r\n\r\n // Unproject near and far clip-space points into model space\r\n _hitNear.set(ndcX, ndcY, -1).applyMatrix4(_hitInv)\r\n _hitFar.set(ndcX, ndcY, 1).applyMatrix4(_hitInv)\r\n\r\n _hitDir.copy(_hitFar).sub(_hitNear).normalize()\r\n\r\n _raycaster.set(_hitNear, _hitDir)\r\n\r\n const intersects = _raycaster.intersectObjects(sceneRef.children, true)\r\n return intersects.length > 0\r\n }\r\n\r\n customLayer = createCustomLayer()\r\n\r\n if (!map.getLayer(customLayer.id)) {\r\n map.addLayer(customLayer)\r\n }\r\n\r\n const removeLayer = () => {\r\n if (customLayer && map.getLayer(customLayer.id)) {\r\n map.removeLayer(customLayer.id)\r\n }\r\n }\r\n\r\n const cleanup = () => {\r\n removeLayer()\r\n components = null\r\n customLayer = null\r\n }\r\n\r\n return { cleanup, remove: removeLayer, hitTest }\r\n}\r\n"],"mappings":"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","names":["map","_a"]}
|
package/dist/core/components/viewers/map/src/MapLayers/src/OpenDataLayer/src/WmsTimeControl.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
interface WmsTimeControlProps {
|
|
3
|
+
/** Ascending frame timestamps (oldest → newest). */
|
|
4
|
+
frames: string[];
|
|
5
|
+
/** Called with the active frame timestamp whenever it changes. */
|
|
6
|
+
onTimeChange: (time: string) => void;
|
|
7
|
+
/** Card title (e.g. the dataset name). */
|
|
8
|
+
label?: string;
|
|
9
|
+
/** Frame advance interval while playing, ms. */
|
|
10
|
+
stepMs?: number;
|
|
11
|
+
/** WMS GetLegendGraphic image URL; shown under the slider when it loads. */
|
|
12
|
+
legendUrl?: string;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Floating scrub + play/pause control for a WMS time dimension. Defaults to the
|
|
16
|
+
* latest frame; play advances oldest→newest on a loop. Purely presentational —
|
|
17
|
+
* it owns only the current index + playing state and reports the active time up.
|
|
18
|
+
*/
|
|
19
|
+
export declare const WmsTimeControl: React.FC<WmsTimeControlProps>;
|
|
20
|
+
export {};
|
|
21
|
+
//# sourceMappingURL=WmsTimeControl.d.ts.map
|
package/dist/core/components/viewers/map/src/MapLayers/src/OpenDataLayer/src/WmsTimeControl.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WmsTimeControl.d.ts","sourceRoot":"","sources":["../../../../../../../../../../src/core/components/viewers/map/src/MapLayers/src/OpenDataLayer/src/WmsTimeControl.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAG/B,UAAU,mBAAmB;IAC3B,oDAAoD;IACpD,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,kEAAkE;IAClE,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,0CAA0C;IAC1C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,gDAAgD;IAChD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,4EAA4E;IAC5E,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;GAIG;AACH,eAAO,MAAM,cAAc,EAAE,KAAK,CAAC,EAAE,CAAC,mBAAmB,CA0GxD,CAAC"}
|
package/dist/core/components/viewers/map/src/MapLayers/src/OpenDataLayer/src/WmsTimeControl.js
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { formatFrameTime } from "../../../../../datasets/src/wmsTime";
|
|
5
|
+
const WmsTimeControl = ({
|
|
6
|
+
frames,
|
|
7
|
+
onTimeChange,
|
|
8
|
+
label,
|
|
9
|
+
stepMs = 500,
|
|
10
|
+
legendUrl
|
|
11
|
+
}) => {
|
|
12
|
+
const [index, setIndex] = React.useState(Math.max(0, frames.length - 1));
|
|
13
|
+
const [playing, setPlaying] = React.useState(false);
|
|
14
|
+
const [legendOk, setLegendOk] = React.useState(true);
|
|
15
|
+
React.useEffect(() => {
|
|
16
|
+
setLegendOk(true);
|
|
17
|
+
}, [legendUrl]);
|
|
18
|
+
React.useEffect(() => {
|
|
19
|
+
setIndex(Math.max(0, frames.length - 1));
|
|
20
|
+
}, [frames.length]);
|
|
21
|
+
React.useEffect(() => {
|
|
22
|
+
const time = frames[index];
|
|
23
|
+
if (time) onTimeChange(time);
|
|
24
|
+
}, [index, frames, onTimeChange]);
|
|
25
|
+
React.useEffect(() => {
|
|
26
|
+
if (!playing || frames.length < 2) return;
|
|
27
|
+
const timer = setInterval(() => {
|
|
28
|
+
setIndex((prev) => (prev + 1) % frames.length);
|
|
29
|
+
}, stepMs);
|
|
30
|
+
return () => clearInterval(timer);
|
|
31
|
+
}, [playing, frames.length, stepMs]);
|
|
32
|
+
if (frames.length === 0) return null;
|
|
33
|
+
const activeTime = frames[index];
|
|
34
|
+
return /* @__PURE__ */ jsxs(
|
|
35
|
+
"div",
|
|
36
|
+
{
|
|
37
|
+
style: {
|
|
38
|
+
// Laid out by the bottom-left flex stack it portals into (see MapViewer),
|
|
39
|
+
// so no absolute positioning — it sits above the legend / dataset-manager cards.
|
|
40
|
+
background: "#ffffff",
|
|
41
|
+
borderRadius: 8,
|
|
42
|
+
boxShadow: "0 1px 4px rgba(0,0,0,0.3)",
|
|
43
|
+
padding: "10px 12px",
|
|
44
|
+
width: 260,
|
|
45
|
+
font: "13px/1.3 system-ui, sans-serif",
|
|
46
|
+
color: "#1a1a1a",
|
|
47
|
+
pointerEvents: "auto"
|
|
48
|
+
},
|
|
49
|
+
children: [
|
|
50
|
+
/* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: 8, marginBottom: 6 }, children: [
|
|
51
|
+
/* @__PURE__ */ jsx(
|
|
52
|
+
"button",
|
|
53
|
+
{
|
|
54
|
+
type: "button",
|
|
55
|
+
onClick: () => setPlaying((p) => !p),
|
|
56
|
+
"aria-label": playing ? "Pause" : "Play",
|
|
57
|
+
style: {
|
|
58
|
+
cursor: "pointer",
|
|
59
|
+
border: "none",
|
|
60
|
+
background: "#0d9488",
|
|
61
|
+
color: "#fff",
|
|
62
|
+
borderRadius: 4,
|
|
63
|
+
width: 28,
|
|
64
|
+
height: 28,
|
|
65
|
+
fontSize: 14,
|
|
66
|
+
lineHeight: 1
|
|
67
|
+
},
|
|
68
|
+
children: playing ? "\u275A\u275A" : "\u25B6"
|
|
69
|
+
}
|
|
70
|
+
),
|
|
71
|
+
/* @__PURE__ */ jsx("div", { style: { fontWeight: 600, flex: 1, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }, children: label != null ? label : "WMS time" }),
|
|
72
|
+
/* @__PURE__ */ jsx("div", { style: { fontVariantNumeric: "tabular-nums", color: "#475569" }, children: formatFrameTime(activeTime) })
|
|
73
|
+
] }),
|
|
74
|
+
/* @__PURE__ */ jsx(
|
|
75
|
+
"input",
|
|
76
|
+
{
|
|
77
|
+
type: "range",
|
|
78
|
+
min: 0,
|
|
79
|
+
max: frames.length - 1,
|
|
80
|
+
value: index,
|
|
81
|
+
onChange: (e) => {
|
|
82
|
+
setPlaying(false);
|
|
83
|
+
setIndex(Number(e.target.value));
|
|
84
|
+
},
|
|
85
|
+
style: { width: "100%", display: "block", accentColor: "#0d9488" }
|
|
86
|
+
}
|
|
87
|
+
),
|
|
88
|
+
legendUrl && legendOk && /* @__PURE__ */ jsx(
|
|
89
|
+
"img",
|
|
90
|
+
{
|
|
91
|
+
src: legendUrl,
|
|
92
|
+
alt: "Legend",
|
|
93
|
+
onError: () => setLegendOk(false),
|
|
94
|
+
style: {
|
|
95
|
+
display: "block",
|
|
96
|
+
marginTop: 8,
|
|
97
|
+
maxWidth: "100%",
|
|
98
|
+
maxHeight: 220,
|
|
99
|
+
objectFit: "contain"
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
)
|
|
103
|
+
]
|
|
104
|
+
}
|
|
105
|
+
);
|
|
106
|
+
};
|
|
107
|
+
WmsTimeControl.displayName = "WmsTimeControl";
|
|
108
|
+
export {
|
|
109
|
+
WmsTimeControl
|
|
110
|
+
};
|
|
111
|
+
//# sourceMappingURL=WmsTimeControl.js.map
|
package/dist/core/components/viewers/map/src/MapLayers/src/OpenDataLayer/src/WmsTimeControl.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../../../../src/core/components/viewers/map/src/MapLayers/src/OpenDataLayer/src/WmsTimeControl.tsx"],"sourcesContent":["\"use client\";\r\n\r\nimport * as React from \"react\";\r\nimport { formatFrameTime } from \"../../../../../datasets/src/wmsTime\";\r\n\r\ninterface WmsTimeControlProps {\r\n /** Ascending frame timestamps (oldest → newest). */\r\n frames: string[];\r\n /** Called with the active frame timestamp whenever it changes. */\r\n onTimeChange: (time: string) => void;\r\n /** Card title (e.g. the dataset name). */\r\n label?: string;\r\n /** Frame advance interval while playing, ms. */\r\n stepMs?: number;\r\n /** WMS GetLegendGraphic image URL; shown under the slider when it loads. */\r\n legendUrl?: string;\r\n}\r\n\r\n/**\r\n * Floating scrub + play/pause control for a WMS time dimension. Defaults to the\r\n * latest frame; play advances oldest→newest on a loop. Purely presentational —\r\n * it owns only the current index + playing state and reports the active time up.\r\n */\r\nexport const WmsTimeControl: React.FC<WmsTimeControlProps> = ({\r\n frames,\r\n onTimeChange,\r\n label,\r\n stepMs = 500,\r\n legendUrl,\r\n}) => {\r\n const [index, setIndex] = React.useState(Math.max(0, frames.length - 1));\r\n const [playing, setPlaying] = React.useState(false);\r\n const [legendOk, setLegendOk] = React.useState(true);\r\n\r\n // Reset legend visibility if the URL changes (different layer).\r\n React.useEffect(() => { setLegendOk(true); }, [legendUrl]);\r\n\r\n // Clamp + re-seat at the latest frame whenever the frame list changes.\r\n React.useEffect(() => {\r\n setIndex(Math.max(0, frames.length - 1));\r\n }, [frames.length]);\r\n\r\n // Report the active frame up whenever the index (or frame list) changes.\r\n React.useEffect(() => {\r\n const time = frames[index];\r\n if (time) onTimeChange(time);\r\n }, [index, frames, onTimeChange]);\r\n\r\n // Play loop.\r\n React.useEffect(() => {\r\n if (!playing || frames.length < 2) return;\r\n const timer = setInterval(() => {\r\n setIndex(prev => (prev + 1) % frames.length);\r\n }, stepMs);\r\n return () => clearInterval(timer);\r\n }, [playing, frames.length, stepMs]);\r\n\r\n if (frames.length === 0) return null;\r\n\r\n const activeTime = frames[index];\r\n\r\n return (\r\n <div\r\n style={{\r\n // Laid out by the bottom-left flex stack it portals into (see MapViewer),\r\n // so no absolute positioning — it sits above the legend / dataset-manager cards.\r\n background: \"#ffffff\",\r\n borderRadius: 8,\r\n boxShadow: \"0 1px 4px rgba(0,0,0,0.3)\",\r\n padding: \"10px 12px\",\r\n width: 260,\r\n font: \"13px/1.3 system-ui, sans-serif\",\r\n color: \"#1a1a1a\",\r\n pointerEvents: \"auto\",\r\n }}\r\n >\r\n <div style={{ display: \"flex\", alignItems: \"center\", gap: 8, marginBottom: 6 }}>\r\n <button\r\n type=\"button\"\r\n onClick={() => setPlaying(p => !p)}\r\n aria-label={playing ? \"Pause\" : \"Play\"}\r\n style={{\r\n cursor: \"pointer\",\r\n border: \"none\",\r\n background: \"#0d9488\",\r\n color: \"#fff\",\r\n borderRadius: 4,\r\n width: 28,\r\n height: 28,\r\n fontSize: 14,\r\n lineHeight: 1,\r\n }}\r\n >\r\n {playing ? \"❚❚\" : \"▶\"}\r\n </button>\r\n <div style={{ fontWeight: 600, flex: 1, overflow: \"hidden\", textOverflow: \"ellipsis\", whiteSpace: \"nowrap\" }}>\r\n {label ?? \"WMS time\"}\r\n </div>\r\n <div style={{ fontVariantNumeric: \"tabular-nums\", color: \"#475569\" }}>\r\n {formatFrameTime(activeTime)}\r\n </div>\r\n </div>\r\n <input\r\n type=\"range\"\r\n min={0}\r\n max={frames.length - 1}\r\n value={index}\r\n onChange={e => {\r\n setPlaying(false);\r\n setIndex(Number(e.target.value));\r\n }}\r\n style={{ width: \"100%\", display: \"block\", accentColor: \"#0d9488\" }}\r\n />\r\n {legendUrl && legendOk && (\r\n <img\r\n src={legendUrl}\r\n alt=\"Legend\"\r\n onError={() => setLegendOk(false)}\r\n style={{\r\n display: \"block\",\r\n marginTop: 8,\r\n maxWidth: \"100%\",\r\n maxHeight: 220,\r\n objectFit: \"contain\",\r\n }}\r\n />\r\n )}\r\n </div>\r\n );\r\n};\r\nWmsTimeControl.displayName = \"WmsTimeControl\";\r\n"],"mappings":"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","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../../../../../src/core/components/viewers/map/src/MapLayers/src/OpenDataLayer/src/index.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../../../../../src/core/components/viewers/map/src/MapLayers/src/OpenDataLayer/src/index.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AA+c/B,eAAO,MAAM,cAAc,yBAqM1B,CAAC"}
|
|
@@ -25,6 +25,9 @@ import { MapContext } from "../../../../../../../../store/Map/context";
|
|
|
25
25
|
import { DatasetsContext } from "../../../../../../../../store";
|
|
26
26
|
import { MapLayerClickPriority } from "../../../../../utils/MapEventManager/MapClickManager";
|
|
27
27
|
import MapFeaturePopoverMenu from "../../../../MapFeaturePopoverMenu";
|
|
28
|
+
import { createPortal } from "react-dom";
|
|
29
|
+
import { WmsTimeControl } from "./WmsTimeControl";
|
|
30
|
+
import { fetchWmsFrames, buildWmsTimeUrl, wmsLegendUrl } from "../../../../../datasets/src/wmsTime";
|
|
28
31
|
const isBuildingDataset = (dataset) => {
|
|
29
32
|
return dataset.type === "buildings" && "data" in dataset;
|
|
30
33
|
};
|
|
@@ -286,7 +289,7 @@ const MVTDatasetLayer = React.memo(({ dataset, index, onLayerReady, onLayerRemov
|
|
|
286
289
|
const layerColor = ((_b = dataset.layerColor) == null ? void 0 : _b.color) || "#0d9488";
|
|
287
290
|
const isPointLayer = dataset.layerType === "circle" || /point/i.test(sourceLayer);
|
|
288
291
|
const isMartinBuilding = /buildings?/i.test(((_c = dataset == null ? void 0 : dataset.serviceInfo) == null ? void 0 : _c.sourceLayer) || dataset.id || dataset.name);
|
|
289
|
-
const extraIsBuilding =
|
|
292
|
+
const extraIsBuilding = isMartinBuilding && !isPointLayer;
|
|
290
293
|
const mainLayerId = isPointLayer ? `${dataset.name}-points` : extraIsBuilding ? `${dataset.name}-extrusion` : `${dataset.name}-fill`;
|
|
291
294
|
const outlineLayerId = `${dataset.name}-outline`;
|
|
292
295
|
React.useEffect(() => {
|
|
@@ -332,10 +335,70 @@ const MVTDatasetLayer = React.memo(({ dataset, index, onLayerReady, onLayerRemov
|
|
|
332
335
|
}
|
|
333
336
|
return /* @__PURE__ */ jsxs(Source, { id: `${dataset.name}-source`, type: "vector", tiles: [tileUrl], children: [
|
|
334
337
|
/* @__PURE__ */ jsx(Layer, { id: mainLayerId, type: "fill", "source-layer": sourceLayer, paint: { "fill-color": layerColor, "fill-opacity": 0.6 } }),
|
|
335
|
-
/* @__PURE__ */ jsx(Layer, { id: outlineLayerId, type: "line", "source-layer": sourceLayer, paint: { "line-color":
|
|
338
|
+
/* @__PURE__ */ jsx(Layer, { id: outlineLayerId, type: "line", "source-layer": sourceLayer, paint: { "line-color": "#ffffff", "line-width": 2 } })
|
|
336
339
|
] }, `${index}-${dataset.name}-source`);
|
|
337
340
|
});
|
|
338
341
|
MVTDatasetLayer.displayName = "MVTDatasetLayer";
|
|
342
|
+
const WMSDatasetLayer = React.memo(({ dataset, index, onLayerReady, onLayerRemoved }) => {
|
|
343
|
+
var _a, _b, _c, _d;
|
|
344
|
+
const { state: mapState } = React.useContext(MapContext);
|
|
345
|
+
const { map } = mapState.map;
|
|
346
|
+
const tileUrl = dataset.url || dataset.information;
|
|
347
|
+
const layerId = `${dataset.name}-wms`;
|
|
348
|
+
const sourceId = `${dataset.name}-source`;
|
|
349
|
+
const timeEnabled = !!dataset.timeEnabled && !!dataset.wms;
|
|
350
|
+
const [frames, setFrames] = React.useState([]);
|
|
351
|
+
const [activeTime, setActiveTime] = React.useState(null);
|
|
352
|
+
const [controlSlot, setControlSlot] = React.useState(null);
|
|
353
|
+
React.useEffect(() => {
|
|
354
|
+
if (timeEnabled) setControlSlot(document.getElementById("wms-time-slot"));
|
|
355
|
+
}, [timeEnabled]);
|
|
356
|
+
React.useEffect(() => {
|
|
357
|
+
onLayerReady(dataset.name, []);
|
|
358
|
+
return () => {
|
|
359
|
+
onLayerRemoved(dataset.name);
|
|
360
|
+
};
|
|
361
|
+
}, [dataset.name, onLayerReady, onLayerRemoved]);
|
|
362
|
+
React.useEffect(() => {
|
|
363
|
+
if (!timeEnabled || !dataset.wms) return;
|
|
364
|
+
let cancelled = false;
|
|
365
|
+
fetchWmsFrames(dataset.wms.baseUrl, dataset.wms.layers).then((f) => {
|
|
366
|
+
if (!cancelled) setFrames(f);
|
|
367
|
+
}).catch(() => {
|
|
368
|
+
});
|
|
369
|
+
return () => {
|
|
370
|
+
cancelled = true;
|
|
371
|
+
};
|
|
372
|
+
}, [timeEnabled, (_a = dataset.wms) == null ? void 0 : _a.baseUrl, (_b = dataset.wms) == null ? void 0 : _b.layers]);
|
|
373
|
+
React.useEffect(() => {
|
|
374
|
+
if (!map || !activeTime || !dataset.wms) return;
|
|
375
|
+
const src = map.getSource(sourceId);
|
|
376
|
+
if (src == null ? void 0 : src.setTiles) {
|
|
377
|
+
src.setTiles([buildWmsTimeUrl(dataset.wms.baseUrl, dataset.wms.layers, activeTime)]);
|
|
378
|
+
}
|
|
379
|
+
}, [map, activeTime, sourceId, (_c = dataset.wms) == null ? void 0 : _c.baseUrl, (_d = dataset.wms) == null ? void 0 : _d.layers]);
|
|
380
|
+
if (!tileUrl) {
|
|
381
|
+
console.error(`\u274C OpenDataLayers: No tile URL found for WMS dataset "${dataset.name}"`);
|
|
382
|
+
return null;
|
|
383
|
+
}
|
|
384
|
+
const showControl = timeEnabled && frames.length > 1 && map && controlSlot;
|
|
385
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
386
|
+
/* @__PURE__ */ jsx(Source, { id: sourceId, type: "raster", tiles: [tileUrl], tileSize: 256, children: /* @__PURE__ */ jsx(Layer, { id: layerId, type: "raster", paint: { "raster-opacity": 0.85 } }) }, `${index}-${dataset.name}-source`),
|
|
387
|
+
showControl && createPortal(
|
|
388
|
+
/* @__PURE__ */ jsx(
|
|
389
|
+
WmsTimeControl,
|
|
390
|
+
{
|
|
391
|
+
frames,
|
|
392
|
+
onTimeChange: setActiveTime,
|
|
393
|
+
label: dataset.name,
|
|
394
|
+
legendUrl: dataset.wms ? wmsLegendUrl(dataset.wms.baseUrl, dataset.wms.layers) : void 0
|
|
395
|
+
}
|
|
396
|
+
),
|
|
397
|
+
controlSlot
|
|
398
|
+
)
|
|
399
|
+
] });
|
|
400
|
+
});
|
|
401
|
+
WMSDatasetLayer.displayName = "WMSDatasetLayer";
|
|
339
402
|
const OpenDataLayers = () => {
|
|
340
403
|
const { "state": mapState, "dispatch": mapDispatch } = React.useContext(MapContext);
|
|
341
404
|
const { map, mapClickManager } = mapState.map;
|
|
@@ -466,6 +529,18 @@ const OpenDataLayers = () => {
|
|
|
466
529
|
sortedDatasets.map((dataset, index) => {
|
|
467
530
|
if (dataset.visible === false) return null;
|
|
468
531
|
if (isBuildingDataset(dataset)) return null;
|
|
532
|
+
if (dataset.type === "WMS" || dataset.datasetType === "WMS") {
|
|
533
|
+
return /* @__PURE__ */ jsx(
|
|
534
|
+
WMSDatasetLayer,
|
|
535
|
+
{
|
|
536
|
+
dataset,
|
|
537
|
+
index,
|
|
538
|
+
onLayerReady: handleLayerReady,
|
|
539
|
+
onLayerRemoved: handleLayerRemoved
|
|
540
|
+
},
|
|
541
|
+
dataset.name
|
|
542
|
+
);
|
|
543
|
+
}
|
|
469
544
|
if (dataset.type === "MVT" || dataset.datasetType === "MVT") {
|
|
470
545
|
return /* @__PURE__ */ jsx(
|
|
471
546
|
MVTDatasetLayer,
|