@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,30 @@
|
|
|
1
|
+
export class ControlPanelModel {
|
|
2
|
+
constructor(options) {
|
|
3
|
+
this._tracker = options.tracker;
|
|
4
|
+
this._documentChanged = this._tracker.currentChanged;
|
|
5
|
+
}
|
|
6
|
+
get documentChanged() {
|
|
7
|
+
return this._documentChanged;
|
|
8
|
+
}
|
|
9
|
+
get filePath() {
|
|
10
|
+
var _a;
|
|
11
|
+
return (_a = this._tracker.currentWidget) === null || _a === void 0 ? void 0 : _a.context.localPath;
|
|
12
|
+
}
|
|
13
|
+
get jGISModel() {
|
|
14
|
+
var _a;
|
|
15
|
+
return (_a = this._tracker.currentWidget) === null || _a === void 0 ? void 0 : _a.context.model;
|
|
16
|
+
}
|
|
17
|
+
get sharedModel() {
|
|
18
|
+
var _a;
|
|
19
|
+
return (_a = this._tracker.currentWidget) === null || _a === void 0 ? void 0 : _a.context.model.sharedModel;
|
|
20
|
+
}
|
|
21
|
+
disconnect(f) {
|
|
22
|
+
this._tracker.forEach(w => {
|
|
23
|
+
w.context.model.sharedLayersChanged.disconnect(f);
|
|
24
|
+
w.context.model.sharedSourcesChanged.disconnect(f);
|
|
25
|
+
w.context.model.sharedOptionsChanged.disconnect(f);
|
|
26
|
+
});
|
|
27
|
+
this._tracker.forEach(w => w.context.model.themeChanged.disconnect(f));
|
|
28
|
+
this._tracker.forEach(w => w.context.model.clientStateChanged.disconnect(f));
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { IJGISFormSchemaRegistry, IJupyterGISTracker } from '@jupytergis/schema';
|
|
2
|
+
import { PanelWithToolbar } from '@jupyterlab/ui-components';
|
|
3
|
+
import { Panel } from '@lumino/widgets';
|
|
4
|
+
import { IControlPanelModel } from '../types';
|
|
5
|
+
export declare class ObjectProperties extends PanelWithToolbar {
|
|
6
|
+
constructor(params: ObjectProperties.IOptions);
|
|
7
|
+
}
|
|
8
|
+
export declare namespace ObjectProperties {
|
|
9
|
+
/**
|
|
10
|
+
* Instantiation options for `ObjectProperties`.
|
|
11
|
+
*/
|
|
12
|
+
interface IOptions extends Panel.IOptions {
|
|
13
|
+
controlPanelModel: IControlPanelModel;
|
|
14
|
+
formSchemaRegistry: IJGISFormSchemaRegistry;
|
|
15
|
+
tracker: IJupyterGISTracker;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { ReactWidget } from '@jupyterlab/apputils';
|
|
2
|
+
import { PanelWithToolbar } from '@jupyterlab/ui-components';
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import { v4 as uuid } from 'uuid';
|
|
5
|
+
import { EditForm } from '../formbuilder/editform';
|
|
6
|
+
export class ObjectProperties extends PanelWithToolbar {
|
|
7
|
+
constructor(params) {
|
|
8
|
+
super(params);
|
|
9
|
+
this.title.label = 'Objects Properties';
|
|
10
|
+
const body = ReactWidget.create(React.createElement(ObjectPropertiesReact, { cpModel: params.controlPanelModel, tracker: params.tracker, formSchemaRegistry: params.formSchemaRegistry }));
|
|
11
|
+
this.addWidget(body);
|
|
12
|
+
this.addClass('jGIS-sidebar-propertiespanel');
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
class ObjectPropertiesReact extends React.Component {
|
|
16
|
+
constructor(props) {
|
|
17
|
+
var _a, _b, _c;
|
|
18
|
+
super(props);
|
|
19
|
+
this._sharedJGISModelChanged = () => {
|
|
20
|
+
this.forceUpdate();
|
|
21
|
+
};
|
|
22
|
+
this._onClientSharedStateChanged = (sender, clients) => {
|
|
23
|
+
var _a, _b;
|
|
24
|
+
let newState;
|
|
25
|
+
const clientId = this.state.clientId;
|
|
26
|
+
const localState = clientId ? clients.get(clientId) : null;
|
|
27
|
+
if (localState &&
|
|
28
|
+
((_a = localState.selected) === null || _a === void 0 ? void 0 : _a.emitter) &&
|
|
29
|
+
localState.selected.emitter !== this.state.id &&
|
|
30
|
+
((_b = localState.selected) === null || _b === void 0 ? void 0 : _b.value)) {
|
|
31
|
+
newState = localState;
|
|
32
|
+
}
|
|
33
|
+
if (newState) {
|
|
34
|
+
const selection = newState.selected.value;
|
|
35
|
+
const selectedObjectIds = Object.keys(selection || {});
|
|
36
|
+
// Only show object properties if ONE object is selected
|
|
37
|
+
if (selection === undefined || selectedObjectIds.length !== 1) {
|
|
38
|
+
this.setState(old => (Object.assign(Object.assign({}, old), { selectedObject: undefined })));
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
const selectedObject = selectedObjectIds[0];
|
|
42
|
+
if (selectedObject !== this.state.selectedObject) {
|
|
43
|
+
this.setState(old => (Object.assign(Object.assign({}, old), { selectedObject })));
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
this.state = {
|
|
48
|
+
context: (_a = props.tracker.currentWidget) === null || _a === void 0 ? void 0 : _a.context,
|
|
49
|
+
clientId: null,
|
|
50
|
+
id: uuid()
|
|
51
|
+
};
|
|
52
|
+
(_b = this.props.cpModel.jGISModel) === null || _b === void 0 ? void 0 : _b.sharedLayersChanged.connect(this._sharedJGISModelChanged);
|
|
53
|
+
(_c = this.props.cpModel.jGISModel) === null || _c === void 0 ? void 0 : _c.sharedSourcesChanged.connect(this._sharedJGISModelChanged);
|
|
54
|
+
this.props.cpModel.documentChanged.connect((_, changed) => {
|
|
55
|
+
if (changed) {
|
|
56
|
+
this.props.cpModel.disconnect(this._sharedJGISModelChanged);
|
|
57
|
+
this.props.cpModel.disconnect(this._onClientSharedStateChanged);
|
|
58
|
+
changed.context.model.sharedLayersChanged.connect(this._sharedJGISModelChanged);
|
|
59
|
+
changed.context.model.sharedSourcesChanged.connect(this._sharedJGISModelChanged);
|
|
60
|
+
changed.context.model.clientStateChanged.connect(this._onClientSharedStateChanged);
|
|
61
|
+
this.setState(old => (Object.assign(Object.assign({}, old), { context: changed.context, filePath: changed.context.localPath, clientId: changed.context.model.getClientId() })));
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
this.setState({
|
|
65
|
+
context: undefined,
|
|
66
|
+
selectedObject: undefined
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
render() {
|
|
72
|
+
var _a;
|
|
73
|
+
const selectedObject = this.state.selectedObject;
|
|
74
|
+
if (!selectedObject || !this.state.context) {
|
|
75
|
+
return React.createElement("div", null);
|
|
76
|
+
}
|
|
77
|
+
let layerId = undefined;
|
|
78
|
+
let sourceId = undefined;
|
|
79
|
+
const layer = this.state.context.model.getLayer(selectedObject);
|
|
80
|
+
if (layer) {
|
|
81
|
+
layerId = selectedObject;
|
|
82
|
+
sourceId = (_a = layer.parameters) === null || _a === void 0 ? void 0 : _a.source;
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
const source = this.state.context.model.getSource(selectedObject);
|
|
86
|
+
if (source) {
|
|
87
|
+
sourceId = selectedObject;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return (React.createElement(EditForm, { layer: layerId, source: sourceId, formSchemaRegistry: this.props.formSchemaRegistry, context: this.state.context }));
|
|
91
|
+
}
|
|
92
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { IJGISFormSchemaRegistry, IJupyterGISTracker, JupyterGISDoc } from '@jupytergis/schema';
|
|
2
|
+
import { SidePanel } from '@jupyterlab/ui-components';
|
|
3
|
+
import { IControlPanelModel } from '../types';
|
|
4
|
+
export declare class RightPanelWidget extends SidePanel {
|
|
5
|
+
constructor(options: RightPanelWidget.IOptions);
|
|
6
|
+
dispose(): void;
|
|
7
|
+
private _model;
|
|
8
|
+
}
|
|
9
|
+
export declare namespace RightPanelWidget {
|
|
10
|
+
interface IOptions {
|
|
11
|
+
model: IControlPanelModel;
|
|
12
|
+
tracker: IJupyterGISTracker;
|
|
13
|
+
formSchemaRegistry: IJGISFormSchemaRegistry;
|
|
14
|
+
}
|
|
15
|
+
interface IProps {
|
|
16
|
+
filePath?: string;
|
|
17
|
+
sharedModel?: JupyterGISDoc;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { SidePanel } from '@jupyterlab/ui-components';
|
|
2
|
+
import { FilterPanel } from './components/filter-panel/Filter';
|
|
3
|
+
import { ControlPanelHeader } from './header';
|
|
4
|
+
import { ObjectProperties } from './objectproperties';
|
|
5
|
+
export class RightPanelWidget extends SidePanel {
|
|
6
|
+
constructor(options) {
|
|
7
|
+
super();
|
|
8
|
+
this.addClass('jGIS-sidepanel-widget');
|
|
9
|
+
this._model = options.model;
|
|
10
|
+
const header = new ControlPanelHeader();
|
|
11
|
+
this.header.addWidget(header);
|
|
12
|
+
const properties = new ObjectProperties({
|
|
13
|
+
controlPanelModel: this._model,
|
|
14
|
+
formSchemaRegistry: options.formSchemaRegistry,
|
|
15
|
+
tracker: options.tracker
|
|
16
|
+
});
|
|
17
|
+
this.addWidget(properties);
|
|
18
|
+
const filterPanel = new FilterPanel({
|
|
19
|
+
model: this._model,
|
|
20
|
+
tracker: options.tracker,
|
|
21
|
+
formSchemaRegistry: options.formSchemaRegistry
|
|
22
|
+
});
|
|
23
|
+
filterPanel.title.caption = 'Filters';
|
|
24
|
+
filterPanel.title.label = 'Filters';
|
|
25
|
+
this.addWidget(filterPanel);
|
|
26
|
+
this._model.documentChanged.connect((_, changed) => {
|
|
27
|
+
if (changed) {
|
|
28
|
+
if (changed.context.model.sharedModel.editable) {
|
|
29
|
+
header.title.label = changed.context.localPath;
|
|
30
|
+
properties.show();
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
header.title.label = `${changed.context.localPath} - Read Only`;
|
|
34
|
+
properties.hide();
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
header.title.label = '-';
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
dispose() {
|
|
43
|
+
super.dispose();
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { IUserData, JupyterGISModel } from '@jupytergis/schema';
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
interface IProps {
|
|
4
|
+
model: JupyterGISModel;
|
|
5
|
+
}
|
|
6
|
+
interface IState {
|
|
7
|
+
usersList: IUserData[];
|
|
8
|
+
selectedUser?: IUserData;
|
|
9
|
+
}
|
|
10
|
+
export declare class UsersItem extends React.Component<IProps, IState> {
|
|
11
|
+
constructor(props: IProps);
|
|
12
|
+
componentDidMount(): void;
|
|
13
|
+
selectUser: (user: IUserData) => void;
|
|
14
|
+
private createUserIcon;
|
|
15
|
+
private filterDuplicated;
|
|
16
|
+
render(): React.ReactNode;
|
|
17
|
+
private _model;
|
|
18
|
+
}
|
|
19
|
+
export {};
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
export class UsersItem extends React.Component {
|
|
3
|
+
constructor(props) {
|
|
4
|
+
super(props);
|
|
5
|
+
this.selectUser = (user) => {
|
|
6
|
+
var _a;
|
|
7
|
+
let selected = undefined;
|
|
8
|
+
if (user.userId !== ((_a = this.state.selectedUser) === null || _a === void 0 ? void 0 : _a.userId)) {
|
|
9
|
+
selected = user;
|
|
10
|
+
}
|
|
11
|
+
this.setState(old => (Object.assign(Object.assign({}, old), { selectedUser: selected })), () => {
|
|
12
|
+
this._model.setUserToFollow(selected === null || selected === void 0 ? void 0 : selected.userId);
|
|
13
|
+
});
|
|
14
|
+
};
|
|
15
|
+
this._model = props.model;
|
|
16
|
+
this.state = { usersList: [] };
|
|
17
|
+
}
|
|
18
|
+
componentDidMount() {
|
|
19
|
+
this.setState(old => (Object.assign(Object.assign({}, old), { usersList: this._model.users })));
|
|
20
|
+
this._model.userChanged.connect((_, usersList) => {
|
|
21
|
+
this.setState(old => (Object.assign(Object.assign({}, old), { usersList: usersList })));
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
createUserIcon(options) {
|
|
25
|
+
var _a;
|
|
26
|
+
let el;
|
|
27
|
+
const { userId, userData } = options;
|
|
28
|
+
const selected = `${userId === ((_a = this.state.selectedUser) === null || _a === void 0 ? void 0 : _a.userId) ? 'selected' : ''}`;
|
|
29
|
+
if (userData.avatar_url) {
|
|
30
|
+
el = (React.createElement("div", { key: userId, title: userData.display_name, className: `lm-MenuBar-itemIcon jp-MenuBar-imageIcon ${selected}`, onClick: () => this.selectUser(options) },
|
|
31
|
+
React.createElement("img", { src: userData.avatar_url, alt: "" })));
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
el = (React.createElement("div", { key: userId, title: userData.display_name, className: `lm-MenuBar-itemIcon jp-MenuBar-anonymousIcon ${selected}`, style: { backgroundColor: userData.color }, onClick: () => this.selectUser(options) },
|
|
35
|
+
React.createElement("span", null, userData.initials)));
|
|
36
|
+
}
|
|
37
|
+
return el;
|
|
38
|
+
}
|
|
39
|
+
filterDuplicated(usersList) {
|
|
40
|
+
const newList = [];
|
|
41
|
+
const selected = new Set();
|
|
42
|
+
for (const element of usersList) {
|
|
43
|
+
if (!selected.has(element.userData.username)) {
|
|
44
|
+
selected.add(element.userData.username);
|
|
45
|
+
newList.push(element);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return newList;
|
|
49
|
+
}
|
|
50
|
+
render() {
|
|
51
|
+
return (React.createElement("div", { className: "jGIS-toolbar-usertoolbar" }, this.filterDuplicated(this.state.usersList).map(item => {
|
|
52
|
+
if (item.userId !== this._model.currentUserId) {
|
|
53
|
+
return this.createUserIcon(item);
|
|
54
|
+
}
|
|
55
|
+
})));
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { IJGISExternalCommand, JupyterGISModel } from '@jupytergis/schema';
|
|
2
|
+
import { Toolbar } from '@jupyterlab/ui-components';
|
|
3
|
+
import { CommandRegistry } from '@lumino/commands';
|
|
4
|
+
import { Widget } from '@lumino/widgets';
|
|
5
|
+
export declare const TOOLBAR_SEPARATOR_CLASS = "jGIS-Toolbar-Separator";
|
|
6
|
+
export declare const TOOLBAR_GROUPNAME_CLASS = "jGIS-Toolbar-GroupName";
|
|
7
|
+
export declare class Separator extends Widget {
|
|
8
|
+
/**
|
|
9
|
+
* Construct a new separator widget.
|
|
10
|
+
*/
|
|
11
|
+
constructor();
|
|
12
|
+
}
|
|
13
|
+
export declare class ToolbarWidget extends Toolbar {
|
|
14
|
+
constructor(options: ToolbarWidget.IOptions);
|
|
15
|
+
}
|
|
16
|
+
export declare namespace ToolbarWidget {
|
|
17
|
+
interface IOptions extends Toolbar.IOptions {
|
|
18
|
+
commands?: CommandRegistry;
|
|
19
|
+
model: JupyterGISModel;
|
|
20
|
+
externalCommands: IJGISExternalCommand[];
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { CommandToolbarButton } from '@jupyterlab/apputils';
|
|
2
|
+
import { ReactWidget, Toolbar, ToolbarButton, addIcon, redoIcon, undoIcon, terminalIcon } from '@jupyterlab/ui-components';
|
|
3
|
+
import { Menu, Widget } from '@lumino/widgets';
|
|
4
|
+
import * as React from 'react';
|
|
5
|
+
import { CommandIDs } from '../constants';
|
|
6
|
+
import { UsersItem } from './usertoolbaritem';
|
|
7
|
+
export const TOOLBAR_SEPARATOR_CLASS = 'jGIS-Toolbar-Separator';
|
|
8
|
+
export const TOOLBAR_GROUPNAME_CLASS = 'jGIS-Toolbar-GroupName';
|
|
9
|
+
export class Separator extends Widget {
|
|
10
|
+
/**
|
|
11
|
+
* Construct a new separator widget.
|
|
12
|
+
*/
|
|
13
|
+
constructor() {
|
|
14
|
+
super();
|
|
15
|
+
this.addClass(TOOLBAR_SEPARATOR_CLASS);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
export class ToolbarWidget extends Toolbar {
|
|
19
|
+
constructor(options) {
|
|
20
|
+
super(options);
|
|
21
|
+
this.addClass('jGIS-toolbar-widget');
|
|
22
|
+
if (options.commands) {
|
|
23
|
+
this.addItem('undo', new CommandToolbarButton({
|
|
24
|
+
id: CommandIDs.undo,
|
|
25
|
+
label: '',
|
|
26
|
+
icon: undoIcon,
|
|
27
|
+
commands: options.commands
|
|
28
|
+
}));
|
|
29
|
+
this.addItem('redo', new CommandToolbarButton({
|
|
30
|
+
id: CommandIDs.redo,
|
|
31
|
+
label: '',
|
|
32
|
+
icon: redoIcon,
|
|
33
|
+
commands: options.commands
|
|
34
|
+
}));
|
|
35
|
+
this.addItem('separator0', new Separator());
|
|
36
|
+
this.addItem('Toggle console', new CommandToolbarButton({
|
|
37
|
+
id: CommandIDs.toggleConsole,
|
|
38
|
+
commands: options.commands,
|
|
39
|
+
label: '',
|
|
40
|
+
icon: terminalIcon
|
|
41
|
+
}));
|
|
42
|
+
this.addItem('separator1', new Separator());
|
|
43
|
+
this.addItem('openLayerBrowser', new CommandToolbarButton({
|
|
44
|
+
id: CommandIDs.openLayerBrowser,
|
|
45
|
+
label: '',
|
|
46
|
+
commands: options.commands
|
|
47
|
+
}));
|
|
48
|
+
this.addItem('newRasterEntry', new CommandToolbarButton({
|
|
49
|
+
id: CommandIDs.newRasterEntry,
|
|
50
|
+
label: '',
|
|
51
|
+
commands: options.commands
|
|
52
|
+
}));
|
|
53
|
+
this.addItem('newVectorTileEntry', new CommandToolbarButton({
|
|
54
|
+
id: CommandIDs.newVectorTileEntry,
|
|
55
|
+
label: '',
|
|
56
|
+
commands: options.commands
|
|
57
|
+
}));
|
|
58
|
+
this.addItem('separator2', new Separator());
|
|
59
|
+
const NewButton = new ToolbarButton({
|
|
60
|
+
icon: addIcon,
|
|
61
|
+
actualOnClick: true,
|
|
62
|
+
onClick: () => {
|
|
63
|
+
if (!options.commands) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
const bbox = NewButton.node.getBoundingClientRect();
|
|
67
|
+
const NewSubMenu = new Menu({ commands: options.commands });
|
|
68
|
+
NewSubMenu.title.label = 'New Layer';
|
|
69
|
+
NewSubMenu.addItem({
|
|
70
|
+
type: 'command',
|
|
71
|
+
command: CommandIDs.newHillshadeEntry
|
|
72
|
+
});
|
|
73
|
+
NewSubMenu.addItem({
|
|
74
|
+
type: 'separator'
|
|
75
|
+
});
|
|
76
|
+
NewSubMenu.addItem({
|
|
77
|
+
type: 'command',
|
|
78
|
+
command: CommandIDs.newImageEntry
|
|
79
|
+
});
|
|
80
|
+
NewSubMenu.addItem({
|
|
81
|
+
type: 'separator'
|
|
82
|
+
});
|
|
83
|
+
NewSubMenu.addItem({
|
|
84
|
+
type: 'command',
|
|
85
|
+
command: CommandIDs.newShapefileLayer
|
|
86
|
+
});
|
|
87
|
+
NewSubMenu.addItem({
|
|
88
|
+
type: 'command',
|
|
89
|
+
command: CommandIDs.newGeoTiffEntry
|
|
90
|
+
});
|
|
91
|
+
NewSubMenu.addItem({
|
|
92
|
+
type: 'command',
|
|
93
|
+
command: CommandIDs.newGeoJSONEntry
|
|
94
|
+
});
|
|
95
|
+
NewSubMenu.open(bbox.x, bbox.bottom);
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
this.addItem('New', NewButton);
|
|
99
|
+
this.addItem('spacer', Toolbar.createSpacerItem());
|
|
100
|
+
// Users
|
|
101
|
+
this.addItem('users', ReactWidget.create(React.createElement(UsersItem, { model: options.model })));
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
package/lib/tools.d.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { VectorTile } from '@mapbox/vector-tile';
|
|
2
|
+
import { IDict, IJGISLayerBrowserRegistry, IJGISOptions } from '@jupytergis/schema';
|
|
3
|
+
export declare const debounce: (func: CallableFunction, timeout?: number) => CallableFunction;
|
|
4
|
+
export declare function throttle<T extends (...args: any[]) => void>(callback: T, delay?: number): T;
|
|
5
|
+
export declare function getElementFromProperty(filePath?: string | null, prop?: string | null): HTMLElement | undefined | null;
|
|
6
|
+
export declare function nearest(n: number, tol: number): number;
|
|
7
|
+
export declare function getCSSVariableColor(name: string): string;
|
|
8
|
+
/**
|
|
9
|
+
* Call the API extension
|
|
10
|
+
*
|
|
11
|
+
* @param endPoint API REST end point for the extension
|
|
12
|
+
* @param init Initial values for the request
|
|
13
|
+
* @returns The response body interpreted as JSON
|
|
14
|
+
*/
|
|
15
|
+
export declare function requestAPI<T>(endPoint?: string, init?: RequestInit): Promise<T>;
|
|
16
|
+
export declare function isLightTheme(): boolean;
|
|
17
|
+
export declare function deepCopy<T = IDict<any>>(value: T): T;
|
|
18
|
+
/**
|
|
19
|
+
* Create a default layer registry
|
|
20
|
+
*
|
|
21
|
+
* @param layerBrowserRegistry Registry to add layers to
|
|
22
|
+
*/
|
|
23
|
+
export declare function createDefaultLayerRegistry(layerBrowserRegistry: IJGISLayerBrowserRegistry): void;
|
|
24
|
+
export declare function getLayerTileInfo(tileUrl: string, mapOptions: Pick<IJGISOptions, 'latitude' | 'longitude' | 'extent' | 'zoom'>, urlParameters?: IDict<string>): Promise<VectorTile>;
|
|
25
|
+
export declare function getSourceLayerNames(tileUrl: string, urlParameters?: IDict<string>): Promise<string[]>;
|
package/lib/tools.js
ADDED
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import Protobuf from 'pbf';
|
|
2
|
+
import { VectorTile } from '@mapbox/vector-tile';
|
|
3
|
+
import { URLExt } from '@jupyterlab/coreutils';
|
|
4
|
+
import { ServerConnection } from '@jupyterlab/services';
|
|
5
|
+
import * as d3Color from 'd3-color';
|
|
6
|
+
import RASTER_LAYER_GALLERY from '../rasterlayer_gallery/raster_layer_gallery.json';
|
|
7
|
+
export const debounce = (func, timeout = 100) => {
|
|
8
|
+
let timeoutId;
|
|
9
|
+
return (...args) => {
|
|
10
|
+
clearTimeout(timeoutId);
|
|
11
|
+
timeoutId = window.setTimeout(() => {
|
|
12
|
+
func(...args);
|
|
13
|
+
}, timeout);
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
export function throttle(callback, delay = 100) {
|
|
17
|
+
let last;
|
|
18
|
+
let timer;
|
|
19
|
+
return function (...args) {
|
|
20
|
+
const now = +new Date();
|
|
21
|
+
if (last && now < last + delay) {
|
|
22
|
+
clearTimeout(timer);
|
|
23
|
+
timer = setTimeout(() => {
|
|
24
|
+
last = now;
|
|
25
|
+
callback(...args);
|
|
26
|
+
}, delay);
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
last = now;
|
|
30
|
+
callback(...args);
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
export function getElementFromProperty(filePath, prop) {
|
|
35
|
+
if (!filePath || !prop) {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
const parent = document.querySelector(`[data-path="${filePath}"]`);
|
|
39
|
+
if (parent) {
|
|
40
|
+
const el = parent.querySelector(`[id$=${prop}]`);
|
|
41
|
+
return el;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
export function nearest(n, tol) {
|
|
45
|
+
const round = Math.round(n);
|
|
46
|
+
if (Math.abs(round - n) < tol) {
|
|
47
|
+
return round;
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
return n;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
export function getCSSVariableColor(name) {
|
|
54
|
+
const color = window.getComputedStyle(document.body).getPropertyValue(name) || '#ffffff';
|
|
55
|
+
return d3Color.rgb(color).formatHex();
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Call the API extension
|
|
59
|
+
*
|
|
60
|
+
* @param endPoint API REST end point for the extension
|
|
61
|
+
* @param init Initial values for the request
|
|
62
|
+
* @returns The response body interpreted as JSON
|
|
63
|
+
*/
|
|
64
|
+
export async function requestAPI(endPoint = '', init = {}) {
|
|
65
|
+
// Make request to Jupyter API
|
|
66
|
+
const settings = ServerConnection.makeSettings();
|
|
67
|
+
const requestUrl = URLExt.join(settings.baseUrl, endPoint);
|
|
68
|
+
let response;
|
|
69
|
+
try {
|
|
70
|
+
response = await ServerConnection.makeRequest(requestUrl, init, settings);
|
|
71
|
+
}
|
|
72
|
+
catch (error) {
|
|
73
|
+
throw new ServerConnection.NetworkError(error);
|
|
74
|
+
}
|
|
75
|
+
let data = await response.text();
|
|
76
|
+
if (data.length > 0) {
|
|
77
|
+
try {
|
|
78
|
+
data = JSON.parse(data);
|
|
79
|
+
}
|
|
80
|
+
catch (error) {
|
|
81
|
+
console.log('Not a JSON response body.', response);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
if (!response.ok) {
|
|
85
|
+
throw new ServerConnection.ResponseError(response, data.message || data);
|
|
86
|
+
}
|
|
87
|
+
return data;
|
|
88
|
+
}
|
|
89
|
+
export function isLightTheme() {
|
|
90
|
+
return document.body.getAttribute('data-jp-theme-light') === 'true';
|
|
91
|
+
}
|
|
92
|
+
export function deepCopy(value) {
|
|
93
|
+
if (!value) {
|
|
94
|
+
return value;
|
|
95
|
+
}
|
|
96
|
+
return JSON.parse(JSON.stringify(value));
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Create a default layer registry
|
|
100
|
+
*
|
|
101
|
+
* @param layerBrowserRegistry Registry to add layers to
|
|
102
|
+
*/
|
|
103
|
+
export function createDefaultLayerRegistry(layerBrowserRegistry) {
|
|
104
|
+
const RASTER_THUMBNAILS = {};
|
|
105
|
+
/**
|
|
106
|
+
* Generate object to hold thumbnail URLs
|
|
107
|
+
*/
|
|
108
|
+
const importAll = (r) => {
|
|
109
|
+
r.keys().forEach(key => {
|
|
110
|
+
const imageName = key.replace('./', '').replace(/\.\w+$/, '');
|
|
111
|
+
RASTER_THUMBNAILS[imageName] = r(key);
|
|
112
|
+
});
|
|
113
|
+
};
|
|
114
|
+
const context = require.context('../rasterlayer_gallery', false, /\.(png|jpe?g|gif|svg)$/);
|
|
115
|
+
importAll(context);
|
|
116
|
+
for (const entry of Object.keys(RASTER_LAYER_GALLERY)) {
|
|
117
|
+
const xyzprovider = RASTER_LAYER_GALLERY[entry];
|
|
118
|
+
if ('url' in xyzprovider) {
|
|
119
|
+
const tile = convertToRegistryEntry(entry, xyzprovider);
|
|
120
|
+
layerBrowserRegistry.addRegistryLayer(tile);
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
Object.keys(xyzprovider).forEach(mapName => {
|
|
124
|
+
const tile = convertToRegistryEntry(xyzprovider[mapName]['name'], xyzprovider[mapName], entry);
|
|
125
|
+
layerBrowserRegistry.addRegistryLayer(tile);
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
// TODO: These need better names
|
|
130
|
+
/**
|
|
131
|
+
* Parse tile information from providers to be useable in the layer registry
|
|
132
|
+
*
|
|
133
|
+
* @param entry - The name of the entry, which may also serve as the default provider name if none is specified.
|
|
134
|
+
* @param xyzprovider - An object containing the XYZ provider's details, including name, URL, zoom levels, attribution, and possibly other properties relevant to the provider.
|
|
135
|
+
* @param provider - Optional. Specifies the provider name. If not provided, the `entry` parameter is used as the default provider name.
|
|
136
|
+
* @returns - An object representing the registry entry
|
|
137
|
+
*/
|
|
138
|
+
function convertToRegistryEntry(entry, xyzprovider, provider) {
|
|
139
|
+
const urlParameters = {};
|
|
140
|
+
if (xyzprovider.time) {
|
|
141
|
+
urlParameters.time = xyzprovider.time;
|
|
142
|
+
}
|
|
143
|
+
if (xyzprovider.variant) {
|
|
144
|
+
urlParameters.variant = xyzprovider.variant;
|
|
145
|
+
}
|
|
146
|
+
if (xyzprovider.tilematrixset) {
|
|
147
|
+
urlParameters.tilematrixset = xyzprovider.tilematrixset;
|
|
148
|
+
}
|
|
149
|
+
if (xyzprovider.format) {
|
|
150
|
+
urlParameters.format = xyzprovider.format;
|
|
151
|
+
}
|
|
152
|
+
return {
|
|
153
|
+
name: entry,
|
|
154
|
+
thumbnail: RASTER_THUMBNAILS[xyzprovider['name'].replace('.', '-')],
|
|
155
|
+
source: {
|
|
156
|
+
url: xyzprovider['url'],
|
|
157
|
+
minZoom: xyzprovider['min_zoom'] || 0,
|
|
158
|
+
maxZoom: xyzprovider['max_zoom'] || 24,
|
|
159
|
+
attribution: xyzprovider['attribution'] || '',
|
|
160
|
+
provider: provider !== null && provider !== void 0 ? provider : entry,
|
|
161
|
+
urlParameters
|
|
162
|
+
}
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
// Get x/y tile values from lat and lng
|
|
167
|
+
// Based on https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames#Mathematics
|
|
168
|
+
function getTileCoordinates(latDeg, lonDeg, zoom) {
|
|
169
|
+
const latRad = latDeg * (Math.PI / 180);
|
|
170
|
+
const n = 1 << zoom;
|
|
171
|
+
const xTile = Math.floor(((lonDeg + 180.0) / 360.0) * n);
|
|
172
|
+
const yTile = Math.floor((n * (1 - Math.log(Math.tan(latRad) + 1 / Math.cos(latRad)) / Math.PI)) / 2);
|
|
173
|
+
return { xTile, yTile };
|
|
174
|
+
}
|
|
175
|
+
export async function getLayerTileInfo(tileUrl, mapOptions, urlParameters) {
|
|
176
|
+
// If it's tilejson, fetch the json to access the pbf url
|
|
177
|
+
if (tileUrl.includes('.json')) {
|
|
178
|
+
const response = await fetch(tileUrl);
|
|
179
|
+
if (!response.ok) {
|
|
180
|
+
throw new Error(`Failed to fetch json: ${response.statusText}`);
|
|
181
|
+
}
|
|
182
|
+
const json = await response.json();
|
|
183
|
+
tileUrl = json.tiles[0];
|
|
184
|
+
}
|
|
185
|
+
const latitude = mapOptions.extent
|
|
186
|
+
? (mapOptions.extent[1] + mapOptions.extent[3]) / 2
|
|
187
|
+
: mapOptions.latitude || 0;
|
|
188
|
+
const longitude = mapOptions.extent
|
|
189
|
+
? (mapOptions.extent[0] + mapOptions.extent[2]) / 2
|
|
190
|
+
: mapOptions.longitude || 0;
|
|
191
|
+
const zoom = mapOptions.zoom || 0;
|
|
192
|
+
const { xTile, yTile } = getTileCoordinates(latitude, longitude, zoom);
|
|
193
|
+
// Replace url params with currently viewed tile
|
|
194
|
+
tileUrl = tileUrl
|
|
195
|
+
.replace('{z}', String(Math.floor(zoom)))
|
|
196
|
+
.replace('{x}', String(xTile))
|
|
197
|
+
.replace('{y}', String(yTile));
|
|
198
|
+
if (urlParameters) {
|
|
199
|
+
for (const param of Object.keys(urlParameters)) {
|
|
200
|
+
tileUrl = tileUrl.replace(`{${param}}`, urlParameters[param]);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
const response = await fetch(tileUrl);
|
|
204
|
+
if (!response.ok) {
|
|
205
|
+
throw new Error(`Failed to fetch tile: ${response.statusText}`);
|
|
206
|
+
}
|
|
207
|
+
const arrayBuffer = await response.arrayBuffer();
|
|
208
|
+
const tile = new VectorTile(new Protobuf(arrayBuffer));
|
|
209
|
+
return tile;
|
|
210
|
+
}
|
|
211
|
+
export async function getSourceLayerNames(tileUrl, urlParameters) {
|
|
212
|
+
const tile = await getLayerTileInfo(tileUrl, { latitude: 0, longitude: 0, zoom: 0, extent: [] }, urlParameters);
|
|
213
|
+
const layerNames = Object.keys(tile.layers);
|
|
214
|
+
return layerNames;
|
|
215
|
+
}
|
package/lib/types.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { IDict, IJupyterGISDoc, IJupyterGISModel, IJupyterGISTracker, IJupyterGISWidget } from '@jupytergis/schema';
|
|
2
|
+
import { ISignal } from '@lumino/signaling';
|
|
3
|
+
export { IDict };
|
|
4
|
+
export type ValueOf<T> = T[keyof T];
|
|
5
|
+
export interface IControlPanelModel {
|
|
6
|
+
disconnect(f: any): void;
|
|
7
|
+
documentChanged: ISignal<IJupyterGISTracker, IJupyterGISWidget | null>;
|
|
8
|
+
filePath: string | undefined;
|
|
9
|
+
jGISModel: IJupyterGISModel | undefined;
|
|
10
|
+
sharedModel: IJupyterGISDoc | undefined;
|
|
11
|
+
}
|
package/lib/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|