@jupytergis/base 0.15.0 → 0.16.0-alpha.0
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/lib/commands/BaseCommandIDs.d.ts +5 -0
- package/lib/commands/BaseCommandIDs.js +5 -0
- package/lib/commands/index.js +218 -47
- package/lib/commands/operationCommands.js +2 -2
- package/lib/constants.js +5 -1
- package/lib/{panelview/annotationPanel.js → features/annotations/AnnotationsPanel.js} +1 -1
- package/lib/{annotations → features/annotations}/index.d.ts +1 -0
- package/lib/{annotations → features/annotations}/index.js +1 -0
- package/lib/{console → features/console}/consoleview.js +1 -1
- package/lib/{panelview/filter-panel → features/filter}/Filter.js +4 -4
- package/lib/{panelview/filter-panel → features/filter}/FilterRow.d.ts +3 -2
- package/lib/{panelview/filter-panel → features/filter}/FilterRow.js +2 -1
- package/lib/{panelview/identify-panel → features/identify}/IdentifyPanel.d.ts +2 -0
- package/lib/features/identify/IdentifyPanel.js +102 -0
- package/lib/features/identify/components/FeatureCard.d.ts +17 -0
- package/lib/features/identify/components/FeatureCard.js +26 -0
- package/lib/features/identify/components/FeatureCardHeader.d.ts +11 -0
- package/lib/features/identify/components/FeatureCardHeader.js +30 -0
- package/lib/features/identify/components/FeatureFloater.d.ts +7 -0
- package/lib/features/identify/components/FeatureFloater.js +19 -0
- package/lib/features/identify/components/FeaturePropertyList.d.ts +11 -0
- package/lib/features/identify/components/FeaturePropertyList.js +18 -0
- package/lib/features/identify/components/FeatureRow.d.ts +13 -0
- package/lib/features/identify/components/FeatureRow.js +25 -0
- package/lib/features/identify/components/PropertyEditors.d.ts +44 -0
- package/lib/features/identify/components/PropertyEditors.js +56 -0
- package/lib/features/identify/hooks/useIdentifyPropertyEditor.d.ts +11 -0
- package/lib/features/identify/hooks/useIdentifyPropertyEditor.js +132 -0
- package/lib/features/identify/types/editorTypes.d.ts +21 -0
- package/lib/features/identify/utils/getFeatureIdentifier.d.ts +5 -0
- package/lib/features/identify/utils/getFeatureIdentifier.js +14 -0
- package/lib/features/identify/utils/highlightLayer.d.ts +11 -0
- package/lib/features/identify/utils/highlightLayer.js +57 -0
- package/lib/features/identify/utils/highlightStyle.d.ts +7 -0
- package/lib/features/identify/utils/highlightStyle.js +40 -0
- package/lib/{dialogs/layerBrowserDialog.js → features/layer-browser/index.js} +2 -2
- package/lib/features/layers/forms/layer/geoTiffLayerForm.d.ts +3 -0
- package/lib/{formbuilder/objectform/layer/webGlLayerForm.js → features/layers/forms/layer/geoTiffLayerForm.js} +5 -5
- package/lib/{formbuilder/objectform → features/layers/forms}/layer/heatmapLayerForm.js +4 -4
- package/lib/{formbuilder/objectform → features/layers/forms}/layer/hillshadeLayerForm.js +4 -4
- package/lib/{formbuilder/objectform → features/layers/forms}/layer/index.d.ts +1 -1
- package/lib/{formbuilder/objectform → features/layers/forms}/layer/index.js +1 -1
- package/lib/{formbuilder/objectform → features/layers/forms}/layer/layerform.d.ts +1 -1
- package/lib/{formbuilder/objectform → features/layers/forms}/layer/layerform.js +4 -4
- package/lib/features/layers/forms/layer/storySegmentLayerForm.js +150 -0
- package/lib/{formbuilder/objectform → features/layers/forms}/layer/vectorlayerform.js +4 -4
- package/lib/{formbuilder/objectform → features/layers/forms}/source/geojsonsource.js +5 -5
- package/lib/features/layers/forms/source/geopackagesource.d.ts +3 -0
- package/lib/features/layers/forms/source/geopackagesource.js +93 -0
- package/lib/{formbuilder/objectform → features/layers/forms}/source/geotiffsource.js +5 -5
- package/lib/{formbuilder/objectform → features/layers/forms}/source/index.d.ts +1 -0
- package/lib/{formbuilder/objectform → features/layers/forms}/source/index.js +1 -0
- package/lib/{formbuilder/objectform → features/layers/forms}/source/pathbasedsource.js +5 -5
- package/lib/{formbuilder/objectform → features/layers/forms}/source/sourceform.d.ts +1 -1
- package/lib/{formbuilder/objectform → features/layers/forms}/source/sourceform.js +4 -4
- package/lib/{formbuilder/objectform → features/layers/forms}/source/tilesourceform.js +4 -4
- package/lib/{formbuilder/objectform → features/layers/forms}/source/wmsTileSource.d.ts +1 -1
- package/lib/{formbuilder/objectform → features/layers/forms}/source/wmsTileSource.js +6 -6
- package/lib/{dialogs → features/layers}/layerCreationFormDialog.d.ts +1 -1
- package/lib/{dialogs → features/layers}/layerCreationFormDialog.js +1 -1
- package/lib/features/layers/symbology/Grammar.d.ts +11 -0
- package/lib/features/layers/symbology/Grammar.js +235 -0
- package/lib/{dialogs/symbology/vector_layer/types → features/layers/symbology}/Heatmap.d.ts +1 -1
- package/lib/{dialogs/symbology/vector_layer/types → features/layers/symbology}/Heatmap.js +30 -10
- package/lib/{dialogs → features/layers}/symbology/classificationModes.d.ts +6 -6
- package/lib/{dialogs → features/layers}/symbology/classificationModes.js +48 -44
- package/lib/{dialogs → features/layers}/symbology/colorRampUtils.d.ts +1 -0
- package/lib/{dialogs → features/layers}/symbology/colorRampUtils.js +12 -1
- package/lib/features/layers/symbology/components/MappingRow.d.ts +40 -0
- package/lib/features/layers/symbology/components/MappingRow.js +516 -0
- package/lib/features/layers/symbology/components/NumericInput.d.ts +20 -0
- package/lib/features/layers/symbology/components/NumericInput.js +44 -0
- package/lib/features/layers/symbology/components/ScaleEditor.d.ts +33 -0
- package/lib/features/layers/symbology/components/ScaleEditor.js +221 -0
- package/lib/{dialogs → features/layers}/symbology/components/color_ramp/ColorRampControls.d.ts +1 -1
- package/lib/{dialogs → features/layers}/symbology/components/color_ramp/ColorRampControls.js +3 -2
- package/lib/{dialogs → features/layers}/symbology/components/color_ramp/ColorRampSelector.d.ts +2 -1
- package/lib/{dialogs → features/layers}/symbology/components/color_ramp/ColorRampSelector.js +6 -1
- package/lib/{dialogs → features/layers}/symbology/components/color_ramp/ModeSelectRow.d.ts +1 -1
- package/lib/{dialogs → features/layers}/symbology/components/color_ramp/RgbaColorPicker.js +39 -9
- package/lib/{dialogs → features/layers}/symbology/components/color_stops/StopRow.d.ts +1 -1
- package/lib/{dialogs → features/layers}/symbology/components/color_stops/StopRow.js +1 -1
- package/lib/features/layers/symbology/grammarToOLLayer.d.ts +27 -0
- package/lib/features/layers/symbology/grammarToOLLayer.js +145 -0
- package/lib/features/layers/symbology/grammarToOLStyle.d.ts +32 -0
- package/lib/features/layers/symbology/grammarToOLStyle.js +467 -0
- package/lib/{dialogs → features/layers}/symbology/hooks/useGetBandInfo.d.ts +1 -1
- package/lib/{dialogs → features/layers}/symbology/hooks/useGetBandInfo.js +1 -1
- package/lib/{dialogs → features/layers}/symbology/hooks/useGetProperties.js +1 -1
- package/lib/{dialogs → features/layers}/symbology/hooks/useGetSymbology.js +4 -2
- package/lib/features/layers/symbology/styleBuilder.d.ts +21 -0
- package/lib/features/layers/symbology/styleBuilder.js +145 -0
- package/lib/{dialogs → features/layers}/symbology/symbologyDialog.d.ts +1 -1
- package/lib/{dialogs → features/layers}/symbology/symbologyDialog.js +12 -12
- package/lib/{dialogs → features/layers}/symbology/symbologyUtils.d.ts +18 -10
- package/lib/{dialogs → features/layers}/symbology/symbologyUtils.js +0 -84
- package/lib/{panelview/objectproperties.d.ts → features/objectproperties/index.d.ts} +1 -1
- package/lib/{panelview/objectproperties.js → features/objectproperties/index.js} +5 -10
- package/lib/{dialogs → features/processing}/ProcessingFormDialog.d.ts +1 -1
- package/lib/{dialogs → features/processing}/ProcessingFormDialog.js +28 -14
- package/lib/features/processing/forms/MapExtentToggle.d.ts +13 -0
- package/lib/features/processing/forms/MapExtentToggle.js +20 -0
- package/lib/features/processing/forms/clipRasterByExtentForm.d.ts +10 -0
- package/lib/features/processing/forms/clipRasterByExtentForm.js +99 -0
- package/lib/{formbuilder/objectform/process → features/processing/forms}/dissolveProcessForm.js +5 -5
- package/lib/{formbuilder/objectform → features/processing/forms}/processingForm.d.ts +1 -1
- package/lib/{formbuilder/objectform → features/processing/forms}/processingForm.js +6 -6
- package/lib/features/processing/forms/rasterizeForm.d.ts +10 -0
- package/lib/features/processing/forms/rasterizeForm.js +75 -0
- package/lib/features/processing/forms/useMapExtent.d.ts +22 -0
- package/lib/features/processing/forms/useMapExtent.js +57 -0
- package/lib/{processing → features/processing}/index.d.ts +19 -2
- package/lib/features/processing/index.js +1246 -0
- package/lib/{processing → features/processing}/processingCommands.d.ts +1 -1
- package/lib/features/processing/processingCommands.js +168 -0
- package/lib/features/processing/serverProcessing.d.ts +51 -0
- package/lib/features/processing/serverProcessing.js +99 -0
- package/lib/{stacBrowser → features/stac-browser}/components/StacPanel.js +2 -2
- package/lib/{stacBrowser → features/stac-browser}/components/filter-extension/QueryableComboBox.js +5 -5
- package/lib/{stacBrowser → features/stac-browser}/components/filter-extension/QueryableRow.js +1 -1
- package/lib/{stacBrowser → features/stac-browser}/components/filter-extension/StacFilterExtensionPanel.js +2 -2
- package/lib/{stacBrowser → features/stac-browser}/components/filter-extension/StacQueryableFilters.js +1 -1
- package/lib/{stacBrowser → features/stac-browser}/components/geodes/StacFilterSection.js +3 -3
- package/lib/{stacBrowser → features/stac-browser}/components/shared/StacPanelResults.js +3 -3
- package/lib/{stacBrowser → features/stac-browser}/components/shared/StacSpatialExtent.js +1 -1
- package/lib/{stacBrowser → features/stac-browser}/components/shared/StacTemporalExtent.js +1 -1
- package/lib/{stacBrowser → features/stac-browser}/context/StacResultsContext.js +2 -2
- package/lib/{stacBrowser → features/stac-browser}/hooks/useGeodesSearch.js +2 -2
- package/lib/{stacBrowser → features/stac-browser}/hooks/useStacFilterExtension.js +3 -3
- package/lib/{stacBrowser → features/stac-browser}/hooks/useStacSearch.js +1 -1
- package/lib/features/stac-browser/types/types.js +1 -0
- package/lib/{panelview/story-maps → features/story}/SpectaPanel.d.ts +4 -1
- package/lib/{panelview/story-maps → features/story}/SpectaPanel.js +3 -4
- package/lib/{panelview/story-maps → features/story}/StoryEditorPanel.js +1 -1
- package/lib/{panelview/story-maps → features/story}/StoryViewerPanel.d.ts +12 -11
- package/lib/features/story/StoryViewerPanel.js +64 -0
- package/lib/features/story/__tests__/fixtures/listStoryTestItems.d.ts +9 -0
- package/lib/features/story/__tests__/fixtures/listStoryTestItems.js +21 -0
- package/lib/features/story/components/ListStoryMapOverlayPanel.d.ts +10 -0
- package/lib/features/story/components/ListStoryMapOverlayPanel.js +11 -0
- package/lib/features/story/components/ListStoryMarkdownMeasurePane.d.ts +11 -0
- package/lib/features/story/components/ListStoryMarkdownMeasurePane.js +55 -0
- package/lib/features/story/components/ListStoryOverlayMarkdown.d.ts +15 -0
- package/lib/features/story/components/ListStoryOverlayMarkdown.js +93 -0
- package/lib/features/story/components/ListStoryStageOverlay.d.ts +12 -0
- package/lib/features/story/components/ListStoryStageOverlay.js +132 -0
- package/lib/features/story/components/ListStoryVirtualScrollTrack.d.ts +6 -0
- package/lib/features/story/components/ListStoryVirtualScrollTrack.js +7 -0
- package/lib/{panelview/story-maps → features/story}/components/SpectaDesktopView.d.ts +4 -2
- package/lib/features/story/components/SpectaDesktopView.js +67 -0
- package/lib/{panelview/story-maps → features/story}/components/SpectaMobileView.d.ts +2 -4
- package/lib/{panelview/story-maps → features/story}/components/SpectaMobileView.js +3 -3
- package/lib/features/story/components/SpectaSingleModeContent.d.ts +18 -0
- package/lib/features/story/components/SpectaSingleModeContent.js +8 -0
- package/lib/features/story/context/ListStoryScrollTrackContext.d.ts +15 -0
- package/lib/features/story/context/ListStoryScrollTrackContext.js +142 -0
- package/lib/features/story/hooks/useCurrentSegmentIndex.d.ts +3 -0
- package/lib/features/story/hooks/useCurrentSegmentIndex.js +17 -0
- package/lib/features/story/hooks/useListStoryScroll.d.ts +15 -0
- package/lib/features/story/hooks/useListStoryScroll.js +107 -0
- package/lib/features/story/hooks/useQueuedMarkdownHeightMeasure.d.ts +19 -0
- package/lib/features/story/hooks/useQueuedMarkdownHeightMeasure.js +56 -0
- package/lib/features/story/hooks/useStoryImagePreload.d.ts +1 -0
- package/lib/features/story/hooks/useStoryImagePreload.js +24 -0
- package/lib/{panelview/story-maps → features/story}/hooks/useStoryMap.d.ts +2 -7
- package/lib/{panelview/story-maps → features/story}/hooks/useStoryMap.js +20 -44
- package/lib/features/story/hooks/useStoryScrollState.d.ts +21 -0
- package/lib/features/story/hooks/useStoryScrollState.js +39 -0
- package/lib/features/story/hooks/useStorySegmentSync.d.ts +8 -0
- package/lib/features/story/hooks/useStorySegmentSync.js +51 -0
- package/lib/features/story/types/types.d.ts +38 -0
- package/lib/features/story/types/types.js +1 -0
- package/lib/features/story/utils/computeListStoryScrollState.d.ts +12 -0
- package/lib/features/story/utils/computeListStoryScrollState.js +70 -0
- package/lib/features/story/utils/listStoryMeasureQueue.d.ts +11 -0
- package/lib/features/story/utils/listStoryMeasureQueue.js +14 -0
- package/lib/features/story/utils/listStoryScrollTrack.d.ts +17 -0
- package/lib/features/story/utils/listStoryScrollTrack.js +72 -0
- package/lib/features/story/utils/spectaPresentation.d.ts +9 -0
- package/lib/features/story/utils/spectaPresentation.js +37 -0
- package/lib/features/story/utils/storySegmentViewItems.d.ts +5 -0
- package/lib/features/story/utils/storySegmentViewItems.js +30 -0
- package/lib/index.d.ts +11 -9
- package/lib/index.js +11 -9
- package/lib/keybindings.json +5 -0
- package/lib/mainview/OpenEOTileLayer.d.ts +49 -0
- package/lib/mainview/OpenEOTileLayer.js +179 -0
- package/lib/mainview/TemporalSlider.js +11 -9
- package/lib/mainview/geoJsonFeaturePatch.d.ts +9 -0
- package/lib/mainview/geoJsonFeaturePatch.js +43 -0
- package/lib/mainview/mainView.d.ts +90 -7
- package/lib/mainview/mainView.js +1196 -586
- package/lib/mainview/mainviewwidget.d.ts +5 -1
- package/lib/mainview/mainviewwidget.js +4 -2
- package/lib/shared/components/Button.d.ts +1 -1
- package/lib/shared/components/DropdownMenu.d.ts +1 -0
- package/lib/shared/components/DropdownMenu.js +3 -2
- package/lib/shared/components/NativeSelect.d.ts +8 -0
- package/lib/shared/components/NativeSelect.js +29 -0
- package/lib/shared/components/Tabs.d.ts +3 -3
- package/lib/shared/components/Tabs.js +5 -5
- package/lib/{formbuilder → shared/formbuilder}/creationform.js +71 -4
- package/lib/{formbuilder → shared/formbuilder}/editform.js +1 -1
- package/lib/{formbuilder → shared/formbuilder}/formselectors.d.ts +2 -2
- package/lib/{formbuilder → shared/formbuilder}/formselectors.js +10 -4
- package/lib/shared/formbuilder/index.d.ts +4 -0
- package/lib/shared/formbuilder/index.js +4 -0
- package/lib/{formbuilder → shared/formbuilder}/objectform/SchemaForm.d.ts +1 -1
- package/lib/{formbuilder → shared/formbuilder}/objectform/StoryEditorForm.d.ts +1 -1
- package/lib/{formbuilder → shared/formbuilder}/objectform/StoryEditorForm.js +1 -1
- package/lib/{formbuilder → shared/formbuilder}/objectform/components/LayerSelect.js +1 -1
- package/lib/{formbuilder → shared/formbuilder}/objectform/components/SegmentFormSymbology.js +4 -4
- package/lib/{formbuilder → shared/formbuilder}/objectform/components/SourcePropertiesField.js +1 -1
- package/lib/{formbuilder → shared/formbuilder}/objectform/components/StorySegmentReset.js +1 -1
- package/lib/{formbuilder → shared/formbuilder}/objectform/components/WmsTileSourceUrlInput.js +4 -4
- package/lib/{formbuilder → shared/formbuilder}/objectform/fileselectorwidget.js +8 -1
- package/lib/{formbuilder → shared/formbuilder}/objectform/schemaUtils.d.ts +3 -1
- package/lib/{formbuilder → shared/formbuilder}/objectform/schemaUtils.js +11 -0
- package/lib/{formbuilder → shared/formbuilder}/objectform/useSchemaFormState.d.ts +1 -1
- package/lib/{formbuilder → shared/formbuilder}/objectform/useSchemaFormState.js +1 -1
- package/lib/{icons.d.ts → shared/icons.d.ts} +2 -0
- package/lib/{icons.js → shared/icons.js} +28 -18
- package/lib/tools.d.ts +2 -0
- package/lib/tools.js +138 -4
- package/lib/types.d.ts +6 -1
- package/lib/types.js +6 -1
- package/lib/{menus.js → workspace/menus.js} +10 -2
- package/lib/workspace/panels/components/TabbedPanel.d.ts +17 -0
- package/lib/workspace/panels/components/TabbedPanel.js +19 -0
- package/lib/{panelview → workspace/panels}/components/layers.js +63 -18
- package/lib/workspace/panels/components/legendItem.js +680 -0
- package/lib/workspace/panels/hooks/useLayerTree.d.ts +19 -0
- package/lib/workspace/panels/hooks/useLayerTree.js +103 -0
- package/lib/workspace/panels/hooks/useRightPanelOptions.d.ts +27 -0
- package/lib/workspace/panels/hooks/useRightPanelOptions.js +72 -0
- package/lib/workspace/panels/hooks/useUIState.d.ts +2 -0
- package/lib/workspace/panels/hooks/useUIState.js +25 -0
- package/lib/{panelview → workspace/panels}/index.d.ts +1 -1
- package/lib/{panelview → workspace/panels}/index.js +1 -1
- package/lib/{panelview → workspace/panels}/leftpanel.d.ts +1 -1
- package/lib/workspace/panels/leftpanel.js +70 -0
- package/lib/{panelview/rightpanel.d.ts → workspace/panels/mergedpanel.d.ts} +6 -5
- package/lib/workspace/panels/mergedpanel.js +166 -0
- package/lib/workspace/panels/rightpanel.d.ts +25 -0
- package/lib/{panelview → workspace/panels}/rightpanel.js +53 -63
- package/lib/{statusbar → workspace/statusbar}/StatusBar.js +5 -4
- package/lib/{toolbar → workspace/toolbar}/widget.d.ts +2 -0
- package/lib/{toolbar → workspace/toolbar}/widget.js +33 -5
- package/lib/{widget.d.ts → workspace/widget.d.ts} +7 -5
- package/lib/{widget.js → workspace/widget.js} +16 -7
- package/package.json +16 -4
- package/style/base.css +109 -1
- package/style/icons/geopackage.svg +95 -0
- package/style/icons/pencil_solid.svg +7 -0
- package/style/identify.css +95 -0
- package/style/layerBrowser.css +28 -0
- package/style/leftPanel.css +25 -0
- package/style/shared/button.css +12 -0
- package/style/shared/dropdownMenu.css +9 -0
- package/style/shared/nativeSelect.css +75 -0
- package/style/shared/tabs.css +1 -1
- package/style/spectaProgressBar.css +0 -1
- package/style/storyPanel.css +140 -9
- package/style/storySpectaArticleOverlay.css +129 -0
- package/style/symbologyDialog.css +285 -27
- package/lib/dialogs/symbology/tiff_layer/TiffRendering.d.ts +0 -4
- package/lib/dialogs/symbology/tiff_layer/TiffRendering.js +0 -42
- package/lib/dialogs/symbology/tiff_layer/components/BandRow.d.ts +0 -23
- package/lib/dialogs/symbology/tiff_layer/components/BandRow.js +0 -59
- package/lib/dialogs/symbology/tiff_layer/types/MultibandColor.d.ts +0 -4
- package/lib/dialogs/symbology/tiff_layer/types/MultibandColor.js +0 -92
- package/lib/dialogs/symbology/tiff_layer/types/SingleBandPseudoColor.d.ts +0 -5
- package/lib/dialogs/symbology/tiff_layer/types/SingleBandPseudoColor.js +0 -313
- package/lib/dialogs/symbology/vector_layer/VectorRendering.d.ts +0 -4
- package/lib/dialogs/symbology/vector_layer/VectorRendering.js +0 -112
- package/lib/dialogs/symbology/vector_layer/components/ValueSelect.d.ts +0 -8
- package/lib/dialogs/symbology/vector_layer/components/ValueSelect.js +0 -9
- package/lib/dialogs/symbology/vector_layer/types/Canonical.d.ts +0 -4
- package/lib/dialogs/symbology/vector_layer/types/Canonical.js +0 -130
- package/lib/dialogs/symbology/vector_layer/types/Categorized.d.ts +0 -4
- package/lib/dialogs/symbology/vector_layer/types/Categorized.js +0 -243
- package/lib/dialogs/symbology/vector_layer/types/Graduated.d.ts +0 -4
- package/lib/dialogs/symbology/vector_layer/types/Graduated.js +0 -362
- package/lib/dialogs/symbology/vector_layer/types/SimpleSymbol.d.ts +0 -4
- package/lib/dialogs/symbology/vector_layer/types/SimpleSymbol.js +0 -120
- package/lib/formbuilder/index.d.ts +0 -4
- package/lib/formbuilder/index.js +0 -4
- package/lib/formbuilder/objectform/layer/storySegmentLayerForm.js +0 -95
- package/lib/formbuilder/objectform/layer/webGlLayerForm.d.ts +0 -3
- package/lib/formbuilder/objectform/process/index.d.ts +0 -1
- package/lib/formbuilder/objectform/process/index.js +0 -1
- package/lib/panelview/components/legendItem.js +0 -210
- package/lib/panelview/identify-panel/IdentifyPanel.js +0 -102
- package/lib/panelview/leftpanel.js +0 -139
- package/lib/panelview/story-maps/StoryViewerPanel.js +0 -116
- package/lib/panelview/story-maps/components/SpectaDesktopView.js +0 -49
- package/lib/processing/index.js +0 -200
- package/lib/processing/processingCommands.js +0 -67
- /package/lib/{panelview/annotationPanel.d.ts → features/annotations/AnnotationsPanel.d.ts} +0 -0
- /package/lib/{annotations → features/annotations}/components/Annotation.d.ts +0 -0
- /package/lib/{annotations → features/annotations}/components/Annotation.js +0 -0
- /package/lib/{annotations → features/annotations}/components/AnnotationFloater.d.ts +0 -0
- /package/lib/{annotations → features/annotations}/components/AnnotationFloater.js +0 -0
- /package/lib/{annotations → features/annotations}/components/Message.d.ts +0 -0
- /package/lib/{annotations → features/annotations}/components/Message.js +0 -0
- /package/lib/{annotations → features/annotations}/model.d.ts +0 -0
- /package/lib/{annotations → features/annotations}/model.js +0 -0
- /package/lib/{console → features/console}/consoleview.d.ts +0 -0
- /package/lib/{console → features/console}/index.d.ts +0 -0
- /package/lib/{console → features/console}/index.js +0 -0
- /package/lib/{panelview/filter-panel → features/filter}/Filter.d.ts +0 -0
- /package/lib/{stacBrowser/types/types.js → features/identify/types/editorTypes.js} +0 -0
- /package/lib/{dialogs/layerBrowserDialog.d.ts → features/layer-browser/index.d.ts} +0 -0
- /package/lib/{formbuilder/objectform → features/layers/forms}/layer/heatmapLayerForm.d.ts +0 -0
- /package/lib/{formbuilder/objectform → features/layers/forms}/layer/hillshadeLayerForm.d.ts +0 -0
- /package/lib/{formbuilder/objectform → features/layers/forms}/layer/storySegmentLayerForm.d.ts +0 -0
- /package/lib/{formbuilder/objectform → features/layers/forms}/layer/vectorlayerform.d.ts +0 -0
- /package/lib/{formbuilder/objectform → features/layers/forms}/source/geojsonsource.d.ts +0 -0
- /package/lib/{formbuilder/objectform → features/layers/forms}/source/geotiffsource.d.ts +0 -0
- /package/lib/{formbuilder/objectform → features/layers/forms}/source/pathbasedsource.d.ts +0 -0
- /package/lib/{formbuilder/objectform → features/layers/forms}/source/tilesourceform.d.ts +0 -0
- /package/lib/{dialogs → features/layers}/symbology/components/color_ramp/ColorRampSelectorEntry.d.ts +0 -0
- /package/lib/{dialogs → features/layers}/symbology/components/color_ramp/ColorRampSelectorEntry.js +0 -0
- /package/lib/{dialogs → features/layers}/symbology/components/color_ramp/ModeSelectRow.js +0 -0
- /package/lib/{dialogs → features/layers}/symbology/components/color_ramp/RgbaColorPicker.d.ts +0 -0
- /package/lib/{dialogs → features/layers}/symbology/components/color_ramp/cmocean.json +0 -0
- /package/lib/{dialogs → features/layers}/symbology/components/color_stops/StopContainer.d.ts +0 -0
- /package/lib/{dialogs → features/layers}/symbology/components/color_stops/StopContainer.js +0 -0
- /package/lib/{dialogs → features/layers}/symbology/hooks/useEffectiveSymbologyParams.d.ts +0 -0
- /package/lib/{dialogs → features/layers}/symbology/hooks/useEffectiveSymbologyParams.js +0 -0
- /package/lib/{dialogs → features/layers}/symbology/hooks/useGetProperties.d.ts +0 -0
- /package/lib/{dialogs → features/layers}/symbology/hooks/useGetSymbology.d.ts +0 -0
- /package/lib/{dialogs → features/layers}/symbology/hooks/useOkSignal.d.ts +0 -0
- /package/lib/{dialogs → features/layers}/symbology/hooks/useOkSignal.js +0 -0
- /package/lib/{formbuilder/objectform/process → features/processing/forms}/dissolveProcessForm.d.ts +0 -0
- /package/lib/{processing → features/processing}/processingFormToParam.d.ts +0 -0
- /package/lib/{processing → features/processing}/processingFormToParam.js +0 -0
- /package/lib/{stacBrowser → features/stac-browser}/components/StacPanel.d.ts +0 -0
- /package/lib/{stacBrowser → features/stac-browser}/components/filter-extension/QueryableComboBox.d.ts +0 -0
- /package/lib/{stacBrowser → features/stac-browser}/components/filter-extension/QueryableRow.d.ts +0 -0
- /package/lib/{stacBrowser → features/stac-browser}/components/filter-extension/StacFilterExtensionPanel.d.ts +0 -0
- /package/lib/{stacBrowser → features/stac-browser}/components/filter-extension/StacQueryableFilters.d.ts +0 -0
- /package/lib/{stacBrowser → features/stac-browser}/components/geodes/StacFilterSection.d.ts +0 -0
- /package/lib/{stacBrowser → features/stac-browser}/components/geodes/StacGeodesFilterPanel.d.ts +0 -0
- /package/lib/{stacBrowser → features/stac-browser}/components/geodes/StacGeodesFilterPanel.js +0 -0
- /package/lib/{stacBrowser → features/stac-browser}/components/shared/StacPanelResults.d.ts +0 -0
- /package/lib/{stacBrowser → features/stac-browser}/components/shared/StacSpatialExtent.d.ts +0 -0
- /package/lib/{stacBrowser → features/stac-browser}/components/shared/StacTemporalExtent.d.ts +0 -0
- /package/lib/{stacBrowser → features/stac-browser}/constants.d.ts +0 -0
- /package/lib/{stacBrowser → features/stac-browser}/constants.js +0 -0
- /package/lib/{stacBrowser → features/stac-browser}/context/StacResultsContext.d.ts +0 -0
- /package/lib/{stacBrowser → features/stac-browser}/hooks/useGeodesSearch.d.ts +0 -0
- /package/lib/{stacBrowser → features/stac-browser}/hooks/useStacFilterExtension.d.ts +0 -0
- /package/lib/{stacBrowser → features/stac-browser}/hooks/useStacSearch.d.ts +0 -0
- /package/lib/{stacBrowser → features/stac-browser}/index.d.ts +0 -0
- /package/lib/{stacBrowser → features/stac-browser}/index.js +0 -0
- /package/lib/{stacBrowser → features/stac-browser}/types/types.d.ts +0 -0
- /package/lib/{panelview/story-maps → features/story}/StoryEditorPanel.d.ts +0 -0
- /package/lib/{panelview/story-maps → features/story}/components/PreviewModeSwitch.d.ts +0 -0
- /package/lib/{panelview/story-maps → features/story}/components/PreviewModeSwitch.js +0 -0
- /package/lib/{panelview/story-maps → features/story}/components/StoryContentSection.d.ts +0 -0
- /package/lib/{panelview/story-maps → features/story}/components/StoryContentSection.js +0 -0
- /package/lib/{panelview/story-maps → features/story}/components/StoryImageSection.d.ts +0 -0
- /package/lib/{panelview/story-maps → features/story}/components/StoryImageSection.js +0 -0
- /package/lib/{panelview/story-maps → features/story}/components/StoryNavBar.d.ts +0 -0
- /package/lib/{panelview/story-maps → features/story}/components/StoryNavBar.js +0 -0
- /package/lib/{panelview/story-maps → features/story}/components/StorySubtitleSection.d.ts +0 -0
- /package/lib/{panelview/story-maps → features/story}/components/StorySubtitleSection.js +0 -0
- /package/lib/{panelview/story-maps → features/story}/components/StoryTitleSection.d.ts +0 -0
- /package/lib/{panelview/story-maps → features/story}/components/StoryTitleSection.js +0 -0
- /package/lib/{formbuilder → shared/formbuilder}/creationform.d.ts +0 -0
- /package/lib/{formbuilder → shared/formbuilder}/editform.d.ts +0 -0
- /package/lib/{formbuilder → shared/formbuilder}/objectform/SchemaForm.js +0 -0
- /package/lib/{formbuilder → shared/formbuilder}/objectform/components/LayerSelect.d.ts +0 -0
- /package/lib/{formbuilder → shared/formbuilder}/objectform/components/OpacitySlider.d.ts +0 -0
- /package/lib/{formbuilder → shared/formbuilder}/objectform/components/OpacitySlider.js +0 -0
- /package/lib/{formbuilder → shared/formbuilder}/objectform/components/SegmentFormSymbology.d.ts +0 -0
- /package/lib/{formbuilder → shared/formbuilder}/objectform/components/SourcePropertiesField.d.ts +0 -0
- /package/lib/{formbuilder → shared/formbuilder}/objectform/components/StorySegmentReset.d.ts +0 -0
- /package/lib/{formbuilder → shared/formbuilder}/objectform/components/WmsTileSourceUrlInput.d.ts +0 -0
- /package/lib/{formbuilder → shared/formbuilder}/objectform/fileselectorwidget.d.ts +0 -0
- /package/lib/{store.d.ts → shared/store.d.ts} +0 -0
- /package/lib/{store.js → shared/store.js} +0 -0
- /package/lib/{menus.d.ts → workspace/menus.d.ts} +0 -0
- /package/lib/{panelview → workspace/panels}/components/layers.d.ts +0 -0
- /package/lib/{panelview → workspace/panels}/components/legendItem.d.ts +0 -0
- /package/lib/{panelview → workspace/panels}/header.d.ts +0 -0
- /package/lib/{panelview → workspace/panels}/header.js +0 -0
- /package/lib/{statusbar → workspace/statusbar}/SpectaPresentationProgressBar.d.ts +0 -0
- /package/lib/{statusbar → workspace/statusbar}/SpectaPresentationProgressBar.js +0 -0
- /package/lib/{statusbar → workspace/statusbar}/StatusBar.d.ts +0 -0
- /package/lib/{toolbar → workspace/toolbar}/index.d.ts +0 -0
- /package/lib/{toolbar → workspace/toolbar}/index.js +0 -0
package/lib/mainview/mainView.js
CHANGED
|
@@ -16,38 +16,72 @@ import { UUID } from '@lumino/coreutils';
|
|
|
16
16
|
import { ContextMenu, Menu } from '@lumino/widgets';
|
|
17
17
|
import { Collection, Map as OlMap, View, getUid, } from 'ol';
|
|
18
18
|
import Feature from 'ol/Feature';
|
|
19
|
+
import TileState from 'ol/TileState';
|
|
19
20
|
import { FullScreen, ScaleLine, Zoom } from 'ol/control';
|
|
20
21
|
import { singleClick } from 'ol/events/condition';
|
|
21
|
-
import { getCenter } from 'ol/extent';
|
|
22
|
+
import { getCenter, getSize } from 'ol/extent';
|
|
22
23
|
import { GeoJSON, MVT } from 'ol/format';
|
|
23
24
|
import { Point } from 'ol/geom';
|
|
24
25
|
import { DragAndDrop, DragPan, DragRotate, DragZoom, KeyboardPan, KeyboardZoom, MouseWheelZoom, PinchRotate, PinchZoom, DoubleClickZoom, Select, } from 'ol/interaction';
|
|
25
|
-
import
|
|
26
|
+
import Draw from 'ol/interaction/Draw';
|
|
27
|
+
import Modify from 'ol/interaction/Modify';
|
|
28
|
+
import Snap from 'ol/interaction/Snap';
|
|
29
|
+
import { Heatmap as HeatmapLayer, Image as ImageLayer, Layer, VectorImage as VectorImageLayer, VectorTile as VectorTileLayer, WebGLTile as GeoTiffLayer, } from 'ol/layer';
|
|
30
|
+
import LayerGroup from 'ol/layer/Group';
|
|
26
31
|
import TileLayer from 'ol/layer/Tile';
|
|
27
32
|
import { fromLonLat, get as getProjection, toLonLat, transformExtent, } from 'ol/proj';
|
|
28
33
|
import { register } from 'ol/proj/proj4.js';
|
|
29
34
|
import RenderFeature, { toGeometry } from 'ol/render/Feature';
|
|
30
35
|
import { GeoTIFF as GeoTIFFSource, ImageTile as ImageTileSource, TileWMS as TileWMSSource, Vector as VectorSource, VectorTile as VectorTileSource, XYZ as XYZSource, Tile as TileSource, } from 'ol/source';
|
|
31
36
|
import Static from 'ol/source/ImageStatic';
|
|
32
|
-
import {
|
|
37
|
+
import { Fill, Icon, Stroke, Style } from 'ol/style';
|
|
38
|
+
import CircleStyle from 'ol/style/Circle';
|
|
33
39
|
//@ts-expect-error no types for ol-pmtiles
|
|
34
40
|
import { PMTilesRasterSource, PMTilesVectorSource } from 'ol-pmtiles';
|
|
35
41
|
import StacLayer from 'ol-stac';
|
|
36
42
|
import proj4 from 'proj4';
|
|
37
43
|
import proj4list from 'proj4-list';
|
|
38
44
|
import * as React from 'react';
|
|
39
|
-
import AnnotationFloater from "../annotations/components/AnnotationFloater";
|
|
40
45
|
import { CommandIDs } from "../constants";
|
|
46
|
+
import AnnotationFloater from "../features/annotations/components/AnnotationFloater";
|
|
47
|
+
import FeatureFloater from "../features/identify/components/FeatureFloater";
|
|
48
|
+
import { getFeatureIdentifier } from "../features/identify/utils/getFeatureIdentifier";
|
|
41
49
|
import { LoadingOverlay } from "../shared/components/loading";
|
|
42
50
|
import useMediaQuery from "../shared/hooks/useMediaQuery";
|
|
43
|
-
import
|
|
44
|
-
import { debounce, isLightTheme, loadFile, throttle } from "../tools";
|
|
51
|
+
import { markerIcon } from "../shared/icons";
|
|
52
|
+
import { debounce, INTERNAL_PROXY_BASE, isJupyterLite, isLightTheme, loadFile, throttle, } from "../tools";
|
|
53
|
+
import StatusBar from "../workspace/statusbar/StatusBar";
|
|
45
54
|
import CollaboratorPointers from './CollaboratorPointers';
|
|
46
55
|
import { FollowIndicator } from './FollowIndicator';
|
|
56
|
+
import { OpenEOTileLayer, OpenEOTileSource } from './OpenEOTileLayer';
|
|
47
57
|
import TemporalSlider from './TemporalSlider';
|
|
48
|
-
import {
|
|
49
|
-
import {
|
|
50
|
-
import {
|
|
58
|
+
import { createGeoJSONFeaturePatcher, } from './geoJsonFeaturePatch';
|
|
59
|
+
import { ensureHighlightLayer } from '../features/identify/utils/highlightLayer';
|
|
60
|
+
import { buildHighlightStyle } from '../features/identify/utils/highlightStyle';
|
|
61
|
+
import { grammarToOLLayer } from '../features/layers/symbology/grammarToOLLayer';
|
|
62
|
+
import { extractEncodingFieldValues, grammarToOLStyle, } from '../features/layers/symbology/grammarToOLStyle';
|
|
63
|
+
import { DEFAULT_FLAT_STYLE } from '../features/layers/symbology/styleBuilder';
|
|
64
|
+
import { SpectaPanel } from '../features/story/SpectaPanel';
|
|
65
|
+
import { ListStoryStageOverlay } from '../features/story/components/ListStoryStageOverlay';
|
|
66
|
+
import { ListStoryScrollTrackProvider } from '../features/story/context/ListStoryScrollTrackContext';
|
|
67
|
+
import { STORY_TYPE } from '../types';
|
|
68
|
+
import { LeftPanel, MergedPanel, RightPanel } from '../workspace/panels';
|
|
69
|
+
const DRAW_GEOMETRIES = ['Point', 'LineString', 'Polygon'];
|
|
70
|
+
const drawInteractionStyle = new Style({
|
|
71
|
+
fill: new Fill({
|
|
72
|
+
color: 'rgba(255, 255, 255, 0.2)',
|
|
73
|
+
}),
|
|
74
|
+
stroke: new Stroke({
|
|
75
|
+
color: '#ffcc33',
|
|
76
|
+
width: 2,
|
|
77
|
+
}),
|
|
78
|
+
image: new CircleStyle({
|
|
79
|
+
radius: 7,
|
|
80
|
+
fill: new Fill({
|
|
81
|
+
color: '#ffcc33',
|
|
82
|
+
}),
|
|
83
|
+
}),
|
|
84
|
+
});
|
|
51
85
|
export class MainView extends React.Component {
|
|
52
86
|
constructor(props) {
|
|
53
87
|
super(props);
|
|
@@ -64,48 +98,8 @@ export class MainView extends React.Component {
|
|
|
64
98
|
return transformExtent(extent, view.getProjection(), targetProjection);
|
|
65
99
|
};
|
|
66
100
|
this.createSelectInteraction = () => {
|
|
67
|
-
const pointStyle = new Style({
|
|
68
|
-
image: new Circle({
|
|
69
|
-
radius: 5,
|
|
70
|
-
fill: new Fill({
|
|
71
|
-
color: '#C52707',
|
|
72
|
-
}),
|
|
73
|
-
stroke: new Stroke({
|
|
74
|
-
color: '#171717',
|
|
75
|
-
width: 2,
|
|
76
|
-
}),
|
|
77
|
-
}),
|
|
78
|
-
});
|
|
79
|
-
const lineStyle = new Style({
|
|
80
|
-
stroke: new Stroke({
|
|
81
|
-
color: '#171717',
|
|
82
|
-
width: 2,
|
|
83
|
-
}),
|
|
84
|
-
});
|
|
85
|
-
const polygonStyle = new Style({
|
|
86
|
-
fill: new Fill({ color: '#C5270780' }),
|
|
87
|
-
stroke: new Stroke({
|
|
88
|
-
color: '#171717',
|
|
89
|
-
width: 2,
|
|
90
|
-
}),
|
|
91
|
-
});
|
|
92
|
-
const styleFunction = (feature) => {
|
|
93
|
-
var _a;
|
|
94
|
-
const geometryType = (_a = feature.getGeometry()) === null || _a === void 0 ? void 0 : _a.getType();
|
|
95
|
-
switch (geometryType) {
|
|
96
|
-
case 'Point':
|
|
97
|
-
case 'MultiPoint':
|
|
98
|
-
return pointStyle;
|
|
99
|
-
case 'LineString':
|
|
100
|
-
case 'MultiLineString':
|
|
101
|
-
return lineStyle;
|
|
102
|
-
case 'Polygon':
|
|
103
|
-
case 'MultiPolygon':
|
|
104
|
-
return polygonStyle;
|
|
105
|
-
}
|
|
106
|
-
};
|
|
107
101
|
const selectInteraction = new Select({
|
|
108
|
-
hitTolerance:
|
|
102
|
+
hitTolerance: 3,
|
|
109
103
|
multi: true,
|
|
110
104
|
layers: layer => {
|
|
111
105
|
var _a, _b;
|
|
@@ -115,19 +109,84 @@ export class MainView extends React.Component {
|
|
|
115
109
|
return false;
|
|
116
110
|
}
|
|
117
111
|
const selectedLayerId = Object.keys(selectedLayers)[0];
|
|
118
|
-
|
|
112
|
+
const expected = this.getLayer(selectedLayerId);
|
|
113
|
+
if (layer === expected) {
|
|
114
|
+
return true;
|
|
115
|
+
}
|
|
116
|
+
// Grammar multi-layer symbology wraps sub-layers in a LayerGroup.
|
|
117
|
+
// OL Select flattens groups, so we receive leaf layers, not the group.
|
|
118
|
+
if (expected instanceof LayerGroup) {
|
|
119
|
+
return expected.getLayers().getArray().includes(layer);
|
|
120
|
+
}
|
|
121
|
+
return false;
|
|
119
122
|
},
|
|
120
123
|
condition: (event) => {
|
|
121
124
|
return singleClick(event) && this._model.currentMode === 'identifying';
|
|
122
125
|
},
|
|
123
|
-
style
|
|
126
|
+
// Use the layer's own style so selected features keep their original
|
|
127
|
+
// appearance. Visual highlight feedback comes from _highlightLayer.
|
|
128
|
+
style: null,
|
|
124
129
|
});
|
|
125
130
|
selectInteraction.on('select', event => {
|
|
131
|
+
var _a, _b, _c;
|
|
126
132
|
const identifiedFeatures = [];
|
|
133
|
+
const highlightFeatures = [];
|
|
134
|
+
// Look up the selected layer's style function for adaptive highlights.
|
|
135
|
+
const localState = (_a = this._model) === null || _a === void 0 ? void 0 : _a.sharedModel.awareness.getLocalState();
|
|
136
|
+
const selectedLayers = (_b = localState === null || localState === void 0 ? void 0 : localState.selected) === null || _b === void 0 ? void 0 : _b.value;
|
|
137
|
+
const selectedLayerId = selectedLayers
|
|
138
|
+
? Object.keys(selectedLayers)[0]
|
|
139
|
+
: undefined;
|
|
140
|
+
const mapLayer = selectedLayerId
|
|
141
|
+
? this.getLayer(selectedLayerId)
|
|
142
|
+
: undefined;
|
|
143
|
+
// For LayerGroup (multi-layer grammar), collect style functions from
|
|
144
|
+
// all sub-layers so we can match the right one per feature.
|
|
145
|
+
const styleFnCandidates = [];
|
|
146
|
+
if (mapLayer instanceof LayerGroup) {
|
|
147
|
+
for (const sub of mapLayer.getLayers().getArray()) {
|
|
148
|
+
if ('getStyleFunction' in sub) {
|
|
149
|
+
styleFnCandidates.push(sub.getStyleFunction());
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
else if (mapLayer && 'getStyleFunction' in mapLayer) {
|
|
154
|
+
styleFnCandidates.push(mapLayer.getStyleFunction());
|
|
155
|
+
}
|
|
156
|
+
const resolution = (_c = this._Map.getView().getResolution()) !== null && _c !== void 0 ? _c : 1;
|
|
127
157
|
selectInteraction.getFeatures().forEach(feature => {
|
|
128
|
-
identifiedFeatures.push(
|
|
158
|
+
identifiedFeatures.push({
|
|
159
|
+
feature: feature.getProperties(),
|
|
160
|
+
floaterOpen: false,
|
|
161
|
+
});
|
|
162
|
+
const geom = feature.getGeometry();
|
|
163
|
+
if (geom) {
|
|
164
|
+
const hlFeature = new Feature({ geometry: geom });
|
|
165
|
+
// Try each style function candidate; use the first that resolves
|
|
166
|
+
// a non-empty style array (important for LayerGroup sub-layers
|
|
167
|
+
// where only one sub-layer's style applies to this feature).
|
|
168
|
+
for (const fn of styleFnCandidates) {
|
|
169
|
+
if (!fn) {
|
|
170
|
+
continue;
|
|
171
|
+
}
|
|
172
|
+
const resolved = fn(feature, resolution);
|
|
173
|
+
const styles = Array.isArray(resolved)
|
|
174
|
+
? resolved
|
|
175
|
+
: resolved
|
|
176
|
+
? [resolved]
|
|
177
|
+
: [];
|
|
178
|
+
if (styles.length > 0) {
|
|
179
|
+
const gType = geom.getType();
|
|
180
|
+
hlFeature.setStyle(styles.map(s => this._buildHighlightStyle(s, gType)));
|
|
181
|
+
break;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
highlightFeatures.push(hlFeature);
|
|
185
|
+
}
|
|
129
186
|
});
|
|
130
187
|
this._model.syncIdentifiedFeatures(identifiedFeatures, this._mainViewModel.id);
|
|
188
|
+
// Sync _highlightLayer with the current selection (clears on deselect).
|
|
189
|
+
this._setHighlightFeatures(highlightFeatures);
|
|
131
190
|
});
|
|
132
191
|
this._Map.addInteraction(selectInteraction);
|
|
133
192
|
};
|
|
@@ -210,25 +269,16 @@ export class MainView extends React.Component {
|
|
|
210
269
|
rank: 2,
|
|
211
270
|
});
|
|
212
271
|
};
|
|
272
|
+
// Used by VectorTileLayer (which shares a flat-style API with Grammar output).
|
|
213
273
|
this.vectorLayerStyleRuleBuilder = (layer) => {
|
|
214
274
|
var _a, _b;
|
|
215
275
|
const layerParams = layer.parameters;
|
|
216
|
-
|
|
217
|
-
|
|
276
|
+
const ss = layerParams === null || layerParams === void 0 ? void 0 : layerParams.symbologyState;
|
|
277
|
+
if (!ss || Object.keys(ss).length === 0) {
|
|
278
|
+
return [{ style: DEFAULT_FLAT_STYLE }];
|
|
218
279
|
}
|
|
219
|
-
const
|
|
220
|
-
|
|
221
|
-
'stroke-color': '#3399CC',
|
|
222
|
-
'stroke-width': 1.25,
|
|
223
|
-
'circle-radius': 5,
|
|
224
|
-
'circle-fill-color': 'rgba(255,255,255,0.4)',
|
|
225
|
-
'circle-stroke-width': 1.25,
|
|
226
|
-
'circle-stroke-color': '#3399CC',
|
|
227
|
-
};
|
|
228
|
-
const defaultRules = {
|
|
229
|
-
style: defaultStyle,
|
|
230
|
-
};
|
|
231
|
-
const layerStyle = Object.assign({}, defaultRules);
|
|
280
|
+
const flatStyle = grammarToOLStyle(layerParams.symbologyState, []);
|
|
281
|
+
const layerStyle = { style: flatStyle };
|
|
232
282
|
if (((_a = layer.filters) === null || _a === void 0 ? void 0 : _a.logicalOp) && ((_b = layer.filters.appliedFilters) === null || _b === void 0 ? void 0 : _b.length) > 0) {
|
|
233
283
|
const buildCondition = (filter) => {
|
|
234
284
|
const base = [filter.operator, ['get', filter.feature]];
|
|
@@ -236,89 +286,13 @@ export class MainView extends React.Component {
|
|
|
236
286
|
? [...base, filter.betweenMin, filter.betweenMax]
|
|
237
287
|
: [...base, filter.value];
|
|
238
288
|
};
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
// Arguments for "Any" and 'All' need to be wrapped in brackets
|
|
247
|
-
filterExpr = [
|
|
248
|
-
layer.filters.logicalOp,
|
|
249
|
-
...layer.filters.appliedFilters.map(buildCondition),
|
|
250
|
-
];
|
|
251
|
-
}
|
|
252
|
-
layerStyle.filter = filterExpr;
|
|
253
|
-
}
|
|
254
|
-
if (!layerParams.color) {
|
|
255
|
-
return [layerStyle];
|
|
256
|
-
}
|
|
257
|
-
const newStyle = Object.assign(Object.assign({}, defaultStyle), layerParams.color);
|
|
258
|
-
layerStyle.style = newStyle;
|
|
259
|
-
// When fallbackColor[3] === 0, add an OL filter so features that would be
|
|
260
|
-
// drawn with a transparent color are excluded from rendering entirely.
|
|
261
|
-
// alpha === 0 is the contract: the default TRANSPARENT [0,0,0,0] triggers
|
|
262
|
-
// this automatically, and a future dedicated picker option can set it.
|
|
263
|
-
const symbologyState = layerParams.symbologyState;
|
|
264
|
-
if (Array.isArray(symbologyState === null || symbologyState === void 0 ? void 0 : symbologyState.fallbackColor) &&
|
|
265
|
-
symbologyState.fallbackColor[3] === 0) {
|
|
266
|
-
let matchFilter;
|
|
267
|
-
if (symbologyState.renderType === 'Categorized') {
|
|
268
|
-
const fillExpr = layerParams.color['fill-color'];
|
|
269
|
-
if (Array.isArray(fillExpr) &&
|
|
270
|
-
fillExpr[0] === 'case' &&
|
|
271
|
-
fillExpr.length >= 4) {
|
|
272
|
-
// Extract conditions from ['case', cond, val, cond, val, ..., fallback],
|
|
273
|
-
// skipping any whose matched output color is also fully transparent.
|
|
274
|
-
const conditions = [];
|
|
275
|
-
for (let i = 1; i < fillExpr.length - 1; i += 2) {
|
|
276
|
-
const output = fillExpr[i + 1];
|
|
277
|
-
if (Array.isArray(output) && output[3] === 0) {
|
|
278
|
-
continue;
|
|
279
|
-
}
|
|
280
|
-
conditions.push(fillExpr[i]);
|
|
281
|
-
}
|
|
282
|
-
// If every stop is transparent, use a never-true filter to hide all.
|
|
283
|
-
matchFilter =
|
|
284
|
-
conditions.length === 0
|
|
285
|
-
? ['==', 0, 1]
|
|
286
|
-
: conditions.length === 1
|
|
287
|
-
? conditions[0]
|
|
288
|
-
: ['any', ...conditions];
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
else if (symbologyState.renderType === 'Graduated') {
|
|
292
|
-
const fillExpr = layerParams.color['fill-color'];
|
|
293
|
-
// Graduated fill is ['case', ['has', field], interpolateExpr, fallback].
|
|
294
|
-
// Features missing the attribute fall through to the fallback, so filter
|
|
295
|
-
// them out with the same ['has', field] condition.
|
|
296
|
-
if (Array.isArray(fillExpr) &&
|
|
297
|
-
fillExpr[0] === 'case' &&
|
|
298
|
-
Array.isArray(fillExpr[1]) &&
|
|
299
|
-
fillExpr[1][0] === 'has') {
|
|
300
|
-
matchFilter = fillExpr[1];
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
else if (symbologyState.renderType === 'Canonical') {
|
|
304
|
-
const fillExpr = layerParams.color['fill-color'];
|
|
305
|
-
// Canonical fill is ['coalesce', ['get', field], fallback].
|
|
306
|
-
// Features missing the attribute fall through to the fallback, so filter
|
|
307
|
-
// them out with ['has', field]. Note: features that have the field but
|
|
308
|
-
// with a non-color value also get the fallback — that gap is accepted.
|
|
309
|
-
if (Array.isArray(fillExpr) &&
|
|
310
|
-
fillExpr[0] === 'coalesce' &&
|
|
311
|
-
Array.isArray(fillExpr[1]) &&
|
|
312
|
-
fillExpr[1][0] === 'get') {
|
|
313
|
-
matchFilter = ['has', fillExpr[1][1]];
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
if (matchFilter) {
|
|
317
|
-
// Combine with any existing user-applied filter.
|
|
318
|
-
layerStyle.filter = layerStyle.filter
|
|
319
|
-
? ['all', layerStyle.filter, matchFilter]
|
|
320
|
-
: matchFilter;
|
|
321
|
-
}
|
|
289
|
+
layerStyle.filter =
|
|
290
|
+
layer.filters.appliedFilters.length === 1
|
|
291
|
+
? buildCondition(layer.filters.appliedFilters[0])
|
|
292
|
+
: [
|
|
293
|
+
layer.filters.logicalOp,
|
|
294
|
+
...layer.filters.appliedFilters.map(buildCondition),
|
|
295
|
+
];
|
|
322
296
|
}
|
|
323
297
|
return [layerStyle];
|
|
324
298
|
};
|
|
@@ -413,96 +387,36 @@ export class MainView extends React.Component {
|
|
|
413
387
|
delete this._originalFeatures[id];
|
|
414
388
|
}
|
|
415
389
|
};
|
|
416
|
-
this.
|
|
417
|
-
var _a
|
|
390
|
+
this._handleSelectedChanged = () => {
|
|
391
|
+
var _a;
|
|
418
392
|
const localState = this._model.localState;
|
|
419
393
|
if (!localState) {
|
|
420
394
|
return;
|
|
421
395
|
}
|
|
422
|
-
const
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
const remoteState = clients.get(remoteUser);
|
|
426
|
-
if (!remoteState) {
|
|
427
|
-
return;
|
|
428
|
-
}
|
|
429
|
-
if (((_a = remoteState.user) === null || _a === void 0 ? void 0 : _a.username) !== ((_b = this.state.remoteUser) === null || _b === void 0 ? void 0 : _b.username)) {
|
|
430
|
-
this.setState(old => (Object.assign(Object.assign({}, old), { remoteUser: remoteState.user })));
|
|
431
|
-
}
|
|
432
|
-
const remoteViewport = remoteState.viewportState;
|
|
433
|
-
if (remoteViewport.value) {
|
|
434
|
-
const { x, y } = remoteViewport.value.coordinates;
|
|
435
|
-
const zoom = remoteViewport.value.zoom;
|
|
436
|
-
this._moveToPosition({ x, y }, zoom, 0);
|
|
437
|
-
}
|
|
396
|
+
const selectedLayers = (_a = localState.selected) === null || _a === void 0 ? void 0 : _a.value;
|
|
397
|
+
if (!selectedLayers) {
|
|
398
|
+
return;
|
|
438
399
|
}
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
const viewportState = (_c = localState.viewportState) === null || _c === void 0 ? void 0 : _c.value;
|
|
444
|
-
if (viewportState) {
|
|
445
|
-
this._moveToPosition(viewportState.coordinates, viewportState.zoom);
|
|
446
|
-
}
|
|
447
|
-
}
|
|
400
|
+
const selectedLayerId = Object.keys(selectedLayers)[0];
|
|
401
|
+
const JGISLayer = this._model.getLayer(selectedLayerId);
|
|
402
|
+
if (!JGISLayer) {
|
|
403
|
+
return;
|
|
448
404
|
}
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
const clientPointers = Object.assign({}, this.state.clientPointers);
|
|
461
|
-
let currentClientPointer = clientPointers[clientId];
|
|
462
|
-
if (pointer) {
|
|
463
|
-
const pixel = this._Map.getPixelFromCoordinate([
|
|
464
|
-
pointer.coordinates.x,
|
|
465
|
-
pointer.coordinates.y,
|
|
466
|
-
]);
|
|
467
|
-
const lonLat = toLonLat([pointer.coordinates.x, pointer.coordinates.y]);
|
|
468
|
-
if (!currentClientPointer) {
|
|
469
|
-
currentClientPointer = {
|
|
470
|
-
username: client.user.username,
|
|
471
|
-
displayName: client.user.display_name,
|
|
472
|
-
color: client.user.color,
|
|
473
|
-
coordinates: {
|
|
474
|
-
x: pixel[0],
|
|
475
|
-
y: pixel[1],
|
|
476
|
-
},
|
|
477
|
-
lonLat: {
|
|
478
|
-
longitude: lonLat[0],
|
|
479
|
-
latitude: lonLat[1],
|
|
480
|
-
},
|
|
481
|
-
};
|
|
482
|
-
}
|
|
483
|
-
else {
|
|
484
|
-
currentClientPointer = Object.assign(Object.assign({}, currentClientPointer), { coordinates: {
|
|
485
|
-
x: pixel[0],
|
|
486
|
-
y: pixel[1],
|
|
487
|
-
}, lonLat: {
|
|
488
|
-
longitude: lonLat[0],
|
|
489
|
-
latitude: lonLat[1],
|
|
490
|
-
} });
|
|
491
|
-
}
|
|
492
|
-
clientPointers[clientId] = currentClientPointer;
|
|
493
|
-
}
|
|
494
|
-
else {
|
|
495
|
-
delete clientPointers[clientId];
|
|
496
|
-
}
|
|
497
|
-
this.setState(old => (Object.assign(Object.assign({}, old), { clientPointers })));
|
|
498
|
-
});
|
|
499
|
-
// Temporal controller bit
|
|
500
|
-
// ? There's probably a better way to get changes in the model to trigger react rerenders
|
|
501
|
-
const isTemporalControllerActive = localState.isTemporalControllerActive;
|
|
502
|
-
if (isTemporalControllerActive !== this.state.displayTemporalController) {
|
|
503
|
-
this.setState(old => (Object.assign(Object.assign({}, old), { displayTemporalController: isTemporalControllerActive })));
|
|
504
|
-
this._mainViewModel.commands.notifyCommandChanged(CommandIDs.temporalController);
|
|
405
|
+
this._syncVectorDrawingFromSelection(JGISLayer, selectedLayerId);
|
|
406
|
+
};
|
|
407
|
+
this._syncVectorDrawingFromSelection = (layer, selectedLayerId) => {
|
|
408
|
+
const decision = this._getVectorDrawingSelectionDecision(layer, selectedLayerId);
|
|
409
|
+
if (decision.disableEditing) {
|
|
410
|
+
this._model.editingVectorLayer = false;
|
|
411
|
+
this._updateEditingVectorLayer();
|
|
412
|
+
return;
|
|
413
|
+
}
|
|
414
|
+
if (!decision.shouldRebind) {
|
|
415
|
+
return;
|
|
505
416
|
}
|
|
417
|
+
this._previousDrawLayerID = selectedLayerId;
|
|
418
|
+
this._currentDrawLayerID = selectedLayerId;
|
|
419
|
+
this._editVectorLayer();
|
|
506
420
|
};
|
|
507
421
|
this._onSharedModelStateChange = (_, change) => {
|
|
508
422
|
var _a;
|
|
@@ -521,6 +435,10 @@ export class MainView extends React.Component {
|
|
|
521
435
|
}
|
|
522
436
|
}
|
|
523
437
|
};
|
|
438
|
+
this._handleIdentifiedFeaturesChanged = () => {
|
|
439
|
+
this.setState(old => (Object.assign(Object.assign({}, old), { identifyFeatureFloatersVersion: old.identifyFeatureFloatersVersion + 1 })));
|
|
440
|
+
this._clearHighlightWhenIdentifyDisabled();
|
|
441
|
+
};
|
|
524
442
|
/**
|
|
525
443
|
* Handler for when story maps change in the model.
|
|
526
444
|
* Updates specta state and presentation colors when story data becomes available.
|
|
@@ -571,6 +489,7 @@ export class MainView extends React.Component {
|
|
|
571
489
|
let accumulatedDeltaY = 0;
|
|
572
490
|
let scrollContainer = (_b = (_a = this.storyViewerPanelRef.current) === null || _a === void 0 ? void 0 : _a.getScrollContainer()) !== null && _b !== void 0 ? _b : null;
|
|
573
491
|
const processStoryScrollFrame = () => {
|
|
492
|
+
var _a;
|
|
574
493
|
this._pendingStoryScrollRafId = null;
|
|
575
494
|
const currentPanelHandle = this.storyViewerPanelRef.current;
|
|
576
495
|
if (!currentPanelHandle || !scrollContainer) {
|
|
@@ -579,6 +498,12 @@ export class MainView extends React.Component {
|
|
|
579
498
|
}
|
|
580
499
|
const deltaY = accumulatedDeltaY;
|
|
581
500
|
accumulatedDeltaY = 0;
|
|
501
|
+
const storyType = (_a = this._model.getSelectedStory().story) === null || _a === void 0 ? void 0 : _a.storyType;
|
|
502
|
+
// Don't want to handle next/prev logic in list mode
|
|
503
|
+
if (storyType === STORY_TYPE.verticalScroll) {
|
|
504
|
+
scrollContainer.scrollBy({ top: deltaY });
|
|
505
|
+
return;
|
|
506
|
+
}
|
|
582
507
|
const isScrollingUp = deltaY < 0;
|
|
583
508
|
const isScrollingDown = deltaY > 0;
|
|
584
509
|
const isAtTop = currentPanelHandle.getAtTop();
|
|
@@ -652,7 +577,7 @@ export class MainView extends React.Component {
|
|
|
652
577
|
jsonData = JSON.parse(data);
|
|
653
578
|
}
|
|
654
579
|
catch (e) {
|
|
655
|
-
|
|
580
|
+
this._log('warning', `Failed to parse annotation data for ${key}: ${e}`);
|
|
656
581
|
return;
|
|
657
582
|
}
|
|
658
583
|
}
|
|
@@ -682,6 +607,9 @@ export class MainView extends React.Component {
|
|
|
682
607
|
this._handleWindowResize = () => {
|
|
683
608
|
// TODO SOMETHING
|
|
684
609
|
};
|
|
610
|
+
this._handleSegmentTransitionChange = (payload) => {
|
|
611
|
+
this.setState({ segmentTransition: payload });
|
|
612
|
+
};
|
|
685
613
|
this._handleSpectaTouchStart = (e) => {
|
|
686
614
|
if (e.touches.length > 0) {
|
|
687
615
|
this._spectaTouchStartX = e.touches[0].clientX;
|
|
@@ -708,6 +636,148 @@ export class MainView extends React.Component {
|
|
|
708
636
|
this._model.setCurrentSegmentIndex(current + 1);
|
|
709
637
|
}
|
|
710
638
|
};
|
|
639
|
+
this._handleDrawGeometryTypeChange = (
|
|
640
|
+
/* handle with the change of geometry and instantiate new draw interaction and other ones accordingly*/
|
|
641
|
+
event) => {
|
|
642
|
+
const drawGeometryLabel = event.target.value;
|
|
643
|
+
this._currentDrawGeometry = drawGeometryLabel;
|
|
644
|
+
this._updateInteractions();
|
|
645
|
+
this._updateDrawSource();
|
|
646
|
+
this.setState(old => (Object.assign(Object.assign({}, old), { drawGeometryLabel })));
|
|
647
|
+
};
|
|
648
|
+
this._getVectorSourceFromLayerID = (layerID) => {
|
|
649
|
+
/* get the OpenLayers VectorSource corresponding to the JGIS currentDrawLayerID */
|
|
650
|
+
const layers = this._Map.getLayers();
|
|
651
|
+
const layerArray = layers.getArray();
|
|
652
|
+
const matchingLayer = layerArray.find(layer => layer.get('id') === layerID);
|
|
653
|
+
const source = matchingLayer === null || matchingLayer === void 0 ? void 0 : matchingLayer.get('source');
|
|
654
|
+
this._currentVectorSource = source;
|
|
655
|
+
return this._currentVectorSource;
|
|
656
|
+
};
|
|
657
|
+
this._getDrawSourceFromSelectedLayer = () => {
|
|
658
|
+
var _a, _b, _c, _d;
|
|
659
|
+
const selectedLayers = (_c = (_b = (_a = this._model) === null || _a === void 0 ? void 0 : _a.sharedModel.awareness.getLocalState()) === null || _b === void 0 ? void 0 : _b.selected) === null || _c === void 0 ? void 0 : _c.value;
|
|
660
|
+
if (!selectedLayers) {
|
|
661
|
+
return;
|
|
662
|
+
}
|
|
663
|
+
const selectedLayerID = Object.keys(selectedLayers)[0];
|
|
664
|
+
this._currentDrawLayerID = selectedLayerID;
|
|
665
|
+
const JGISLayer = this._model.getLayer(selectedLayerID);
|
|
666
|
+
this._currentDrawSourceID = (_d = JGISLayer === null || JGISLayer === void 0 ? void 0 : JGISLayer.parameters) === null || _d === void 0 ? void 0 : _d.source;
|
|
667
|
+
if (this._currentDrawSourceID) {
|
|
668
|
+
this._currentDrawSource = this._model.getSource(this._currentDrawSourceID);
|
|
669
|
+
}
|
|
670
|
+
};
|
|
671
|
+
this._onVectorSourceChange = () => {
|
|
672
|
+
if (!this._currentVectorSource ||
|
|
673
|
+
!this._currentDrawSource ||
|
|
674
|
+
!this._currentDrawSourceID) {
|
|
675
|
+
return;
|
|
676
|
+
}
|
|
677
|
+
const geojsonWriter = new GeoJSON({
|
|
678
|
+
featureProjection: this._Map.getView().getProjection(),
|
|
679
|
+
});
|
|
680
|
+
const features = this._currentVectorSource
|
|
681
|
+
.getFeatures()
|
|
682
|
+
.map(feature => geojsonWriter.writeFeatureObject(feature));
|
|
683
|
+
const updatedData = {
|
|
684
|
+
type: 'FeatureCollection',
|
|
685
|
+
features: features,
|
|
686
|
+
};
|
|
687
|
+
const updatedJGISLayerSource = {
|
|
688
|
+
name: this._currentDrawSource.name,
|
|
689
|
+
type: this._currentDrawSource.type,
|
|
690
|
+
parameters: {
|
|
691
|
+
data: updatedData,
|
|
692
|
+
},
|
|
693
|
+
};
|
|
694
|
+
this._currentDrawSource = updatedJGISLayerSource;
|
|
695
|
+
this._model.sharedModel.updateSource(this._currentDrawSourceID, updatedJGISLayerSource);
|
|
696
|
+
};
|
|
697
|
+
this._updateDrawSource = () => {
|
|
698
|
+
if (this._currentVectorSource) {
|
|
699
|
+
this._currentVectorSource.on('change', this._onVectorSourceChange);
|
|
700
|
+
}
|
|
701
|
+
};
|
|
702
|
+
this._updateInteractions = () => {
|
|
703
|
+
if (this._draw) {
|
|
704
|
+
this._removeDrawInteraction();
|
|
705
|
+
}
|
|
706
|
+
if (this._select) {
|
|
707
|
+
this._removeSelectInteraction();
|
|
708
|
+
}
|
|
709
|
+
if (this._modify) {
|
|
710
|
+
this._removeModifyInteraction();
|
|
711
|
+
}
|
|
712
|
+
if (this._snap) {
|
|
713
|
+
this._removeSnapInteraction();
|
|
714
|
+
}
|
|
715
|
+
this._draw = new Draw({
|
|
716
|
+
style: drawInteractionStyle,
|
|
717
|
+
type: this._currentDrawGeometry,
|
|
718
|
+
source: this._currentVectorSource,
|
|
719
|
+
});
|
|
720
|
+
this._draw.on('drawend', this._handleDrawEnd);
|
|
721
|
+
this._select = new Select();
|
|
722
|
+
this._modify = new Modify({
|
|
723
|
+
features: this._select.getFeatures(),
|
|
724
|
+
});
|
|
725
|
+
this._snap = new Snap({
|
|
726
|
+
source: this._currentVectorSource,
|
|
727
|
+
});
|
|
728
|
+
this._Map.addInteraction(this._draw);
|
|
729
|
+
this._Map.addInteraction(this._select);
|
|
730
|
+
this._Map.addInteraction(this._modify);
|
|
731
|
+
this._Map.addInteraction(this._snap);
|
|
732
|
+
this._draw.setActive(true);
|
|
733
|
+
this._select.setActive(false);
|
|
734
|
+
this._modify.setActive(false);
|
|
735
|
+
this._snap.setActive(true);
|
|
736
|
+
};
|
|
737
|
+
this._handleDrawEnd = (event) => {
|
|
738
|
+
const feature = event.feature;
|
|
739
|
+
feature.set('_id', UUID.uuid4());
|
|
740
|
+
feature.set('_createdAt', new Date().toISOString());
|
|
741
|
+
feature.set('_creatorClientId', this._model.getClientId().toString());
|
|
742
|
+
feature.set('_fromDrawTool', true);
|
|
743
|
+
feature.set('Label', 'New Label');
|
|
744
|
+
};
|
|
745
|
+
this._editVectorLayer = () => {
|
|
746
|
+
this._getDrawSourceFromSelectedLayer();
|
|
747
|
+
if (!this._currentDrawLayerID) {
|
|
748
|
+
return;
|
|
749
|
+
}
|
|
750
|
+
this._currentVectorSource = this._getVectorSourceFromLayerID(this._currentDrawLayerID);
|
|
751
|
+
if (!this._currentVectorSource || !this._currentDrawGeometry) {
|
|
752
|
+
return;
|
|
753
|
+
}
|
|
754
|
+
this._updateInteractions(); /* remove previous interactions and instantiate new ones */
|
|
755
|
+
this._updateDrawSource(); /*add new features, update source and get changes reported to the JGIS Document in geoJSON format */
|
|
756
|
+
};
|
|
757
|
+
this._removeDrawInteraction = () => {
|
|
758
|
+
this._draw.setActive(false);
|
|
759
|
+
this._Map.removeInteraction(this._draw);
|
|
760
|
+
};
|
|
761
|
+
this._removeSelectInteraction = () => {
|
|
762
|
+
this._select.setActive(false);
|
|
763
|
+
this._Map.removeInteraction(this._select);
|
|
764
|
+
};
|
|
765
|
+
this._removeSnapInteraction = () => {
|
|
766
|
+
this._snap.setActive(false);
|
|
767
|
+
this._Map.removeInteraction(this._snap);
|
|
768
|
+
};
|
|
769
|
+
this._removeModifyInteraction = () => {
|
|
770
|
+
this._modify.setActive(false);
|
|
771
|
+
this._Map.removeInteraction(this._modify);
|
|
772
|
+
};
|
|
773
|
+
/**
|
|
774
|
+
* Shared source update wrapper for child components that need to mutate a
|
|
775
|
+
* source and refresh corresponding map layers.
|
|
776
|
+
*/
|
|
777
|
+
this.persistAndRefreshSource = async (id, source) => {
|
|
778
|
+
this._model.sharedModel.updateSource(id, source);
|
|
779
|
+
await this.updateSource(id, source);
|
|
780
|
+
};
|
|
711
781
|
this._isPositionInitialized = false;
|
|
712
782
|
this.divRef = React.createRef(); // Reference of render div
|
|
713
783
|
this.mainViewRef = React.createRef();
|
|
@@ -717,6 +787,9 @@ export class MainView extends React.Component {
|
|
|
717
787
|
this._ready = false;
|
|
718
788
|
this._sourceToLayerMap = new Map();
|
|
719
789
|
this._originalFeatures = {};
|
|
790
|
+
this._highlightLayerRef = { current: null };
|
|
791
|
+
this._addLayerForPanels = (id, layer, index) => this.addLayer(id, layer, index);
|
|
792
|
+
this._removeLayerForPanels = (id) => this.removeLayer(id);
|
|
720
793
|
this._featurePropertyCache = new Map();
|
|
721
794
|
this._isSpectaPresentationInitialized = false;
|
|
722
795
|
this._storyScrollHandler = null;
|
|
@@ -725,6 +798,7 @@ export class MainView extends React.Component {
|
|
|
725
798
|
this._state = props.state;
|
|
726
799
|
this._formSchemaRegistry = props.formSchemaRegistry;
|
|
727
800
|
this._annotationModel = props.annotationModel;
|
|
801
|
+
this._loggerRegistry = props.loggerRegistry;
|
|
728
802
|
// Enforce the map to take the full available width in the case of Jupyter Notebook viewer
|
|
729
803
|
const el = document.getElementById('main-panel');
|
|
730
804
|
if (el) {
|
|
@@ -747,31 +821,39 @@ export class MainView extends React.Component {
|
|
|
747
821
|
this._mainViewModel = this.props.viewModel;
|
|
748
822
|
this._mainViewModel.viewSettingChanged.connect(this._onViewChanged, this);
|
|
749
823
|
this._model = this._mainViewModel.jGISModel;
|
|
824
|
+
this._patchGeoJSONFeatureProperties = createGeoJSONFeaturePatcher({
|
|
825
|
+
model: this._model,
|
|
826
|
+
persistAndRefreshSource: this.persistAndRefreshSource,
|
|
827
|
+
});
|
|
750
828
|
this._model.themeChanged.connect(this._handleThemeChange, this);
|
|
751
829
|
this._model.sharedOptionsChanged.connect(this._onSharedOptionsChanged, this);
|
|
752
|
-
this._model.
|
|
830
|
+
this._model.temporalControllerActiveChanged.connect(this._handleTemporalControllerActiveChanged, this);
|
|
831
|
+
const remoteUserSignals = [
|
|
832
|
+
this._model.remoteUserChanged,
|
|
833
|
+
this._model.viewportStateChanged,
|
|
834
|
+
];
|
|
835
|
+
remoteUserSignals.forEach(signal => signal.connect(this._handleRemoteUserChanged, this));
|
|
836
|
+
this._model.pointerChanged.connect(this._handlePointerChanged, this);
|
|
837
|
+
this._model.selectedChanged.connect(this._handleTemporalControllerActiveChanged, this);
|
|
838
|
+
this._model.selectedChanged.connect(this._handleSelectedChanged, this);
|
|
753
839
|
this._model.sharedLayersChanged.connect(this._onLayersChanged, this);
|
|
754
840
|
this._model.sharedLayerTreeChanged.connect(this._onLayerTreeChange, this);
|
|
755
841
|
this._model.sharedSourcesChanged.connect(this._onSourcesChange, this);
|
|
756
842
|
this._model.sharedModel.changed.connect(this._onSharedModelStateChange);
|
|
757
843
|
this._model.sharedMetadataChanged.connect(this._onSharedMetadataChanged, this);
|
|
844
|
+
this._model.identifiedFeaturesChanged.connect(this._handleIdentifiedFeaturesChanged, this);
|
|
758
845
|
this._model.zoomToPositionSignal.connect(this._onZoomToPosition, this);
|
|
759
846
|
this._model.settingsChanged.connect(this._onSettingsChanged, this);
|
|
760
847
|
this._model.updateLayerSignal.connect(this._triggerLayerUpdate, this);
|
|
761
848
|
this._model.addFeatureAsMsSignal.connect(this._convertFeatureToMs, this);
|
|
762
849
|
this._model.geolocationChanged.connect(this._handleGeolocationChanged, this);
|
|
850
|
+
// Keep draw editing UI/interactions in sync with the shared editing mode.
|
|
851
|
+
this._model.editingVectorLayerChanged.connect(this._updateEditingVectorLayer, this);
|
|
763
852
|
this._model.flyToGeometrySignal.connect(this.flyToGeometry, this);
|
|
764
853
|
this._model.highlightFeatureSignal.connect(this.highlightFeatureOnMap, this);
|
|
765
854
|
Promise.resolve().then(() => {
|
|
766
855
|
this._syncSettingsFromRegistry();
|
|
767
856
|
});
|
|
768
|
-
// Watch isIdentifying and clear the highlight when Identify Tool is turned off
|
|
769
|
-
this._model.sharedModel.awareness.on('change', () => {
|
|
770
|
-
var _a;
|
|
771
|
-
if (this._model.currentMode !== 'identifying' && this._highlightLayer) {
|
|
772
|
-
(_a = this._highlightLayer.getSource()) === null || _a === void 0 ? void 0 : _a.clear();
|
|
773
|
-
}
|
|
774
|
-
});
|
|
775
857
|
this.state = {
|
|
776
858
|
id: this._mainViewModel.id,
|
|
777
859
|
lightTheme: isLightTheme(),
|
|
@@ -784,9 +866,13 @@ export class MainView extends React.Component {
|
|
|
784
866
|
loadingErrors: [],
|
|
785
867
|
displayTemporalController: false,
|
|
786
868
|
filterStates: {},
|
|
869
|
+
editingVectorLayer: false,
|
|
870
|
+
drawGeometryLabel: '',
|
|
787
871
|
jgisSettings: this._model.jgisSettings,
|
|
788
872
|
isSpectaPresentation: this._model.isSpectaMode(),
|
|
789
873
|
initialLayersReady: false,
|
|
874
|
+
identifyFeatureFloatersVersion: 0,
|
|
875
|
+
segmentTransition: null,
|
|
790
876
|
};
|
|
791
877
|
this._sources = [];
|
|
792
878
|
this._loadingLayers = new Set();
|
|
@@ -798,6 +884,10 @@ export class MainView extends React.Component {
|
|
|
798
884
|
}
|
|
799
885
|
async componentDidMount() {
|
|
800
886
|
var _a;
|
|
887
|
+
if (this._loggerRegistry) {
|
|
888
|
+
const logger = this._loggerRegistry.getLogger(this._model.filePath);
|
|
889
|
+
logger.level = 'debug';
|
|
890
|
+
}
|
|
801
891
|
window.addEventListener('resize', this._handleWindowResize);
|
|
802
892
|
const options = this._model.getOptions();
|
|
803
893
|
const projection = (_a = options.projection) !== null && _a !== void 0 ? _a : DEFAULT_PROJECTION;
|
|
@@ -806,6 +896,10 @@ export class MainView extends React.Component {
|
|
|
806
896
|
: [0, 0];
|
|
807
897
|
const zoom = options.zoom !== undefined ? options.zoom : 1;
|
|
808
898
|
await this.generateMap(center, zoom, projection);
|
|
899
|
+
this._handleRemoteUserChanged();
|
|
900
|
+
this._handlePointerChanged();
|
|
901
|
+
this._handleTemporalControllerActiveChanged();
|
|
902
|
+
this._handleSelectedChanged();
|
|
809
903
|
this._mainViewModel.initSignal();
|
|
810
904
|
if (window.jupytergisMaps !== undefined && this._documentPath) {
|
|
811
905
|
window.jupytergisMaps[this._documentPath] = this._Map;
|
|
@@ -828,7 +922,16 @@ export class MainView extends React.Component {
|
|
|
828
922
|
this._model.themeChanged.disconnect(this._handleThemeChange, this);
|
|
829
923
|
this._model.settingsChanged.disconnect(this._onSettingsChanged, this);
|
|
830
924
|
this._model.sharedOptionsChanged.disconnect(this._onSharedOptionsChanged, this);
|
|
831
|
-
this._model.
|
|
925
|
+
this._model.temporalControllerActiveChanged.disconnect(this._handleTemporalControllerActiveChanged, this);
|
|
926
|
+
const remoteUserSignals = [
|
|
927
|
+
this._model.remoteUserChanged,
|
|
928
|
+
this._model.viewportStateChanged,
|
|
929
|
+
];
|
|
930
|
+
remoteUserSignals.forEach(signal => signal.disconnect(this._handleRemoteUserChanged, this));
|
|
931
|
+
this._model.pointerChanged.disconnect(this._handlePointerChanged, this);
|
|
932
|
+
this._model.selectedChanged.disconnect(this._handleTemporalControllerActiveChanged, this);
|
|
933
|
+
this._model.selectedChanged.disconnect(this._handleSelectedChanged, this);
|
|
934
|
+
this._model.identifiedFeaturesChanged.disconnect(this._handleIdentifiedFeaturesChanged, this);
|
|
832
935
|
// Clean up story scroll listener
|
|
833
936
|
this._cleanupStoryScrollListener();
|
|
834
937
|
this._mainViewModel.dispose();
|
|
@@ -892,9 +995,7 @@ export class MainView extends React.Component {
|
|
|
892
995
|
this._Map.addInteraction(dragAndDropInteraction);
|
|
893
996
|
this.createSelectInteraction();
|
|
894
997
|
const view = this._Map.getView();
|
|
895
|
-
|
|
896
|
-
// TODO: Note for the future, will need to update listeners if view changes
|
|
897
|
-
view.on('change:center', throttle(() => {
|
|
998
|
+
const syncViewportThrottled = throttle(() => {
|
|
898
999
|
var _a;
|
|
899
1000
|
// Not syncing center if following someone else
|
|
900
1001
|
if ((_a = this._model.localState) === null || _a === void 0 ? void 0 : _a.remoteUser) {
|
|
@@ -906,18 +1007,30 @@ export class MainView extends React.Component {
|
|
|
906
1007
|
if (!center || !zoom) {
|
|
907
1008
|
return;
|
|
908
1009
|
}
|
|
1010
|
+
const currentExtent = view.calculateExtent(this._Map.getSize());
|
|
909
1011
|
this._model.syncViewport({
|
|
910
1012
|
coordinates: {
|
|
911
1013
|
x: center[0],
|
|
912
1014
|
y: center[1],
|
|
913
1015
|
},
|
|
914
1016
|
zoom,
|
|
1017
|
+
extent: [
|
|
1018
|
+
currentExtent[0],
|
|
1019
|
+
currentExtent[1],
|
|
1020
|
+
currentExtent[2],
|
|
1021
|
+
currentExtent[3],
|
|
1022
|
+
],
|
|
915
1023
|
}, this._mainViewModel.id);
|
|
916
|
-
})
|
|
1024
|
+
}, 200);
|
|
1025
|
+
view.on('change:center', () => {
|
|
1026
|
+
this._updateCenter();
|
|
1027
|
+
syncViewportThrottled();
|
|
1028
|
+
});
|
|
917
1029
|
this._Map.on('postrender', () => {
|
|
918
1030
|
if (this.state.annotations) {
|
|
919
1031
|
this._updateAnnotation();
|
|
920
1032
|
}
|
|
1033
|
+
this._updateFeatureFloaters();
|
|
921
1034
|
});
|
|
922
1035
|
this._Map.on('moveend', () => {
|
|
923
1036
|
var _a;
|
|
@@ -981,241 +1094,359 @@ export class MainView extends React.Component {
|
|
|
981
1094
|
* @param source - the source object.
|
|
982
1095
|
*/
|
|
983
1096
|
async addSource(id, source) {
|
|
984
|
-
var _a, _b, _c;
|
|
1097
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
1098
|
+
this._log('info', `Loading source "${(_a = source.name) !== null && _a !== void 0 ? _a : id}" (${source.type})`);
|
|
985
1099
|
let newSource;
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
sourceParameters.url.endsWith('pmtiles
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
1100
|
+
try {
|
|
1101
|
+
switch (source.type) {
|
|
1102
|
+
case 'RasterSource': {
|
|
1103
|
+
const sourceParameters = source.parameters;
|
|
1104
|
+
const pmTiles = sourceParameters.url.endsWith('.pmtiles') ||
|
|
1105
|
+
sourceParameters.url.endsWith('pmtiles.gz');
|
|
1106
|
+
const url = this.computeSourceUrl(source);
|
|
1107
|
+
if (!pmTiles) {
|
|
1108
|
+
newSource = new XYZSource({
|
|
1109
|
+
interpolate: sourceParameters.interpolate,
|
|
1110
|
+
attributions: sourceParameters.attribution,
|
|
1111
|
+
minZoom: sourceParameters.minZoom,
|
|
1112
|
+
maxZoom: sourceParameters.maxZoom,
|
|
1113
|
+
tileSize: 256,
|
|
1114
|
+
url: url,
|
|
1115
|
+
});
|
|
1116
|
+
}
|
|
1117
|
+
else {
|
|
1118
|
+
newSource = new PMTilesRasterSource({
|
|
1119
|
+
interpolate: sourceParameters.interpolate,
|
|
1120
|
+
attributions: sourceParameters.attribution,
|
|
1121
|
+
tileSize: 256,
|
|
1122
|
+
url: url,
|
|
1123
|
+
});
|
|
1124
|
+
}
|
|
1125
|
+
break;
|
|
1126
|
+
}
|
|
1127
|
+
case 'RasterDemSource': {
|
|
1128
|
+
const sourceParameters = source.parameters;
|
|
1129
|
+
newSource = new ImageTileSource({
|
|
994
1130
|
interpolate: sourceParameters.interpolate,
|
|
1131
|
+
url: this.computeSourceUrl(source),
|
|
995
1132
|
attributions: sourceParameters.attribution,
|
|
996
|
-
minZoom: sourceParameters.minZoom,
|
|
997
|
-
maxZoom: sourceParameters.maxZoom,
|
|
998
|
-
tileSize: 256,
|
|
999
|
-
url: url,
|
|
1000
1133
|
});
|
|
1134
|
+
break;
|
|
1001
1135
|
}
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1136
|
+
case 'VectorTileSource': {
|
|
1137
|
+
const sourceParameters = source.parameters;
|
|
1138
|
+
const pmTiles = sourceParameters.url.endsWith('.pmtiles') ||
|
|
1139
|
+
sourceParameters.url.endsWith('pmtiles.gz');
|
|
1140
|
+
const url = this.computeSourceUrl(source);
|
|
1141
|
+
if (!pmTiles) {
|
|
1142
|
+
const vtSourceOptions = {
|
|
1143
|
+
attributions: sourceParameters.attribution,
|
|
1144
|
+
minZoom: sourceParameters.minZoom,
|
|
1145
|
+
maxZoom: sourceParameters.maxZoom,
|
|
1146
|
+
url: url,
|
|
1147
|
+
format: new MVT({
|
|
1148
|
+
featureClass: RenderFeature,
|
|
1149
|
+
}),
|
|
1150
|
+
};
|
|
1151
|
+
if (sourceParameters.useProxy) {
|
|
1152
|
+
const extraHeaders = (_b = sourceParameters.httpHeaders) !== null && _b !== void 0 ? _b : {};
|
|
1153
|
+
const headersParam = Object.keys(extraHeaders).length > 0
|
|
1154
|
+
? `&headers=${encodeURIComponent(JSON.stringify(extraHeaders))}`
|
|
1155
|
+
: '';
|
|
1156
|
+
const proxyBase = isJupyterLite()
|
|
1157
|
+
? `${this._model.jgisSettings.proxyUrl}/`
|
|
1158
|
+
: `${INTERNAL_PROXY_BASE}`;
|
|
1159
|
+
vtSourceOptions.tileLoadFunction = (tile, tileUrl) => {
|
|
1160
|
+
const vtTile = tile;
|
|
1161
|
+
const proxyUrl = `${proxyBase}?url=${encodeURIComponent(tileUrl)}${headersParam}`;
|
|
1162
|
+
vtTile.setLoader((extent, _resolution, projection) => {
|
|
1163
|
+
return fetch(proxyUrl)
|
|
1164
|
+
.then(response => {
|
|
1165
|
+
if (!response.ok) {
|
|
1166
|
+
throw new Error(`Tile proxy request failed: ${response.status} ${response.statusText}`);
|
|
1167
|
+
}
|
|
1168
|
+
return response.arrayBuffer();
|
|
1169
|
+
})
|
|
1170
|
+
.then(data => {
|
|
1171
|
+
const features = vtTile.getFormat().readFeatures(data, {
|
|
1172
|
+
extent,
|
|
1173
|
+
featureProjection: projection,
|
|
1174
|
+
});
|
|
1175
|
+
vtTile.setFeatures(features);
|
|
1176
|
+
this._log('debug', `Proxy tile loaded: ${tileUrl}`);
|
|
1177
|
+
return features;
|
|
1178
|
+
})
|
|
1179
|
+
.catch((err) => {
|
|
1180
|
+
this._log('error', `Proxy tile error for ${tileUrl}: ${err.message}`);
|
|
1181
|
+
tile.setState(TileState.ERROR);
|
|
1182
|
+
return [];
|
|
1183
|
+
});
|
|
1184
|
+
});
|
|
1185
|
+
};
|
|
1186
|
+
}
|
|
1187
|
+
newSource = new VectorTileSource(vtSourceOptions);
|
|
1188
|
+
}
|
|
1189
|
+
else {
|
|
1190
|
+
newSource = new PMTilesVectorSource({
|
|
1191
|
+
attributions: sourceParameters.attribution,
|
|
1192
|
+
url: url,
|
|
1193
|
+
});
|
|
1194
|
+
}
|
|
1195
|
+
newSource.on('tileloadend', (event) => {
|
|
1196
|
+
const tile = event.tile;
|
|
1197
|
+
const features = tile.getFeatures();
|
|
1198
|
+
if (features && features.length > 0) {
|
|
1199
|
+
this._model.syncTileFeatures({
|
|
1200
|
+
sourceId: id,
|
|
1201
|
+
features,
|
|
1202
|
+
});
|
|
1203
|
+
}
|
|
1008
1204
|
});
|
|
1205
|
+
break;
|
|
1009
1206
|
}
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
});
|
|
1019
|
-
break;
|
|
1020
|
-
}
|
|
1021
|
-
case 'VectorTileSource': {
|
|
1022
|
-
const sourceParameters = source.parameters;
|
|
1023
|
-
const pmTiles = sourceParameters.url.endsWith('.pmtiles') ||
|
|
1024
|
-
sourceParameters.url.endsWith('pmtiles.gz');
|
|
1025
|
-
const url = this.computeSourceUrl(source);
|
|
1026
|
-
if (!pmTiles) {
|
|
1027
|
-
newSource = new VectorTileSource({
|
|
1028
|
-
attributions: sourceParameters.attribution,
|
|
1029
|
-
minZoom: sourceParameters.minZoom,
|
|
1030
|
-
maxZoom: sourceParameters.maxZoom,
|
|
1031
|
-
url: url,
|
|
1032
|
-
format: new MVT({
|
|
1033
|
-
featureClass: RenderFeature,
|
|
1034
|
-
}),
|
|
1207
|
+
case 'OpenEOTileSource': {
|
|
1208
|
+
const sourceParameters = source.parameters;
|
|
1209
|
+
newSource = new OpenEOTileSource({
|
|
1210
|
+
connectionInfo: {
|
|
1211
|
+
url: sourceParameters.serverUrl,
|
|
1212
|
+
authBearer: sourceParameters.authBearer,
|
|
1213
|
+
},
|
|
1214
|
+
processGraph: sourceParameters.processGraph,
|
|
1035
1215
|
});
|
|
1216
|
+
break;
|
|
1036
1217
|
}
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1218
|
+
case 'GeoJSONSource': {
|
|
1219
|
+
const data = ((_c = source.parameters) === null || _c === void 0 ? void 0 : _c.data) ||
|
|
1220
|
+
(await loadFile({
|
|
1221
|
+
filepath: (_d = source.parameters) === null || _d === void 0 ? void 0 : _d.path,
|
|
1222
|
+
type: 'GeoJSONSource',
|
|
1223
|
+
model: this._model,
|
|
1224
|
+
}));
|
|
1225
|
+
const format = new GeoJSON({
|
|
1226
|
+
featureProjection: this._Map.getView().getProjection(),
|
|
1227
|
+
});
|
|
1228
|
+
const featureArray = format.readFeatures(data, {
|
|
1229
|
+
featureProjection: this._Map.getView().getProjection(),
|
|
1230
|
+
});
|
|
1231
|
+
const featureCollection = new Collection(featureArray);
|
|
1232
|
+
featureCollection.forEach(feature => {
|
|
1233
|
+
feature.setId(getUid(feature));
|
|
1041
1234
|
});
|
|
1235
|
+
newSource = new VectorSource({
|
|
1236
|
+
features: featureCollection,
|
|
1237
|
+
});
|
|
1238
|
+
break;
|
|
1042
1239
|
}
|
|
1043
|
-
|
|
1044
|
-
const
|
|
1045
|
-
const
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
sourceId: id,
|
|
1049
|
-
features,
|
|
1050
|
-
});
|
|
1051
|
-
}
|
|
1052
|
-
});
|
|
1053
|
-
break;
|
|
1054
|
-
}
|
|
1055
|
-
case 'GeoJSONSource': {
|
|
1056
|
-
const data = ((_a = source.parameters) === null || _a === void 0 ? void 0 : _a.data) ||
|
|
1057
|
-
(await loadFile({
|
|
1058
|
-
filepath: (_b = source.parameters) === null || _b === void 0 ? void 0 : _b.path,
|
|
1059
|
-
type: 'GeoJSONSource',
|
|
1240
|
+
case 'ShapefileSource': {
|
|
1241
|
+
const parameters = source.parameters;
|
|
1242
|
+
const geojson = await loadFile({
|
|
1243
|
+
filepath: parameters.path,
|
|
1244
|
+
type: 'ShapefileSource',
|
|
1060
1245
|
model: this._model,
|
|
1246
|
+
});
|
|
1247
|
+
const geojsonData = Array.isArray(geojson) ? geojson[0] : geojson;
|
|
1248
|
+
const format = new GeoJSON();
|
|
1249
|
+
newSource = new VectorSource({
|
|
1250
|
+
features: format.readFeatures(geojsonData, {
|
|
1251
|
+
dataProjection: 'EPSG:4326',
|
|
1252
|
+
featureProjection: this._Map.getView().getProjection(),
|
|
1253
|
+
}),
|
|
1254
|
+
});
|
|
1255
|
+
break;
|
|
1256
|
+
}
|
|
1257
|
+
case 'ImageSource': {
|
|
1258
|
+
const sourceParameters = source.parameters;
|
|
1259
|
+
// Convert lon/lat array to extent
|
|
1260
|
+
// Get lon/lat from source coordinates
|
|
1261
|
+
const leftSide = Math.min(...sourceParameters.coordinates.map(corner => corner[0]));
|
|
1262
|
+
const bottomSide = Math.min(...sourceParameters.coordinates.map(corner => corner[1]));
|
|
1263
|
+
const rightSide = Math.max(...sourceParameters.coordinates.map(corner => corner[0]));
|
|
1264
|
+
const topSide = Math.max(...sourceParameters.coordinates.map(corner => corner[1]));
|
|
1265
|
+
// Convert lon/lat to OpenLayer coordinates
|
|
1266
|
+
const topLeft = fromLonLat([leftSide, topSide]);
|
|
1267
|
+
const bottomRight = fromLonLat([rightSide, bottomSide]);
|
|
1268
|
+
// Get extent from coordinates
|
|
1269
|
+
const minX = topLeft[0];
|
|
1270
|
+
const maxY = topLeft[1];
|
|
1271
|
+
const maxX = bottomRight[0];
|
|
1272
|
+
const minY = bottomRight[1];
|
|
1273
|
+
const extent = [minX, minY, maxX, maxY];
|
|
1274
|
+
const imageUrl = await loadFile({
|
|
1275
|
+
filepath: sourceParameters.path,
|
|
1276
|
+
type: 'ImageSource',
|
|
1277
|
+
model: this._model,
|
|
1278
|
+
});
|
|
1279
|
+
newSource = new Static({
|
|
1280
|
+
interpolate: sourceParameters.interpolate,
|
|
1281
|
+
imageExtent: extent,
|
|
1282
|
+
url: imageUrl,
|
|
1283
|
+
crossOrigin: '',
|
|
1284
|
+
});
|
|
1285
|
+
break;
|
|
1286
|
+
}
|
|
1287
|
+
case 'VideoSource': {
|
|
1288
|
+
this._log('warning', 'Video Tiles not supported with Open Layers');
|
|
1289
|
+
break;
|
|
1290
|
+
}
|
|
1291
|
+
case 'GeoTiffSource': {
|
|
1292
|
+
const sourceParameters = source.parameters;
|
|
1293
|
+
const addNoData = (url) => {
|
|
1294
|
+
return Object.assign(Object.assign({}, url), { nodata: 0 });
|
|
1295
|
+
};
|
|
1296
|
+
const sources = await Promise.all(sourceParameters.urls.map(async (sourceInfo) => {
|
|
1297
|
+
var _a, _b, _c, _d;
|
|
1298
|
+
const isRemote = ((_a = sourceInfo.url) === null || _a === void 0 ? void 0 : _a.startsWith('http://')) ||
|
|
1299
|
+
((_b = sourceInfo.url) === null || _b === void 0 ? void 0 : _b.startsWith('https://'));
|
|
1300
|
+
const isDataUrl = (_c = sourceInfo.url) === null || _c === void 0 ? void 0 : _c.startsWith('data:');
|
|
1301
|
+
if (isRemote) {
|
|
1302
|
+
return Object.assign(Object.assign({}, addNoData(sourceInfo)), { min: sourceInfo.min, max: sourceInfo.max, url: sourceInfo.url });
|
|
1303
|
+
}
|
|
1304
|
+
else if (isDataUrl) {
|
|
1305
|
+
// Inline base64 GeoTIFF embedded in the .jGIS doc.
|
|
1306
|
+
const blob = await (await fetch(sourceInfo.url)).blob();
|
|
1307
|
+
return Object.assign(Object.assign({}, addNoData(sourceInfo)), { min: sourceInfo.min, max: sourceInfo.max, url: URL.createObjectURL(blob) });
|
|
1308
|
+
}
|
|
1309
|
+
else {
|
|
1310
|
+
const geotiff = await loadFile({
|
|
1311
|
+
filepath: (_d = sourceInfo.url) !== null && _d !== void 0 ? _d : '',
|
|
1312
|
+
type: 'GeoTiffSource',
|
|
1313
|
+
model: this._model,
|
|
1314
|
+
});
|
|
1315
|
+
return Object.assign(Object.assign({}, addNoData(sourceInfo)), { min: sourceInfo.min, max: sourceInfo.max, geotiff, url: URL.createObjectURL(geotiff.file) });
|
|
1316
|
+
}
|
|
1061
1317
|
}));
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
});
|
|
1075
|
-
break;
|
|
1076
|
-
}
|
|
1077
|
-
case 'ShapefileSource': {
|
|
1078
|
-
const parameters = source.parameters;
|
|
1079
|
-
const geojson = await loadFile({
|
|
1080
|
-
filepath: parameters.path,
|
|
1081
|
-
type: 'ShapefileSource',
|
|
1082
|
-
model: this._model,
|
|
1083
|
-
});
|
|
1084
|
-
const geojsonData = Array.isArray(geojson) ? geojson[0] : geojson;
|
|
1085
|
-
const format = new GeoJSON();
|
|
1086
|
-
newSource = new VectorSource({
|
|
1087
|
-
features: format.readFeatures(geojsonData, {
|
|
1088
|
-
dataProjection: 'EPSG:4326',
|
|
1089
|
-
featureProjection: this._Map.getView().getProjection(),
|
|
1090
|
-
}),
|
|
1091
|
-
});
|
|
1092
|
-
break;
|
|
1093
|
-
}
|
|
1094
|
-
case 'ImageSource': {
|
|
1095
|
-
const sourceParameters = source.parameters;
|
|
1096
|
-
// Convert lon/lat array to extent
|
|
1097
|
-
// Get lon/lat from source coordinates
|
|
1098
|
-
const leftSide = Math.min(...sourceParameters.coordinates.map(corner => corner[0]));
|
|
1099
|
-
const bottomSide = Math.min(...sourceParameters.coordinates.map(corner => corner[1]));
|
|
1100
|
-
const rightSide = Math.max(...sourceParameters.coordinates.map(corner => corner[0]));
|
|
1101
|
-
const topSide = Math.max(...sourceParameters.coordinates.map(corner => corner[1]));
|
|
1102
|
-
// Convert lon/lat to OpenLayer coordinates
|
|
1103
|
-
const topLeft = fromLonLat([leftSide, topSide]);
|
|
1104
|
-
const bottomRight = fromLonLat([rightSide, bottomSide]);
|
|
1105
|
-
// Get extent from coordinates
|
|
1106
|
-
const minX = topLeft[0];
|
|
1107
|
-
const maxY = topLeft[1];
|
|
1108
|
-
const maxX = bottomRight[0];
|
|
1109
|
-
const minY = bottomRight[1];
|
|
1110
|
-
const extent = [minX, minY, maxX, maxY];
|
|
1111
|
-
const imageUrl = await loadFile({
|
|
1112
|
-
filepath: sourceParameters.path,
|
|
1113
|
-
type: 'ImageSource',
|
|
1114
|
-
model: this._model,
|
|
1115
|
-
});
|
|
1116
|
-
newSource = new Static({
|
|
1117
|
-
interpolate: sourceParameters.interpolate,
|
|
1118
|
-
imageExtent: extent,
|
|
1119
|
-
url: imageUrl,
|
|
1120
|
-
crossOrigin: '',
|
|
1121
|
-
});
|
|
1122
|
-
break;
|
|
1123
|
-
}
|
|
1124
|
-
case 'VideoSource': {
|
|
1125
|
-
console.warn('Video Tiles not supported with Open Layers');
|
|
1126
|
-
break;
|
|
1127
|
-
}
|
|
1128
|
-
case 'GeoTiffSource': {
|
|
1129
|
-
const sourceParameters = source.parameters;
|
|
1130
|
-
const addNoData = (url) => {
|
|
1131
|
-
return Object.assign(Object.assign({}, url), { nodata: 0 });
|
|
1132
|
-
};
|
|
1133
|
-
const sources = await Promise.all(sourceParameters.urls.map(async (sourceInfo) => {
|
|
1134
|
-
var _a, _b, _c;
|
|
1135
|
-
const isRemote = ((_a = sourceInfo.url) === null || _a === void 0 ? void 0 : _a.startsWith('http://')) ||
|
|
1136
|
-
((_b = sourceInfo.url) === null || _b === void 0 ? void 0 : _b.startsWith('https://'));
|
|
1137
|
-
if (isRemote) {
|
|
1138
|
-
return Object.assign(Object.assign({}, addNoData(sourceInfo)), { min: sourceInfo.min, max: sourceInfo.max, url: sourceInfo.url });
|
|
1318
|
+
newSource = new GeoTIFFSource({
|
|
1319
|
+
interpolate: sourceParameters.interpolate,
|
|
1320
|
+
sources,
|
|
1321
|
+
normalize: sourceParameters.normalize,
|
|
1322
|
+
wrapX: sourceParameters.wrapX,
|
|
1323
|
+
});
|
|
1324
|
+
break;
|
|
1325
|
+
}
|
|
1326
|
+
case 'GeoPackageVectorSource': {
|
|
1327
|
+
const sourceParameters = source.parameters;
|
|
1328
|
+
if (!sourceParameters) {
|
|
1329
|
+
throw new Error('GeoPackageSource has no parameters');
|
|
1139
1330
|
}
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1331
|
+
const tableMap = await loadFile({
|
|
1332
|
+
filepath: sourceParameters.path,
|
|
1333
|
+
type: 'GeoPackageVectorSource',
|
|
1334
|
+
model: this._model,
|
|
1335
|
+
});
|
|
1336
|
+
const table = tableMap[sourceParameters.tables];
|
|
1337
|
+
const vectorSource = table.source;
|
|
1338
|
+
vectorSource['projection'] = getProjection(sourceParameters.projection);
|
|
1339
|
+
newSource = vectorSource;
|
|
1340
|
+
break;
|
|
1341
|
+
}
|
|
1342
|
+
case 'GeoPackageRasterSource': {
|
|
1343
|
+
const sourceParameters = source.parameters;
|
|
1344
|
+
if (!sourceParameters) {
|
|
1345
|
+
throw new Error('GeoPackageSource has no parameters');
|
|
1147
1346
|
}
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
})
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
}
|
|
1212
|
-
|
|
1213
|
-
|
|
1347
|
+
const tableMap = await loadFile({
|
|
1348
|
+
filepath: sourceParameters.path,
|
|
1349
|
+
type: 'GeoPackageRasterSource',
|
|
1350
|
+
model: this._model,
|
|
1351
|
+
});
|
|
1352
|
+
const { gpr, tileDao } = tableMap[sourceParameters.tables];
|
|
1353
|
+
const rasterSource = new XYZSource({
|
|
1354
|
+
minZoom: (_e = sourceParameters.minZoom) !== null && _e !== void 0 ? _e : tileDao.minWebMapZoom,
|
|
1355
|
+
maxZoom: (_f = sourceParameters.maxZoom) !== null && _f !== void 0 ? _f : tileDao.maxWebMapZoom,
|
|
1356
|
+
interpolate: sourceParameters.interpolate,
|
|
1357
|
+
url: '{z},{x},{y}',
|
|
1358
|
+
tileLoadFunction(tile, src) {
|
|
1359
|
+
const [z, x, y] = src.split(',').map(Number);
|
|
1360
|
+
gpr
|
|
1361
|
+
.getTile(x, y, z)
|
|
1362
|
+
.then((dataUri) => (tile.getImage().src = dataUri));
|
|
1363
|
+
},
|
|
1364
|
+
attributions: sourceParameters.attribution,
|
|
1365
|
+
});
|
|
1366
|
+
newSource = rasterSource;
|
|
1367
|
+
break;
|
|
1368
|
+
}
|
|
1369
|
+
case 'GeoParquetSource': {
|
|
1370
|
+
const parameters = source.parameters;
|
|
1371
|
+
const geojson = await loadFile({
|
|
1372
|
+
filepath: parameters.path,
|
|
1373
|
+
type: 'GeoParquetSource',
|
|
1374
|
+
model: this._model,
|
|
1375
|
+
});
|
|
1376
|
+
const geojsonData = Array.isArray(geojson) ? geojson[0] : geojson;
|
|
1377
|
+
const format = new GeoJSON();
|
|
1378
|
+
newSource = new VectorSource({
|
|
1379
|
+
features: format.readFeatures(geojsonData, {
|
|
1380
|
+
dataProjection: parameters.projection,
|
|
1381
|
+
featureProjection: this._Map.getView().getProjection(),
|
|
1382
|
+
}),
|
|
1383
|
+
});
|
|
1384
|
+
break;
|
|
1385
|
+
}
|
|
1386
|
+
case 'MarkerSource': {
|
|
1387
|
+
const parameters = source.parameters;
|
|
1388
|
+
const point = new Point(parameters.feature.coords);
|
|
1389
|
+
const marker = new Feature({
|
|
1390
|
+
type: 'icon',
|
|
1391
|
+
geometry: point,
|
|
1392
|
+
});
|
|
1393
|
+
// Replace color placeholder in SVG with the parameter color
|
|
1394
|
+
const markerColor = parameters.color || '#3463a0';
|
|
1395
|
+
const svgString = markerIcon.svgstr
|
|
1396
|
+
.replace('{{COLOR}}', markerColor)
|
|
1397
|
+
.replace('<svg', '<svg width="128" height="128"');
|
|
1398
|
+
const iconStyle = new Style({
|
|
1399
|
+
image: new Icon({
|
|
1400
|
+
src: `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svgString)}`,
|
|
1401
|
+
scale: 0.25,
|
|
1402
|
+
anchor: [0.5, 1],
|
|
1403
|
+
anchorXUnits: 'fraction',
|
|
1404
|
+
anchorYUnits: 'fraction',
|
|
1405
|
+
}),
|
|
1406
|
+
});
|
|
1407
|
+
marker.setStyle(iconStyle);
|
|
1408
|
+
newSource = new VectorSource({
|
|
1409
|
+
features: [marker],
|
|
1410
|
+
});
|
|
1411
|
+
break;
|
|
1412
|
+
}
|
|
1413
|
+
case 'WmsTileSource': {
|
|
1414
|
+
const sourceParameters = source.parameters;
|
|
1415
|
+
const url = sourceParameters.url;
|
|
1416
|
+
const selectedLayer = (_g = sourceParameters === null || sourceParameters === void 0 ? void 0 : sourceParameters.params) === null || _g === void 0 ? void 0 : _g.layers;
|
|
1417
|
+
newSource = new TileWMSSource({
|
|
1418
|
+
attributions: sourceParameters === null || sourceParameters === void 0 ? void 0 : sourceParameters.attribution,
|
|
1419
|
+
url,
|
|
1420
|
+
params: {
|
|
1421
|
+
LAYERS: selectedLayer,
|
|
1422
|
+
TILED: true,
|
|
1423
|
+
},
|
|
1424
|
+
});
|
|
1425
|
+
break;
|
|
1426
|
+
}
|
|
1214
1427
|
}
|
|
1215
1428
|
}
|
|
1429
|
+
catch (err) {
|
|
1430
|
+
this._log('error', `Failed to load source "${(_h = source.name) !== null && _h !== void 0 ? _h : id}" (${source.type}): ${err.message}`);
|
|
1431
|
+
return;
|
|
1432
|
+
}
|
|
1433
|
+
this._log('info', `Source "${(_j = source.name) !== null && _j !== void 0 ? _j : id}" (${source.type}) loaded successfully`);
|
|
1216
1434
|
newSource.set('id', id);
|
|
1435
|
+
// Forward OL tile/feature load errors to the JupyterLab log console.
|
|
1436
|
+
// These errors (CORS failures, network errors, etc.) are written directly
|
|
1437
|
+
// by the browser to DevTools and cannot be captured by console patching —
|
|
1438
|
+
// OL's own events are the only reliable interception point.
|
|
1439
|
+
newSource.on('tileloaderror', (evt) => {
|
|
1440
|
+
var _a, _b, _c;
|
|
1441
|
+
const url = (_c = (_b = (_a = evt === null || evt === void 0 ? void 0 : evt.tile) === null || _a === void 0 ? void 0 : _a.getKey) === null || _b === void 0 ? void 0 : _b.call(_a)) !== null && _c !== void 0 ? _c : '';
|
|
1442
|
+
this._log('error', `Tile load error for source "${id}"${url ? ': ' + url : ''}`);
|
|
1443
|
+
});
|
|
1444
|
+
newSource.on('featuresloaderror', () => {
|
|
1445
|
+
this._log('error', `Features load error for source "${id}"`);
|
|
1446
|
+
});
|
|
1217
1447
|
// _sources is a list of OpenLayers sources
|
|
1218
1448
|
this._sources[id] = newSource;
|
|
1449
|
+
this._trackSourceExtZoom(id, newSource);
|
|
1219
1450
|
}
|
|
1220
1451
|
computeSourceUrl(source) {
|
|
1221
1452
|
const parameters = source.parameters;
|
|
@@ -1286,8 +1517,11 @@ export class MainView extends React.Component {
|
|
|
1286
1517
|
for (let targetLayerPosition = 0; targetLayerPosition < layerIds.length; targetLayerPosition++) {
|
|
1287
1518
|
const layerId = layerIds[targetLayerPosition];
|
|
1288
1519
|
const layer = this._model.sharedModel.getLayer(layerId);
|
|
1520
|
+
if (this._loadingLayers.has(layerId)) {
|
|
1521
|
+
continue;
|
|
1522
|
+
}
|
|
1289
1523
|
if (!layer) {
|
|
1290
|
-
|
|
1524
|
+
this._log('warning', `Layer with ID ${layerId} does not exist in the shared model.`);
|
|
1291
1525
|
continue;
|
|
1292
1526
|
}
|
|
1293
1527
|
const mapLayer = this.getLayer(layerId);
|
|
@@ -1319,7 +1553,7 @@ export class MainView extends React.Component {
|
|
|
1319
1553
|
* @returns - the map layer.
|
|
1320
1554
|
*/
|
|
1321
1555
|
async _buildMapLayer(id, layer) {
|
|
1322
|
-
var _a, _b, _c;
|
|
1556
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
1323
1557
|
this.setState(old => (Object.assign(Object.assign({}, old), { loadingLayer: true })));
|
|
1324
1558
|
this._loadingLayers.add(id);
|
|
1325
1559
|
let newMapLayer;
|
|
@@ -1354,12 +1588,23 @@ export class MainView extends React.Component {
|
|
|
1354
1588
|
}
|
|
1355
1589
|
case 'VectorLayer': {
|
|
1356
1590
|
layerParameters = layer.parameters;
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1591
|
+
if (Array.isArray((_b = layerParameters.symbologyState) === null || _b === void 0 ? void 0 : _b.layers)) {
|
|
1592
|
+
const olSource = this._sources[layerParameters.source];
|
|
1593
|
+
const grammarState = layerParameters.symbologyState;
|
|
1594
|
+
const rows = olSource instanceof VectorSource
|
|
1595
|
+
? olSource.getFeatures().map(f => f.getProperties())
|
|
1596
|
+
: [];
|
|
1597
|
+
const featureValues = extractEncodingFieldValues(grammarState, rows);
|
|
1598
|
+
newMapLayer = grammarToOLLayer(layerParameters.symbologyState, olSource, layerParameters.opacity, layer.visible, featureValues);
|
|
1599
|
+
}
|
|
1600
|
+
else {
|
|
1601
|
+
newMapLayer = new VectorImageLayer({
|
|
1602
|
+
opacity: layerParameters.opacity,
|
|
1603
|
+
visible: layer.visible,
|
|
1604
|
+
source: this._sources[layerParameters.source],
|
|
1605
|
+
style: this.vectorLayerStyleRuleBuilder(layer),
|
|
1606
|
+
});
|
|
1607
|
+
}
|
|
1363
1608
|
break;
|
|
1364
1609
|
}
|
|
1365
1610
|
case 'VectorTileLayer': {
|
|
@@ -1374,7 +1619,7 @@ export class MainView extends React.Component {
|
|
|
1374
1619
|
}
|
|
1375
1620
|
case 'HillshadeLayer': {
|
|
1376
1621
|
layerParameters = layer.parameters;
|
|
1377
|
-
newMapLayer = new
|
|
1622
|
+
newMapLayer = new GeoTiffLayer({
|
|
1378
1623
|
opacity: 0.3,
|
|
1379
1624
|
visible: layer.visible,
|
|
1380
1625
|
source: this._sources[layerParameters.source],
|
|
@@ -1393,20 +1638,35 @@ export class MainView extends React.Component {
|
|
|
1393
1638
|
});
|
|
1394
1639
|
break;
|
|
1395
1640
|
}
|
|
1396
|
-
case '
|
|
1641
|
+
case 'OpenEOTileLayer': {
|
|
1397
1642
|
layerParameters = layer.parameters;
|
|
1398
|
-
|
|
1399
|
-
const layerOptions = {
|
|
1643
|
+
newMapLayer = new OpenEOTileLayer({
|
|
1400
1644
|
opacity: layerParameters.opacity,
|
|
1401
1645
|
visible: layer.visible,
|
|
1402
1646
|
source: this._sources[layerParameters.source],
|
|
1403
|
-
};
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1647
|
+
});
|
|
1648
|
+
break;
|
|
1649
|
+
}
|
|
1650
|
+
case 'GeoTiffLayer': {
|
|
1651
|
+
layerParameters = layer.parameters;
|
|
1652
|
+
const geoTiffSource = this._sources[layerParameters.source];
|
|
1653
|
+
if (Array.isArray((_c = layerParameters.symbologyState) === null || _c === void 0 ? void 0 : _c.layers)) {
|
|
1654
|
+
newMapLayer = grammarToOLLayer(layerParameters.symbologyState, geoTiffSource, (_d = layerParameters.opacity) !== null && _d !== void 0 ? _d : 1, (_e = layer.visible) !== null && _e !== void 0 ? _e : true, [], true);
|
|
1655
|
+
}
|
|
1656
|
+
else {
|
|
1657
|
+
// This is to handle python sending a None for the color
|
|
1658
|
+
const layerOptions = {
|
|
1659
|
+
opacity: layerParameters.opacity,
|
|
1660
|
+
visible: layer.visible,
|
|
1661
|
+
source: geoTiffSource,
|
|
1407
1662
|
};
|
|
1663
|
+
if (layerParameters.color) {
|
|
1664
|
+
layerOptions['style'] = {
|
|
1665
|
+
color: layerParameters.color,
|
|
1666
|
+
};
|
|
1667
|
+
}
|
|
1668
|
+
newMapLayer = new GeoTiffLayer(layerOptions);
|
|
1408
1669
|
}
|
|
1409
|
-
newMapLayer = new WebGlTileLayer(layerOptions);
|
|
1410
1670
|
break;
|
|
1411
1671
|
}
|
|
1412
1672
|
case 'HeatmapLayer': {
|
|
@@ -1415,9 +1675,9 @@ export class MainView extends React.Component {
|
|
|
1415
1675
|
opacity: layerParameters.opacity,
|
|
1416
1676
|
visible: layer.visible,
|
|
1417
1677
|
source: this._sources[layerParameters.source],
|
|
1418
|
-
blur: (
|
|
1419
|
-
radius: (
|
|
1420
|
-
gradient: layerParameters.
|
|
1678
|
+
blur: (_f = layerParameters.blur) !== null && _f !== void 0 ? _f : 15,
|
|
1679
|
+
radius: (_g = layerParameters.radius) !== null && _g !== void 0 ? _g : 8,
|
|
1680
|
+
gradient: (_h = layerParameters.symbologyState) === null || _h === void 0 ? void 0 : _h.gradient,
|
|
1421
1681
|
});
|
|
1422
1682
|
break;
|
|
1423
1683
|
}
|
|
@@ -1458,7 +1718,7 @@ export class MainView extends React.Component {
|
|
|
1458
1718
|
var _a;
|
|
1459
1719
|
const sourceProjection = (_a = newMapLayer.getSource()) === null || _a === void 0 ? void 0 : _a.getProjection();
|
|
1460
1720
|
if (!sourceProjection) {
|
|
1461
|
-
|
|
1721
|
+
this._log('warning', 'Layer source projection is undefined or invalid');
|
|
1462
1722
|
return;
|
|
1463
1723
|
}
|
|
1464
1724
|
const projectionCode = sourceProjection.getCode();
|
|
@@ -1466,7 +1726,7 @@ export class MainView extends React.Component {
|
|
|
1466
1726
|
if (!isProjectionRegistered) {
|
|
1467
1727
|
// Check if the projection exists in proj4list
|
|
1468
1728
|
if (!proj4list[projectionCode]) {
|
|
1469
|
-
|
|
1729
|
+
this._log('warning', `Projection code '${projectionCode}' not found in proj4list`);
|
|
1470
1730
|
return;
|
|
1471
1731
|
}
|
|
1472
1732
|
try {
|
|
@@ -1474,7 +1734,7 @@ export class MainView extends React.Component {
|
|
|
1474
1734
|
register(proj4);
|
|
1475
1735
|
}
|
|
1476
1736
|
catch (error) {
|
|
1477
|
-
|
|
1737
|
+
this._log('warning', `Failed to register projection '${projectionCode}'. Error: ${error.message}`);
|
|
1478
1738
|
return;
|
|
1479
1739
|
}
|
|
1480
1740
|
}
|
|
@@ -1499,12 +1759,14 @@ export class MainView extends React.Component {
|
|
|
1499
1759
|
const numLayers = this._Map.getLayers().getLength();
|
|
1500
1760
|
const safeIndex = Math.min(index, numLayers);
|
|
1501
1761
|
this._Map.getLayers().insertAt(safeIndex, newMapLayer);
|
|
1762
|
+
this._trackLayerViewState(id, newMapLayer);
|
|
1502
1763
|
// doing +1 instead of calling method again
|
|
1503
1764
|
if (!this.state.initialLayersReady &&
|
|
1504
1765
|
numLayers + 1 === this._initialLayersCount) {
|
|
1505
1766
|
this.setState(old => (Object.assign(Object.assign({}, old), { initialLayersReady: true })));
|
|
1506
1767
|
}
|
|
1507
1768
|
}
|
|
1769
|
+
this._model.syncSelected({ [id]: { type: 'layer' } }, this._model.getClientId().toString());
|
|
1508
1770
|
}
|
|
1509
1771
|
catch (error) {
|
|
1510
1772
|
if (this.state.loadingErrors.find(item => item.id === id && item.error === error.message)) {
|
|
@@ -1530,7 +1792,7 @@ export class MainView extends React.Component {
|
|
|
1530
1792
|
* @param layer - the layer object.
|
|
1531
1793
|
*/
|
|
1532
1794
|
async updateLayer(id, layer, mapLayer, oldLayer) {
|
|
1533
|
-
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
1795
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o;
|
|
1534
1796
|
layer.type !== 'StorySegmentLayer' && mapLayer.setVisible(layer.visible);
|
|
1535
1797
|
switch (layer.type) {
|
|
1536
1798
|
case 'RasterLayer': {
|
|
@@ -1539,6 +1801,11 @@ export class MainView extends React.Component {
|
|
|
1539
1801
|
}
|
|
1540
1802
|
case 'VectorLayer': {
|
|
1541
1803
|
const layerParams = layer.parameters;
|
|
1804
|
+
if (Array.isArray((_b = layerParams.symbologyState) === null || _b === void 0 ? void 0 : _b.layers)) {
|
|
1805
|
+
// Grammar layers may change structure (e.g. KDE added/removed) — rebuild.
|
|
1806
|
+
this.replaceLayer(id, layer);
|
|
1807
|
+
break;
|
|
1808
|
+
}
|
|
1542
1809
|
mapLayer.setOpacity(layerParams.opacity || 1);
|
|
1543
1810
|
mapLayer.setStyle(this.vectorLayerStyleRuleBuilder(layer));
|
|
1544
1811
|
break;
|
|
@@ -1556,33 +1823,50 @@ export class MainView extends React.Component {
|
|
|
1556
1823
|
case 'ImageLayer': {
|
|
1557
1824
|
break;
|
|
1558
1825
|
}
|
|
1559
|
-
case '
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1826
|
+
case 'GeoTiffLayer': {
|
|
1827
|
+
if (Array.isArray((_d = (_c = layer === null || layer === void 0 ? void 0 : layer.parameters) === null || _c === void 0 ? void 0 : _c.symbologyState) === null || _d === void 0 ? void 0 : _d.layers)) {
|
|
1828
|
+
this.replaceLayer(id, layer);
|
|
1829
|
+
}
|
|
1830
|
+
else {
|
|
1831
|
+
mapLayer.setOpacity((_e = layer.parameters) === null || _e === void 0 ? void 0 : _e.opacity);
|
|
1832
|
+
if ((_f = layer === null || layer === void 0 ? void 0 : layer.parameters) === null || _f === void 0 ? void 0 : _f.color) {
|
|
1833
|
+
mapLayer.setStyle({
|
|
1834
|
+
color: layer.parameters.color,
|
|
1835
|
+
});
|
|
1836
|
+
}
|
|
1565
1837
|
}
|
|
1566
1838
|
break;
|
|
1567
1839
|
}
|
|
1840
|
+
case 'OpenEOTileLayer': {
|
|
1841
|
+
const layerParams = layer.parameters;
|
|
1842
|
+
const openeoLayer = mapLayer;
|
|
1843
|
+
openeoLayer.setOpacity((_g = layerParams.opacity) !== null && _g !== void 0 ? _g : 1);
|
|
1844
|
+
break;
|
|
1845
|
+
}
|
|
1568
1846
|
case 'HeatmapLayer': {
|
|
1569
1847
|
const layerParams = layer.parameters;
|
|
1570
1848
|
const heatmap = mapLayer;
|
|
1571
|
-
heatmap.setOpacity((
|
|
1572
|
-
heatmap.setBlur((
|
|
1573
|
-
heatmap.setRadius((
|
|
1574
|
-
heatmap.setGradient((
|
|
1849
|
+
heatmap.setOpacity((_h = layerParams.opacity) !== null && _h !== void 0 ? _h : 1);
|
|
1850
|
+
heatmap.setBlur((_j = layerParams.blur) !== null && _j !== void 0 ? _j : 15);
|
|
1851
|
+
heatmap.setRadius((_k = layerParams.radius) !== null && _k !== void 0 ? _k : 8);
|
|
1852
|
+
heatmap.setGradient((_m = (_l = layerParams.symbologyState) === null || _l === void 0 ? void 0 : _l.gradient) !== null && _m !== void 0 ? _m : [
|
|
1853
|
+
'#00f',
|
|
1854
|
+
'#0ff',
|
|
1855
|
+
'#0f0',
|
|
1856
|
+
'#ff0',
|
|
1857
|
+
'#f00',
|
|
1858
|
+
]);
|
|
1575
1859
|
this.handleTemporalController(id, layer);
|
|
1576
1860
|
break;
|
|
1577
1861
|
}
|
|
1578
1862
|
case 'StacLayer':
|
|
1579
|
-
mapLayer.setOpacity(((
|
|
1863
|
+
mapLayer.setOpacity(((_o = layer.parameters) === null || _o === void 0 ? void 0 : _o.opacity) || 1);
|
|
1580
1864
|
break;
|
|
1581
1865
|
}
|
|
1582
1866
|
}
|
|
1583
1867
|
flyToGeometry(sender, geometry) {
|
|
1584
1868
|
if (!geometry || typeof geometry.getExtent !== 'function') {
|
|
1585
|
-
|
|
1869
|
+
this._log('warning', `Invalid geometry for flyToGeometry: ${geometry}`);
|
|
1586
1870
|
return;
|
|
1587
1871
|
}
|
|
1588
1872
|
const view = this._Map.getView();
|
|
@@ -1594,11 +1878,12 @@ export class MainView extends React.Component {
|
|
|
1594
1878
|
});
|
|
1595
1879
|
}
|
|
1596
1880
|
highlightFeatureOnMap(sender, featureOrGeometry) {
|
|
1881
|
+
var _a;
|
|
1597
1882
|
const geometry = (featureOrGeometry === null || featureOrGeometry === void 0 ? void 0 : featureOrGeometry.geometry) ||
|
|
1598
1883
|
(featureOrGeometry === null || featureOrGeometry === void 0 ? void 0 : featureOrGeometry._geometry) ||
|
|
1599
1884
|
featureOrGeometry;
|
|
1600
1885
|
if (!geometry) {
|
|
1601
|
-
|
|
1886
|
+
this._log('warning', `No geometry found in feature: ${featureOrGeometry}`);
|
|
1602
1887
|
return;
|
|
1603
1888
|
}
|
|
1604
1889
|
const isOlGeometry = typeof geometry.getCoordinates === 'function';
|
|
@@ -1608,63 +1893,128 @@ export class MainView extends React.Component {
|
|
|
1608
1893
|
featureProjection: this._Map.getView().getProjection(),
|
|
1609
1894
|
});
|
|
1610
1895
|
const olFeature = new Feature(Object.assign({ geometry: parsedGeometry }, (geometry !== featureOrGeometry ? featureOrGeometry : {})));
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
source: new VectorSource(),
|
|
1614
|
-
style: feature => {
|
|
1615
|
-
var _a;
|
|
1616
|
-
const geomType = (_a = feature.getGeometry()) === null || _a === void 0 ? void 0 : _a.getType();
|
|
1617
|
-
switch (geomType) {
|
|
1618
|
-
case 'Point':
|
|
1619
|
-
case 'MultiPoint':
|
|
1620
|
-
return new Style({
|
|
1621
|
-
image: new Circle({
|
|
1622
|
-
radius: 6,
|
|
1623
|
-
fill: new Fill({
|
|
1624
|
-
color: 'rgba(255, 255, 0, 0.8)',
|
|
1625
|
-
}),
|
|
1626
|
-
stroke: new Stroke({
|
|
1627
|
-
color: '#ff0',
|
|
1628
|
-
width: 2,
|
|
1629
|
-
}),
|
|
1630
|
-
}),
|
|
1631
|
-
});
|
|
1632
|
-
case 'LineString':
|
|
1633
|
-
case 'MultiLineString':
|
|
1634
|
-
return new Style({
|
|
1635
|
-
stroke: new Stroke({
|
|
1636
|
-
color: 'rgba(255, 255, 0, 0.8)',
|
|
1637
|
-
width: 3,
|
|
1638
|
-
}),
|
|
1639
|
-
});
|
|
1640
|
-
case 'Polygon':
|
|
1641
|
-
case 'MultiPolygon':
|
|
1642
|
-
return new Style({
|
|
1643
|
-
stroke: new Stroke({
|
|
1644
|
-
color: '#f00',
|
|
1645
|
-
width: 2,
|
|
1646
|
-
}),
|
|
1647
|
-
fill: new Fill({
|
|
1648
|
-
color: 'rgba(255, 255, 0, 0.8)',
|
|
1649
|
-
}),
|
|
1650
|
-
});
|
|
1651
|
-
default:
|
|
1652
|
-
return new Style({
|
|
1653
|
-
stroke: new Stroke({
|
|
1654
|
-
color: '#000',
|
|
1655
|
-
width: 2,
|
|
1656
|
-
}),
|
|
1657
|
-
});
|
|
1658
|
-
}
|
|
1659
|
-
},
|
|
1660
|
-
zIndex: 999,
|
|
1661
|
-
});
|
|
1662
|
-
this._Map.addLayer(this._highlightLayer);
|
|
1663
|
-
}
|
|
1664
|
-
const source = this._highlightLayer.getSource();
|
|
1896
|
+
this._ensureHighlightLayer();
|
|
1897
|
+
const source = (_a = this._highlightLayerRef.current) === null || _a === void 0 ? void 0 : _a.getSource();
|
|
1665
1898
|
source === null || source === void 0 ? void 0 : source.clear();
|
|
1666
1899
|
source === null || source === void 0 ? void 0 : source.addFeature(olFeature);
|
|
1667
1900
|
}
|
|
1901
|
+
_ensureHighlightLayer() {
|
|
1902
|
+
ensureHighlightLayer(this._Map, this._highlightLayerRef);
|
|
1903
|
+
}
|
|
1904
|
+
/**
|
|
1905
|
+
* Replace the highlight layer contents with the given geometries.
|
|
1906
|
+
* Clears the source first so that stale highlights are always removed,
|
|
1907
|
+
* including when the selection becomes empty (geometries = []).
|
|
1908
|
+
*/
|
|
1909
|
+
_setHighlightGeometries(geometries) {
|
|
1910
|
+
var _a;
|
|
1911
|
+
this._ensureHighlightLayer();
|
|
1912
|
+
const source = (_a = this._highlightLayerRef.current) === null || _a === void 0 ? void 0 : _a.getSource();
|
|
1913
|
+
source === null || source === void 0 ? void 0 : source.clear();
|
|
1914
|
+
for (const geom of geometries) {
|
|
1915
|
+
source === null || source === void 0 ? void 0 : source.addFeature(new Feature({ geometry: geom }));
|
|
1916
|
+
}
|
|
1917
|
+
}
|
|
1918
|
+
/**
|
|
1919
|
+
* Replace the highlight layer contents with pre-styled features.
|
|
1920
|
+
* Each feature carries its own highlight style via feature.setStyle().
|
|
1921
|
+
*/
|
|
1922
|
+
_setHighlightFeatures(features) {
|
|
1923
|
+
var _a;
|
|
1924
|
+
this._ensureHighlightLayer();
|
|
1925
|
+
const source = (_a = this._highlightLayerRef.current) === null || _a === void 0 ? void 0 : _a.getSource();
|
|
1926
|
+
source === null || source === void 0 ? void 0 : source.clear();
|
|
1927
|
+
for (const f of features) {
|
|
1928
|
+
source === null || source === void 0 ? void 0 : source.addFeature(f);
|
|
1929
|
+
}
|
|
1930
|
+
}
|
|
1931
|
+
_buildHighlightStyle(original, geomType) {
|
|
1932
|
+
return buildHighlightStyle(original, geomType);
|
|
1933
|
+
}
|
|
1934
|
+
/**
|
|
1935
|
+
* Compute extent for layer or source
|
|
1936
|
+
*/
|
|
1937
|
+
_computeExtent(layer, source) {
|
|
1938
|
+
try {
|
|
1939
|
+
if (source instanceof VectorSource) {
|
|
1940
|
+
const extent = source.getExtent();
|
|
1941
|
+
if (extent) {
|
|
1942
|
+
return extent;
|
|
1943
|
+
}
|
|
1944
|
+
}
|
|
1945
|
+
if (source instanceof TileSource || source instanceof VectorTileSource) {
|
|
1946
|
+
const tileGrid = source.getTileGrid();
|
|
1947
|
+
const extent = tileGrid === null || tileGrid === void 0 ? void 0 : tileGrid.getExtent();
|
|
1948
|
+
if (extent) {
|
|
1949
|
+
return extent;
|
|
1950
|
+
}
|
|
1951
|
+
}
|
|
1952
|
+
if (layer instanceof StacLayer) {
|
|
1953
|
+
const extent = layer.getExtent();
|
|
1954
|
+
if (extent) {
|
|
1955
|
+
return extent;
|
|
1956
|
+
}
|
|
1957
|
+
}
|
|
1958
|
+
}
|
|
1959
|
+
catch (error) {
|
|
1960
|
+
this._log('warning', `Failed to compute extent: ${error}`);
|
|
1961
|
+
}
|
|
1962
|
+
return undefined;
|
|
1963
|
+
}
|
|
1964
|
+
_computeZoomFromExtent(extent) {
|
|
1965
|
+
var _a, _b;
|
|
1966
|
+
if (!this._Map) {
|
|
1967
|
+
return null;
|
|
1968
|
+
}
|
|
1969
|
+
const view = this._Map.getView();
|
|
1970
|
+
const size = (_a = this._Map.getSize()) !== null && _a !== void 0 ? _a : getSize(extent);
|
|
1971
|
+
const resolution = view.getResolutionForExtent(extent, size);
|
|
1972
|
+
const zoom = view.getZoomForResolution(resolution);
|
|
1973
|
+
return (_b = zoom !== null && zoom !== void 0 ? zoom : view.getZoom()) !== null && _b !== void 0 ? _b : 0;
|
|
1974
|
+
}
|
|
1975
|
+
/**
|
|
1976
|
+
* Track layer's extent and zoom in model's view state
|
|
1977
|
+
*/
|
|
1978
|
+
_trackLayerViewState(layerId, olLayer) {
|
|
1979
|
+
var _a;
|
|
1980
|
+
const effectiveLayer = olLayer instanceof LayerGroup
|
|
1981
|
+
? olLayer.getLayers().getArray()[0]
|
|
1982
|
+
: olLayer;
|
|
1983
|
+
if (!effectiveLayer) {
|
|
1984
|
+
return;
|
|
1985
|
+
}
|
|
1986
|
+
const source = effectiveLayer.getSource();
|
|
1987
|
+
const sourceId = (_a = source === null || source === void 0 ? void 0 : source.get) === null || _a === void 0 ? void 0 : _a.call(source, 'id');
|
|
1988
|
+
let extent = sourceId ? this._model.getExtent(sourceId) : undefined;
|
|
1989
|
+
if (!extent) {
|
|
1990
|
+
extent = this._computeExtent(effectiveLayer, source);
|
|
1991
|
+
}
|
|
1992
|
+
if (extent) {
|
|
1993
|
+
const zoom = this._computeZoomFromExtent(extent);
|
|
1994
|
+
if (zoom === null) {
|
|
1995
|
+
return;
|
|
1996
|
+
}
|
|
1997
|
+
const view = { extent, zoom };
|
|
1998
|
+
this._model.updateLayerViewState(layerId, view);
|
|
1999
|
+
}
|
|
2000
|
+
}
|
|
2001
|
+
/**
|
|
2002
|
+
* Track source's extent and zoom in model's view state
|
|
2003
|
+
*/
|
|
2004
|
+
_trackSourceExtZoom(sourceId, olSource) {
|
|
2005
|
+
var _a, _b, _c;
|
|
2006
|
+
const extent = this._computeExtent(undefined, olSource);
|
|
2007
|
+
if (extent) {
|
|
2008
|
+
const projection = (_c = (_b = (_a = olSource === null || olSource === void 0 ? void 0 : olSource.getProjection) === null || _a === void 0 ? void 0 : _a.call(olSource)) === null || _b === void 0 ? void 0 : _b.getCode) === null || _c === void 0 ? void 0 : _c.call(_b);
|
|
2009
|
+
const zoom = this._computeZoomFromExtent(extent);
|
|
2010
|
+
if (zoom === null) {
|
|
2011
|
+
return;
|
|
2012
|
+
}
|
|
2013
|
+
const view = Object.assign({ extent,
|
|
2014
|
+
zoom }, (projection && { projection }));
|
|
2015
|
+
this._model.updateLayerViewState(sourceId, view);
|
|
2016
|
+
}
|
|
2017
|
+
}
|
|
1668
2018
|
/**
|
|
1669
2019
|
* Wait for all layers to be loaded.
|
|
1670
2020
|
*/
|
|
@@ -1716,6 +2066,133 @@ export class MainView extends React.Component {
|
|
|
1716
2066
|
this._Map.removeLayer(mapLayer);
|
|
1717
2067
|
}
|
|
1718
2068
|
}
|
|
2069
|
+
/**
|
|
2070
|
+
* Decide how selection changes should affect vector drawing state.
|
|
2071
|
+
*
|
|
2072
|
+
* This helper only computes whether
|
|
2073
|
+
* draw mode must be disabled (non-draw layer selected) and whether draw
|
|
2074
|
+
* interactions should be rebound (draw mode enabled and selected draw layer
|
|
2075
|
+
* changed).
|
|
2076
|
+
*/
|
|
2077
|
+
_getVectorDrawingSelectionDecision(layer, selectedLayerId) {
|
|
2078
|
+
const isDrawVectorLayer = this._model.checkIfIsADrawVectorLayer(layer);
|
|
2079
|
+
if (!isDrawVectorLayer) {
|
|
2080
|
+
return { disableEditing: true, shouldRebind: false };
|
|
2081
|
+
}
|
|
2082
|
+
if (!this._model.editingVectorLayer) {
|
|
2083
|
+
return { disableEditing: false, shouldRebind: false };
|
|
2084
|
+
}
|
|
2085
|
+
if (selectedLayerId === this._previousDrawLayerID) {
|
|
2086
|
+
return { disableEditing: false, shouldRebind: false };
|
|
2087
|
+
}
|
|
2088
|
+
return { disableEditing: false, shouldRebind: true };
|
|
2089
|
+
}
|
|
2090
|
+
_handleTemporalControllerActiveChanged() {
|
|
2091
|
+
var _a, _b, _c;
|
|
2092
|
+
const localState = this._model.localState;
|
|
2093
|
+
if (!localState) {
|
|
2094
|
+
return;
|
|
2095
|
+
}
|
|
2096
|
+
const isTemporalControllerActive = localState.isTemporalControllerActive === true;
|
|
2097
|
+
const selectedLayers = (_a = localState.selected) === null || _a === void 0 ? void 0 : _a.value;
|
|
2098
|
+
const selectedLayerId = selectedLayers
|
|
2099
|
+
? ((_b = Object.keys(selectedLayers)[0]) !== null && _b !== void 0 ? _b : null)
|
|
2100
|
+
: null;
|
|
2101
|
+
const layerType = selectedLayerId
|
|
2102
|
+
? (_c = this._model.getLayer(selectedLayerId)) === null || _c === void 0 ? void 0 : _c.type
|
|
2103
|
+
: null;
|
|
2104
|
+
const isSelectionValid = !!selectedLayers &&
|
|
2105
|
+
Object.keys(selectedLayers).length === 1 &&
|
|
2106
|
+
!this._model.getSource(selectedLayerId) &&
|
|
2107
|
+
['VectorLayer', 'HeatmapLayer'].includes(layerType !== null && layerType !== void 0 ? layerType : '');
|
|
2108
|
+
const displayTemporalController = isTemporalControllerActive && isSelectionValid;
|
|
2109
|
+
if (displayTemporalController !== this.state.displayTemporalController) {
|
|
2110
|
+
this.setState(old => (Object.assign(Object.assign({}, old), { displayTemporalController })));
|
|
2111
|
+
this._mainViewModel.commands.notifyCommandChanged(CommandIDs.temporalController);
|
|
2112
|
+
}
|
|
2113
|
+
}
|
|
2114
|
+
_handleRemoteUserChanged() {
|
|
2115
|
+
var _a, _b, _c;
|
|
2116
|
+
const localState = this._model.localState;
|
|
2117
|
+
if (!localState) {
|
|
2118
|
+
return;
|
|
2119
|
+
}
|
|
2120
|
+
const remoteUser = localState.remoteUser;
|
|
2121
|
+
const clients = this._model.sharedModel.awareness.getStates();
|
|
2122
|
+
// If we are in following mode, update UI and viewport from the remote user.
|
|
2123
|
+
if (remoteUser) {
|
|
2124
|
+
const remoteState = clients.get(remoteUser);
|
|
2125
|
+
if (!remoteState) {
|
|
2126
|
+
return;
|
|
2127
|
+
}
|
|
2128
|
+
if (((_a = remoteState.user) === null || _a === void 0 ? void 0 : _a.username) !== ((_b = this.state.remoteUser) === null || _b === void 0 ? void 0 : _b.username)) {
|
|
2129
|
+
this.setState(old => (Object.assign(Object.assign({}, old), { remoteUser: remoteState.user })));
|
|
2130
|
+
}
|
|
2131
|
+
const remoteViewport = remoteState.viewportState;
|
|
2132
|
+
if (remoteViewport.value) {
|
|
2133
|
+
const { x, y } = remoteViewport.value.coordinates;
|
|
2134
|
+
const zoom = remoteViewport.value.zoom;
|
|
2135
|
+
this._moveToPosition({ x, y }, zoom, 0);
|
|
2136
|
+
}
|
|
2137
|
+
return;
|
|
2138
|
+
}
|
|
2139
|
+
// If we are unfollowing, reset to local viewport and clear follow UI.
|
|
2140
|
+
if (this.state.remoteUser !== null) {
|
|
2141
|
+
this.setState(old => (Object.assign(Object.assign({}, old), { remoteUser: null })));
|
|
2142
|
+
const viewportState = (_c = localState.viewportState) === null || _c === void 0 ? void 0 : _c.value;
|
|
2143
|
+
if (viewportState) {
|
|
2144
|
+
this._moveToPosition(viewportState.coordinates, viewportState.zoom);
|
|
2145
|
+
}
|
|
2146
|
+
}
|
|
2147
|
+
}
|
|
2148
|
+
_handlePointerChanged() {
|
|
2149
|
+
const clients = this._model.sharedModel.awareness.getStates();
|
|
2150
|
+
const clientPointers = Object.assign({}, this.state.clientPointers);
|
|
2151
|
+
clients.forEach((client, clientId) => {
|
|
2152
|
+
var _a;
|
|
2153
|
+
if (!(client === null || client === void 0 ? void 0 : client.user) || this._model.getClientId() === clientId) {
|
|
2154
|
+
return;
|
|
2155
|
+
}
|
|
2156
|
+
const pointer = (_a = client.pointer) === null || _a === void 0 ? void 0 : _a.value;
|
|
2157
|
+
let currentClientPointer = clientPointers[clientId];
|
|
2158
|
+
if (pointer) {
|
|
2159
|
+
const pixel = this._Map.getPixelFromCoordinate([
|
|
2160
|
+
pointer.coordinates.x,
|
|
2161
|
+
pointer.coordinates.y,
|
|
2162
|
+
]);
|
|
2163
|
+
const lonLat = toLonLat([pointer.coordinates.x, pointer.coordinates.y]);
|
|
2164
|
+
if (!currentClientPointer) {
|
|
2165
|
+
currentClientPointer = {
|
|
2166
|
+
username: client.user.username,
|
|
2167
|
+
displayName: client.user.display_name,
|
|
2168
|
+
color: client.user.color,
|
|
2169
|
+
coordinates: {
|
|
2170
|
+
x: pixel[0],
|
|
2171
|
+
y: pixel[1],
|
|
2172
|
+
},
|
|
2173
|
+
lonLat: {
|
|
2174
|
+
longitude: lonLat[0],
|
|
2175
|
+
latitude: lonLat[1],
|
|
2176
|
+
},
|
|
2177
|
+
};
|
|
2178
|
+
}
|
|
2179
|
+
else {
|
|
2180
|
+
currentClientPointer = Object.assign(Object.assign({}, currentClientPointer), { coordinates: {
|
|
2181
|
+
x: pixel[0],
|
|
2182
|
+
y: pixel[1],
|
|
2183
|
+
}, lonLat: {
|
|
2184
|
+
longitude: lonLat[0],
|
|
2185
|
+
latitude: lonLat[1],
|
|
2186
|
+
} });
|
|
2187
|
+
}
|
|
2188
|
+
clientPointers[clientId] = currentClientPointer;
|
|
2189
|
+
}
|
|
2190
|
+
else {
|
|
2191
|
+
delete clientPointers[clientId];
|
|
2192
|
+
}
|
|
2193
|
+
});
|
|
2194
|
+
this.setState(old => (Object.assign(Object.assign({}, old), { clientPointers })));
|
|
2195
|
+
}
|
|
1719
2196
|
_onSharedOptionsChanged() {
|
|
1720
2197
|
if (!this._Map) {
|
|
1721
2198
|
return;
|
|
@@ -1781,7 +2258,7 @@ export class MainView extends React.Component {
|
|
|
1781
2258
|
view = new View({ projection: newProjection });
|
|
1782
2259
|
}
|
|
1783
2260
|
else {
|
|
1784
|
-
|
|
2261
|
+
this._log('warning', `Invalid projection: ${projection}`);
|
|
1785
2262
|
return;
|
|
1786
2263
|
}
|
|
1787
2264
|
}
|
|
@@ -1876,6 +2353,11 @@ export class MainView extends React.Component {
|
|
|
1876
2353
|
const { id, oldValue: oldLayer, newValue: newLayer } = change;
|
|
1877
2354
|
if (!newLayer || Object.keys(newLayer).length === 0) {
|
|
1878
2355
|
this.removeLayer(id);
|
|
2356
|
+
if (this._model.checkIfIsADrawVectorLayer(oldLayer)) {
|
|
2357
|
+
this._model.editingVectorLayer = false;
|
|
2358
|
+
this._updateEditingVectorLayer();
|
|
2359
|
+
this._mainViewModel.commands.notifyCommandChanged(CommandIDs.toggleDrawFeatures);
|
|
2360
|
+
}
|
|
1879
2361
|
return;
|
|
1880
2362
|
}
|
|
1881
2363
|
if (oldLayer && oldLayer.type !== newLayer.type) {
|
|
@@ -1886,6 +2368,9 @@ export class MainView extends React.Component {
|
|
|
1886
2368
|
const layerTree = JupyterGISModel.getOrderedLayerIds(this._model);
|
|
1887
2369
|
if (layerTree.includes(id)) {
|
|
1888
2370
|
this.updateLayer(id, newLayer, mapLayer, oldLayer);
|
|
2371
|
+
if (mapLayer) {
|
|
2372
|
+
this._trackLayerViewState(id, mapLayer);
|
|
2373
|
+
}
|
|
1889
2374
|
}
|
|
1890
2375
|
else {
|
|
1891
2376
|
this.updateLayers(layerTree);
|
|
@@ -1914,6 +2399,14 @@ export class MainView extends React.Component {
|
|
|
1914
2399
|
}
|
|
1915
2400
|
}
|
|
1916
2401
|
});
|
|
2402
|
+
this.setState(old => (Object.assign(Object.assign({}, old), { identifyFeatureFloatersVersion: old.identifyFeatureFloatersVersion + 1 })));
|
|
2403
|
+
}
|
|
2404
|
+
_clearHighlightWhenIdentifyDisabled() {
|
|
2405
|
+
var _a, _b;
|
|
2406
|
+
if (this._model.currentMode !== 'identifying' &&
|
|
2407
|
+
this._highlightLayerRef.current) {
|
|
2408
|
+
(_b = (_a = this._highlightLayerRef.current) === null || _a === void 0 ? void 0 : _a.getSource()) === null || _b === void 0 ? void 0 : _b.clear();
|
|
2409
|
+
}
|
|
1917
2410
|
}
|
|
1918
2411
|
_computeAnnotationPosition(annotation) {
|
|
1919
2412
|
const { x, y } = annotation.position;
|
|
@@ -1938,6 +2431,58 @@ export class MainView extends React.Component {
|
|
|
1938
2431
|
}
|
|
1939
2432
|
});
|
|
1940
2433
|
}
|
|
2434
|
+
_computeFeatureFloaterPosition(feature) {
|
|
2435
|
+
var _a;
|
|
2436
|
+
const geometry = (_a = feature === null || feature === void 0 ? void 0 : feature.geometry) !== null && _a !== void 0 ? _a : feature === null || feature === void 0 ? void 0 : feature._geometry;
|
|
2437
|
+
if (!geometry) {
|
|
2438
|
+
return undefined;
|
|
2439
|
+
}
|
|
2440
|
+
if (typeof geometry.getExtent === 'function') {
|
|
2441
|
+
const extent = geometry.getExtent();
|
|
2442
|
+
const center = getCenter(extent);
|
|
2443
|
+
const pixels = this._Map.getPixelFromCoordinate(center);
|
|
2444
|
+
if (pixels) {
|
|
2445
|
+
return { x: pixels[0], y: pixels[1] };
|
|
2446
|
+
}
|
|
2447
|
+
return undefined;
|
|
2448
|
+
}
|
|
2449
|
+
if (geometry.type === 'Point' && Array.isArray(geometry.coordinates)) {
|
|
2450
|
+
const pixels = this._Map.getPixelFromCoordinate(geometry.coordinates);
|
|
2451
|
+
if (pixels) {
|
|
2452
|
+
return { x: pixels[0], y: pixels[1] };
|
|
2453
|
+
}
|
|
2454
|
+
}
|
|
2455
|
+
return undefined;
|
|
2456
|
+
}
|
|
2457
|
+
_getVisibleDrawIdentifiedFeatures() {
|
|
2458
|
+
var _a, _b, _c;
|
|
2459
|
+
const identifiedFeatures = (_c = (_b = (_a = this._model.localState) === null || _a === void 0 ? void 0 : _a.identifiedFeatures) === null || _b === void 0 ? void 0 : _b.value) !== null && _c !== void 0 ? _c : [];
|
|
2460
|
+
const drawEntries = identifiedFeatures.filter(entry => entry.floaterOpen === true);
|
|
2461
|
+
const visibleFeatures = drawEntries
|
|
2462
|
+
.map(entry => {
|
|
2463
|
+
const featureId = getFeatureIdentifier(entry.feature);
|
|
2464
|
+
if (!featureId) {
|
|
2465
|
+
return undefined;
|
|
2466
|
+
}
|
|
2467
|
+
return [featureId, entry.feature];
|
|
2468
|
+
})
|
|
2469
|
+
.filter((entry) => !!entry);
|
|
2470
|
+
return visibleFeatures;
|
|
2471
|
+
}
|
|
2472
|
+
_updateFeatureFloaters() {
|
|
2473
|
+
this._getVisibleDrawIdentifiedFeatures().forEach(([floaterKey, feature]) => {
|
|
2474
|
+
const el = document.getElementById(`feature-floater-${floaterKey}`);
|
|
2475
|
+
if (!el) {
|
|
2476
|
+
return;
|
|
2477
|
+
}
|
|
2478
|
+
const screenPosition = this._computeFeatureFloaterPosition(feature);
|
|
2479
|
+
if (!screenPosition) {
|
|
2480
|
+
return;
|
|
2481
|
+
}
|
|
2482
|
+
el.style.left = `${Math.round(screenPosition.x)}px`;
|
|
2483
|
+
el.style.top = `${Math.round(screenPosition.y)}px`;
|
|
2484
|
+
});
|
|
2485
|
+
}
|
|
1941
2486
|
// TODO this and flyToPosition need a rework
|
|
1942
2487
|
_onZoomToPosition(_, id) {
|
|
1943
2488
|
var _a, _b, _c;
|
|
@@ -1948,7 +2493,6 @@ export class MainView extends React.Component {
|
|
|
1948
2493
|
return;
|
|
1949
2494
|
}
|
|
1950
2495
|
// The id is a layer
|
|
1951
|
-
let extent;
|
|
1952
2496
|
const layer = this.getLayer(id);
|
|
1953
2497
|
const source = layer === null || layer === void 0 ? void 0 : layer.getSource();
|
|
1954
2498
|
const jgisLayer = this._model.getLayer(id);
|
|
@@ -1998,19 +2542,13 @@ export class MainView extends React.Component {
|
|
|
1998
2542
|
return;
|
|
1999
2543
|
}
|
|
2000
2544
|
}
|
|
2001
|
-
|
|
2002
|
-
extent = source.getExtent();
|
|
2003
|
-
}
|
|
2004
|
-
if (source instanceof TileSource) {
|
|
2005
|
-
// Tiled sources don't have getExtent() so we get it from the grid
|
|
2006
|
-
const tileGrid = source.getTileGrid();
|
|
2007
|
-
extent = tileGrid === null || tileGrid === void 0 ? void 0 : tileGrid.getExtent();
|
|
2008
|
-
}
|
|
2009
|
-
if (layer instanceof StacLayer) {
|
|
2010
|
-
extent = layer.getExtent();
|
|
2011
|
-
}
|
|
2545
|
+
const extent = this._computeExtent(layer, source);
|
|
2012
2546
|
if (!extent) {
|
|
2013
|
-
|
|
2547
|
+
this._log('warning', 'Layer ${id} has no extent.');
|
|
2548
|
+
return;
|
|
2549
|
+
}
|
|
2550
|
+
if (!extent.every(value => Number.isFinite(value))) {
|
|
2551
|
+
this._log('warning', `Layer ${id} has an invalid extent: ${extent.join(', ')}`);
|
|
2014
2552
|
return;
|
|
2015
2553
|
}
|
|
2016
2554
|
// Convert layer extent value to view projection if needed
|
|
@@ -2019,6 +2557,10 @@ export class MainView extends React.Component {
|
|
|
2019
2557
|
const transformedExtent = sourceProjection && sourceProjection !== viewProjection
|
|
2020
2558
|
? transformExtent(extent, sourceProjection, viewProjection)
|
|
2021
2559
|
: extent;
|
|
2560
|
+
if (!transformedExtent.every(value => Number.isFinite(value))) {
|
|
2561
|
+
this._log('warning', `Layer ${id} has an invalid transformed extent: ${transformedExtent.join(', ')}`);
|
|
2562
|
+
return;
|
|
2563
|
+
}
|
|
2022
2564
|
this._Map.getView().fit(transformedExtent, {
|
|
2023
2565
|
size: this._Map.getSize(),
|
|
2024
2566
|
duration: 500,
|
|
@@ -2082,7 +2624,8 @@ export class MainView extends React.Component {
|
|
|
2082
2624
|
this._syncPointer(coordinates);
|
|
2083
2625
|
}
|
|
2084
2626
|
async _addMarker(e) {
|
|
2085
|
-
if (this.
|
|
2627
|
+
if (this.state.editingVectorLayer ||
|
|
2628
|
+
this._model.currentMode !== 'marking') {
|
|
2086
2629
|
return;
|
|
2087
2630
|
}
|
|
2088
2631
|
const coordinate = this._Map.getCoordinateFromPixel(e.pixel);
|
|
@@ -2094,7 +2637,7 @@ export class MainView extends React.Component {
|
|
|
2094
2637
|
const layerParams = {
|
|
2095
2638
|
opacity: 1.0,
|
|
2096
2639
|
source: sourceId,
|
|
2097
|
-
symbologyState: {
|
|
2640
|
+
symbologyState: { layers: [] },
|
|
2098
2641
|
};
|
|
2099
2642
|
const sourceModel = {
|
|
2100
2643
|
type: 'MarkerSource',
|
|
@@ -2114,25 +2657,29 @@ export class MainView extends React.Component {
|
|
|
2114
2657
|
}
|
|
2115
2658
|
_identifyFeature(e) {
|
|
2116
2659
|
var _a, _b;
|
|
2117
|
-
if (this.
|
|
2660
|
+
if (this.state.editingVectorLayer ||
|
|
2661
|
+
this._model.currentMode !== 'identifying') {
|
|
2118
2662
|
return;
|
|
2119
2663
|
}
|
|
2120
2664
|
const localState = (_a = this._model) === null || _a === void 0 ? void 0 : _a.sharedModel.awareness.getLocalState();
|
|
2121
2665
|
const selectedLayer = (_b = localState === null || localState === void 0 ? void 0 : localState.selected) === null || _b === void 0 ? void 0 : _b.value;
|
|
2122
2666
|
if (!selectedLayer) {
|
|
2123
|
-
|
|
2667
|
+
this._log('warning', 'Layer must be selected to use identify tool');
|
|
2124
2668
|
return;
|
|
2125
2669
|
}
|
|
2126
2670
|
const layerId = Object.keys(selectedLayer)[0];
|
|
2127
2671
|
const jgisLayer = this._model.getLayer(layerId);
|
|
2128
2672
|
switch (jgisLayer === null || jgisLayer === void 0 ? void 0 : jgisLayer.type) {
|
|
2673
|
+
case 'VectorLayer':
|
|
2674
|
+
// Handled by selectInteraction (createSelectInteraction).
|
|
2675
|
+
break;
|
|
2129
2676
|
case 'VectorTileLayer': {
|
|
2130
2677
|
const geometries = [];
|
|
2131
2678
|
const features = [];
|
|
2132
|
-
let
|
|
2679
|
+
let foundAnyFeatures = false;
|
|
2133
2680
|
this._Map.forEachFeatureAtPixel(e.pixel, (feature) => {
|
|
2134
2681
|
var _a, _b;
|
|
2135
|
-
|
|
2682
|
+
foundAnyFeatures = true;
|
|
2136
2683
|
let geom;
|
|
2137
2684
|
let props = {};
|
|
2138
2685
|
if (feature instanceof RenderFeature) {
|
|
@@ -2158,15 +2705,18 @@ export class MainView extends React.Component {
|
|
|
2158
2705
|
geometries.push(geom);
|
|
2159
2706
|
}
|
|
2160
2707
|
if (props && Object.keys(props).length > 0) {
|
|
2161
|
-
features.push(
|
|
2708
|
+
features.push({
|
|
2709
|
+
feature: props,
|
|
2710
|
+
floaterOpen: false,
|
|
2711
|
+
});
|
|
2162
2712
|
}
|
|
2163
2713
|
return true;
|
|
2164
2714
|
});
|
|
2165
2715
|
if (features.length > 0) {
|
|
2166
|
-
this._model.syncIdentifiedFeatures(features, this.
|
|
2716
|
+
this._model.syncIdentifiedFeatures(features, this._model.getClientId().toString());
|
|
2167
2717
|
}
|
|
2168
|
-
else if (!
|
|
2169
|
-
this._model.syncIdentifiedFeatures([], this.
|
|
2718
|
+
else if (!foundAnyFeatures) {
|
|
2719
|
+
this._model.syncIdentifiedFeatures([], this._model.getClientId().toString());
|
|
2170
2720
|
}
|
|
2171
2721
|
if (geometries.length > 0) {
|
|
2172
2722
|
for (const geom of geometries) {
|
|
@@ -2180,7 +2730,7 @@ export class MainView extends React.Component {
|
|
|
2180
2730
|
}
|
|
2181
2731
|
break;
|
|
2182
2732
|
}
|
|
2183
|
-
case '
|
|
2733
|
+
case 'GeoTiffLayer': {
|
|
2184
2734
|
const layer = this.getLayer(layerId);
|
|
2185
2735
|
const data = layer.getData(e.pixel);
|
|
2186
2736
|
// TODO: Handle dataviews?
|
|
@@ -2194,7 +2744,7 @@ export class MainView extends React.Component {
|
|
|
2194
2744
|
}
|
|
2195
2745
|
// last element is alpha
|
|
2196
2746
|
bandValues['Alpha'] = data[data.length - 1];
|
|
2197
|
-
this._model.syncIdentifiedFeatures([bandValues], this._mainViewModel.id);
|
|
2747
|
+
this._model.syncIdentifiedFeatures([{ feature: bandValues, floaterOpen: false }], this._mainViewModel.id);
|
|
2198
2748
|
const coordinate = this._Map.getCoordinateFromPixel(e.pixel);
|
|
2199
2749
|
const point = new Point(coordinate);
|
|
2200
2750
|
// trigger highlight via signal
|
|
@@ -2213,7 +2763,7 @@ export class MainView extends React.Component {
|
|
|
2213
2763
|
this.updateSource(layerId, jgisLayer);
|
|
2214
2764
|
}
|
|
2215
2765
|
if (!jgisLayer || !olLayer) {
|
|
2216
|
-
|
|
2766
|
+
this._log('error', 'Failed to update layer -- layer not found');
|
|
2217
2767
|
return;
|
|
2218
2768
|
}
|
|
2219
2769
|
this.updateLayer(layerId, jgisLayer, olLayer);
|
|
@@ -2223,6 +2773,9 @@ export class MainView extends React.Component {
|
|
|
2223
2773
|
const { id: layerId, selectedFeature } = json;
|
|
2224
2774
|
const olLayer = this.getLayer(layerId);
|
|
2225
2775
|
const source = olLayer.getSource();
|
|
2776
|
+
if (typeof source.forEachFeature !== 'function') {
|
|
2777
|
+
return;
|
|
2778
|
+
}
|
|
2226
2779
|
source.forEachFeature(feature => {
|
|
2227
2780
|
const time = feature.get(selectedFeature);
|
|
2228
2781
|
const parsedTime = typeof time === 'string' ? Date.parse(time) : time;
|
|
@@ -2239,7 +2792,19 @@ export class MainView extends React.Component {
|
|
|
2239
2792
|
throw new Error('Could not move to geolocation, because current zoom is not defined.');
|
|
2240
2793
|
}
|
|
2241
2794
|
}
|
|
2795
|
+
_updateEditingVectorLayer() {
|
|
2796
|
+
const editingVectorLayer = this._model.editingVectorLayer;
|
|
2797
|
+
this.setState(old => (Object.assign(Object.assign({}, old), { editingVectorLayer })));
|
|
2798
|
+
if (editingVectorLayer === true) {
|
|
2799
|
+
this._editVectorLayer();
|
|
2800
|
+
}
|
|
2801
|
+
if (editingVectorLayer === false && this._draw) {
|
|
2802
|
+
this._removeDrawInteraction();
|
|
2803
|
+
this._currentDrawLayerID = undefined;
|
|
2804
|
+
}
|
|
2805
|
+
}
|
|
2242
2806
|
render() {
|
|
2807
|
+
var _a, _b, _c;
|
|
2243
2808
|
return (React.createElement(React.Fragment, null,
|
|
2244
2809
|
Object.entries(this.state.annotations).map(([key, annotation]) => {
|
|
2245
2810
|
if (!this._model.annotationModel) {
|
|
@@ -2252,6 +2817,21 @@ export class MainView extends React.Component {
|
|
|
2252
2817
|
}, className: 'jGIS-Popup-Wrapper' },
|
|
2253
2818
|
React.createElement(AnnotationFloater, { itemId: key, annotationModel: this._model.annotationModel }))));
|
|
2254
2819
|
}),
|
|
2820
|
+
this._getVisibleDrawIdentifiedFeatures().map(([floaterKey, feature]) => {
|
|
2821
|
+
const screenPosition = this._computeFeatureFloaterPosition(feature);
|
|
2822
|
+
if (!screenPosition) {
|
|
2823
|
+
return null;
|
|
2824
|
+
}
|
|
2825
|
+
return (React.createElement("div", { key: `feature-floater-${floaterKey}`, id: `feature-floater-${floaterKey}`, style: {
|
|
2826
|
+
left: screenPosition.x,
|
|
2827
|
+
top: screenPosition.y,
|
|
2828
|
+
}, className: "jGIS-Popup-Wrapper jGIS-FeatureFloater-Wrapper" },
|
|
2829
|
+
React.createElement(FeatureFloater, { feature: feature })));
|
|
2830
|
+
}),
|
|
2831
|
+
this.state.editingVectorLayer && (React.createElement("div", { className: "jgis-geometry-type-selector-overlay" },
|
|
2832
|
+
React.createElement("select", { className: "geometry-type-selector", id: "geometry-type-selector", value: (_a = this.state.drawGeometryLabel) !== null && _a !== void 0 ? _a : '', onChange: this._handleDrawGeometryTypeChange },
|
|
2833
|
+
React.createElement("option", { value: "", disabled: true, hidden: true }, "Geometry type"),
|
|
2834
|
+
DRAW_GEOMETRIES.map(geometryType => (React.createElement("option", { key: geometryType, value: geometryType }, geometryType)))))),
|
|
2255
2835
|
React.createElement("div", { className: "jGIS-Mainview-Container" },
|
|
2256
2836
|
this.state.displayTemporalController && (React.createElement(TemporalSlider, { model: this._model, filterStates: this.state.filterStates })),
|
|
2257
2837
|
React.createElement("div", { ref: this.mainViewRef, className: "jGIS-Mainview data-jgis-keybinding", tabIndex: 0, style: {
|
|
@@ -2266,16 +2846,46 @@ export class MainView extends React.Component {
|
|
|
2266
2846
|
React.createElement(LoadingOverlay, { loading: this.state.loading }),
|
|
2267
2847
|
React.createElement(FollowIndicator, { remoteUser: this.state.remoteUser }),
|
|
2268
2848
|
React.createElement(CollaboratorPointers, { clients: this.state.clientPointers }),
|
|
2269
|
-
React.createElement("div", { ref: this.divRef, style: {
|
|
2849
|
+
React.createElement("div", { ref: this.divRef, className: "jgis-mainview-stage", style: {
|
|
2270
2850
|
width: '100%',
|
|
2271
2851
|
height: '100%',
|
|
2852
|
+
position: 'relative',
|
|
2272
2853
|
} },
|
|
2273
|
-
React.createElement(
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2854
|
+
React.createElement(ListStoryScrollTrackProvider, { model: this._model, enabled: this.state.isSpectaPresentation &&
|
|
2855
|
+
((_b = this._model.getSelectedStory().story) === null || _b === void 0 ? void 0 : _b.storyType) ===
|
|
2856
|
+
STORY_TYPE.verticalScroll },
|
|
2857
|
+
this.state.isSpectaPresentation &&
|
|
2858
|
+
((_c = this._model.getSelectedStory().story) === null || _c === void 0 ? void 0 : _c.storyType) ===
|
|
2859
|
+
STORY_TYPE.verticalScroll ? (React.createElement(ListStoryStageOverlay, { model: this._model, segmentTransition: this.state.segmentTransition })) : null,
|
|
2860
|
+
React.createElement("div", { className: "jgis-panels-wrapper" }, !this.state.isSpectaPresentation ? (React.createElement(React.Fragment, null, this.props.isMobile &&
|
|
2861
|
+
this._state &&
|
|
2862
|
+
this._formSchemaRegistry &&
|
|
2863
|
+
this._annotationModel ? (React.createElement(MergedPanel, { model: this._model, commands: this._mainViewModel.commands, state: this._state, settings: this.state.jgisSettings, formSchemaRegistry: this._formSchemaRegistry, annotationModel: this._annotationModel, addLayer: this.addLayer.bind(this), removeLayer: this.removeLayer.bind(this) })) : (React.createElement(React.Fragment, null,
|
|
2864
|
+
this._state && (React.createElement(LeftPanel, { model: this._model, commands: this._mainViewModel.commands, state: this._state, settings: this.state.jgisSettings })),
|
|
2865
|
+
this._formSchemaRegistry &&
|
|
2866
|
+
this._annotationModel && (React.createElement(RightPanel, { model: this._model, commands: this._mainViewModel.commands, formSchemaRegistry: this._formSchemaRegistry, annotationModel: this._annotationModel, addLayer: this.addLayer.bind(this), removeLayer: this.removeLayer.bind(this), settings: this.state.jgisSettings, patchGeoJSONFeatureProperties: this._patchGeoJSONFeatureProperties })))))) : (this.state.initialLayersReady && (React.createElement(SpectaPanel, { model: this._model, isSpecta: this.state.isSpectaPresentation, isMobile: this.props.isMobile, onSegmentTransitionEnd: () => this._clearStoryScrollGuard(), containerRef: this.spectaContainerRef, storyViewerPanelRef: this.storyViewerPanelRef, addLayer: this._addLayerForPanels, removeLayer: this._removeLayerForPanels, onSegmentTransitionChange: this._handleSegmentTransitionChange })))),
|
|
2867
|
+
React.createElement("div", { ref: this.controlsToolbarRef, className: "jgis-controls-toolbar" })))),
|
|
2277
2868
|
!this.state.isSpectaPresentation && (React.createElement(StatusBar, { jgisModel: this._model, loading: this.state.loadingLayer, projection: this.state.viewProjection, scale: this.state.scale })))));
|
|
2278
2869
|
}
|
|
2870
|
+
_log(level, message) {
|
|
2871
|
+
var _a;
|
|
2872
|
+
// Always mirror to the browser console regardless of whether the JupyterLab
|
|
2873
|
+
// logger is available.
|
|
2874
|
+
if (level === 'error' || level === 'critical') {
|
|
2875
|
+
// eslint-disable-next-line no-console
|
|
2876
|
+
console.error(message);
|
|
2877
|
+
}
|
|
2878
|
+
else if (level === 'warning') {
|
|
2879
|
+
// eslint-disable-next-line no-console
|
|
2880
|
+
console.warn(message);
|
|
2881
|
+
}
|
|
2882
|
+
else {
|
|
2883
|
+
// eslint-disable-next-line no-console
|
|
2884
|
+
console.log(message);
|
|
2885
|
+
}
|
|
2886
|
+
// Forward to JupyterLab log console when available.
|
|
2887
|
+
(_a = this._loggerRegistry) === null || _a === void 0 ? void 0 : _a.getLogger(this._model.filePath).log({ type: 'text', level, data: message });
|
|
2888
|
+
}
|
|
2279
2889
|
}
|
|
2280
2890
|
// ! TODO make mainview a modern react component instead of a class
|
|
2281
2891
|
/** Thin wrapper that injects isMobile from useMediaQuery so MainView can use it in JSX. */
|