@jupytergis/base 0.1.6 → 0.2.0

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 (96) hide show
  1. package/lib/annotations/components/Annotation.d.ts +11 -0
  2. package/lib/annotations/components/Annotation.js +61 -0
  3. package/lib/annotations/components/AnnotationFloater.d.ts +7 -0
  4. package/lib/annotations/components/AnnotationFloater.js +30 -0
  5. package/lib/annotations/components/Message.d.ts +8 -0
  6. package/lib/annotations/components/Message.js +17 -0
  7. package/lib/annotations/index.d.ts +3 -0
  8. package/lib/annotations/index.js +3 -0
  9. package/lib/annotations/model.d.ts +28 -0
  10. package/lib/annotations/model.js +67 -0
  11. package/lib/classificationModes.d.ts +13 -0
  12. package/lib/classificationModes.js +326 -0
  13. package/lib/commands.js +52 -7
  14. package/lib/constants.d.ts +2 -0
  15. package/lib/constants.js +5 -1
  16. package/lib/dialogs/symbology/classificationModes.d.ts +13 -0
  17. package/lib/dialogs/symbology/classificationModes.js +326 -0
  18. package/lib/dialogs/symbology/components/color_ramp/CanvasSelectComponent.d.ts +11 -0
  19. package/lib/dialogs/symbology/components/color_ramp/CanvasSelectComponent.js +119 -0
  20. package/lib/dialogs/symbology/components/color_ramp/ColorRamp.d.ts +15 -0
  21. package/lib/dialogs/symbology/components/color_ramp/ColorRamp.js +33 -0
  22. package/lib/dialogs/symbology/components/color_ramp/ColorRampEntry.d.ts +9 -0
  23. package/lib/dialogs/symbology/components/color_ramp/ColorRampEntry.js +24 -0
  24. package/lib/dialogs/symbology/components/color_ramp/ModeSelectRow.d.ts +10 -0
  25. package/lib/dialogs/symbology/components/color_ramp/ModeSelectRow.js +11 -0
  26. package/lib/dialogs/symbology/components/color_stops/StopContainer.d.ts +9 -0
  27. package/lib/dialogs/symbology/components/color_stops/StopContainer.js +28 -0
  28. package/lib/dialogs/{components/symbology → symbology/components/color_stops}/StopRow.js +9 -2
  29. package/lib/dialogs/symbology/hooks/useGetProperties.d.ts +12 -0
  30. package/lib/dialogs/symbology/hooks/useGetProperties.js +47 -0
  31. package/lib/dialogs/{symbologyDialog.js → symbology/symbologyDialog.js} +3 -3
  32. package/lib/dialogs/symbology/symbologyUtils.d.ts +9 -0
  33. package/lib/dialogs/symbology/symbologyUtils.js +94 -0
  34. package/lib/dialogs/symbology/tiff_layer/TiffRendering.d.ts +4 -0
  35. package/lib/dialogs/{components/symbology/BandRendering.js → symbology/tiff_layer/TiffRendering.js} +3 -3
  36. package/lib/dialogs/{components/symbology → symbology/tiff_layer/components}/BandRow.d.ts +1 -1
  37. package/lib/dialogs/{components/symbology → symbology/tiff_layer/types}/SingleBandPseudoColor.d.ts +9 -1
  38. package/lib/dialogs/{components/symbology → symbology/tiff_layer/types}/SingleBandPseudoColor.js +131 -83
  39. package/lib/dialogs/{components/symbology → symbology/vector_layer}/VectorRendering.d.ts +1 -1
  40. package/lib/dialogs/{components/symbology → symbology/vector_layer}/VectorRendering.js +10 -13
  41. package/lib/dialogs/symbology/vector_layer/components/ValueSelect.d.ts +8 -0
  42. package/lib/dialogs/symbology/vector_layer/components/ValueSelect.js +7 -0
  43. package/lib/dialogs/symbology/vector_layer/types/Categorized.d.ts +4 -0
  44. package/lib/dialogs/symbology/vector_layer/types/Categorized.js +94 -0
  45. package/lib/dialogs/symbology/vector_layer/types/Graduated.js +169 -0
  46. package/lib/dialogs/{components/symbology → symbology/vector_layer/types}/SimpleSymbol.js +8 -13
  47. package/lib/formbuilder/formselectors.js +4 -0
  48. package/lib/formbuilder/objectform/baseform.d.ts +1 -1
  49. package/lib/formbuilder/objectform/baseform.js +31 -42
  50. package/lib/formbuilder/objectform/geojsonsource.js +33 -30
  51. package/lib/formbuilder/objectform/geotiffsource.d.ts +16 -0
  52. package/lib/formbuilder/objectform/geotiffsource.js +71 -0
  53. package/lib/formbuilder/objectform/vectorlayerform.js +1 -0
  54. package/lib/formbuilder/objectform/webGlLayerForm.js +1 -0
  55. package/lib/index.d.ts +7 -4
  56. package/lib/index.js +7 -4
  57. package/lib/mainview/CollaboratorPointers.d.ts +17 -0
  58. package/lib/mainview/CollaboratorPointers.js +37 -0
  59. package/lib/mainview/FollowIndicator.d.ts +7 -0
  60. package/lib/mainview/FollowIndicator.js +9 -0
  61. package/lib/mainview/mainView.d.ts +39 -3
  62. package/lib/mainview/mainView.js +451 -41
  63. package/lib/mainview/mainviewmodel.d.ts +2 -1
  64. package/lib/mainview/mainviewmodel.js +5 -0
  65. package/lib/panelview/annotationPanel.d.ts +27 -0
  66. package/lib/panelview/annotationPanel.js +45 -0
  67. package/lib/panelview/components/filter-panel/Filter.d.ts +7 -2
  68. package/lib/panelview/components/filter-panel/Filter.js +1 -1
  69. package/lib/panelview/components/filter-panel/FilterRow.js +3 -3
  70. package/lib/panelview/components/identify-panel/IdentifyPanel.d.ts +15 -0
  71. package/lib/panelview/components/identify-panel/IdentifyPanel.js +108 -0
  72. package/lib/panelview/components/layers.js +4 -4
  73. package/lib/panelview/leftpanel.js +8 -0
  74. package/lib/panelview/rightpanel.d.ts +4 -1
  75. package/lib/panelview/rightpanel.js +28 -7
  76. package/lib/store.d.ts +9 -0
  77. package/lib/store.js +25 -0
  78. package/lib/toolbar/widget.js +12 -2
  79. package/lib/tools.d.ts +35 -0
  80. package/lib/tools.js +86 -0
  81. package/lib/types.d.ts +14 -0
  82. package/package.json +18 -20
  83. package/style/base.css +4 -8
  84. package/style/dialog.css +1 -1
  85. package/style/icons/logo_mini.svg +70 -148
  86. package/style/icons/nonvisibility.svg +2 -7
  87. package/style/icons/visibility.svg +2 -6
  88. package/style/leftPanel.css +5 -0
  89. package/style/symbologyDialog.css +104 -3
  90. package/lib/dialogs/components/symbology/BandRendering.d.ts +0 -4
  91. package/lib/dialogs/components/symbology/Graduated.js +0 -188
  92. /package/lib/dialogs/{components/symbology → symbology/components/color_stops}/StopRow.d.ts +0 -0
  93. /package/lib/dialogs/{symbologyDialog.d.ts → symbology/symbologyDialog.d.ts} +0 -0
  94. /package/lib/dialogs/{components/symbology → symbology/tiff_layer/components}/BandRow.js +0 -0
  95. /package/lib/dialogs/{components/symbology → symbology/vector_layer/types}/Graduated.d.ts +0 -0
  96. /package/lib/dialogs/{components/symbology → symbology/vector_layer/types}/SimpleSymbol.d.ts +0 -0
@@ -0,0 +1,11 @@
1
+ import { IAnnotationModel } from '@jupytergis/schema';
2
+ import React from 'react';
3
+ import { IControlPanelModel } from '../../types';
4
+ export interface IAnnotationProps {
5
+ itemId: string;
6
+ annotationModel: IAnnotationModel;
7
+ rightPanelModel?: IControlPanelModel;
8
+ children?: JSX.Element[] | JSX.Element;
9
+ }
10
+ declare const Annotation: ({ itemId, annotationModel, rightPanelModel, children }: IAnnotationProps) => React.JSX.Element;
11
+ export default Annotation;
@@ -0,0 +1,61 @@
1
+ import { faTrash, faPaperPlane, faArrowsToDot } from '@fortawesome/free-solid-svg-icons';
2
+ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
3
+ import { showDialog, Dialog } from '@jupyterlab/apputils';
4
+ import { Button } from '@jupyterlab/ui-components';
5
+ import React, { useMemo, useState } from 'react';
6
+ import { Message } from './Message';
7
+ const Annotation = ({ itemId, annotationModel, rightPanelModel, children }) => {
8
+ const [messageContent, setMessageContent] = useState('');
9
+ const [jgisModel, setJgisModel] = useState(rightPanelModel === null || rightPanelModel === void 0 ? void 0 : rightPanelModel.jGISModel);
10
+ const annotation = annotationModel.getAnnotation(itemId);
11
+ const contents = useMemo(() => { var _a; return (_a = annotation === null || annotation === void 0 ? void 0 : annotation.contents) !== null && _a !== void 0 ? _a : []; }, [annotation]);
12
+ /**
13
+ * Update the model when it changes.
14
+ */
15
+ rightPanelModel === null || rightPanelModel === void 0 ? void 0 : rightPanelModel.documentChanged.connect((_, widget) => {
16
+ setJgisModel(widget === null || widget === void 0 ? void 0 : widget.context.model);
17
+ });
18
+ const handleSubmit = () => {
19
+ annotationModel.addContent(itemId, messageContent);
20
+ setMessageContent('');
21
+ };
22
+ const handleDelete = async () => {
23
+ var _a;
24
+ // If the annotation has no content
25
+ // we remove it right away without prompting
26
+ if (!((_a = annotationModel.getAnnotation(itemId)) === null || _a === void 0 ? void 0 : _a.contents.length)) {
27
+ return annotationModel.removeAnnotation(itemId);
28
+ }
29
+ const result = await showDialog({
30
+ title: 'Delete Annotation',
31
+ body: 'Are you sure you want to delete this annotation?',
32
+ buttons: [Dialog.cancelButton(), Dialog.okButton({ label: 'Delete' })]
33
+ });
34
+ if (result.button.accept) {
35
+ annotationModel.removeAnnotation(itemId);
36
+ }
37
+ };
38
+ const centerOnAnnotation = () => {
39
+ jgisModel === null || jgisModel === void 0 ? void 0 : jgisModel.centerOnAnnotation(itemId);
40
+ };
41
+ return (React.createElement("div", { className: "jGIS-Annotation" },
42
+ children,
43
+ React.createElement("div", null, contents.map(content => {
44
+ var _a, _b;
45
+ return (React.createElement(Message, { user: content.user, message: content.value, self: ((_a = annotationModel.user) === null || _a === void 0 ? void 0 : _a.username) === ((_b = content.user) === null || _b === void 0 ? void 0 : _b.username) }));
46
+ })),
47
+ React.createElement("div", { className: "jGIS-Annotation-Message" },
48
+ React.createElement("textarea", { rows: 3, placeholder: 'Ctrl+Enter to submit', value: messageContent, onChange: e => setMessageContent(e.currentTarget.value), onKeyDown: e => {
49
+ if (e.ctrlKey && e.key === 'Enter') {
50
+ handleSubmit();
51
+ }
52
+ } })),
53
+ React.createElement("div", { className: "jGIS-Annotation-Buttons" },
54
+ React.createElement(Button, { className: "jp-mod-styled jp-mod-warn", onClick: handleDelete },
55
+ React.createElement(FontAwesomeIcon, { icon: faTrash })),
56
+ rightPanelModel && (React.createElement(Button, { className: "jp-mod-styled jp-mod-accept", onClick: centerOnAnnotation },
57
+ React.createElement(FontAwesomeIcon, { icon: faArrowsToDot }))),
58
+ React.createElement(Button, { className: "jp-mod-styled jp-mod-accept", onClick: handleSubmit },
59
+ React.createElement(FontAwesomeIcon, { icon: faPaperPlane })))));
60
+ };
61
+ export default Annotation;
@@ -0,0 +1,7 @@
1
+ import React from 'react';
2
+ import { IAnnotationProps } from './Annotation';
3
+ interface IAnnotationFloaterProps extends IAnnotationProps {
4
+ open: boolean;
5
+ }
6
+ declare const AnnotationFloater: ({ itemId, annotationModel: model, open }: IAnnotationFloaterProps) => React.JSX.Element;
7
+ export default AnnotationFloater;
@@ -0,0 +1,30 @@
1
+ import React, { useState } from 'react';
2
+ import { faWindowMinimize } from '@fortawesome/free-solid-svg-icons';
3
+ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
4
+ import Annotation from './Annotation';
5
+ const AnnotationFloater = ({ itemId, annotationModel: model, open }) => {
6
+ const [isOpen, setIsOpen] = useState(open);
7
+ // Function that either
8
+ // - opens the annotation if `open`
9
+ // - removes the annotation if `!open` and the annotation is empty
10
+ // - closes the annotation if `!open` and the annotation is not empty
11
+ const setOpenOrDelete = (open) => {
12
+ var _a;
13
+ if (open) {
14
+ return setIsOpen(true);
15
+ }
16
+ if (!((_a = model.getAnnotation(itemId)) === null || _a === void 0 ? void 0 : _a.contents.length)) {
17
+ return model.removeAnnotation(itemId);
18
+ }
19
+ setIsOpen(false);
20
+ };
21
+ return (React.createElement(React.Fragment, null,
22
+ React.createElement("div", { className: "jGIS-Annotation-Handler", onClick: () => setOpenOrDelete(!isOpen) }),
23
+ React.createElement("div", { className: "jGIS-FloatingAnnotation", style: { visibility: isOpen ? 'visible' : 'hidden' } },
24
+ React.createElement(Annotation, { itemId: itemId, annotationModel: model },
25
+ React.createElement("div", { className: "jGIS-Popup-Topbar", onClick: () => {
26
+ setOpenOrDelete(false);
27
+ } },
28
+ React.createElement(FontAwesomeIcon, { icon: faWindowMinimize, className: "jGIS-Popup-TopBarIcon" }))))));
29
+ };
30
+ export default AnnotationFloater;
@@ -0,0 +1,8 @@
1
+ import { User } from '@jupyterlab/services';
2
+ interface IProps {
3
+ message: string;
4
+ self: boolean;
5
+ user?: User.IIdentity;
6
+ }
7
+ export declare const Message: (props: IProps) => JSX.Element;
8
+ export {};
@@ -0,0 +1,17 @@
1
+ import React from 'react';
2
+ export const Message = (props) => {
3
+ var _a, _b, _c;
4
+ const { self, message, user } = props;
5
+ const color = (_a = user === null || user === void 0 ? void 0 : user.color) !== null && _a !== void 0 ? _a : 'black';
6
+ const author = (_b = user === null || user === void 0 ? void 0 : user.display_name) !== null && _b !== void 0 ? _b : '';
7
+ const initials = (_c = user === null || user === void 0 ? void 0 : user.initials) !== null && _c !== void 0 ? _c : '';
8
+ return (React.createElement("div", { className: "jGIS-Annotation-Message", style: {
9
+ flexFlow: self ? 'row' : 'row-reverse'
10
+ } },
11
+ React.createElement("div", { className: "jGIS-Annotation-User-Icon", style: {
12
+ backgroundColor: color
13
+ }, title: author },
14
+ React.createElement("span", { style: { width: 24, textAlign: 'center' } }, initials)),
15
+ React.createElement("div", { className: "jGIS-Annotation-Message-Content" },
16
+ React.createElement("p", { style: { padding: 7, margin: 0 } }, message))));
17
+ };
@@ -0,0 +1,3 @@
1
+ export * from './model';
2
+ export * from './components/Annotation';
3
+ export * from './components/AnnotationFloater';
@@ -0,0 +1,3 @@
1
+ export * from './model';
2
+ export * from './components/Annotation';
3
+ export * from './components/AnnotationFloater';
@@ -0,0 +1,28 @@
1
+ import { IAnnotation, IAnnotationModel, IJupyterGISModel } from '@jupytergis/schema';
2
+ import { DocumentRegistry } from '@jupyterlab/docregistry';
3
+ import { User } from '@jupyterlab/services';
4
+ import { ISignal } from '@lumino/signaling';
5
+ export declare class AnnotationModel implements IAnnotationModel {
6
+ constructor(options: AnnotationModel.IOptions);
7
+ get updateSignal(): ISignal<this, null>;
8
+ get user(): User.IIdentity | undefined;
9
+ set context(context: DocumentRegistry.IContext<IJupyterGISModel> | undefined);
10
+ get context(): DocumentRegistry.IContext<IJupyterGISModel> | undefined;
11
+ get contextChanged(): ISignal<this, void>;
12
+ update(): void;
13
+ getAnnotation(id: string): IAnnotation | undefined;
14
+ getAnnotationIds(): string[];
15
+ addAnnotation(key: string, value: IAnnotation): void;
16
+ removeAnnotation(key: string): void;
17
+ addContent(id: string, value: string): void;
18
+ private _context;
19
+ private _contextChanged;
20
+ private _updateSignal;
21
+ private _user?;
22
+ }
23
+ declare namespace AnnotationModel {
24
+ interface IOptions {
25
+ context: DocumentRegistry.IContext<IJupyterGISModel> | undefined;
26
+ }
27
+ }
28
+ export {};
@@ -0,0 +1,67 @@
1
+ import { Signal } from '@lumino/signaling';
2
+ export class AnnotationModel {
3
+ constructor(options) {
4
+ this._contextChanged = new Signal(this);
5
+ this._updateSignal = new Signal(this);
6
+ this.context = options.context;
7
+ }
8
+ get updateSignal() {
9
+ return this._updateSignal;
10
+ }
11
+ get user() {
12
+ return this._user;
13
+ }
14
+ set context(context) {
15
+ var _a;
16
+ this._context = context;
17
+ const state = (_a = this._context) === null || _a === void 0 ? void 0 : _a.model.sharedModel.awareness.getLocalState();
18
+ this._user = state === null || state === void 0 ? void 0 : state.user;
19
+ this._contextChanged.emit(void 0);
20
+ }
21
+ get context() {
22
+ return this._context;
23
+ }
24
+ get contextChanged() {
25
+ return this._contextChanged;
26
+ }
27
+ update() {
28
+ this._updateSignal.emit(null);
29
+ }
30
+ getAnnotation(id) {
31
+ var _a;
32
+ const rawData = (_a = this._context) === null || _a === void 0 ? void 0 : _a.model.sharedModel.getMetadata(id);
33
+ if (rawData) {
34
+ return JSON.parse(rawData);
35
+ }
36
+ }
37
+ getAnnotationIds() {
38
+ var _a;
39
+ const annotationIds = [];
40
+ for (const id in (_a = this._context) === null || _a === void 0 ? void 0 : _a.model.sharedModel.metadata) {
41
+ if (id.startsWith('annotation')) {
42
+ annotationIds.push(id);
43
+ }
44
+ }
45
+ return annotationIds;
46
+ }
47
+ addAnnotation(key, value) {
48
+ var _a;
49
+ (_a = this._context) === null || _a === void 0 ? void 0 : _a.model.sharedModel.setMetadata(`annotation_${key}`, JSON.stringify(value));
50
+ }
51
+ removeAnnotation(key) {
52
+ var _a;
53
+ (_a = this._context) === null || _a === void 0 ? void 0 : _a.model.removeMetadata(key);
54
+ }
55
+ addContent(id, value) {
56
+ var _a;
57
+ const newContent = {
58
+ value,
59
+ user: this._user
60
+ };
61
+ const currentAnnotation = this.getAnnotation(id);
62
+ if (currentAnnotation) {
63
+ const newAnnotation = Object.assign(Object.assign({}, currentAnnotation), { contents: [...currentAnnotation.contents, newContent] });
64
+ (_a = this._context) === null || _a === void 0 ? void 0 : _a.model.sharedModel.setMetadata(id, JSON.stringify(newAnnotation));
65
+ }
66
+ }
67
+ }
@@ -0,0 +1,13 @@
1
+ import { InterpolationType } from './dialogs/symbology/tiff_layer/types/SingleBandPseudoColor';
2
+ export declare namespace VectorClassifications {
3
+ const calculateQuantileBreaks: (values: number[], nClasses: number) => number[];
4
+ const calculateEqualIntervalBreaks: (values: number[], nClasses: number) => number[];
5
+ const calculateJenksBreaks: (values: number[], nClasses: number) => any[];
6
+ const calculatePrettyBreaks: (values: number[], nClasses: number) => number[];
7
+ const calculateLogarithmicBreaks: (values: number[], nClasses: number) => number[];
8
+ }
9
+ export declare namespace GeoTiffClassifications {
10
+ const classifyQuantileBreaks: (nClasses: number, bandNumber: number, url: string, colorRampType: string) => Promise<number[]>;
11
+ const classifyContinuousBreaks: (nClasses: number, minimumValue: number, maximumValue: number, colorRampType: InterpolationType) => number[];
12
+ const classifyEqualIntervalBreaks: (nClasses: number, minimumValue: number, maximumValue: number, colorRampType: InterpolationType) => number[];
13
+ }
@@ -0,0 +1,326 @@
1
+ // Adapted from https://github.com/qgis/QGIS/blob/master/src/core/classification/
2
+ import { Pool, fromUrl } from 'geotiff';
3
+ export var VectorClassifications;
4
+ (function (VectorClassifications) {
5
+ VectorClassifications.calculateQuantileBreaks = (values, nClasses) => {
6
+ // q-th quantile of a data set:
7
+ // value where q fraction of data is below and (1-q) fraction is above this value
8
+ // Xq = (1 - r) * X_NI1 + r * X_NI2
9
+ // NI1 = (int) (q * (n+1))
10
+ // NI2 = NI1 + 1
11
+ // r = q * (n+1) - (int) (q * (n+1))
12
+ // (indices of X: 1...n)
13
+ const sortedValues = [...values].sort((a, b) => a - b);
14
+ const breaks = [];
15
+ if (!sortedValues) {
16
+ return [];
17
+ }
18
+ const n = sortedValues.length;
19
+ let xq = n > 0 ? sortedValues[0] : 0;
20
+ for (let i = 1; i < nClasses; i++) {
21
+ if (n > 1) {
22
+ const q = i / nClasses;
23
+ const a = q * (n - 1);
24
+ const aa = Math.floor(a);
25
+ const r = a - aa;
26
+ xq = (1 - r) * sortedValues[aa] + r * sortedValues[aa + 1];
27
+ }
28
+ breaks.push(xq);
29
+ }
30
+ breaks.push(sortedValues[n - 1]);
31
+ return breaks;
32
+ };
33
+ VectorClassifications.calculateEqualIntervalBreaks = (values, nClasses) => {
34
+ const minimum = Math.min(...values);
35
+ const maximum = Math.max(...values);
36
+ const breaks = [];
37
+ const step = (maximum - minimum) / nClasses;
38
+ let value = minimum;
39
+ for (let i = 0; i < nClasses; i++) {
40
+ value += step;
41
+ breaks.push(value);
42
+ }
43
+ breaks[nClasses - 1] = maximum;
44
+ return breaks;
45
+ };
46
+ VectorClassifications.calculateJenksBreaks = (values, nClasses) => {
47
+ const maximum = Math.max(...values);
48
+ if (values.length === 0) {
49
+ return [];
50
+ }
51
+ if (nClasses <= 1) {
52
+ return [maximum];
53
+ }
54
+ if (nClasses >= values.length) {
55
+ return values;
56
+ }
57
+ const sample = [...values].sort((a, b) => a - b);
58
+ const n = sample.length;
59
+ const matrixOne = Array.from({ length: n + 1 }, () => Array(nClasses + 1).fill(0));
60
+ const matrixTwo = Array.from({ length: n + 1 }, () => Array(nClasses + 1).fill(Number.MAX_VALUE));
61
+ for (let i = 1; i <= nClasses; i++) {
62
+ matrixOne[0][i] = 1;
63
+ matrixOne[1][i] = 1;
64
+ matrixTwo[0][i] = 0.0;
65
+ for (let j = 2; j <= n; j++) {
66
+ matrixTwo[j][i] = Number.MAX_VALUE;
67
+ }
68
+ }
69
+ for (let l = 2; l <= n; l++) {
70
+ let s1 = 0.0;
71
+ let s2 = 0.0;
72
+ let w = 0;
73
+ let v = 0.0;
74
+ for (let m = 1; m <= l; m++) {
75
+ const i3 = l - m + 1;
76
+ const val = sample[i3 - 1];
77
+ s2 += val * val;
78
+ s1 += val;
79
+ w++;
80
+ v = s2 - (s1 * s1) / w;
81
+ const i4 = i3 - 1;
82
+ if (i4 !== 0) {
83
+ for (let j = 2; j <= nClasses; j++) {
84
+ if (matrixTwo[l][j] >= v + matrixTwo[i4][j - 1]) {
85
+ matrixOne[l][j] = i4;
86
+ matrixTwo[l][j] = v + matrixTwo[i4][j - 1];
87
+ }
88
+ }
89
+ }
90
+ }
91
+ matrixOne[l][1] = 1;
92
+ matrixTwo[l][1] = v;
93
+ }
94
+ const breaks = Array(nClasses);
95
+ breaks[nClasses - 1] = sample[n - 1];
96
+ for (let j = nClasses, k = n; j >= 2; j--) {
97
+ const id = matrixOne[k][j] - 1;
98
+ breaks[j - 2] = sample[id];
99
+ k = matrixOne[k][j] - 1;
100
+ }
101
+ return breaks;
102
+ };
103
+ VectorClassifications.calculatePrettyBreaks = (values, nClasses) => {
104
+ const minimum = Math.min(...values);
105
+ const maximum = Math.max(...values);
106
+ const breaks = [];
107
+ if (nClasses < 1) {
108
+ breaks.push(maximum);
109
+ return breaks;
110
+ }
111
+ const minimumCount = Math.floor(nClasses / 3);
112
+ const shrink = 0.75;
113
+ const highBias = 1.5;
114
+ const adjustBias = 0.5 + 1.5 * highBias;
115
+ const divisions = nClasses;
116
+ const h = highBias;
117
+ let cell;
118
+ let small = false;
119
+ const dx = maximum - minimum;
120
+ let U;
121
+ cell = Math.max(Math.abs(minimum), Math.abs(maximum));
122
+ if (adjustBias >= 1.5 * h + 0.5) {
123
+ U = 1 + 1.0 / (1 + h);
124
+ }
125
+ else {
126
+ U = 1 + 1.5 / (1 + adjustBias);
127
+ }
128
+ small = dx < cell * U * Math.max(1, divisions) * 1e-7 * 3.0;
129
+ if (small) {
130
+ if (cell > 10) {
131
+ cell = 9 + cell / 10;
132
+ cell = cell * shrink;
133
+ }
134
+ if (minimumCount > 1) {
135
+ cell = cell / minimumCount;
136
+ }
137
+ }
138
+ else {
139
+ cell = dx;
140
+ if (divisions > 1) {
141
+ cell = cell / divisions;
142
+ }
143
+ }
144
+ if (cell < 20 * 1e-7) {
145
+ cell = 20 * 1e-7;
146
+ }
147
+ const base = Math.pow(10.0, Math.floor(Math.log10(cell)));
148
+ let unit = base;
149
+ if (2 * base - cell < h * (cell - unit)) {
150
+ unit = 2.0 * base;
151
+ if (5 * base - cell < adjustBias * (cell - unit)) {
152
+ unit = 5.0 * base;
153
+ if (10.0 * base - cell < h * (cell - unit)) {
154
+ unit = 10.0 * base;
155
+ }
156
+ }
157
+ }
158
+ let start = Math.floor(minimum / unit + 1e-7);
159
+ let end = Math.ceil(maximum / unit - 1e-7);
160
+ while (start * unit > minimum + 1e-7 * unit) {
161
+ start = start - 1;
162
+ }
163
+ while (end * unit < maximum - 1e-7 * unit) {
164
+ end = end + 1;
165
+ }
166
+ let k = Math.floor(0.5 + end - start);
167
+ if (k < minimumCount) {
168
+ k = minimumCount - k;
169
+ if (start >= 0) {
170
+ end = end + k / 2;
171
+ start = start - k / 2 + (k % 2);
172
+ }
173
+ else {
174
+ start = start - k / 2;
175
+ end = end + k / 2 + (k % 2);
176
+ }
177
+ }
178
+ const minimumBreak = start * unit;
179
+ const count = end - start;
180
+ for (let i = 1; i < count + 1; i++) {
181
+ breaks.push(minimumBreak + i * unit);
182
+ }
183
+ if (breaks.length === 0) {
184
+ return breaks;
185
+ }
186
+ if (breaks[0] < minimum) {
187
+ breaks[0] = minimum;
188
+ }
189
+ if (breaks[breaks.length - 1] > maximum) {
190
+ breaks[breaks.length - 1] = maximum;
191
+ }
192
+ if (minimum < 0.0 && maximum > 0.0) {
193
+ const breaksMinusZero = breaks.map(b => b - 0.0);
194
+ let posOfMin = 0;
195
+ for (let i = 1; i < breaks.length; i++) {
196
+ if (Math.abs(breaksMinusZero[i]) < Math.abs(breaksMinusZero[posOfMin])) {
197
+ posOfMin = i;
198
+ }
199
+ }
200
+ breaks[posOfMin] = 0.0; // Set the closest break to zero
201
+ }
202
+ return breaks;
203
+ };
204
+ VectorClassifications.calculateLogarithmicBreaks = (values, nClasses) => {
205
+ const minimum = Math.min(...values);
206
+ const maximum = Math.max(...values);
207
+ let positiveMinimum = Number.MAX_VALUE;
208
+ let breaks = [];
209
+ positiveMinimum = minimum;
210
+ const actualLogMin = Math.log10(positiveMinimum);
211
+ let logMin = Math.floor(actualLogMin);
212
+ const logMax = Math.ceil(Math.log10(maximum));
213
+ let prettyBreaks = VectorClassifications.calculatePrettyBreaks([logMin, logMax], nClasses);
214
+ while (prettyBreaks.length > 0 && prettyBreaks[0] < actualLogMin) {
215
+ logMin += 1.0;
216
+ prettyBreaks = VectorClassifications.calculatePrettyBreaks([logMin, logMax], nClasses);
217
+ }
218
+ breaks = prettyBreaks;
219
+ for (let i = 0; i < breaks.length; i++) {
220
+ breaks[i] = Math.pow(10, breaks[i]);
221
+ }
222
+ return breaks;
223
+ };
224
+ })(VectorClassifications || (VectorClassifications = {}));
225
+ export var GeoTiffClassifications;
226
+ (function (GeoTiffClassifications) {
227
+ GeoTiffClassifications.classifyQuantileBreaks = async (nClasses, bandNumber, url, colorRampType) => {
228
+ const breaks = [];
229
+ const isDiscrete = colorRampType === 'discrete';
230
+ const pool = new Pool();
231
+ const tiff = await fromUrl(url);
232
+ const image = await tiff.getImage();
233
+ const values = await image.readRasters({ pool });
234
+ // Band numbers are 1 indexed
235
+ const bandValues = values[bandNumber - 1];
236
+ const bandSortedValues = bandValues
237
+ .filter(value => value !== 0)
238
+ .sort((a, b) => a - b);
239
+ pool.destroy();
240
+ if (!bandSortedValues) {
241
+ return [];
242
+ }
243
+ // Adapted from https://github.com/GeoTIFF/geoblaze/blob/master/src/histogram/histogram.core.js#L64
244
+ // iterate through values and use a counter to
245
+ // decide when to set up the next bin.
246
+ let numValuesInCurrentBin;
247
+ let valuesPerBin;
248
+ let startIndex;
249
+ if (isDiscrete) {
250
+ valuesPerBin = bandSortedValues.length / nClasses;
251
+ numValuesInCurrentBin = 0;
252
+ startIndex = 0;
253
+ }
254
+ else {
255
+ valuesPerBin = bandSortedValues.length / (nClasses - 1);
256
+ breaks.push(1);
257
+ numValuesInCurrentBin = 1;
258
+ startIndex = 1;
259
+ }
260
+ for (let i = startIndex; i < bandSortedValues.length; i++) {
261
+ if (numValuesInCurrentBin + 1 < valuesPerBin) {
262
+ numValuesInCurrentBin++;
263
+ }
264
+ else {
265
+ breaks.push(bandSortedValues[i]);
266
+ numValuesInCurrentBin = 0;
267
+ }
268
+ }
269
+ if (breaks.length !== nClasses) {
270
+ //TODO: This should be set based on the type of bandSortedValues I think
271
+ breaks.push(65535);
272
+ }
273
+ return breaks;
274
+ };
275
+ GeoTiffClassifications.classifyContinuousBreaks = (nClasses, minimumValue, maximumValue, colorRampType) => {
276
+ const min = minimumValue;
277
+ const max = maximumValue;
278
+ if (min > max) {
279
+ return [];
280
+ }
281
+ const isDiscrete = colorRampType === 'discrete';
282
+ const breaks = [];
283
+ const numberOfEntries = nClasses;
284
+ if (isDiscrete) {
285
+ const intervalDiff = ((max - min) * (numberOfEntries - 1)) / numberOfEntries;
286
+ for (let i = 1; i < numberOfEntries; i++) {
287
+ const val = i / numberOfEntries;
288
+ breaks.push(min + val * intervalDiff);
289
+ }
290
+ breaks.push(max);
291
+ }
292
+ else {
293
+ for (let i = 0; i <= numberOfEntries; i++) {
294
+ if (i === 26) {
295
+ continue;
296
+ }
297
+ const val = i / numberOfEntries;
298
+ breaks.push(min + val * (max - min));
299
+ }
300
+ }
301
+ return breaks;
302
+ };
303
+ GeoTiffClassifications.classifyEqualIntervalBreaks = (nClasses, minimumValue, maximumValue, colorRampType) => {
304
+ const min = minimumValue;
305
+ const max = maximumValue;
306
+ if (min > max) {
307
+ return [];
308
+ }
309
+ const isDiscrete = colorRampType === 'discrete';
310
+ const breaks = [];
311
+ if (isDiscrete) {
312
+ const intervalDiff = (max - min) / nClasses;
313
+ for (let i = 1; i < nClasses; i++) {
314
+ breaks.push(min + i * intervalDiff);
315
+ }
316
+ breaks.push(max);
317
+ }
318
+ else {
319
+ const intervalDiff = (max - min) / (nClasses - 1);
320
+ for (let i = 0; i < nClasses; i++) {
321
+ breaks.push(min + i * intervalDiff);
322
+ }
323
+ }
324
+ return breaks;
325
+ };
326
+ })(GeoTiffClassifications || (GeoTiffClassifications = {}));