@jupytergis/base 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/commands.d.ts +11 -0
- package/lib/commands.js +809 -0
- package/lib/console/consoleview.d.ts +24 -0
- package/lib/console/consoleview.js +55 -0
- package/lib/console/index.d.ts +1 -0
- package/lib/console/index.js +1 -0
- package/lib/constants.d.ts +57 -0
- package/lib/constants.js +89 -0
- package/lib/dialogs/components/symbology/BandRendering.d.ts +4 -0
- package/lib/dialogs/components/symbology/BandRendering.js +29 -0
- package/lib/dialogs/components/symbology/BandRow.d.ts +10 -0
- package/lib/dialogs/components/symbology/BandRow.js +43 -0
- package/lib/dialogs/components/symbology/SingleBandPseudoColor.d.ts +20 -0
- package/lib/dialogs/components/symbology/SingleBandPseudoColor.js +281 -0
- package/lib/dialogs/components/symbology/StopRow.d.ts +11 -0
- package/lib/dialogs/components/symbology/StopRow.js +58 -0
- package/lib/dialogs/formdialog.d.ts +31 -0
- package/lib/dialogs/formdialog.js +68 -0
- package/lib/dialogs/layerBrowserDialog.d.ts +25 -0
- package/lib/dialogs/layerBrowserDialog.js +141 -0
- package/lib/dialogs/symbologyDialog.d.ts +23 -0
- package/lib/dialogs/symbologyDialog.js +68 -0
- package/lib/dialogs/terrainDialog.d.ts +21 -0
- package/lib/dialogs/terrainDialog.js +60 -0
- package/lib/formbuilder/creationform.d.ts +56 -0
- package/lib/formbuilder/creationform.js +117 -0
- package/lib/formbuilder/editform.d.ts +24 -0
- package/lib/formbuilder/editform.js +60 -0
- package/lib/formbuilder/formselectors.d.ts +5 -0
- package/lib/formbuilder/formselectors.js +38 -0
- package/lib/formbuilder/index.d.ts +6 -0
- package/lib/formbuilder/index.js +6 -0
- package/lib/formbuilder/objectform/baseform.d.ts +79 -0
- package/lib/formbuilder/objectform/baseform.js +167 -0
- package/lib/formbuilder/objectform/geojsonsource.d.ts +19 -0
- package/lib/formbuilder/objectform/geojsonsource.js +80 -0
- package/lib/formbuilder/objectform/hillshadeLayerForm.d.ts +8 -0
- package/lib/formbuilder/objectform/hillshadeLayerForm.js +12 -0
- package/lib/formbuilder/objectform/layerform.d.ts +19 -0
- package/lib/formbuilder/objectform/layerform.js +17 -0
- package/lib/formbuilder/objectform/tilesourceform.d.ts +7 -0
- package/lib/formbuilder/objectform/tilesourceform.js +60 -0
- package/lib/formbuilder/objectform/vectorlayerform.d.ts +15 -0
- package/lib/formbuilder/objectform/vectorlayerform.js +88 -0
- package/lib/formbuilder/objectform/webGlLayerForm.d.ts +8 -0
- package/lib/formbuilder/objectform/webGlLayerForm.js +10 -0
- package/lib/icons.d.ts +6 -0
- package/lib/icons.js +31 -0
- package/lib/index.d.ts +10 -0
- package/lib/index.js +10 -0
- package/lib/mainview/index.d.ts +3 -0
- package/lib/mainview/index.js +3 -0
- package/lib/mainview/mainView.d.ts +113 -0
- package/lib/mainview/mainView.js +743 -0
- package/lib/mainview/mainviewmodel.d.ts +24 -0
- package/lib/mainview/mainviewmodel.js +34 -0
- package/lib/mainview/mainviewwidget.d.ts +14 -0
- package/lib/mainview/mainviewwidget.js +18 -0
- package/lib/mainview/spinner.d.ts +6 -0
- package/lib/mainview/spinner.js +5 -0
- package/lib/panelview/components/filter-panel/Filter.d.ts +19 -0
- package/lib/panelview/components/filter-panel/Filter.js +223 -0
- package/lib/panelview/components/filter-panel/FilterRow.d.ts +9 -0
- package/lib/panelview/components/filter-panel/FilterRow.js +61 -0
- package/lib/panelview/components/layers.d.ts +13 -0
- package/lib/panelview/components/layers.js +275 -0
- package/lib/panelview/components/sources.d.ts +10 -0
- package/lib/panelview/components/sources.js +147 -0
- package/lib/panelview/header.d.ts +11 -0
- package/lib/panelview/header.js +20 -0
- package/lib/panelview/index.d.ts +5 -0
- package/lib/panelview/index.js +5 -0
- package/lib/panelview/leftpanel.d.ts +51 -0
- package/lib/panelview/leftpanel.js +125 -0
- package/lib/panelview/model.d.ts +19 -0
- package/lib/panelview/model.js +30 -0
- package/lib/panelview/objectproperties.d.ts +17 -0
- package/lib/panelview/objectproperties.js +92 -0
- package/lib/panelview/rightpanel.d.ts +19 -0
- package/lib/panelview/rightpanel.js +45 -0
- package/lib/toolbar/index.d.ts +2 -0
- package/lib/toolbar/index.js +2 -0
- package/lib/toolbar/usertoolbaritem.d.ts +19 -0
- package/lib/toolbar/usertoolbaritem.js +57 -0
- package/lib/toolbar/widget.d.ts +22 -0
- package/lib/toolbar/widget.js +104 -0
- package/lib/tools.d.ts +25 -0
- package/lib/tools.js +215 -0
- package/lib/types.d.ts +11 -0
- package/lib/types.js +1 -0
- package/lib/widget.d.ts +49 -0
- package/lib/widget.js +144 -0
- package/package.json +95 -0
- package/style/base.css +55 -0
- package/style/colorExpression.css +36 -0
- package/style/dialog.css +8 -0
- package/style/filterPanel.css +70 -0
- package/style/icons/geojson.svg +12 -0
- package/style/icons/mound.svg +9 -0
- package/style/icons/nonvisibility.svg +8 -0
- package/style/icons/raster.svg +5 -0
- package/style/icons/visibility.svg +7 -0
- package/style/index.css +6 -0
- package/style/index.js +6 -0
- package/style/layerBrowser.css +256 -0
- package/style/leftPanel.css +150 -0
- package/style/symbologyDialog.css +86 -0
- package/style/terrainDialog.css +14 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { IJupyterGISModel } from '@jupytergis/schema';
|
|
2
|
+
import { ObservableMap } from '@jupyterlab/observables';
|
|
3
|
+
import { JSONValue } from '@lumino/coreutils';
|
|
4
|
+
import { IDisposable } from '@lumino/disposable';
|
|
5
|
+
export declare class MainViewModel implements IDisposable {
|
|
6
|
+
constructor(options: MainViewModel.IOptions);
|
|
7
|
+
get isDisposed(): boolean;
|
|
8
|
+
get id(): string;
|
|
9
|
+
get jGISModel(): IJupyterGISModel;
|
|
10
|
+
get viewSettingChanged(): import("@lumino/signaling").ISignal<ObservableMap<JSONValue>, import("@jupyterlab/observables").IObservableMap.IChangedArgs<JSONValue>>;
|
|
11
|
+
dispose(): void;
|
|
12
|
+
initSignal(): void;
|
|
13
|
+
private _onsharedLayersChanged;
|
|
14
|
+
private _jGISModel;
|
|
15
|
+
private _viewSetting;
|
|
16
|
+
private _id;
|
|
17
|
+
private _isDisposed;
|
|
18
|
+
}
|
|
19
|
+
export declare namespace MainViewModel {
|
|
20
|
+
interface IOptions {
|
|
21
|
+
jGISModel: IJupyterGISModel;
|
|
22
|
+
viewSetting: ObservableMap<JSONValue>;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export class MainViewModel {
|
|
2
|
+
constructor(options) {
|
|
3
|
+
this._isDisposed = false;
|
|
4
|
+
this._jGISModel = options.jGISModel;
|
|
5
|
+
this._viewSetting = options.viewSetting;
|
|
6
|
+
}
|
|
7
|
+
get isDisposed() {
|
|
8
|
+
return this._isDisposed;
|
|
9
|
+
}
|
|
10
|
+
get id() {
|
|
11
|
+
return this._id;
|
|
12
|
+
}
|
|
13
|
+
get jGISModel() {
|
|
14
|
+
return this._jGISModel;
|
|
15
|
+
}
|
|
16
|
+
get viewSettingChanged() {
|
|
17
|
+
return this._viewSetting.changed;
|
|
18
|
+
}
|
|
19
|
+
dispose() {
|
|
20
|
+
if (this._isDisposed) {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
this._jGISModel.sharedLayersChanged.disconnect(this._onsharedLayersChanged, this);
|
|
24
|
+
this._isDisposed = true;
|
|
25
|
+
}
|
|
26
|
+
initSignal() {
|
|
27
|
+
this._jGISModel.sharedLayersChanged.connect(this._onsharedLayersChanged, this);
|
|
28
|
+
}
|
|
29
|
+
async _onsharedLayersChanged(_, change) {
|
|
30
|
+
if (change.layerChange) {
|
|
31
|
+
// TODO STUFF with the new updated shared model
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { ReactWidget } from '@jupyterlab/apputils';
|
|
2
|
+
import { MainViewModel } from './mainviewmodel';
|
|
3
|
+
export declare class JupyterGISMainViewPanel extends ReactWidget {
|
|
4
|
+
/**
|
|
5
|
+
* Construct a `JupyterGISPanel`.
|
|
6
|
+
*
|
|
7
|
+
* @param context - The documents context.
|
|
8
|
+
*/
|
|
9
|
+
constructor(options: {
|
|
10
|
+
mainViewModel: MainViewModel;
|
|
11
|
+
});
|
|
12
|
+
render(): JSX.Element;
|
|
13
|
+
private _mainViewModel;
|
|
14
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { ReactWidget } from '@jupyterlab/apputils';
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
import { MainView } from './mainView';
|
|
4
|
+
export class JupyterGISMainViewPanel extends ReactWidget {
|
|
5
|
+
/**
|
|
6
|
+
* Construct a `JupyterGISPanel`.
|
|
7
|
+
*
|
|
8
|
+
* @param context - The documents context.
|
|
9
|
+
*/
|
|
10
|
+
constructor(options) {
|
|
11
|
+
super();
|
|
12
|
+
this._mainViewModel = options.mainViewModel;
|
|
13
|
+
this.addClass('jp-jupytergis-panel');
|
|
14
|
+
}
|
|
15
|
+
render() {
|
|
16
|
+
return React.createElement(MainView, { viewModel: this._mainViewModel });
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { IJupyterGISTracker } from '@jupytergis/schema';
|
|
2
|
+
import { Panel } from '@lumino/widgets';
|
|
3
|
+
import React from 'react';
|
|
4
|
+
import { IControlPanelModel } from '../../../types';
|
|
5
|
+
import { RightPanelWidget } from '../../rightpanel';
|
|
6
|
+
/**
|
|
7
|
+
* The filters panel widget.
|
|
8
|
+
*/
|
|
9
|
+
export declare class FilterPanel extends Panel {
|
|
10
|
+
constructor(options: RightPanelWidget.IOptions);
|
|
11
|
+
private _model;
|
|
12
|
+
private _tracker;
|
|
13
|
+
}
|
|
14
|
+
interface IFilterComponentProps {
|
|
15
|
+
model: IControlPanelModel;
|
|
16
|
+
tracker: IJupyterGISTracker;
|
|
17
|
+
}
|
|
18
|
+
declare const FilterComponent: (props: IFilterComponentProps) => React.JSX.Element;
|
|
19
|
+
export default FilterComponent;
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
import { Button, ReactWidget } from '@jupyterlab/ui-components';
|
|
2
|
+
import { Panel } from '@lumino/widgets';
|
|
3
|
+
import { cloneDeep } from 'lodash';
|
|
4
|
+
import React, { useEffect, useRef, useState } from 'react';
|
|
5
|
+
import { debounce, getLayerTileInfo } from '../../../tools';
|
|
6
|
+
import FilterRow from './FilterRow';
|
|
7
|
+
/**
|
|
8
|
+
* The filters panel widget.
|
|
9
|
+
*/
|
|
10
|
+
export class FilterPanel extends Panel {
|
|
11
|
+
constructor(options) {
|
|
12
|
+
super();
|
|
13
|
+
this._model = options.model;
|
|
14
|
+
this._tracker = options.tracker;
|
|
15
|
+
this.id = 'jupytergis::layerTree';
|
|
16
|
+
// this.addClass(LAYERS_PANEL_CLASS);
|
|
17
|
+
this.addWidget(ReactWidget.create(React.createElement(FilterComponent, { model: this._model, tracker: this._tracker })));
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
const FilterComponent = (props) => {
|
|
21
|
+
var _a;
|
|
22
|
+
const featuresInLayerRef = useRef({});
|
|
23
|
+
const [widgetId, setWidgetId] = useState('');
|
|
24
|
+
const [logicalOp, setLogicalOp] = useState('all');
|
|
25
|
+
const [selectedLayer, setSelectedLayer] = useState('');
|
|
26
|
+
const [shouldDisplay, setShouldDisplay] = useState(false);
|
|
27
|
+
const [filterRows, setFilterRows] = useState([]);
|
|
28
|
+
const [featuresInLayer, setFeaturesInLayer] = useState({});
|
|
29
|
+
const [model, setModel] = useState(props.model.jGISModel);
|
|
30
|
+
(_a = props.model) === null || _a === void 0 ? void 0 : _a.documentChanged.connect((_, widget) => {
|
|
31
|
+
setModel(widget === null || widget === void 0 ? void 0 : widget.context.model);
|
|
32
|
+
});
|
|
33
|
+
// Reset state values when current widget changes
|
|
34
|
+
useEffect(() => {
|
|
35
|
+
const handleCurrentChanged = () => {
|
|
36
|
+
var _a;
|
|
37
|
+
if (((_a = props.tracker.currentWidget) === null || _a === void 0 ? void 0 : _a.id) === widgetId) {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
if (props.tracker.currentWidget) {
|
|
41
|
+
setWidgetId(props.tracker.currentWidget.id);
|
|
42
|
+
}
|
|
43
|
+
setFeaturesInLayer({});
|
|
44
|
+
setFilterRows([]);
|
|
45
|
+
setLogicalOp('all');
|
|
46
|
+
setSelectedLayer('');
|
|
47
|
+
};
|
|
48
|
+
props.tracker.currentChanged.connect(handleCurrentChanged);
|
|
49
|
+
return () => {
|
|
50
|
+
props.tracker.currentChanged.disconnect(handleCurrentChanged);
|
|
51
|
+
};
|
|
52
|
+
}, []);
|
|
53
|
+
useEffect(() => {
|
|
54
|
+
var _a, _b, _c, _d;
|
|
55
|
+
// Keep layer selected when widget changes
|
|
56
|
+
if ((_b = (_a = model === null || model === void 0 ? void 0 : model.localState) === null || _a === void 0 ? void 0 : _a.selected) === null || _b === void 0 ? void 0 : _b.value) {
|
|
57
|
+
setSelectedLayer(Object.keys((_d = (_c = model === null || model === void 0 ? void 0 : model.localState) === null || _c === void 0 ? void 0 : _c.selected) === null || _d === void 0 ? void 0 : _d.value)[0]);
|
|
58
|
+
}
|
|
59
|
+
}, [widgetId]);
|
|
60
|
+
useEffect(() => {
|
|
61
|
+
const handleClientStateChanged = () => {
|
|
62
|
+
var _a, _b, _c, _d;
|
|
63
|
+
if (!((_b = (_a = model === null || model === void 0 ? void 0 : model.localState) === null || _a === void 0 ? void 0 : _a.selected) === null || _b === void 0 ? void 0 : _b.value)) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
// TODO: handle multi select better
|
|
67
|
+
const currentLayer = Object.keys((_d = (_c = model === null || model === void 0 ? void 0 : model.localState) === null || _c === void 0 ? void 0 : _c.selected) === null || _d === void 0 ? void 0 : _d.value)[0];
|
|
68
|
+
setSelectedLayer(currentLayer);
|
|
69
|
+
};
|
|
70
|
+
const handleSharedOptionsChanged = (_, keys) => {
|
|
71
|
+
var _a, _b, _c, _d, _e;
|
|
72
|
+
// model changes when current widget changes, don't want this to run in that case
|
|
73
|
+
if (((_a = props.tracker.currentWidget) === null || _a === void 0 ? void 0 : _a.id) === widgetId && keys.has('zoom')) {
|
|
74
|
+
if (!((_c = (_b = model === null || model === void 0 ? void 0 : model.localState) === null || _b === void 0 ? void 0 : _b.selected) === null || _c === void 0 ? void 0 : _c.value)) {
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
const currentLayer = Object.keys((_e = (_d = model === null || model === void 0 ? void 0 : model.localState) === null || _d === void 0 ? void 0 : _d.selected) === null || _e === void 0 ? void 0 : _e.value)[0];
|
|
78
|
+
// TODO: Probably want to debounce/throttle here
|
|
79
|
+
buildFilterDebounce(currentLayer);
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
model === null || model === void 0 ? void 0 : model.clientStateChanged.connect(handleClientStateChanged);
|
|
83
|
+
// Want to rebuild filter object when zoom changes to get values for that zoom level
|
|
84
|
+
// This is because the filtering inputs may depend on the currently visible features
|
|
85
|
+
model === null || model === void 0 ? void 0 : model.sharedOptionsChanged.connect(handleSharedOptionsChanged);
|
|
86
|
+
return () => {
|
|
87
|
+
model === null || model === void 0 ? void 0 : model.clientStateChanged.disconnect(handleClientStateChanged);
|
|
88
|
+
model === null || model === void 0 ? void 0 : model.sharedOptionsChanged.disconnect(handleSharedOptionsChanged);
|
|
89
|
+
};
|
|
90
|
+
}, [model]);
|
|
91
|
+
useEffect(() => {
|
|
92
|
+
var _a, _b, _c, _d;
|
|
93
|
+
// Reset filter stuff for new layer
|
|
94
|
+
setFeaturesInLayer({});
|
|
95
|
+
const layer = model === null || model === void 0 ? void 0 : model.getLayer(selectedLayer);
|
|
96
|
+
if (!layer || layer.type !== 'VectorLayer') {
|
|
97
|
+
setShouldDisplay(false);
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
setShouldDisplay(true);
|
|
101
|
+
// Add existing filters to filterRows
|
|
102
|
+
setFilterRows((_b = (_a = layer.filters) === null || _a === void 0 ? void 0 : _a.appliedFilters) !== null && _b !== void 0 ? _b : []);
|
|
103
|
+
setLogicalOp((_d = (_c = layer.filters) === null || _c === void 0 ? void 0 : _c.logicalOp) !== null && _d !== void 0 ? _d : 'all');
|
|
104
|
+
buildFilterObject();
|
|
105
|
+
}, [selectedLayer]);
|
|
106
|
+
useEffect(() => {
|
|
107
|
+
featuresInLayerRef.current = featuresInLayer;
|
|
108
|
+
}, [featuresInLayer]);
|
|
109
|
+
const buildFilterObject = async (currentLayer) => {
|
|
110
|
+
var _a, _b, _c, _d;
|
|
111
|
+
if (!model) {
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
const layer = model.getLayer(currentLayer !== null && currentLayer !== void 0 ? currentLayer : selectedLayer);
|
|
115
|
+
const source = model.getSource((_a = layer === null || layer === void 0 ? void 0 : layer.parameters) === null || _a === void 0 ? void 0 : _a.source);
|
|
116
|
+
const { latitude, longitude, extent, zoom } = model.getOptions();
|
|
117
|
+
if (!source || !layer) {
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
const aggregatedProperties = cloneDeep(featuresInLayerRef.current);
|
|
121
|
+
// When we open a map, the filter object is empty.
|
|
122
|
+
// We want to populate it with the values from the
|
|
123
|
+
// selected layers filter so they show up on the panel
|
|
124
|
+
if (layer.filters) {
|
|
125
|
+
layer.filters.appliedFilters.map(filterItem => {
|
|
126
|
+
if (!(filterItem.feature in aggregatedProperties)) {
|
|
127
|
+
aggregatedProperties[filterItem.feature] = new Set();
|
|
128
|
+
}
|
|
129
|
+
aggregatedProperties[filterItem.feature].add(filterItem.value);
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
switch (source.type) {
|
|
133
|
+
case 'VectorTileSource': {
|
|
134
|
+
try {
|
|
135
|
+
const tile = await getLayerTileInfo((_b = source === null || source === void 0 ? void 0 : source.parameters) === null || _b === void 0 ? void 0 : _b.url, {
|
|
136
|
+
latitude,
|
|
137
|
+
longitude,
|
|
138
|
+
extent,
|
|
139
|
+
zoom
|
|
140
|
+
});
|
|
141
|
+
const layerValue = tile.layers[(_c = layer.parameters) === null || _c === void 0 ? void 0 : _c.sourceLayer];
|
|
142
|
+
for (let i = 0; i < layerValue.length; i++) {
|
|
143
|
+
const feature = layerValue.feature(i);
|
|
144
|
+
addFeatureValue(feature.properties, aggregatedProperties);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
catch (error) {
|
|
148
|
+
console.warn(`Error fetching tile info: ${error}`);
|
|
149
|
+
}
|
|
150
|
+
break;
|
|
151
|
+
}
|
|
152
|
+
case 'GeoJSONSource': {
|
|
153
|
+
const data = await (model === null || model === void 0 ? void 0 : model.readGeoJSON((_d = source.parameters) === null || _d === void 0 ? void 0 : _d.path));
|
|
154
|
+
data === null || data === void 0 ? void 0 : data.features.forEach((feature) => {
|
|
155
|
+
feature.properties &&
|
|
156
|
+
addFeatureValue(feature.properties, aggregatedProperties);
|
|
157
|
+
});
|
|
158
|
+
break;
|
|
159
|
+
}
|
|
160
|
+
default: {
|
|
161
|
+
console.warn('Source type not supported');
|
|
162
|
+
break;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
setFeaturesInLayer(aggregatedProperties);
|
|
166
|
+
};
|
|
167
|
+
const buildFilterDebounce = debounce(buildFilterObject, 500);
|
|
168
|
+
const addFeatureValue = (featureProperties, aggregatedProperties) => {
|
|
169
|
+
Object.entries(featureProperties).forEach(([key, value]) => {
|
|
170
|
+
if (!(key in aggregatedProperties)) {
|
|
171
|
+
aggregatedProperties[key] = new Set();
|
|
172
|
+
}
|
|
173
|
+
aggregatedProperties[key].add(value);
|
|
174
|
+
});
|
|
175
|
+
};
|
|
176
|
+
const addFilterRow = () => {
|
|
177
|
+
setFilterRows([
|
|
178
|
+
...filterRows,
|
|
179
|
+
{
|
|
180
|
+
feature: Object.keys(featuresInLayer)[0],
|
|
181
|
+
operator: '==',
|
|
182
|
+
value: [...Object.values(featuresInLayer)[0]][0]
|
|
183
|
+
}
|
|
184
|
+
]);
|
|
185
|
+
};
|
|
186
|
+
const deleteRow = (index) => {
|
|
187
|
+
const newFilters = [...filterRows];
|
|
188
|
+
newFilters.splice(index, 1);
|
|
189
|
+
updateLayerFilters(newFilters);
|
|
190
|
+
setFilterRows(newFilters);
|
|
191
|
+
};
|
|
192
|
+
const handleLogicalOpChange = (event) => {
|
|
193
|
+
setLogicalOp(event.target.value);
|
|
194
|
+
updateLayerFilters(filterRows, event.target.value);
|
|
195
|
+
};
|
|
196
|
+
const clearFilters = () => {
|
|
197
|
+
updateLayerFilters([]);
|
|
198
|
+
setFilterRows([]);
|
|
199
|
+
};
|
|
200
|
+
const submitFilter = () => {
|
|
201
|
+
updateLayerFilters(filterRows);
|
|
202
|
+
};
|
|
203
|
+
const updateLayerFilters = (filters, op) => {
|
|
204
|
+
const layer = model === null || model === void 0 ? void 0 : model.getLayer(selectedLayer);
|
|
205
|
+
if (!layer) {
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
layer.filters = { logicalOp: op !== null && op !== void 0 ? op : logicalOp, appliedFilters: filters };
|
|
209
|
+
model === null || model === void 0 ? void 0 : model.sharedModel.updateLayer(selectedLayer, layer);
|
|
210
|
+
};
|
|
211
|
+
return (React.createElement(React.Fragment, null, shouldDisplay && (React.createElement("div", { className: "jp-gis-filter-main" },
|
|
212
|
+
React.createElement("div", { id: "filter-container", className: "jp-gis-filter-select-container" },
|
|
213
|
+
React.createElement("select", { className: "jp-mod-styled jp-SchemaForm jp-gis-logical-select", onChange: handleLogicalOpChange },
|
|
214
|
+
React.createElement("option", { key: "all", value: "all", selected: logicalOp === 'all' }, "All"),
|
|
215
|
+
React.createElement("option", { key: "any", value: "any", selected: logicalOp === 'any' }, "Any")),
|
|
216
|
+
filterRows.map((row, index) => (React.createElement(FilterRow, { key: index, index: index, features: featuresInLayer, filterRows: filterRows, setFilterRows: setFilterRows, deleteRow: () => deleteRow(index) })))),
|
|
217
|
+
React.createElement("div", { className: "jp-gis-filter-button-container" },
|
|
218
|
+
React.createElement("div", { style: { justifyContent: 'flex-start' } },
|
|
219
|
+
React.createElement(Button, { className: "jp-Dialog-button jp-mod-accept jp-mod-styled", onClick: addFilterRow }, "Add"),
|
|
220
|
+
React.createElement(Button, { className: "jp-Dialog-button jp-mod-reject jp-mod-styled", onClick: clearFilters }, "Clear")),
|
|
221
|
+
React.createElement(Button, { className: "jp-Dialog-button jp-mod-accept jp-mod-styled", onClick: submitFilter }, "Submit"))))));
|
|
222
|
+
};
|
|
223
|
+
export default FilterComponent;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
declare const FilterRow: ({ index, features, filterRows, setFilterRows, deleteRow }: {
|
|
3
|
+
index: number;
|
|
4
|
+
features: Record<string, Set<string | number>>;
|
|
5
|
+
filterRows: any;
|
|
6
|
+
setFilterRows: any;
|
|
7
|
+
deleteRow: () => void;
|
|
8
|
+
}) => React.JSX.Element;
|
|
9
|
+
export default FilterRow;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { faTrash } from '@fortawesome/free-solid-svg-icons';
|
|
2
|
+
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
|
3
|
+
import { Button } from '@jupyterlab/ui-components';
|
|
4
|
+
import React, { useEffect, useState } from 'react';
|
|
5
|
+
const FilterRow = ({ index, features, filterRows, setFilterRows, deleteRow }) => {
|
|
6
|
+
const operators = ['==', '!=', '>', '<', '>=', '<='];
|
|
7
|
+
const [sortedFeatures, setSortedFeatures] = useState({});
|
|
8
|
+
const [selectedFeature, setSelectedFeature] = useState(filterRows[index].feature || Object.keys(features)[0]);
|
|
9
|
+
// Ensure selected feature matches filter rows and proper values are displayed
|
|
10
|
+
useEffect(() => {
|
|
11
|
+
setSelectedFeature(filterRows[index].feature);
|
|
12
|
+
}, [filterRows]);
|
|
13
|
+
useEffect(() => {
|
|
14
|
+
const sortedKeys = Object.keys(features).sort();
|
|
15
|
+
const sortedResult = {};
|
|
16
|
+
for (const key of sortedKeys) {
|
|
17
|
+
// Convert each Set to a sorted array
|
|
18
|
+
const sortedArray = Array.from(features[key]).sort();
|
|
19
|
+
sortedResult[key] = sortedArray;
|
|
20
|
+
}
|
|
21
|
+
setSortedFeatures(sortedResult);
|
|
22
|
+
}, [features]);
|
|
23
|
+
// Update the value when a new feature is selected
|
|
24
|
+
useEffect(() => {
|
|
25
|
+
var _a;
|
|
26
|
+
const valueSelect = document.getElementById(`jp-gis-value-select-${index}`);
|
|
27
|
+
if (!valueSelect) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
const currentValue = (_a = valueSelect.options[valueSelect.selectedIndex]) === null || _a === void 0 ? void 0 : _a.value;
|
|
31
|
+
currentValue && onValueChange(currentValue);
|
|
32
|
+
}, [selectedFeature]);
|
|
33
|
+
const onValueChange = (value) => {
|
|
34
|
+
const newFilters = [...filterRows];
|
|
35
|
+
const isNum = typeof sortedFeatures[selectedFeature][0] === 'number';
|
|
36
|
+
newFilters[index].value = isNum ? +value : value;
|
|
37
|
+
setFilterRows(newFilters);
|
|
38
|
+
};
|
|
39
|
+
const handleKeyChange = (event) => {
|
|
40
|
+
const newFilters = [...filterRows];
|
|
41
|
+
newFilters[index].feature = event.target.value;
|
|
42
|
+
setSelectedFeature(event.target.value);
|
|
43
|
+
setFilterRows(newFilters);
|
|
44
|
+
};
|
|
45
|
+
const handleOperatorChange = (event) => {
|
|
46
|
+
const newFilters = [...filterRows];
|
|
47
|
+
newFilters[index].operator = event.target.value;
|
|
48
|
+
setFilterRows(newFilters);
|
|
49
|
+
};
|
|
50
|
+
const handleValueChange = (event) => {
|
|
51
|
+
onValueChange(event.target.value);
|
|
52
|
+
};
|
|
53
|
+
return (React.createElement("div", { className: "jp-gis-filter-row" },
|
|
54
|
+
React.createElement("select", { id: `jp-gis-feature-select-${index}`, className: "jp-mod-styled jp-SchemaForm", onChange: handleKeyChange }, Object.keys(sortedFeatures).map((feature, featureIndex) => (React.createElement("option", { key: featureIndex, value: feature, selected: feature === filterRows[index].feature }, feature)))),
|
|
55
|
+
React.createElement("select", { id: `jp-gis-operator-select-${index}`, className: "jp-mod-styled jp-SchemaForm", onChange: handleOperatorChange }, operators.map((operator, operatorIndex) => (React.createElement("option", { key: operatorIndex, value: operator, selected: operator === filterRows[index].operator }, operator)))),
|
|
56
|
+
React.createElement("select", { id: `jp-gis-value-select-${index}`, className: "jp-mod-styled jp-SchemaForm", onChange: handleValueChange }, sortedFeatures[selectedFeature] &&
|
|
57
|
+
[...sortedFeatures[selectedFeature]].map((value, valueIndex) => (React.createElement("option", { key: valueIndex, value: value, selected: value === filterRows[index].value }, value)))),
|
|
58
|
+
React.createElement(Button, { id: `jp-gis-remove-filter-${index}`, className: "jp-Button jp-gis-filter-icon" },
|
|
59
|
+
React.createElement(FontAwesomeIcon, { icon: faTrash, onClick: deleteRow }))));
|
|
60
|
+
};
|
|
61
|
+
export default FilterRow;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Panel } from '@lumino/widgets';
|
|
2
|
+
import { ILayerPanelOptions } from '../leftpanel';
|
|
3
|
+
/**
|
|
4
|
+
* The layers panel widget.
|
|
5
|
+
*/
|
|
6
|
+
export declare class LayersPanel extends Panel {
|
|
7
|
+
constructor(options: ILayerPanelOptions);
|
|
8
|
+
private _onDragOver;
|
|
9
|
+
private _onDrop;
|
|
10
|
+
private _model;
|
|
11
|
+
private _state;
|
|
12
|
+
private _onSelect;
|
|
13
|
+
}
|