@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.
Files changed (108) hide show
  1. package/lib/commands.d.ts +11 -0
  2. package/lib/commands.js +809 -0
  3. package/lib/console/consoleview.d.ts +24 -0
  4. package/lib/console/consoleview.js +55 -0
  5. package/lib/console/index.d.ts +1 -0
  6. package/lib/console/index.js +1 -0
  7. package/lib/constants.d.ts +57 -0
  8. package/lib/constants.js +89 -0
  9. package/lib/dialogs/components/symbology/BandRendering.d.ts +4 -0
  10. package/lib/dialogs/components/symbology/BandRendering.js +29 -0
  11. package/lib/dialogs/components/symbology/BandRow.d.ts +10 -0
  12. package/lib/dialogs/components/symbology/BandRow.js +43 -0
  13. package/lib/dialogs/components/symbology/SingleBandPseudoColor.d.ts +20 -0
  14. package/lib/dialogs/components/symbology/SingleBandPseudoColor.js +281 -0
  15. package/lib/dialogs/components/symbology/StopRow.d.ts +11 -0
  16. package/lib/dialogs/components/symbology/StopRow.js +58 -0
  17. package/lib/dialogs/formdialog.d.ts +31 -0
  18. package/lib/dialogs/formdialog.js +68 -0
  19. package/lib/dialogs/layerBrowserDialog.d.ts +25 -0
  20. package/lib/dialogs/layerBrowserDialog.js +141 -0
  21. package/lib/dialogs/symbologyDialog.d.ts +23 -0
  22. package/lib/dialogs/symbologyDialog.js +68 -0
  23. package/lib/dialogs/terrainDialog.d.ts +21 -0
  24. package/lib/dialogs/terrainDialog.js +60 -0
  25. package/lib/formbuilder/creationform.d.ts +56 -0
  26. package/lib/formbuilder/creationform.js +117 -0
  27. package/lib/formbuilder/editform.d.ts +24 -0
  28. package/lib/formbuilder/editform.js +60 -0
  29. package/lib/formbuilder/formselectors.d.ts +5 -0
  30. package/lib/formbuilder/formselectors.js +38 -0
  31. package/lib/formbuilder/index.d.ts +6 -0
  32. package/lib/formbuilder/index.js +6 -0
  33. package/lib/formbuilder/objectform/baseform.d.ts +79 -0
  34. package/lib/formbuilder/objectform/baseform.js +167 -0
  35. package/lib/formbuilder/objectform/geojsonsource.d.ts +19 -0
  36. package/lib/formbuilder/objectform/geojsonsource.js +80 -0
  37. package/lib/formbuilder/objectform/hillshadeLayerForm.d.ts +8 -0
  38. package/lib/formbuilder/objectform/hillshadeLayerForm.js +12 -0
  39. package/lib/formbuilder/objectform/layerform.d.ts +19 -0
  40. package/lib/formbuilder/objectform/layerform.js +17 -0
  41. package/lib/formbuilder/objectform/tilesourceform.d.ts +7 -0
  42. package/lib/formbuilder/objectform/tilesourceform.js +60 -0
  43. package/lib/formbuilder/objectform/vectorlayerform.d.ts +15 -0
  44. package/lib/formbuilder/objectform/vectorlayerform.js +88 -0
  45. package/lib/formbuilder/objectform/webGlLayerForm.d.ts +8 -0
  46. package/lib/formbuilder/objectform/webGlLayerForm.js +10 -0
  47. package/lib/icons.d.ts +6 -0
  48. package/lib/icons.js +31 -0
  49. package/lib/index.d.ts +10 -0
  50. package/lib/index.js +10 -0
  51. package/lib/mainview/index.d.ts +3 -0
  52. package/lib/mainview/index.js +3 -0
  53. package/lib/mainview/mainView.d.ts +113 -0
  54. package/lib/mainview/mainView.js +743 -0
  55. package/lib/mainview/mainviewmodel.d.ts +24 -0
  56. package/lib/mainview/mainviewmodel.js +34 -0
  57. package/lib/mainview/mainviewwidget.d.ts +14 -0
  58. package/lib/mainview/mainviewwidget.js +18 -0
  59. package/lib/mainview/spinner.d.ts +6 -0
  60. package/lib/mainview/spinner.js +5 -0
  61. package/lib/panelview/components/filter-panel/Filter.d.ts +19 -0
  62. package/lib/panelview/components/filter-panel/Filter.js +223 -0
  63. package/lib/panelview/components/filter-panel/FilterRow.d.ts +9 -0
  64. package/lib/panelview/components/filter-panel/FilterRow.js +61 -0
  65. package/lib/panelview/components/layers.d.ts +13 -0
  66. package/lib/panelview/components/layers.js +275 -0
  67. package/lib/panelview/components/sources.d.ts +10 -0
  68. package/lib/panelview/components/sources.js +147 -0
  69. package/lib/panelview/header.d.ts +11 -0
  70. package/lib/panelview/header.js +20 -0
  71. package/lib/panelview/index.d.ts +5 -0
  72. package/lib/panelview/index.js +5 -0
  73. package/lib/panelview/leftpanel.d.ts +51 -0
  74. package/lib/panelview/leftpanel.js +125 -0
  75. package/lib/panelview/model.d.ts +19 -0
  76. package/lib/panelview/model.js +30 -0
  77. package/lib/panelview/objectproperties.d.ts +17 -0
  78. package/lib/panelview/objectproperties.js +92 -0
  79. package/lib/panelview/rightpanel.d.ts +19 -0
  80. package/lib/panelview/rightpanel.js +45 -0
  81. package/lib/toolbar/index.d.ts +2 -0
  82. package/lib/toolbar/index.js +2 -0
  83. package/lib/toolbar/usertoolbaritem.d.ts +19 -0
  84. package/lib/toolbar/usertoolbaritem.js +57 -0
  85. package/lib/toolbar/widget.d.ts +22 -0
  86. package/lib/toolbar/widget.js +104 -0
  87. package/lib/tools.d.ts +25 -0
  88. package/lib/tools.js +215 -0
  89. package/lib/types.d.ts +11 -0
  90. package/lib/types.js +1 -0
  91. package/lib/widget.d.ts +49 -0
  92. package/lib/widget.js +144 -0
  93. package/package.json +95 -0
  94. package/style/base.css +55 -0
  95. package/style/colorExpression.css +36 -0
  96. package/style/dialog.css +8 -0
  97. package/style/filterPanel.css +70 -0
  98. package/style/icons/geojson.svg +12 -0
  99. package/style/icons/mound.svg +9 -0
  100. package/style/icons/nonvisibility.svg +8 -0
  101. package/style/icons/raster.svg +5 -0
  102. package/style/icons/visibility.svg +7 -0
  103. package/style/index.css +6 -0
  104. package/style/index.js +6 -0
  105. package/style/layerBrowser.css +256 -0
  106. package/style/leftPanel.css +150 -0
  107. package/style/symbologyDialog.css +86 -0
  108. 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,2 @@
1
+ export * from './usertoolbaritem';
2
+ export * from './widget';
@@ -0,0 +1,2 @@
1
+ export * from './usertoolbaritem';
2
+ export * from './widget';
@@ -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 {};