@jupytergis/base 0.13.3 → 0.14.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 +14 -13
- package/lib/commands/BaseCommandIDs.js +14 -14
- package/lib/commands/index.js +523 -117
- package/lib/commands/operationCommands.d.ts +22 -0
- package/lib/commands/operationCommands.js +305 -0
- package/lib/constants.js +9 -9
- package/lib/dialogs/ProcessingFormDialog.d.ts +1 -1
- package/lib/dialogs/ProcessingFormDialog.js +2 -2
- package/lib/dialogs/layerBrowserDialog.d.ts +2 -0
- package/lib/dialogs/layerBrowserDialog.js +12 -5
- package/lib/dialogs/layerCreationFormDialog.d.ts +7 -0
- package/lib/dialogs/layerCreationFormDialog.js +10 -2
- package/lib/dialogs/symbology/components/color_ramp/ColorRampControls.d.ts +2 -1
- package/lib/dialogs/symbology/components/color_ramp/ColorRampControls.js +21 -19
- package/lib/dialogs/symbology/components/color_ramp/ColorRampSelector.d.ts +3 -1
- package/lib/dialogs/symbology/components/color_ramp/ColorRampSelector.js +13 -5
- package/lib/dialogs/symbology/tiff_layer/types/SingleBandPseudoColor.js +6 -4
- package/lib/dialogs/symbology/vector_layer/types/Categorized.js +7 -11
- package/lib/dialogs/symbology/vector_layer/types/Graduated.js +7 -10
- package/lib/dialogs/symbology/vector_layer/types/Heatmap.js +7 -8
- package/lib/formbuilder/creationform.d.ts +8 -8
- package/lib/formbuilder/creationform.js +130 -85
- package/lib/formbuilder/editform.d.ts +1 -7
- package/lib/formbuilder/editform.js +64 -52
- package/lib/formbuilder/formselectors.d.ts +5 -4
- package/lib/formbuilder/index.d.ts +1 -1
- package/lib/formbuilder/index.js +1 -1
- package/lib/formbuilder/objectform/SchemaForm.d.ts +36 -0
- package/lib/formbuilder/objectform/SchemaForm.js +77 -0
- package/lib/formbuilder/objectform/StoryEditorForm.d.ts +3 -9
- package/lib/formbuilder/objectform/StoryEditorForm.js +20 -14
- package/lib/formbuilder/objectform/components/LayerSelect.js +3 -8
- package/lib/formbuilder/objectform/components/SegmentFormSymbology.js +23 -10
- package/lib/formbuilder/objectform/components/SourcePropertiesField.d.ts +7 -0
- package/lib/formbuilder/objectform/components/SourcePropertiesField.js +29 -0
- package/lib/formbuilder/objectform/components/StorySegmentReset.js +1 -1
- package/lib/formbuilder/objectform/fileselectorwidget.js +1 -1
- package/lib/formbuilder/objectform/layer/heatmapLayerForm.d.ts +3 -12
- package/lib/formbuilder/objectform/layer/heatmapLayerForm.js +87 -55
- package/lib/formbuilder/objectform/layer/hillshadeLayerForm.d.ts +3 -8
- package/lib/formbuilder/objectform/layer/hillshadeLayerForm.js +36 -10
- package/lib/formbuilder/objectform/layer/layerform.d.ts +7 -9
- package/lib/formbuilder/objectform/layer/layerform.js +33 -20
- package/lib/formbuilder/objectform/layer/storySegmentLayerForm.d.ts +3 -5
- package/lib/formbuilder/objectform/layer/storySegmentLayerForm.js +73 -29
- package/lib/formbuilder/objectform/layer/vectorlayerform.d.ts +3 -14
- package/lib/formbuilder/objectform/layer/vectorlayerform.js +36 -29
- package/lib/formbuilder/objectform/layer/webGlLayerForm.d.ts +3 -10
- package/lib/formbuilder/objectform/layer/webGlLayerForm.js +37 -13
- package/lib/formbuilder/objectform/process/dissolveProcessForm.d.ts +8 -18
- package/lib/formbuilder/objectform/process/dissolveProcessForm.js +68 -56
- package/lib/formbuilder/objectform/processingForm.d.ts +12 -0
- package/lib/formbuilder/objectform/processingForm.js +33 -0
- package/lib/formbuilder/objectform/schemaUtils.d.ts +16 -0
- package/lib/formbuilder/objectform/schemaUtils.js +59 -0
- package/lib/formbuilder/objectform/source/geojsonsource.d.ts +3 -19
- package/lib/formbuilder/objectform/source/geojsonsource.js +94 -53
- package/lib/formbuilder/objectform/source/geotiffsource.d.ts +3 -20
- package/lib/formbuilder/objectform/source/geotiffsource.js +73 -74
- package/lib/formbuilder/objectform/source/pathbasedsource.d.ts +3 -19
- package/lib/formbuilder/objectform/source/pathbasedsource.js +76 -75
- package/lib/formbuilder/objectform/source/sourceform.d.ts +7 -8
- package/lib/formbuilder/objectform/source/sourceform.js +28 -11
- package/lib/formbuilder/objectform/source/tilesourceform.d.ts +3 -7
- package/lib/formbuilder/objectform/source/tilesourceform.js +63 -53
- package/lib/formbuilder/objectform/useSchemaFormState.d.ts +48 -0
- package/lib/formbuilder/objectform/useSchemaFormState.js +35 -0
- package/lib/index.d.ts +0 -1
- package/lib/index.js +0 -1
- package/lib/keybindings.json +10 -10
- package/lib/mainview/mainView.d.ts +11 -7
- package/lib/mainview/mainView.js +62 -35
- package/lib/mainview/mainviewmodel.js +2 -2
- package/lib/menus.js +8 -8
- package/lib/panelview/components/layers.js +5 -2
- package/lib/panelview/objectproperties.js +2 -2
- package/lib/panelview/rightpanel.js +17 -2
- package/lib/panelview/story-maps/SpectaPanel.d.ts +15 -0
- package/lib/panelview/story-maps/SpectaPanel.js +35 -0
- package/lib/panelview/story-maps/StoryViewerPanel.d.ts +24 -9
- package/lib/panelview/story-maps/StoryViewerPanel.js +22 -268
- package/lib/panelview/story-maps/{PreviewModeSwitch.js → components/PreviewModeSwitch.js} +1 -1
- package/lib/panelview/story-maps/components/SpectaDesktopView.d.ts +21 -0
- package/lib/panelview/story-maps/components/SpectaDesktopView.js +49 -0
- package/lib/panelview/story-maps/components/SpectaMobileView.d.ts +17 -0
- package/lib/panelview/story-maps/{MobileSpectaPanel.js → components/SpectaMobileView.js} +8 -22
- package/lib/panelview/story-maps/{StoryNavBar.d.ts → components/StoryNavBar.d.ts} +1 -1
- package/lib/panelview/story-maps/{StoryNavBar.js → components/StoryNavBar.js} +2 -4
- package/lib/panelview/story-maps/hooks/useStoryMap.d.ts +39 -0
- package/lib/panelview/story-maps/hooks/useStoryMap.js +252 -0
- package/lib/processing/index.d.ts +2 -2
- package/lib/processing/index.js +62 -35
- package/lib/processing/processingCommands.d.ts +1 -1
- package/lib/processing/processingCommands.js +26 -6
- package/lib/shared/components/Collapsible.d.ts +6 -0
- package/lib/shared/components/Collapsible.js +26 -0
- package/lib/statusbar/SpectaPresentationProgressBar.d.ts +7 -0
- package/lib/statusbar/SpectaPresentationProgressBar.js +40 -0
- package/lib/toolbar/widget.js +4 -2
- package/lib/tools.d.ts +6 -0
- package/lib/tools.js +9 -0
- package/lib/types.d.ts +29 -2
- package/package.json +2 -4
- package/style/base.css +23 -1
- package/style/dialog.css +5 -0
- package/style/leftPanel.css +14 -37
- package/style/shared/button.css +0 -10
- package/style/shared/switch.css +8 -7
- package/style/spectaProgressBar.css +144 -0
- package/style/storyPanel.css +33 -0
- package/style/symbologyDialog.css +2 -2
- package/lib/formbuilder/objectform/baseform.d.ts +0 -91
- package/lib/formbuilder/objectform/baseform.js +0 -231
- package/lib/panelview/story-maps/MobileSpectaPanel.d.ts +0 -7
- /package/lib/panelview/story-maps/{PreviewModeSwitch.d.ts → components/PreviewModeSwitch.d.ts} +0 -0
package/lib/mainview/mainView.js
CHANGED
|
@@ -45,11 +45,9 @@ import { debounce, isLightTheme, loadFile, throttle } from "../tools";
|
|
|
45
45
|
import CollaboratorPointers from './CollaboratorPointers';
|
|
46
46
|
import { FollowIndicator } from './FollowIndicator';
|
|
47
47
|
import TemporalSlider from './TemporalSlider';
|
|
48
|
-
import { hexToRgb } from '../dialogs/symbology/colorRampUtils';
|
|
49
48
|
import { markerIcon } from '../icons';
|
|
50
49
|
import { LeftPanel, RightPanel } from '../panelview';
|
|
51
|
-
import {
|
|
52
|
-
import StoryViewerPanel from '../panelview/story-maps/StoryViewerPanel';
|
|
50
|
+
import { SpectaPanel } from '../panelview/story-maps/SpectaPanel';
|
|
53
51
|
export class MainView extends React.Component {
|
|
54
52
|
constructor(props) {
|
|
55
53
|
super(props);
|
|
@@ -135,6 +133,16 @@ export class MainView extends React.Component {
|
|
|
135
133
|
};
|
|
136
134
|
this.addContextMenu = () => {
|
|
137
135
|
this._commands.addCommand(CommandIDs.addAnnotation, {
|
|
136
|
+
label: 'Add annotation',
|
|
137
|
+
describedBy: {
|
|
138
|
+
args: {
|
|
139
|
+
type: 'object',
|
|
140
|
+
properties: {},
|
|
141
|
+
},
|
|
142
|
+
},
|
|
143
|
+
isEnabled: () => {
|
|
144
|
+
return !!this._Map;
|
|
145
|
+
},
|
|
138
146
|
execute: () => {
|
|
139
147
|
var _a;
|
|
140
148
|
if (!this._Map) {
|
|
@@ -152,10 +160,6 @@ export class MainView extends React.Component {
|
|
|
152
160
|
open: true,
|
|
153
161
|
});
|
|
154
162
|
},
|
|
155
|
-
label: 'Add annotation',
|
|
156
|
-
isEnabled: () => {
|
|
157
|
-
return !!this._Map;
|
|
158
|
-
},
|
|
159
163
|
});
|
|
160
164
|
this._contextMenu.addItem({
|
|
161
165
|
command: CommandIDs.addAnnotation,
|
|
@@ -417,8 +421,6 @@ export class MainView extends React.Component {
|
|
|
417
421
|
this._setupSpectaMode = () => {
|
|
418
422
|
this._removeAllInteractions();
|
|
419
423
|
this._setupStoryScrollListener();
|
|
420
|
-
// Update colors CSS variables with colors from story
|
|
421
|
-
this._updateSpectaPresentationColors();
|
|
422
424
|
};
|
|
423
425
|
this._removeAllInteractions = () => {
|
|
424
426
|
// Remove all default interactions
|
|
@@ -524,27 +526,6 @@ export class MainView extends React.Component {
|
|
|
524
526
|
this._storyScrollHandler = null;
|
|
525
527
|
}
|
|
526
528
|
};
|
|
527
|
-
this._updateSpectaPresentationColors = () => {
|
|
528
|
-
var _a;
|
|
529
|
-
// Try ref first, fallback to querySelector if ref not available yet
|
|
530
|
-
const container = this.spectaContainerRef.current ||
|
|
531
|
-
((_a = this.divRef.current) === null || _a === void 0 ? void 0 : _a.querySelector('.jgis-specta-story-panel-container'));
|
|
532
|
-
if (!container) {
|
|
533
|
-
return;
|
|
534
|
-
}
|
|
535
|
-
const story = this._model.getSelectedStory().story;
|
|
536
|
-
const bgColor = story === null || story === void 0 ? void 0 : story.presentationBgColor;
|
|
537
|
-
const textColor = story === null || story === void 0 ? void 0 : story.presentationTextColor;
|
|
538
|
-
// Set background color
|
|
539
|
-
if (bgColor) {
|
|
540
|
-
const rgb = hexToRgb(bgColor);
|
|
541
|
-
container.style.setProperty('--jgis-specta-bg-color', `rgba(${rgb[0]}, ${rgb[1]}, ${rgb[2]})`);
|
|
542
|
-
}
|
|
543
|
-
// Set text color
|
|
544
|
-
if (textColor) {
|
|
545
|
-
container.style.setProperty('--jgis-specta-text-color', textColor);
|
|
546
|
-
}
|
|
547
|
-
};
|
|
548
529
|
this._onSharedMetadataChanged = (_, changes) => {
|
|
549
530
|
const newState = Object.assign({}, this.state.annotations);
|
|
550
531
|
changes.forEach((val, key) => {
|
|
@@ -588,6 +569,32 @@ export class MainView extends React.Component {
|
|
|
588
569
|
this._handleWindowResize = () => {
|
|
589
570
|
// TODO SOMETHING
|
|
590
571
|
};
|
|
572
|
+
this._handleSpectaTouchStart = (e) => {
|
|
573
|
+
if (e.touches.length > 0) {
|
|
574
|
+
this._spectaTouchStartX = e.touches[0].clientX;
|
|
575
|
+
}
|
|
576
|
+
};
|
|
577
|
+
this._handleSpectaTouchEnd = (e) => {
|
|
578
|
+
var _a, _b, _c;
|
|
579
|
+
if (e.changedTouches.length === 0) {
|
|
580
|
+
return;
|
|
581
|
+
}
|
|
582
|
+
const endX = e.changedTouches[0].clientX;
|
|
583
|
+
const deltaX = endX - this._spectaTouchStartX;
|
|
584
|
+
const threshold = 50;
|
|
585
|
+
const story = this._model.getSelectedStory().story;
|
|
586
|
+
const segmentCount = (_b = (_a = story === null || story === void 0 ? void 0 : story.storySegments) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0;
|
|
587
|
+
if (segmentCount === 0) {
|
|
588
|
+
return;
|
|
589
|
+
}
|
|
590
|
+
const current = (_c = this._model.getCurrentSegmentIndex()) !== null && _c !== void 0 ? _c : 0;
|
|
591
|
+
if (deltaX > threshold && current > 0) {
|
|
592
|
+
this._model.setCurrentSegmentIndex(current - 1);
|
|
593
|
+
}
|
|
594
|
+
else if (deltaX < -threshold && current < segmentCount - 1) {
|
|
595
|
+
this._model.setCurrentSegmentIndex(current + 1);
|
|
596
|
+
}
|
|
597
|
+
};
|
|
591
598
|
this._isPositionInitialized = false;
|
|
592
599
|
this.divRef = React.createRef(); // Reference of render div
|
|
593
600
|
this.controlsToolbarRef = React.createRef();
|
|
@@ -600,6 +607,7 @@ export class MainView extends React.Component {
|
|
|
600
607
|
this._isSpectaPresentationInitialized = false;
|
|
601
608
|
this._storyScrollHandler = null;
|
|
602
609
|
this._pendingStoryScrollRafId = null;
|
|
610
|
+
this._spectaTouchStartX = 0;
|
|
603
611
|
this._state = props.state;
|
|
604
612
|
this._formSchemaRegistry = props.formSchemaRegistry;
|
|
605
613
|
this._annotationModel = props.annotationModel;
|
|
@@ -664,6 +672,7 @@ export class MainView extends React.Component {
|
|
|
664
672
|
filterStates: {},
|
|
665
673
|
jgisSettings: this._model.jgisSettings,
|
|
666
674
|
isSpectaPresentation: this._model.isSpectaMode(),
|
|
675
|
+
initialLayersReady: false,
|
|
667
676
|
};
|
|
668
677
|
this._sources = [];
|
|
669
678
|
this._loadingLayers = new Set();
|
|
@@ -709,6 +718,8 @@ export class MainView extends React.Component {
|
|
|
709
718
|
this._mainViewModel.dispose();
|
|
710
719
|
}
|
|
711
720
|
async generateMap(center, zoom) {
|
|
721
|
+
const layers = this._model.getLayers();
|
|
722
|
+
this._initialLayersCount = Object.values(layers).filter(layer => layer.type !== 'StorySegmentLayer').length;
|
|
712
723
|
const scaleLine = new ScaleLine({
|
|
713
724
|
target: this.controlsToolbarRef.current || undefined,
|
|
714
725
|
});
|
|
@@ -1047,11 +1058,16 @@ export class MainView extends React.Component {
|
|
|
1047
1058
|
});
|
|
1048
1059
|
// Replace color placeholder in SVG with the parameter color
|
|
1049
1060
|
const markerColor = parameters.color || '#3463a0';
|
|
1050
|
-
const svgString = markerIcon.svgstr
|
|
1061
|
+
const svgString = markerIcon.svgstr
|
|
1062
|
+
.replace('{{COLOR}}', markerColor)
|
|
1063
|
+
.replace('<svg', '<svg width="128" height="128"');
|
|
1051
1064
|
const iconStyle = new Style({
|
|
1052
1065
|
image: new Icon({
|
|
1053
1066
|
src: `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svgString)}`,
|
|
1054
1067
|
scale: 0.25,
|
|
1068
|
+
anchor: [0.5, 1],
|
|
1069
|
+
anchorXUnits: 'fraction',
|
|
1070
|
+
anchorYUnits: 'fraction',
|
|
1055
1071
|
}),
|
|
1056
1072
|
});
|
|
1057
1073
|
marker.setStyle(iconStyle);
|
|
@@ -1346,6 +1362,11 @@ export class MainView extends React.Component {
|
|
|
1346
1362
|
const numLayers = this._Map.getLayers().getLength();
|
|
1347
1363
|
const safeIndex = Math.min(index, numLayers);
|
|
1348
1364
|
this._Map.getLayers().insertAt(safeIndex, newMapLayer);
|
|
1365
|
+
// doing +1 instead of calling method again
|
|
1366
|
+
if (!this.state.initialLayersReady &&
|
|
1367
|
+
numLayers + 1 === this._initialLayersCount) {
|
|
1368
|
+
this.setState(old => (Object.assign(Object.assign({}, old), { initialLayersReady: true })));
|
|
1369
|
+
}
|
|
1349
1370
|
}
|
|
1350
1371
|
}
|
|
1351
1372
|
catch (error) {
|
|
@@ -2039,7 +2060,11 @@ export class MainView extends React.Component {
|
|
|
2039
2060
|
// ? could send just the filters object and modify that instead of emitting whole layer
|
|
2040
2061
|
const json = JSON.parse(args);
|
|
2041
2062
|
const { layerId, layer: jgisLayer } = json;
|
|
2063
|
+
const isSourceType = typeof (jgisLayer === null || jgisLayer === void 0 ? void 0 : jgisLayer.type) === 'string' && jgisLayer.type.includes('Source');
|
|
2042
2064
|
const olLayer = this.getLayer(layerId);
|
|
2065
|
+
if (isSourceType) {
|
|
2066
|
+
this.updateSource(layerId, jgisLayer);
|
|
2067
|
+
}
|
|
2043
2068
|
if (!jgisLayer || !olLayer) {
|
|
2044
2069
|
console.error('Failed to update layer -- layer not found');
|
|
2045
2070
|
return;
|
|
@@ -2086,7 +2111,11 @@ export class MainView extends React.Component {
|
|
|
2086
2111
|
border: this.state.remoteUser
|
|
2087
2112
|
? `solid 3px ${this.state.remoteUser.color}`
|
|
2088
2113
|
: 'unset',
|
|
2089
|
-
}
|
|
2114
|
+
}, onTouchStart: this.state.isSpectaPresentation && this.props.isMobile
|
|
2115
|
+
? this._handleSpectaTouchStart
|
|
2116
|
+
: undefined, onTouchEnd: this.state.isSpectaPresentation && this.props.isMobile
|
|
2117
|
+
? this._handleSpectaTouchEnd
|
|
2118
|
+
: undefined },
|
|
2090
2119
|
React.createElement(LoadingOverlay, { loading: this.state.loading }),
|
|
2091
2120
|
React.createElement(FollowIndicator, { remoteUser: this.state.remoteUser }),
|
|
2092
2121
|
React.createElement(CollaboratorPointers, { clients: this.state.clientPointers }),
|
|
@@ -2096,9 +2125,7 @@ export class MainView extends React.Component {
|
|
|
2096
2125
|
} },
|
|
2097
2126
|
React.createElement("div", { className: "jgis-panels-wrapper" }, !this.state.isSpectaPresentation ? (React.createElement(React.Fragment, null,
|
|
2098
2127
|
this._state && (React.createElement(LeftPanel, { model: this._model, commands: this._mainViewModel.commands, state: this._state, settings: this.state.jgisSettings })),
|
|
2099
|
-
this._formSchemaRegistry && 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 })))) : this.
|
|
2100
|
-
React.createElement("div", { ref: this.spectaContainerRef, className: "jgis-specta-story-panel-container" },
|
|
2101
|
-
React.createElement(StoryViewerPanel, { ref: this.storyViewerPanelRef, model: this._model, isSpecta: this.state.isSpectaPresentation, className: "jgis-story-viewer-panel-specta-mod", onSegmentTransitionEnd: () => this._clearStoryScrollGuard() }))))),
|
|
2128
|
+
this._formSchemaRegistry && 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 })))) : (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.addLayer.bind(this), removeLayer: this.removeLayer.bind(this) })))),
|
|
2102
2129
|
React.createElement("div", { ref: this.controlsToolbarRef, className: "jgis-controls-toolbar" }))),
|
|
2103
2130
|
!this.state.isSpectaPresentation && (React.createElement(StatusBar, { jgisModel: this._model, loading: this.state.loadingLayer, projection: this.state.viewProjection, scale: this.state.scale })))));
|
|
2104
2131
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { UUID } from '@lumino/coreutils';
|
|
2
2
|
export class MainViewModel {
|
|
3
3
|
constructor(options) {
|
|
4
4
|
this._isDisposed = false;
|
|
@@ -33,7 +33,7 @@ export class MainViewModel {
|
|
|
33
33
|
}
|
|
34
34
|
addAnnotation(value) {
|
|
35
35
|
var _a;
|
|
36
|
-
(_a = this._jGISModel.annotationModel) === null || _a === void 0 ? void 0 : _a.addAnnotation(
|
|
36
|
+
(_a = this._jGISModel.annotationModel) === null || _a === void 0 ? void 0 : _a.addAnnotation(UUID.uuid4(), value);
|
|
37
37
|
}
|
|
38
38
|
async _onsharedLayersChanged(_, change) {
|
|
39
39
|
if (change.layerChange) {
|
package/lib/menus.js
CHANGED
|
@@ -8,19 +8,19 @@ export const vectorSubMenu = (commands) => {
|
|
|
8
8
|
subMenu.id = 'jp-gis-toolbar-vector-menu';
|
|
9
9
|
subMenu.addItem({
|
|
10
10
|
type: 'command',
|
|
11
|
-
command: CommandIDs.
|
|
11
|
+
command: CommandIDs.openNewVectorTileDialog,
|
|
12
12
|
});
|
|
13
13
|
subMenu.addItem({
|
|
14
14
|
type: 'command',
|
|
15
|
-
command: CommandIDs.
|
|
15
|
+
command: CommandIDs.openNewGeoJSONDialog,
|
|
16
16
|
});
|
|
17
17
|
subMenu.addItem({
|
|
18
18
|
type: 'command',
|
|
19
|
-
command: CommandIDs.
|
|
19
|
+
command: CommandIDs.openNewShapefileDialog,
|
|
20
20
|
});
|
|
21
21
|
subMenu.addItem({
|
|
22
22
|
type: 'command',
|
|
23
|
-
command: CommandIDs.
|
|
23
|
+
command: CommandIDs.openNewGeoParquetDialog,
|
|
24
24
|
});
|
|
25
25
|
return subMenu;
|
|
26
26
|
};
|
|
@@ -31,19 +31,19 @@ export const rasterSubMenu = (commands) => {
|
|
|
31
31
|
subMenu.id = 'jp-gis-toolbar-raster-menu';
|
|
32
32
|
subMenu.addItem({
|
|
33
33
|
type: 'command',
|
|
34
|
-
command: CommandIDs.
|
|
34
|
+
command: CommandIDs.openNewRasterDialog,
|
|
35
35
|
});
|
|
36
36
|
subMenu.addItem({
|
|
37
37
|
type: 'command',
|
|
38
|
-
command: CommandIDs.
|
|
38
|
+
command: CommandIDs.openNewHillshadeDialog,
|
|
39
39
|
});
|
|
40
40
|
subMenu.addItem({
|
|
41
41
|
type: 'command',
|
|
42
|
-
command: CommandIDs.
|
|
42
|
+
command: CommandIDs.openNewImageDialog,
|
|
43
43
|
});
|
|
44
44
|
subMenu.addItem({
|
|
45
45
|
type: 'command',
|
|
46
|
-
command: CommandIDs.
|
|
46
|
+
command: CommandIDs.openNewGeoTiffDialog,
|
|
47
47
|
});
|
|
48
48
|
return subMenu;
|
|
49
49
|
};
|
|
@@ -261,6 +261,7 @@ const LayerComponent = props => {
|
|
|
261
261
|
model: gisModel,
|
|
262
262
|
});
|
|
263
263
|
const hasSupportedSymbology = (symbology === null || symbology === void 0 ? void 0 : symbology.symbologyState) !== undefined;
|
|
264
|
+
const isStorySegmentLayer = layer.type === 'StorySegmentLayer';
|
|
264
265
|
const name = layer.name;
|
|
265
266
|
useEffect(() => {
|
|
266
267
|
setId(DOMUtils.createDomID());
|
|
@@ -361,14 +362,16 @@ const LayerComponent = props => {
|
|
|
361
362
|
const slideNum = story.storySegments.indexOf(layerId) + 1;
|
|
362
363
|
return slideNum;
|
|
363
364
|
};
|
|
364
|
-
return (React.createElement("div", { className: `${LAYER_ITEM_CLASS} ${LAYER_CLASS}
|
|
365
|
+
return (React.createElement("div", { className: `${LAYER_ITEM_CLASS} ${LAYER_CLASS}
|
|
366
|
+
${isStorySegmentLayer ? 'jp-gis-storySegmentLayer' : ''}
|
|
367
|
+
${selected ? ' jp-mod-selected' : ''}`, draggable: true, onDragStart: Private.onDragStart, onDragOver: Private.onDragOver, onDragEnd: Private.onDragEnd, "data-id": layerId, style: { display: 'flex', flexDirection: 'column' } },
|
|
365
368
|
React.createElement("div", { className: LAYER_TITLE_CLASS, onClick: setSelection, onContextMenu: setSelection, style: { display: 'flex' } },
|
|
366
369
|
hasSupportedSymbology && (React.createElement(Button, { minimal: true, onClick: e => {
|
|
367
370
|
e.stopPropagation();
|
|
368
371
|
setExpanded(v => !v);
|
|
369
372
|
}, title: expanded ? 'Hide legend' : 'Show legend' },
|
|
370
373
|
React.createElement(LabIcon.resolveReact, { icon: expanded ? caretDownIcon : caretRightIcon, tag: "span" }))),
|
|
371
|
-
|
|
374
|
+
isStorySegmentLayer ? (React.createElement("span", { className: LAYER_SLIDE_NUMBER_CLASS, title: "Slide number" }, getSlideNumber())) : (React.createElement(Button, { title: layer.visible ? 'Hide layer' : 'Show layer', onClick: toggleVisibility, minimal: true },
|
|
372
375
|
React.createElement(LabIcon.resolveReact, { icon: layer.visible ? visibilityIcon : nonVisibilityIcon, className: `${LAYER_ICON_CLASS}${layer.visible ? '' : ' jp-gis-mod-hidden'}`, tag: "span" }))),
|
|
373
376
|
icons.has(layer.type) && (React.createElement(LabIcon.resolveReact, Object.assign({}, icons.get(layer.type), { className: LAYER_ICON_CLASS }))),
|
|
374
377
|
isEditing ? (React.createElement("input", { type: "text", value: editValue, onChange: e => setEditValue(e.target.value), onKeyDown: handleRenameKeyDown, onBlur: handleRenameSave, className: LAYER_TEXT_CLASS, style: {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import { UUID } from '@lumino/coreutils';
|
|
1
2
|
import * as React from 'react';
|
|
2
|
-
import { v4 as uuid } from 'uuid';
|
|
3
3
|
import { EditForm } from "../formbuilder/editform";
|
|
4
4
|
export class ObjectPropertiesReact extends React.Component {
|
|
5
5
|
constructor(props) {
|
|
@@ -37,7 +37,7 @@ export class ObjectPropertiesReact extends React.Component {
|
|
|
37
37
|
};
|
|
38
38
|
this.state = {
|
|
39
39
|
clientId: props.model.getClientId(),
|
|
40
|
-
id:
|
|
40
|
+
id: UUID.uuid4(),
|
|
41
41
|
model: props.model,
|
|
42
42
|
selectedObject: props.selectedObject,
|
|
43
43
|
setSelectedObject: props.setSelectedObject,
|
|
@@ -3,10 +3,25 @@ import Draggable from 'react-draggable';
|
|
|
3
3
|
import { AnnotationsPanel } from './annotationPanel';
|
|
4
4
|
import { IdentifyPanelComponent } from './identify-panel/IdentifyPanel';
|
|
5
5
|
import { ObjectPropertiesReact } from './objectproperties';
|
|
6
|
-
import { PreviewModeSwitch } from './story-maps/PreviewModeSwitch';
|
|
7
6
|
import StoryEditorPanel from './story-maps/StoryEditorPanel';
|
|
8
7
|
import StoryViewerPanel from './story-maps/StoryViewerPanel';
|
|
8
|
+
import { PreviewModeSwitch } from './story-maps/components/PreviewModeSwitch';
|
|
9
|
+
import { useStoryMap, } from './story-maps/hooks/useStoryMap';
|
|
9
10
|
import { PanelTabs, TabsContent, TabsList, TabsTrigger, } from '../shared/components/Tabs';
|
|
11
|
+
/** Story viewer + useStoryMap hook
|
|
12
|
+
* only mounted when story tab is active to avoid the hook causing re-renders when tab is hidden.
|
|
13
|
+
**/
|
|
14
|
+
function RightPanelStoryViewer({ model, addLayer, removeLayer, }) {
|
|
15
|
+
const overrideLayerEntriesRef = React.useRef([]);
|
|
16
|
+
const { storyData, currentIndex, setIndex, handlePrev, handleNext, hasPrev, hasNext, activeSlide, layerName, } = useStoryMap({
|
|
17
|
+
model,
|
|
18
|
+
overrideLayerEntriesRef,
|
|
19
|
+
removeLayer,
|
|
20
|
+
addLayer,
|
|
21
|
+
isSpecta: false,
|
|
22
|
+
});
|
|
23
|
+
return (React.createElement(StoryViewerPanel, { model: model, isSpecta: false, storyData: storyData, currentIndex: currentIndex, activeSlide: activeSlide, layerName: layerName, handlePrev: handlePrev, handleNext: handleNext, hasPrev: hasPrev, hasNext: hasNext, setIndex: setIndex }));
|
|
24
|
+
}
|
|
10
25
|
export const RightPanel = props => {
|
|
11
26
|
var _a;
|
|
12
27
|
const [editorMode, setEditorMode] = React.useState(true);
|
|
@@ -90,7 +105,7 @@ export const RightPanel = props => {
|
|
|
90
105
|
React.createElement(ObjectPropertiesReact, { setSelectedObject: setSelectedObjectProperties, selectedObject: selectedObjectProperties, formSchemaRegistry: props.formSchemaRegistry, model: props.model }))),
|
|
91
106
|
!props.settings.storyMapsDisabled && (React.createElement(TabsContent, { value: "storyPanel", className: "jgis-panel-tab-content", style: { paddingTop: 0 } },
|
|
92
107
|
!storyMapPresentationMode && (React.createElement(PreviewModeSwitch, { checked: !editorMode, onCheckedChange: toggleEditor })),
|
|
93
|
-
showEditor ? (React.createElement(StoryEditorPanel, { model: props.model, commands: props.commands })) : (React.createElement(
|
|
108
|
+
showEditor ? (React.createElement(StoryEditorPanel, { model: props.model, commands: props.commands })) : curTab === 'storyPanel' ? (React.createElement(RightPanelStoryViewer, { model: props.model, addLayer: props.addLayer, removeLayer: props.removeLayer })) : null)),
|
|
94
109
|
!props.settings.annotationsDisabled && (React.createElement(TabsContent, { value: "annotations", className: "jgis-panel-tab-content" },
|
|
95
110
|
React.createElement(AnnotationsPanel, { annotationModel: props.annotationModel, jgisModel: props.model }))),
|
|
96
111
|
!props.settings.identifyDisabled && (React.createElement(TabsContent, { value: "identifyPanel", className: "jgis-panel-tab-content" },
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { IJGISLayer, IJupyterGISModel } from '@jupytergis/schema';
|
|
2
|
+
import React, { RefObject } from 'react';
|
|
3
|
+
import type { IStoryViewerPanelHandle } from './StoryViewerPanel';
|
|
4
|
+
interface ISpectaPanelProps {
|
|
5
|
+
model: IJupyterGISModel;
|
|
6
|
+
isSpecta: boolean;
|
|
7
|
+
isMobile: boolean;
|
|
8
|
+
onSegmentTransitionEnd: () => void;
|
|
9
|
+
containerRef: RefObject<HTMLDivElement>;
|
|
10
|
+
storyViewerPanelRef: RefObject<IStoryViewerPanelHandle>;
|
|
11
|
+
addLayer?: (id: string, layer: IJGISLayer, index: number) => Promise<void>;
|
|
12
|
+
removeLayer?: (id: string) => void;
|
|
13
|
+
}
|
|
14
|
+
export declare function SpectaPanel({ model, isSpecta, isMobile, onSegmentTransitionEnd, containerRef, storyViewerPanelRef, addLayer, removeLayer, }: ISpectaPanelProps): React.JSX.Element;
|
|
15
|
+
export {};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import React, { useEffect, useRef } from 'react';
|
|
2
|
+
import { SpectaDesktopView } from './components/SpectaDesktopView';
|
|
3
|
+
import { SpectaMobileView } from './components/SpectaMobileView';
|
|
4
|
+
import { useStoryMap } from './hooks/useStoryMap';
|
|
5
|
+
export function SpectaPanel({ model, isSpecta, isMobile, onSegmentTransitionEnd, containerRef, storyViewerPanelRef, addLayer, removeLayer, }) {
|
|
6
|
+
const overrideLayerEntriesRef = useRef([]);
|
|
7
|
+
const segmentContainerRef = useRef(null);
|
|
8
|
+
const { storyData, currentIndex, setIndex, handlePrev, handleNext, hasPrev, hasNext, activeSlide, layerName, } = useStoryMap({
|
|
9
|
+
model,
|
|
10
|
+
overrideLayerEntriesRef,
|
|
11
|
+
removeLayer,
|
|
12
|
+
addLayer,
|
|
13
|
+
panelRef: isMobile ? undefined : containerRef,
|
|
14
|
+
isSpecta,
|
|
15
|
+
});
|
|
16
|
+
// Notify when segment transition animation ends
|
|
17
|
+
useEffect(() => {
|
|
18
|
+
const el = segmentContainerRef.current;
|
|
19
|
+
if (!el || !onSegmentTransitionEnd) {
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
const handleAnimationEnd = (e) => {
|
|
23
|
+
if (e.animationName === 'fadeIn') {
|
|
24
|
+
el.removeEventListener('animationend', handleAnimationEnd);
|
|
25
|
+
onSegmentTransitionEnd();
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
el.addEventListener('animationend', handleAnimationEnd);
|
|
29
|
+
return () => el.removeEventListener('animationend', handleAnimationEnd);
|
|
30
|
+
}, [currentIndex, onSegmentTransitionEnd]);
|
|
31
|
+
if (isMobile) {
|
|
32
|
+
return (React.createElement(SpectaMobileView, { model: model, segmentContainerRef: segmentContainerRef, storyData: storyData, currentIndex: currentIndex, activeSlide: activeSlide, layerName: layerName, handlePrev: handlePrev, handleNext: handleNext, hasPrev: hasPrev, hasNext: hasNext, setIndex: setIndex }));
|
|
33
|
+
}
|
|
34
|
+
return (React.createElement(SpectaDesktopView, { model: model, isSpecta: isSpecta, containerRef: containerRef, storyViewerPanelRef: storyViewerPanelRef, segmentContainerRef: segmentContainerRef, storyData: storyData, currentIndex: currentIndex, activeSlide: activeSlide, layerName: layerName, handlePrev: handlePrev, handleNext: handleNext, hasPrev: hasPrev, hasNext: hasNext, setIndex: setIndex }));
|
|
35
|
+
}
|
|
@@ -1,14 +1,22 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import React from 'react';
|
|
1
|
+
import { IJGISStoryMap, IJupyterGISModel, IStorySegmentLayer } from '@jupytergis/schema';
|
|
2
|
+
import React, { RefObject } from 'react';
|
|
3
|
+
/** Props: story state and callbacks come from useStoryMap in parent (SpectaPanel or SpectaMobileView). */
|
|
3
4
|
interface IStoryViewerPanelProps {
|
|
4
5
|
model: IJupyterGISModel;
|
|
5
6
|
isSpecta: boolean;
|
|
6
7
|
isMobile?: boolean;
|
|
7
8
|
className?: string;
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
/** Ref for the segment container (SpectaPanel uses it for animationend). */
|
|
10
|
+
segmentContainerRef?: RefObject<HTMLDivElement>;
|
|
11
|
+
storyData: IJGISStoryMap | null;
|
|
12
|
+
currentIndex: number;
|
|
13
|
+
activeSlide: IStorySegmentLayer['parameters'] | undefined;
|
|
14
|
+
layerName: string;
|
|
15
|
+
handlePrev: () => void;
|
|
16
|
+
handleNext: () => void;
|
|
17
|
+
hasPrev: boolean;
|
|
18
|
+
hasNext: boolean;
|
|
19
|
+
setIndex: (index: number) => void;
|
|
12
20
|
}
|
|
13
21
|
export interface IStoryViewerPanelHandle {
|
|
14
22
|
handlePrev: () => void;
|
|
@@ -26,8 +34,15 @@ export interface IStoryViewerPanelHandle {
|
|
|
26
34
|
* - below-title: normal mode, guided, no image (under the title)
|
|
27
35
|
* - over-image: normal mode, guided, with image (over the image)
|
|
28
36
|
* - subtitle-specta: specta mode desktop (next to subtitle, fixed centered)
|
|
29
|
-
*
|
|
37
|
+
* Specta mode mobile returns null (nav hidden).
|
|
30
38
|
*/
|
|
31
|
-
export type StoryNavPlacement = 'below-title' | 'over-image' | 'subtitle-specta'
|
|
32
|
-
|
|
39
|
+
export type StoryNavPlacement = 'below-title' | 'over-image' | 'subtitle-specta';
|
|
40
|
+
/**
|
|
41
|
+
* Story viewer (presentational). Receives story state and callbacks from parent.
|
|
42
|
+
* Desktop scroll/sentinel/imperative handle live in SpectaDesktopView.
|
|
43
|
+
*/
|
|
44
|
+
declare function StoryViewerPanel({ model, isSpecta, isMobile, className, segmentContainerRef, storyData, currentIndex, activeSlide, layerName, handlePrev, handleNext, hasPrev, hasNext, setIndex, }: IStoryViewerPanelProps): React.JSX.Element;
|
|
45
|
+
declare namespace StoryViewerPanel {
|
|
46
|
+
var displayName: string;
|
|
47
|
+
}
|
|
33
48
|
export default StoryViewerPanel;
|