@jupytergis/base 0.1.2 → 0.1.3

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.
Binary file
@@ -1,8 +1,6 @@
1
1
  import { IJGISLayer, IJGISSource } from '@jupytergis/schema';
2
2
  import { User } from '@jupyterlab/services';
3
- import { FeatureLike } from 'ol/Feature';
4
3
  import BaseLayer from 'ol/layer/Base';
5
- import { Style } from 'ol/style';
6
4
  import * as React from 'react';
7
5
  import { MainViewModel } from './mainviewmodel';
8
6
  interface IProps {
@@ -57,7 +55,11 @@ export declare class MainView extends React.Component<IProps, IStates> {
57
55
  * @param index - expected index of the layer.
58
56
  */
59
57
  addLayer(id: string, layer: IJGISLayer, index: number): Promise<void>;
60
- vectorLayerStyleFunc: (currentFeature: FeatureLike, layer: IJGISLayer) => Style | undefined;
58
+ vectorLayerStyleRuleBuilder: (layer: IJGISLayer) => {
59
+ style: import("ol/style/flat").FlatStyle | Array<import("ol/style/flat").FlatStyle>;
60
+ filter?: import("ol/expr/expression").EncodedExpression | undefined;
61
+ else?: boolean | undefined;
62
+ }[] | undefined;
61
63
  /**
62
64
  * Taken from https://openlayers.org/en/latest/examples/webgl-shaded-relief.html
63
65
  * @returns
@@ -10,7 +10,6 @@ import { fromLonLat, toLonLat } from 'ol/proj';
10
10
  import Feature from 'ol/render/Feature';
11
11
  import { GeoTIFF as GeoTIFFSource, ImageTile as ImageTileSource, Vector as VectorSource, VectorTile as VectorTileSource, XYZ as XYZSource } from 'ol/source';
12
12
  import Static from 'ol/source/ImageStatic';
13
- import { Circle, Fill, Stroke, Style } from 'ol/style';
14
13
  //@ts-expect-error no types for ol-pmtiles
15
14
  import { PMTilesRasterSource, PMTilesVectorSource } from 'ol-pmtiles';
16
15
  import * as React from 'react';
@@ -20,73 +19,52 @@ import { Spinner } from './spinner';
20
19
  export class MainView extends React.Component {
21
20
  constructor(props) {
22
21
  super(props);
23
- this.vectorLayerStyleFunc = (currentFeature, layer) => {
24
- var _a;
25
- const layerParameters = layer.parameters;
26
- // const flatStyle = {
27
- // 'fill-color': 'rgba(255,255,255,0.4)',
28
- // 'stroke-color': '#3399CC',
29
- // 'stroke-width': 1.25,
30
- // 'circle-radius': 5,
31
- // 'circle-fill-color': 'rgba(255,255,255,0.4)',
32
- // 'circle-stroke-width': 1.25,
33
- // 'circle-stroke-color': '#3399CC'
34
- // };
35
- // TODO: Need to make a version that works with strings as well
36
- const operators = {
37
- '>': (a, b) => a > b,
38
- '<': (a, b) => a < b,
39
- '>=': (a, b) => a >= b,
40
- '<=': (a, b) => a <= b,
41
- '==': (a, b) => a === b,
42
- '!=': (a, b) => a !== b
22
+ this.vectorLayerStyleRuleBuilder = (layer) => {
23
+ const layerParams = layer.parameters;
24
+ if (!layerParams) {
25
+ return;
26
+ }
27
+ const defaultStyle = {
28
+ 'fill-color': 'rgba(255,255,255,0.4)',
29
+ 'stroke-color': '#3399CC',
30
+ 'stroke-width': 1.25,
31
+ 'circle-radius': 5,
32
+ 'circle-fill-color': 'rgba(255,255,255,0.4)',
33
+ 'circle-stroke-width': 1.25,
34
+ 'circle-stroke-color': '#3399CC'
43
35
  };
44
- // TODO: I don't think this will work with fancy color expressions
45
- const fill = new Fill({
46
- color: layerParameters.type === 'fill' || layerParameters.type === 'circle'
47
- ? layerParameters.color
48
- : 'rgba(0, 0, 0, 0)'
49
- });
50
- const stroke = new Stroke({
51
- color: layerParameters.type === 'line' || layerParameters.type === 'circle'
52
- ? layerParameters.color
53
- : '#392F5A',
54
- width: 2
55
- });
56
- const style = new Style({
57
- fill,
58
- stroke,
59
- image: new Circle({
60
- radius: 5,
61
- fill,
62
- stroke
63
- })
64
- });
65
- if (layer.filters && ((_a = layer.filters) === null || _a === void 0 ? void 0 : _a.appliedFilters.length) !== 0) {
66
- const props = currentFeature.getProperties();
67
- let shouldDisplayFeature = true;
68
- switch (layer.filters.logicalOp) {
69
- case 'any': {
70
- // Display the feature if any filter conditions apply
71
- shouldDisplayFeature = layer.filters.appliedFilters.some(({ feature, operator, value }) => operators[operator](props[feature], value));
72
- break;
73
- }
74
- case 'all': {
75
- // Display the feature only if all the filter conditions apply
76
- shouldDisplayFeature = layer.filters.appliedFilters.every(({ feature, operator, value }) => operators[operator](props[feature], value));
77
- break;
78
- }
79
- }
80
- if (shouldDisplayFeature) {
81
- return style;
36
+ const defaultRules = {
37
+ style: defaultStyle
38
+ };
39
+ const layerStyle = Object.assign({}, defaultRules);
40
+ if (layer.filters && layer.filters.appliedFilters.length !== 0) {
41
+ const filterExpr = [];
42
+ // 'Any' and 'All' operators require more than one argument
43
+ // So if there's only one filter, skip that part to avoid error
44
+ if (layer.filters.appliedFilters.length === 1) {
45
+ layer.filters.appliedFilters.forEach(filter => {
46
+ filterExpr.push(filter.operator, ['get', filter.feature], filter.value);
47
+ });
82
48
  }
83
49
  else {
84
- return undefined;
50
+ filterExpr.push(layer.filters.logicalOp);
51
+ // Arguments for "Any" and 'All' need to be wrapped in brackets
52
+ layer.filters.appliedFilters.forEach(filter => {
53
+ filterExpr.push([
54
+ filter.operator,
55
+ ['get', filter.feature],
56
+ filter.value
57
+ ]);
58
+ });
85
59
  }
60
+ layerStyle.filter = filterExpr;
86
61
  }
87
- else {
88
- return style;
62
+ if (!layerParams.color) {
63
+ return [layerStyle];
89
64
  }
65
+ const newStyle = Object.assign(Object.assign({}, defaultStyle), layerParams.color);
66
+ layerStyle.style = newStyle;
67
+ return [layerStyle];
90
68
  };
91
69
  /**
92
70
  * Taken from https://openlayers.org/en/latest/examples/webgl-shaded-relief.html
@@ -247,6 +225,7 @@ export class MainView extends React.Component {
247
225
  await this._updateLayersImpl(JupyterGISModel.getOrderedLayerIds(this._model));
248
226
  const options = this._model.getOptions();
249
227
  this.updateOptions(options);
228
+ this._initializedPosition = true;
250
229
  }
251
230
  this.setState(old => (Object.assign(Object.assign({}, old), { loading: false })));
252
231
  }
@@ -528,17 +507,20 @@ export class MainView extends React.Component {
528
507
  opacity: layerParameters.opacity,
529
508
  visible: layer.visible,
530
509
  source: this._sources[layerParameters.source],
531
- style: currentFeature => this.vectorLayerStyleFunc(currentFeature, layer)
510
+ style: this.vectorLayerStyleRuleBuilder(layer)
532
511
  });
533
512
  break;
534
513
  }
535
514
  case 'VectorTileLayer': {
536
515
  layerParameters = layer.parameters;
516
+ if (!layerParameters.color) {
517
+ return;
518
+ }
537
519
  newLayer = new VectorTileLayer({
538
520
  opacity: layerParameters.opacity,
539
- source: this._sources[layerParameters.source],
540
- style: currentFeature => this.vectorLayerStyleFunc(currentFeature, layer)
521
+ source: this._sources[layerParameters.source]
541
522
  });
523
+ this.updateLayer(id, layer, newLayer);
542
524
  break;
543
525
  }
544
526
  case 'HillshadeLayer': {
@@ -633,13 +615,13 @@ export class MainView extends React.Component {
633
615
  case 'VectorLayer': {
634
616
  const layerParams = layer.parameters;
635
617
  mapLayer.setOpacity(layerParams.opacity || 1);
636
- mapLayer.setStyle(currentFeature => this.vectorLayerStyleFunc(currentFeature, layer));
618
+ mapLayer.setStyle(this.vectorLayerStyleRuleBuilder(layer));
637
619
  break;
638
620
  }
639
621
  case 'VectorTileLayer': {
640
622
  const layerParams = layer.parameters;
641
623
  mapLayer.setOpacity(layerParams.opacity || 1);
642
- mapLayer.setStyle(currentFeature => this.vectorLayerStyleFunc(currentFeature, layer));
624
+ mapLayer.setStyle(this.vectorLayerStyleRuleBuilder(layer));
643
625
  break;
644
626
  }
645
627
  case 'HillshadeLayer': {
@@ -132,8 +132,8 @@ function LayerGroupComponent(props) {
132
132
  setId(DOMUtils.createDomID());
133
133
  const getExpandedState = async () => {
134
134
  var _a;
135
- const groupState = await state.fetch(group.name);
136
- setOpen(groupState ? ((_a = groupState['expanded']) !== null && _a !== void 0 ? _a : false) : false);
135
+ const groupState = await state.fetch(`jupytergis:${group.name}`);
136
+ setOpen((_a = groupState.expanded) !== null && _a !== void 0 ? _a : false);
137
137
  };
138
138
  getExpandedState();
139
139
  }, []);
@@ -156,7 +156,7 @@ function LayerGroupComponent(props) {
156
156
  onClick({ type: 'group', item: name, nodeId: childId, event });
157
157
  };
158
158
  const handleExpand = async () => {
159
- state.save(group.name, { expanded: !open });
159
+ state.save(`jupytergis:${group.name}`, { expanded: !open });
160
160
  setOpen(!open);
161
161
  };
162
162
  return (React.createElement("div", { className: `${LAYER_ITEM_CLASS} ${LAYER_GROUP_CLASS}`, draggable: true, onDragStart: Private.onDragStart, onDragEnd: Private.onDragEnd, "data-id": name },
package/lib/tools.d.ts CHANGED
@@ -23,3 +23,12 @@ export declare function deepCopy<T = IDict<any>>(value: T): T;
23
23
  export declare function createDefaultLayerRegistry(layerBrowserRegistry: IJGISLayerBrowserRegistry): void;
24
24
  export declare function getLayerTileInfo(tileUrl: string, mapOptions: Pick<IJGISOptions, 'latitude' | 'longitude' | 'extent' | 'zoom'>, urlParameters?: IDict<string>): Promise<VectorTile>;
25
25
  export declare function getSourceLayerNames(tileUrl: string, urlParameters?: IDict<string>): Promise<string[]>;
26
+ export interface IParsedStyle {
27
+ fillColor: string;
28
+ strokeColor: string;
29
+ strokeWidth: number;
30
+ joinStyle: string;
31
+ capStyle: string;
32
+ radius?: number;
33
+ }
34
+ export declare function parseColor(type: string, style: any): IParsedStyle | undefined;
package/lib/tools.js CHANGED
@@ -170,6 +170,10 @@ function getTileCoordinates(latDeg, lonDeg, zoom) {
170
170
  const n = 1 << zoom;
171
171
  const xTile = Math.floor(((lonDeg + 180.0) / 360.0) * n);
172
172
  const yTile = Math.floor((n * (1 - Math.log(Math.tan(latRad) + 1 / Math.cos(latRad)) / Math.PI)) / 2);
173
+ // Check if either xTile or yTile is NaN
174
+ if (isNaN(xTile) || isNaN(yTile)) {
175
+ return { xTile: 0, yTile: 0 };
176
+ }
173
177
  return { xTile, yTile };
174
178
  }
175
179
  export async function getLayerTileInfo(tileUrl, mapOptions, urlParameters) {
@@ -213,3 +217,37 @@ export async function getSourceLayerNames(tileUrl, urlParameters) {
213
217
  const layerNames = Object.keys(tile.layers);
214
218
  return layerNames;
215
219
  }
220
+ export function parseColor(type, style) {
221
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
222
+ if (!type || !style) {
223
+ return;
224
+ }
225
+ const type2 = type === 'circle' ? 'circle' : 'default';
226
+ const shapeStyles = {
227
+ circle: {
228
+ radius: (_a = style['circle-radius']) !== null && _a !== void 0 ? _a : 5,
229
+ fillColor: (_b = style['circle-fill-color']) !== null && _b !== void 0 ? _b : '#3399CC',
230
+ strokeColor: (_c = style['circle-stroke-color']) !== null && _c !== void 0 ? _c : '#3399CC',
231
+ strokeWidth: (_d = style['circle-stroke-width']) !== null && _d !== void 0 ? _d : 1.25,
232
+ joinStyle: (_e = style['circle-stroke-line-join']) !== null && _e !== void 0 ? _e : 'round',
233
+ capStyle: (_f = style['circle-stroke-line-cap']) !== null && _f !== void 0 ? _f : 'round'
234
+ },
235
+ default: {
236
+ fillColor: (_g = style['fill-color']) !== null && _g !== void 0 ? _g : '[255, 255, 255, 0.4]',
237
+ strokeColor: (_h = style['stroke-color']) !== null && _h !== void 0 ? _h : '#3399CC',
238
+ strokeWidth: (_j = style['stroke-width']) !== null && _j !== void 0 ? _j : 1.25,
239
+ capStyle: (_k = style['stroke-line-cap']) !== null && _k !== void 0 ? _k : 'round',
240
+ joinStyle: (_l = style['stroke-line-join']) !== null && _l !== void 0 ? _l : 'round'
241
+ }
242
+ };
243
+ const parsedStyle = shapeStyles[type2];
244
+ Object.assign(parsedStyle, {
245
+ radius: parsedStyle.radius,
246
+ fillColor: parsedStyle.fillColor,
247
+ strokeColor: parsedStyle.strokeColor,
248
+ strokeWidth: parsedStyle.strokeWidth,
249
+ joinStyle: parsedStyle.joinStyle,
250
+ capStyle: parsedStyle.capStyle
251
+ });
252
+ return parsedStyle;
253
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jupytergis/base",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "A JupyterLab extension for 3D modelling.",
5
5
  "keywords": [
6
6
  "jupyter",
@@ -16,7 +16,7 @@
16
16
  "name": "JupyterGIS contributors"
17
17
  },
18
18
  "files": [
19
- "lib/**/*.{d.ts,eot,gif,html,jpg,js,js.map,json,png,svg,woff2,ttf}",
19
+ "lib/**/*.{d.ts,eot,gif,html,jpg,js,js.map,json,png,svg,woff2,ttf,data,wasm}",
20
20
  "style/**/*.{css,js,eot,gif,html,jpg,json,png,svg,woff2,ttf}"
21
21
  ],
22
22
  "main": "lib/index.js",
@@ -27,10 +27,11 @@
27
27
  "url": "https://github.com/geojupyter/jupytergis.git"
28
28
  },
29
29
  "scripts": {
30
- "build": "jlpm run build:gallery && tsc -b",
30
+ "build": "jlpm run build:gallery && tsc -b && jlpm run cp:gdal",
31
31
  "build:gallery": "python rasterlayer_gallery_generator.py",
32
+ "cp:gdal": "cp ../../node_modules/gdal3.js/dist/package/gdal3WebAssembly.data lib && cp ../../node_modules/gdal3.js/dist/package/gdal3WebAssembly.wasm lib",
32
33
  "build:prod": "jlpm run clean && jlpm run build",
33
- "build:dev": "tsc -b",
34
+ "build:dev": "tsc -b && jlpm run cp:gdal",
34
35
  "clean": "rimraf tsconfig.tsbuildinfo",
35
36
  "clean:lib": "rimraf lib tsconfig.tsbuildinfo",
36
37
  "clean:all": "jlpm run clean:lib",
@@ -40,7 +41,7 @@
40
41
  "@deathbeds/jupyterlab-rjsf": "^1.1.0",
41
42
  "@jupyter/docprovider": "^2.0.0",
42
43
  "@jupyter/ydoc": "^1.0.0",
43
- "@jupytergis/schema": "^0.1.2",
44
+ "@jupytergis/schema": "^0.1.3",
44
45
  "@jupyterlab/application": "^4.0.0",
45
46
  "@jupyterlab/apputils": "^4.0.0",
46
47
  "@jupyterlab/completer": "^4.2.4",
@@ -21,7 +21,8 @@
21
21
  flex: 0 1 20%;
22
22
  }
23
23
 
24
- .jp-gis-symbology-row > .jp-select-wrapper {
24
+ .jp-gis-symbology-row > .jp-select-wrapper,
25
+ .jp-gis-symbology-row > .jp-mod-styled {
25
26
  flex: 1 0 50%;
26
27
  max-width: 50%;
27
28
  }
@@ -35,6 +36,13 @@
35
36
  .jp-gis-layer-symbology-container {
36
37
  display: flex;
37
38
  flex-direction: column;
39
+ gap: 13px;
40
+ border-top: 1px solid var(--jp-border-color2);
41
+ padding-top: 8px;
42
+ }
43
+
44
+ .jp-gis-layer-symbology-container .jp-select-wrapper {
45
+ margin-bottom: unset;
38
46
  }
39
47
 
40
48
  .jp-gis-band-container .jp-gis-symbology-row:last-child {
@@ -66,12 +74,12 @@
66
74
  height: 32px;
67
75
  }
68
76
 
69
- .jp-gis-color-row > input[type='number'] {
77
+ .jp-gis-color-row-value-input {
70
78
  flex: 0 1 18%;
71
79
  min-width: 0px;
72
80
  }
73
81
 
74
- .jp-gis-color-row > input[type='color'] {
82
+ .jp-gis-color-row-output-input {
75
83
  flex-grow: 1;
76
84
  }
77
85