@haniffalab/cherita-react 0.2.0-dev.2024-05-22.5ce64346 → 0.2.0-dev.2024-09-26.f9979478

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 (32) hide show
  1. package/dist/App.scss +58 -24
  2. package/dist/components/Offcanvas/index.js +9 -6
  3. package/dist/components/dotplot/Dotplot.js +5 -189
  4. package/dist/components/dotplot/DotplotControls.js +197 -0
  5. package/dist/components/heatmap/Heatmap.js +5 -31
  6. package/dist/components/heatmap/HeatmapControls.js +36 -0
  7. package/dist/components/matrixplot/Matrixplot.js +5 -59
  8. package/dist/components/matrixplot/MatrixplotControls.js +65 -0
  9. package/dist/components/obs-list/ObsList.js +231 -113
  10. package/dist/components/obs-list/ObsValueList.js +101 -0
  11. package/dist/components/obsm-list/ObsmList.js +13 -20
  12. package/dist/components/scatterplot/Legend.js +28 -36
  13. package/dist/components/scatterplot/Scatterplot.js +302 -124
  14. package/dist/components/scatterplot/ScatterplotControls.js +93 -0
  15. package/dist/components/scatterplot/SpatialControls.js +68 -17
  16. package/dist/components/scatterplot/Toolbox.js +14 -18
  17. package/dist/components/search-bar/SearchBar.js +2 -2
  18. package/dist/components/search-bar/SearchResults.js +2 -2
  19. package/dist/components/var-list/VarList.js +51 -24
  20. package/dist/components/violin/Violin.js +7 -46
  21. package/dist/components/violin/ViolinControls.js +50 -0
  22. package/dist/constants/colorscales.js +28 -0
  23. package/dist/constants/constants.js +11 -43
  24. package/dist/context/DatasetContext.js +122 -23
  25. package/dist/helpers/color-helper.js +54 -21
  26. package/dist/helpers/zarr-helper.js +39 -17
  27. package/dist/index.js +17 -11
  28. package/dist/utils/LoadingIndicators.js +33 -0
  29. package/dist/utils/requests.js +1 -1
  30. package/dist/utils/search.js +4 -3
  31. package/package.json +10 -4
  32. package/dist/utils/LoadingSpinner.js +0 -44
@@ -4,52 +4,30 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.Scatterplot = Scatterplot;
7
- exports.ScatterplotControls = ScatterplotControls;
8
7
  var _react = _interopRequireWildcard(require("react"));
9
- var _lodash = _interopRequireDefault(require("lodash"));
10
- require("bootstrap/dist/css/bootstrap.min.css");
11
- var _react2 = _interopRequireDefault(require("@deck.gl/react"));
12
8
  var _layers = require("@deck.gl/layers");
13
- var _layers2 = require("@nebula.gl/layers");
9
+ var _react2 = require("@deck.gl/react");
10
+ var _freeSolidSvgIcons = require("@fortawesome/free-solid-svg-icons");
11
+ var _reactFontawesome = require("@fortawesome/react-fontawesome");
14
12
  var _editModes = require("@nebula.gl/edit-modes");
15
- var _Dropdown = _interopRequireDefault(require("react-bootstrap/Dropdown"));
16
- var _Toolbox = require("./Toolbox");
17
- var _SpatialControls = require("./SpatialControls");
13
+ var _layers2 = require("@nebula.gl/layers");
14
+ var _turf = require("@turf/turf");
15
+ var _lodash = _interopRequireDefault(require("lodash"));
16
+ var _reactBootstrap = require("react-bootstrap");
18
17
  var _Legend = require("./Legend");
18
+ var _SpatialControls = require("./SpatialControls");
19
+ var _Toolbox = require("./Toolbox");
19
20
  var _constants = require("../../constants/constants");
20
21
  var _DatasetContext = require("../../context/DatasetContext");
22
+ var _colorHelper = require("../../helpers/color-helper");
21
23
  var _mapHelper = require("../../helpers/map-helper");
22
24
  var _zarrHelper = require("../../helpers/zarr-helper");
23
- var _colorHelper = require("../../helpers/color-helper");
24
- var _LoadingSpinner = require("../../utils/LoadingSpinner");
25
+ var _LoadingIndicators = require("../../utils/LoadingIndicators");
25
26
  var _jsxRuntime = require("react/jsx-runtime");
26
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
27
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
27
28
  function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
28
- function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
29
+ function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
29
30
  window.deck.log.level = 1;
30
- function ScatterplotControls() {
31
- const dataset = (0, _DatasetContext.useDataset)();
32
- const dispatch = (0, _DatasetContext.useDatasetDispatch)();
33
- const colormapList = _constants.PLOTLY_COLORSCALES.map(item => /*#__PURE__*/(0, _jsxRuntime.jsx)(_Dropdown.default.Item, {
34
- active: dataset.controls.colorScale === item,
35
- onClick: () => {
36
- dispatch({
37
- type: "set.controls.colorScale",
38
- colorScale: item
39
- });
40
- },
41
- children: item
42
- }, item));
43
- return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_Dropdown.default, {
44
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_Dropdown.default.Toggle, {
45
- id: "dropdownColorscale",
46
- variant: "light",
47
- children: dataset.controls.colorScale
48
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_Dropdown.default.Menu, {
49
- children: colormapList
50
- })]
51
- });
52
- }
53
31
  const INITIAL_VIEW_STATE = {
54
32
  longitude: 0,
55
33
  latitude: 0,
@@ -58,31 +36,32 @@ const INITIAL_VIEW_STATE = {
58
36
  pitch: 0,
59
37
  bearing: 0
60
38
  };
61
- const DEFAULT_DATA_POINT = {
62
- value: null,
63
- position: null,
64
- color: null
65
- };
66
39
  function Scatterplot(_ref) {
67
- var _dataset$selectedObs;
40
+ var _dataset$selectedObs, _dataset$selectedObs2, _dataset$selectedObs6, _dataset$selectedObs8, _dataset$selectedObs10, _features$features2, _obsmData$serverError, _xData$serverError, _obsData$serverError, _labelObsData$serverE, _obsmData$data;
68
41
  let {
69
42
  radius = 30
70
43
  } = _ref;
71
44
  const dataset = (0, _DatasetContext.useDataset)();
45
+ const dispatch = (0, _DatasetContext.useDatasetDispatch)();
72
46
  const {
73
- getScale,
74
47
  getColor
75
48
  } = (0, _colorHelper.useColor)();
76
49
  const [viewState, setViewState] = (0, _react.useState)(INITIAL_VIEW_STATE);
50
+ const [isRendering, setIsRendering] = (0, _react.useState)(true);
51
+ const [data, setData] = (0, _react.useState)({
52
+ ids: [],
53
+ positions: [],
54
+ values: [],
55
+ sliceValues: []
56
+ });
57
+
58
+ // EditableGeoJsonLayer
59
+ const [mode, setMode] = (0, _react.useState)(() => _editModes.ViewMode);
77
60
  const [features, setFeatures] = (0, _react.useState)({
78
61
  type: "FeatureCollection",
79
62
  features: []
80
63
  });
81
- const [mode, setMode] = (0, _react.useState)(() => _editModes.ViewMode);
82
64
  const [selectedFeatureIndexes, setSelectedFeatureIndexes] = (0, _react.useState)([]);
83
- const [featureState, setFeatureState] = (0, _react.useState)([]);
84
- const [scale, setScale] = (0, _react.useState)(() => getScale());
85
- const [data, setData] = (0, _react.useState)([]);
86
65
  const [obsmParams, setObsmParams] = (0, _react.useState)({
87
66
  url: dataset.url,
88
67
  path: "obsm/" + dataset.selectedObsm
@@ -93,8 +72,9 @@ function Scatterplot(_ref) {
93
72
  });
94
73
  const [obsParams, setObsParams] = (0, _react.useState)({
95
74
  url: dataset.url,
96
- path: "obs/" + ((_dataset$selectedObs = dataset.selectedObs) === null || _dataset$selectedObs === void 0 ? void 0 : _dataset$selectedObs.name) + "/codes"
75
+ path: "obs/" + ((_dataset$selectedObs = dataset.selectedObs) === null || _dataset$selectedObs === void 0 ? void 0 : _dataset$selectedObs.name) + (((_dataset$selectedObs2 = dataset.selectedObs) === null || _dataset$selectedObs2 === void 0 ? void 0 : _dataset$selectedObs2.type) === _constants.OBS_TYPES.CONTINUOUS ? "" : "/codes")
97
76
  });
77
+ const [labelObsParams, setLabelObsParams] = (0, _react.useState)([]);
98
78
 
99
79
  // needs to be wrapped in useMemo as it is an array an could cause an infinite loop otherwise
100
80
  const xSelection = (0, _react.useMemo)(() => {
@@ -104,6 +84,7 @@ function Scatterplot(_ref) {
104
84
  const obsmData = (0, _zarrHelper.useZarr)(obsmParams, null, _zarrHelper.GET_OPTIONS);
105
85
  const xData = (0, _zarrHelper.useZarr)(xParams, xSelection, _zarrHelper.GET_OPTIONS);
106
86
  const obsData = (0, _zarrHelper.useZarr)(obsParams, null, _zarrHelper.GET_OPTIONS);
87
+ const labelObsData = (0, _zarrHelper.useMultipleZarr)(labelObsParams, _zarrHelper.GET_OPTIONS);
107
88
  (0, _react.useEffect)(() => {
108
89
  setObsmParams(p => {
109
90
  return {
@@ -123,13 +104,22 @@ function Scatterplot(_ref) {
123
104
  }, [dataset.selectedVar]);
124
105
  (0, _react.useEffect)(() => {
125
106
  setObsParams(p => {
126
- var _dataset$selectedObs2;
107
+ var _dataset$selectedObs3, _dataset$selectedObs4;
127
108
  return {
128
109
  ...p,
129
- path: "obs/" + ((_dataset$selectedObs2 = dataset.selectedObs) === null || _dataset$selectedObs2 === void 0 ? void 0 : _dataset$selectedObs2.name) + "/codes"
110
+ path: "obs/" + ((_dataset$selectedObs3 = dataset.selectedObs) === null || _dataset$selectedObs3 === void 0 ? void 0 : _dataset$selectedObs3.name) + (((_dataset$selectedObs4 = dataset.selectedObs) === null || _dataset$selectedObs4 === void 0 ? void 0 : _dataset$selectedObs4.type) === _constants.OBS_TYPES.CONTINUOUS ? "" : "/codes")
130
111
  };
131
112
  });
132
113
  }, [dataset.selectedObs]);
114
+ (0, _react.useEffect)(() => {
115
+ setLabelObsParams(_lodash.default.map(dataset.labelObs, obs => {
116
+ return {
117
+ url: dataset.url,
118
+ path: "obs/" + obs.name + (obs.type === _constants.OBS_TYPES.CONTINUOUS ? "" : "/codes"),
119
+ key: obs.name
120
+ };
121
+ }));
122
+ }, [dataset.labelObs, dataset.url]);
133
123
  (0, _react.useEffect)(() => {
134
124
  setObsmParams(p => {
135
125
  return {
@@ -155,12 +145,12 @@ function Scatterplot(_ref) {
155
145
 
156
146
  (0, _react.useEffect)(() => {
157
147
  if (!obsmData.isPending && !obsmData.serverError) {
148
+ setIsRendering(true);
158
149
  setData(d => {
159
- return _lodash.default.map(obsmData.data, (p, index) => {
160
- return _lodash.default.defaults({
161
- position: p
162
- }, d === null || d === void 0 ? void 0 : d[index], DEFAULT_DATA_POINT);
163
- });
150
+ return {
151
+ ...d,
152
+ positions: obsmData.data
153
+ };
164
154
  });
165
155
  const mapHelper = new _mapHelper.MapHelper();
166
156
  const {
@@ -177,134 +167,322 @@ function Scatterplot(_ref) {
177
167
  };
178
168
  });
179
169
  } else if (!obsmData.isPending && obsmData.serverError) {
170
+ setIsRendering(true);
180
171
  setData(d => {
181
- return _lodash.default.map(d, e => {
182
- return _lodash.default.defaults({
183
- position: null
184
- }, e, DEFAULT_DATA_POINT);
185
- });
172
+ return {
173
+ ...d,
174
+ positions: []
175
+ };
186
176
  });
187
177
  }
188
178
  }, [dataset.selectedObsm, obsmData.data, obsmData.isPending, obsmData.serverError]);
179
+ const bounds = (0, _react.useMemo)(() => {
180
+ const {
181
+ latitude,
182
+ longitude,
183
+ zoom
184
+ } = new _mapHelper.MapHelper().fitBounds(data.positions);
185
+ return {
186
+ latitude,
187
+ longitude,
188
+ zoom
189
+ };
190
+ }, [data.positions]);
189
191
  (0, _react.useEffect)(() => {
190
- if (dataset.colorEncoding === "var") {
192
+ if (dataset.colorEncoding === _constants.COLOR_ENCODINGS.VAR) {
193
+ setIsRendering(true);
191
194
  if (!xData.isPending && !xData.serverError) {
192
- const s = getScale(xData.data);
193
- setScale(() => s);
195
+ // @TODO: add condition to check obs slicing
194
196
  setData(d => {
195
- return _lodash.default.map(xData.data, (v, index) => {
196
- return _lodash.default.defaults({
197
- value: v,
198
- color: getColor(s, v)
199
- }, d === null || d === void 0 ? void 0 : d[index], DEFAULT_DATA_POINT);
200
- });
197
+ return {
198
+ ...d,
199
+ values: xData.data
200
+ };
201
201
  });
202
202
  } else if (!xData.isPending && xData.serverError) {
203
- const s = getScale();
204
- setScale(() => s);
205
203
  setData(d => {
206
- return _lodash.default.map(d, e => {
207
- return _lodash.default.defaults({
208
- value: null,
209
- color: null
210
- }, e, DEFAULT_DATA_POINT);
211
- });
204
+ return {
205
+ ...d,
206
+ values: []
207
+ };
212
208
  });
213
209
  }
214
210
  }
215
- }, [dataset.colorEncoding, xData.data, xData.isPending, xData.serverError, getScale, getColor]);
211
+ }, [dataset.colorEncoding, xData.data, xData.isPending, xData.serverError, getColor]);
216
212
  (0, _react.useEffect)(() => {
217
- if (dataset.colorEncoding === "obs") {
213
+ if (dataset.colorEncoding === _constants.COLOR_ENCODINGS.OBS) {
214
+ setIsRendering(true);
218
215
  if (!obsData.isPending && !obsData.serverError) {
219
- const s = getScale(obsData.data);
220
- setScale(() => s);
221
216
  setData(d => {
222
- return _lodash.default.map(obsData.data, (v, index) => {
223
- return _lodash.default.defaults({
224
- value: v,
225
- color: getColor(s, v)
226
- }, d === null || d === void 0 ? void 0 : d[index], DEFAULT_DATA_POINT);
227
- });
217
+ return {
218
+ ...d,
219
+ values: obsData.data
220
+ };
228
221
  });
229
222
  } else if (!obsData.isPending && obsData.serverError) {
230
- const s = getScale();
231
- setScale(() => s);
232
223
  setData(d => {
233
- return _lodash.default.map(d, e => {
234
- return _lodash.default.defaults({
235
- value: null,
236
- color: null
237
- }, e, DEFAULT_DATA_POINT);
238
- });
224
+ return {
225
+ ...d,
226
+ values: []
227
+ };
239
228
  });
240
229
  }
230
+ } else if (dataset.colorEncoding === _constants.COLOR_ENCODINGS.VAR && dataset.sliceBy.obs) {
231
+ if (!obsData.isPending && !obsData.serverError) {
232
+ setData(d => {
233
+ return {
234
+ ...d,
235
+ sliceValues: obsData.data
236
+ };
237
+ });
238
+ } else if (!obsData.isPending && obsData.serverError) {
239
+ setData(d => {
240
+ return {
241
+ ...d,
242
+ sliceValues: []
243
+ };
244
+ });
245
+ }
246
+ }
247
+ }, [dataset.colorEncoding, obsData.data, obsData.isPending, obsData.serverError, dataset.sliceBy.obs]);
248
+ const isCategorical = (0, _react.useMemo)(() => {
249
+ if (dataset.colorEncoding === _constants.COLOR_ENCODINGS.OBS) {
250
+ var _dataset$selectedObs5;
251
+ return ((_dataset$selectedObs5 = dataset.selectedObs) === null || _dataset$selectedObs5 === void 0 ? void 0 : _dataset$selectedObs5.type) === _constants.OBS_TYPES.CATEGORICAL;
252
+ } else {
253
+ return false;
254
+ }
255
+ }, [dataset.colorEncoding, (_dataset$selectedObs6 = dataset.selectedObs) === null || _dataset$selectedObs6 === void 0 ? void 0 : _dataset$selectedObs6.type]);
256
+ const isInSlice = (0, _react.useCallback)((index, values, positions) => {
257
+ let inSlice = true;
258
+ if ((dataset.sliceBy.obs || isCategorical) && values) {
259
+ var _dataset$selectedObs7;
260
+ inSlice &= !_lodash.default.includes((_dataset$selectedObs7 = dataset.selectedObs) === null || _dataset$selectedObs7 === void 0 ? void 0 : _dataset$selectedObs7.omit, values[index]);
261
+ }
262
+ if (dataset.sliceBy.polygons && positions) {
263
+ inSlice &= _lodash.default.some(features === null || features === void 0 ? void 0 : features.features, (_f, i) => {
264
+ return (0, _turf.booleanPointInPolygon)((0, _turf.point)([positions[index][0], positions[index][1]]), features.features[i]);
265
+ });
266
+ }
267
+ return inSlice;
268
+ }, [(_dataset$selectedObs8 = dataset.selectedObs) === null || _dataset$selectedObs8 === void 0 ? void 0 : _dataset$selectedObs8.omit, dataset.sliceBy.obs, dataset.sliceBy.polygons, features.features, isCategorical]);
269
+ const {
270
+ filteredIndices,
271
+ valueMin,
272
+ valueMax,
273
+ slicedLength
274
+ } = (0, _react.useMemo)(() => {
275
+ if (dataset.colorEncoding === _constants.COLOR_ENCODINGS.VAR) {
276
+ const {
277
+ filtered,
278
+ filteredIndices
279
+ } = _lodash.default.reduce(data.values, (acc, v, i) => {
280
+ if (isInSlice(i, data.sliceValues, data.positions)) {
281
+ acc.filtered.push(v);
282
+ acc.filteredIndices.add(i);
283
+ }
284
+ return acc;
285
+ }, {
286
+ filtered: [],
287
+ filteredIndices: new Set()
288
+ });
289
+ return {
290
+ filteredIndices: filteredIndices,
291
+ valueMin: _lodash.default.min(filtered),
292
+ valueMax: _lodash.default.max(filtered),
293
+ slicedLength: filtered.length
294
+ };
295
+ } else if (dataset.colorEncoding === _constants.COLOR_ENCODINGS.OBS) {
296
+ var _dataset$selectedObs9;
297
+ const isContinuous = ((_dataset$selectedObs9 = dataset.selectedObs) === null || _dataset$selectedObs9 === void 0 ? void 0 : _dataset$selectedObs9.type) === _constants.OBS_TYPES.CONTINUOUS;
298
+ const {
299
+ filtered,
300
+ filteredIndices
301
+ } = _lodash.default.reduce(data.values, (acc, v, i) => {
302
+ if (isInSlice(i, data.values, data.positions)) {
303
+ acc.filtered.push(v);
304
+ acc.filteredIndices.add(i);
305
+ }
306
+ return acc;
307
+ }, {
308
+ filtered: [],
309
+ filteredIndices: new Set()
310
+ });
311
+ return {
312
+ filteredIndices: filteredIndices,
313
+ valueMin: _lodash.default.min(isContinuous ? filtered : data.values),
314
+ valueMax: _lodash.default.max(isContinuous ? filtered : data.values),
315
+ slicedLength: filtered.length
316
+ };
317
+ } else {
318
+ return {
319
+ filteredIndices: null,
320
+ valueMin: _lodash.default.min(data.values),
321
+ valueMax: _lodash.default.max(data.values),
322
+ slicedLength: data.values.length
323
+ };
241
324
  }
242
- }, [dataset.colorEncoding, obsData.data, obsData.isPending, obsData.serverError, getScale, getColor]);
243
- const layers = (0, _react.useMemo)(() => {
325
+ }, [data.positions, data.sliceValues, data.values, dataset.colorEncoding, (_dataset$selectedObs10 = dataset.selectedObs) === null || _dataset$selectedObs10 === void 0 ? void 0 : _dataset$selectedObs10.type, isInSlice]);
326
+ (0, _react.useEffect)(() => {
327
+ dispatch({
328
+ type: "set.controls.valueRange",
329
+ valueRange: [valueMin, valueMax]
330
+ });
331
+ }, [dispatch, valueMax, valueMin]);
332
+ const {
333
+ min,
334
+ max
335
+ } = {
336
+ min: dataset.controls.range[0] * (valueMax - valueMin) + valueMin,
337
+ max: dataset.controls.range[1] * (valueMax - valueMin) + valueMin
338
+ };
339
+ const getFillColor = (0, _react.useCallback)((_d, _ref2) => {
340
+ let {
341
+ index
342
+ } = _ref2;
343
+ const grayOut = filteredIndices && !filteredIndices.has(index);
344
+ return getColor((data.values[index] - min) / (max - min), isCategorical, grayOut);
345
+ }, [data.values, filteredIndices, getColor, isCategorical, max, min]);
346
+ const memoizedLayers = (0, _react.useMemo)(() => {
244
347
  return [new _layers.ScatterplotLayer({
245
348
  id: "cherita-layer-scatterplot",
246
- data: data,
349
+ pickable: true,
350
+ data: data.positions,
247
351
  radiusScale: radius,
248
352
  radiusMinPixels: 1,
249
- getPosition: d => d.position,
250
- getFillColor: d => d.color,
251
- getRadius: 1
353
+ getPosition: d => d,
354
+ getFillColor: getFillColor,
355
+ getRadius: 1,
356
+ updateTriggers: {
357
+ getFillColor: getFillColor
358
+ }
252
359
  }), new _layers2.EditableGeoJsonLayer({
253
360
  id: "cherita-layer-draw",
254
361
  data: features,
255
362
  mode: mode,
256
363
  selectedFeatureIndexes,
257
- onEdit: _ref2 => {
364
+ onEdit: _ref3 => {
258
365
  let {
259
366
  updatedData,
260
367
  editType,
261
368
  editContext
262
- } = _ref2;
369
+ } = _ref3;
263
370
  setFeatures(updatedData);
264
371
  let updatedSelectedFeatureIndexes = selectedFeatureIndexes;
265
- setFeatureState({
266
- data: updatedData
267
- });
268
372
  if (editType === "addFeature") {
269
- // when a drawing is complete, the value of editType becomes addFeature
270
373
  const {
271
374
  featureIndexes
272
- } = editContext; //extracting indexes of current features selected
375
+ } = editContext;
273
376
  updatedSelectedFeatureIndexes = [...selectedFeatureIndexes, ...featureIndexes];
274
377
  }
275
- setSelectedFeatureIndexes(updatedSelectedFeatureIndexes); //now update your state
378
+ setSelectedFeatureIndexes(updatedSelectedFeatureIndexes);
379
+ },
380
+ // getFillColor: POLYGON_FILLCOLOR,
381
+ _subLayerProps: {
382
+ geojson: {
383
+ getFillColor: feature => {
384
+ if (selectedFeatureIndexes.some(i => features.features[i] === feature)) {
385
+ return _constants.SELECTED_POLYGON_FILLCOLOR;
386
+ } else {
387
+ return _constants.UNSELECTED_POLYGON_FILLCOLOR;
388
+ }
389
+ }
390
+ }
276
391
  }
277
392
  })];
278
- }, [data, features, mode, radius, selectedFeatureIndexes]);
393
+ }, [data.positions, features, getFillColor, mode, radius, selectedFeatureIndexes]);
394
+ const layers = (0, _react.useDeferredValue)(mode === _editModes.ViewMode ? memoizedLayers.reverse() : memoizedLayers); // draw scatterplot on top of polygons when in ViewMode
395
+
396
+ (0, _react.useEffect)(() => {
397
+ var _features$features;
398
+ if (!(features !== null && features !== void 0 && (_features$features = features.features) !== null && _features$features !== void 0 && _features$features.length)) {
399
+ dispatch({
400
+ type: "disable.slice.polygons"
401
+ });
402
+ }
403
+ }, [dispatch, features === null || features === void 0 || (_features$features2 = features.features) === null || _features$features2 === void 0 ? void 0 : _features$features2.length]);
279
404
  function onLayerClick(info) {
280
405
  if (mode !== _editModes.ViewMode) {
281
406
  // don't change selection while editing
282
407
  return;
283
408
  }
284
- setSelectedFeatureIndexes(info.object ? [info.index] : []);
409
+ setSelectedFeatureIndexes(f => info.object ? info.layer.id === "cherita-layer-draw" ? [info.index] : f : []);
285
410
  }
286
-
287
- // @TODO: add error message
411
+ const getTooltip = _ref4 => {
412
+ let {
413
+ object,
414
+ index
415
+ } = _ref4;
416
+ return object && dataset.labelObs.length && {
417
+ text: _lodash.default.map(labelObsData, (v, k) => {
418
+ const labelObs = _lodash.default.find(dataset.labelObs, o => o.name === k);
419
+ if (labelObs.type === _constants.OBS_TYPES.CONTINUOUS) {
420
+ return "".concat(k, ": ").concat(parseFloat(v === null || v === void 0 ? void 0 : v[index]).toLocaleString());
421
+ } else {
422
+ return "".concat(k, ": ").concat(labelObs.codesMap[v === null || v === void 0 ? void 0 : v[index]]);
423
+ }
424
+ }).join("\n")
425
+ };
426
+ };
427
+ const isPending = (isRendering || xData.isPending || obsmData.isPending) && !obsmData.isPending;
428
+ const error = dataset.selectedObsm && ((_obsmData$serverError = obsmData.serverError) === null || _obsmData$serverError === void 0 ? void 0 : _obsmData$serverError.length) || dataset.colorEncoding === _constants.COLOR_ENCODINGS.VAR && ((_xData$serverError = xData.serverError) === null || _xData$serverError === void 0 ? void 0 : _xData$serverError.length) || dataset.colorEncoding === _constants.COLOR_ENCODINGS.OBS && ((_obsData$serverError = obsData.serverError) === null || _obsData$serverError === void 0 ? void 0 : _obsData$serverError.length) || dataset.labelObs.lengh && ((_labelObsData$serverE = labelObsData.serverError) === null || _labelObsData$serverE === void 0 ? void 0 : _labelObsData$serverE.length);
288
429
  return /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
289
430
  className: "cherita-scatterplot",
290
- children: [(obsmData.isPending || xData.isPending || obsmData.isPending) && /*#__PURE__*/(0, _jsxRuntime.jsx)(_LoadingSpinner.LoadingSpinner, {}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_react2.default, {
431
+ children: [obsmData.isPending && /*#__PURE__*/(0, _jsxRuntime.jsx)(_LoadingIndicators.LoadingSpinner, {
432
+ disableShrink: true
433
+ }), isPending && /*#__PURE__*/(0, _jsxRuntime.jsx)(_LoadingIndicators.LoadingLinear, {}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_react2.DeckGL, {
291
434
  viewState: viewState,
292
435
  onViewStateChange: e => setViewState(e.viewState),
293
- controller: true,
436
+ controller: {
437
+ doubleClickZoom: mode === _editModes.ViewMode
438
+ },
294
439
  layers: layers,
295
- onClick: onLayerClick
440
+ onClick: onLayerClick,
441
+ getTooltip: getTooltip,
442
+ onAfterRender: () => {
443
+ setIsRendering(false);
444
+ },
445
+ useDevicePixels: false,
446
+ getCursor: _ref5 => {
447
+ let {
448
+ isDragging
449
+ } = _ref5;
450
+ return mode !== _editModes.ViewMode ? "crosshair" : isDragging ? "grabbing" : "grab";
451
+ }
296
452
  }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_SpatialControls.SpatialControls, {
297
453
  mode: mode,
298
454
  setMode: setMode,
299
- features: mode,
300
- setFeatures: setFeatures
301
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_Toolbox.Toolbox, {
302
- mode: mode,
303
- setMode: setMode,
304
- features: mode,
305
- setFeatures: setFeatures
306
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_Legend.Legend, {
307
- scale: scale
455
+ features: features,
456
+ setFeatures: setFeatures,
457
+ selectedFeatureIndexes: selectedFeatureIndexes,
458
+ resetBounds: () => setViewState(bounds),
459
+ increaseZoom: () => setViewState(v => ({
460
+ ...v,
461
+ zoom: v.zoom + 1
462
+ })),
463
+ decreaseZoom: () => setViewState(v => ({
464
+ ...v,
465
+ zoom: v.zoom - 1
466
+ }))
467
+ }), error && !isPending && /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
468
+ className: "cherita-alert",
469
+ children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactBootstrap.Alert, {
470
+ variant: "danger",
471
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactFontawesome.FontAwesomeIcon, {
472
+ icon: _freeSolidSvgIcons.faTriangleExclamation
473
+ }), "Error loading data"]
474
+ })
475
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
476
+ className: "cherita-spatial-footer",
477
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_Toolbox.Toolbox, {
478
+ mode: dataset.colorEncoding === _constants.COLOR_ENCODINGS.VAR ? dataset.selectedVar.name : dataset.colorEncoding === _constants.COLOR_ENCODINGS.OBS ? dataset.selectedObs.name : null,
479
+ obsLength: parseInt((_obsmData$data = obsmData.data) === null || _obsmData$data === void 0 ? void 0 : _obsmData$data.length),
480
+ slicedLength: parseInt(slicedLength)
481
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_Legend.Legend, {
482
+ isCategorical: isCategorical,
483
+ min: min,
484
+ max: max
485
+ })]
308
486
  })]
309
487
  });
310
488
  }
@@ -0,0 +1,93 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.ScatterplotControls = void 0;
7
+ var _react = _interopRequireWildcard(require("react"));
8
+ var _material = require("@mui/material");
9
+ var _lodash = _interopRequireDefault(require("lodash"));
10
+ var _reactBootstrap = require("react-bootstrap");
11
+ var _colorscales = require("../../constants/colorscales");
12
+ var _constants = require("../../constants/constants");
13
+ var _DatasetContext = require("../../context/DatasetContext");
14
+ var _jsxRuntime = require("react/jsx-runtime");
15
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
16
+ function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
17
+ function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
18
+ const ScatterplotControls = () => {
19
+ var _dataset$selectedObs;
20
+ const dataset = (0, _DatasetContext.useDataset)();
21
+ const dispatch = (0, _DatasetContext.useDatasetDispatch)();
22
+ const [sliderValue, setSliderValue] = _react.default.useState(dataset.controls.range || [0, 1]);
23
+ const isCategorical = dataset.colorEncoding === _constants.COLOR_ENCODINGS.OBS ? ((_dataset$selectedObs = dataset.selectedObs) === null || _dataset$selectedObs === void 0 ? void 0 : _dataset$selectedObs.type) === _constants.OBS_TYPES.CATEGORICAL : false;
24
+ const colormapList = _lodash.default.keys(_colorscales.COLORSCALES).map(key => /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactBootstrap.Dropdown.Item, {
25
+ active: dataset.controls.colorScale === key,
26
+ onClick: () => {
27
+ dispatch({
28
+ type: "set.controls.colorScale",
29
+ colorScale: key
30
+ });
31
+ },
32
+ children: key
33
+ }, key));
34
+ const valueLabelFormat = value => {
35
+ return (value * (dataset.controls.valueRange[1] - dataset.controls.valueRange[0]) + dataset.controls.valueRange[0]).toFixed(2);
36
+ };
37
+ const marks = [{
38
+ value: 0,
39
+ label: valueLabelFormat(0)
40
+ }, {
41
+ value: 1,
42
+ label: valueLabelFormat(1)
43
+ }];
44
+ const updateSlider = (_e, value) => {
45
+ setSliderValue(value);
46
+ };
47
+ const updateRange = (_e, value) => {
48
+ setSliderValue(value);
49
+ dispatch({
50
+ type: "set.controls.range",
51
+ range: sliderValue
52
+ });
53
+ };
54
+ (0, _react.useEffect)(() => {
55
+ setSliderValue(dataset.controls.range);
56
+ }, [dataset.controls.range]);
57
+ const rangeSlider = /*#__PURE__*/(0, _jsxRuntime.jsxs)(_material.Box, {
58
+ className: "w-100",
59
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Typography, {
60
+ id: "colorscale-range",
61
+ gutterBottom: true,
62
+ children: "Colorscale range"
63
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Slider, {
64
+ "aria-labelledby": "colorscale-range",
65
+ min: 0,
66
+ max: 1,
67
+ step: 0.001,
68
+ value: sliderValue,
69
+ onChange: updateSlider,
70
+ onChangeCommitted: updateRange,
71
+ valueLabelDisplay: "auto",
72
+ getAriaValueText: valueLabelFormat,
73
+ valueLabelFormat: valueLabelFormat,
74
+ marks: marks,
75
+ disabled: isCategorical
76
+ })]
77
+ });
78
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
79
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactBootstrap.Dropdown, {
80
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactBootstrap.Dropdown.Toggle, {
81
+ id: "dropdownColorscale",
82
+ variant: "light",
83
+ children: dataset.controls.colorScale
84
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactBootstrap.Dropdown.Menu, {
85
+ children: colormapList
86
+ })]
87
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
88
+ className: "m-4",
89
+ children: rangeSlider
90
+ })]
91
+ });
92
+ };
93
+ exports.ScatterplotControls = ScatterplotControls;