@deephaven/chart 0.43.0 → 0.44.1-beta.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.
package/dist/Chart.css ADDED
@@ -0,0 +1,71 @@
1
+ /* stylelint-disable scss/at-import-no-partial-leading-underscore */
2
+ .plotly-notifier {
3
+ margin-right: 15px;
4
+ }
5
+
6
+ .plotly-notifier .notifier-note {
7
+ color: #f0f0ee !important;
8
+ border: 0 !important;
9
+ border-radius: 2px !important;
10
+ background: #555356 !important;
11
+ overflow-wrap: normal !important;
12
+ hyphens: unset !important;
13
+ margin-bottom: 0.5rem !important;
14
+ box-shadow: 0 0.1rem 1rem rgba(26, 23, 26, 0.45) !important;
15
+ }
16
+
17
+ .plotly-notifier .notifier-close {
18
+ color: #929192 !important;
19
+ transition: all 0.2s ease-in-out !important;
20
+ }
21
+ .plotly-notifier .notifier-close:hover {
22
+ color: #f0f0ee !important;
23
+ }
24
+
25
+ .chart-wrapper {
26
+ background: #2d2a2e;
27
+ }
28
+ .chart-wrapper .plot-container .cartesianlayer text {
29
+ user-select: none;
30
+ }
31
+ .chart-wrapper .plot-container .hovertext path,
32
+ .chart-wrapper .plot-container .axistext path {
33
+ stroke: none !important;
34
+ }
35
+ .chart-wrapper .plot-container .axistext path {
36
+ fill: #555356 !important;
37
+ box-shadow: 4px 4px #1a171a;
38
+ }
39
+ .chart-wrapper .plot-container .zoomlayer .zoombox {
40
+ fill: rgba(0, 0, 0, 0.5) !important;
41
+ }
42
+ .chart-wrapper .plot-container .zoomlayer .zoombox-corners {
43
+ fill: #f0f0ee;
44
+ stroke: #211f22;
45
+ }
46
+ .chart-wrapper .js-plotly-plot .plotly [data-title]::before {
47
+ border-color: transparent transparent #403e41;
48
+ z-index: 1002;
49
+ }
50
+ .chart-wrapper .js-plotly-plot .plotly [data-title]::after {
51
+ border-radius: 4px;
52
+ background: #403e41;
53
+ color: #f0f0ee;
54
+ padding: 0.25rem 0.5rem;
55
+ box-shadow: 0 0.1rem 1.5rem 0.1rem rgba(26, 23, 26, 0.8);
56
+ z-index: 1001;
57
+ }
58
+ .chart-wrapper .js-plotly-plot .plotly .modebar {
59
+ z-index: auto;
60
+ }
61
+ .chart-wrapper .js-plotly-plot .plotly .modebar .modebar-btn[data-attr=animation-spin] svg {
62
+ animation: fa-spin 2s infinite linear;
63
+ }
64
+ .chart-wrapper .js-plotly-plot .plotly .modebar .modebar-btn[data-attr=fill-active] svg path {
65
+ fill: rgba(255, 255, 255, 0.7) !important;
66
+ }
67
+ .chart-wrapper .js-plotly-plot .plotly .modebar .modebar-btn[data-attr=fill-warning] svg path {
68
+ fill: #f37e3f !important;
69
+ }
70
+
71
+ /*# sourceMappingURL=Chart.css.map */
@@ -0,0 +1 @@
1
+ {"version":3,"sourceRoot":"","sources":["../../../node_modules/@deephaven/components/scss/custom.scss","../src/Chart.scss","../../../node_modules/@deephaven/components/scss/bootstrap_overrides.scss"],"names":[],"mappings":"AAAA;ACQA;EACE,cAN6B;;;AAS/B;EAIE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;;AACA;EACE;;;AAIJ;EACE,YCxBc;;AD2BZ;EACE;;AAGF;AAAA;EAEE;;AAGF;EACE;EACA;;AAGF;EACE;;AAGF;EACE,MC5CW;ED6CX,QC/BK;;ADoCT;EACE;EAGA;;AAGF;EACE,eCkDY;EDjDZ,YChDO;EDiDP,OC5Da;ED6Db;EACA,YCuGiB;EDpGjB;;AAGF;EAEE;;AAII;EACE;;AAMA;EACE;;AAOF;EACE","file":"Chart.css","sourcesContent":["/* stylelint-disable scss/at-import-no-partial-leading-underscore */\n// Consumers should be able to resolve bootstrap/ to node_modules/bootstrap\n\n//Make bootstrap functions available for use in overrides\n@import 'bootstrap/scss/_functions.scss';\n@import './bootstrap_overrides.scss';\n\n//_variable imports come after bootstrap default overrides,\n// makes all other variables and mixins from bootstrap available\n/// with just importing customer.scss\n@import 'bootstrap/scss/_variables.scss';\n@import 'bootstrap/scss/_mixins.scss';\n\n//New variables come after imports\n@import './new_variables.scss';\n","@import '@deephaven/components/scss/custom.scss';\n\n$chart-bg: $content-bg;\n$plotly-notifier-margin-right: 15px;\n$plotly-notifier-note-bg: $gray-600;\n$plotly-notifier-note-border-radius: 2px;\n$plotly-color-btn-active: rgba(255, 255, 255, 70%);\n\n.plotly-notifier {\n margin-right: $plotly-notifier-margin-right;\n}\n\n.plotly-notifier .notifier-note {\n // Mark these properties as !important because plotly css can be loaded in a different order in production\n // See comments on IDS-4808\n // https://illumon.aha.io/comments/6737799632463662636\n color: $foreground !important;\n border: 0 !important;\n border-radius: $plotly-notifier-note-border-radius !important;\n background: $plotly-notifier-note-bg !important;\n overflow-wrap: normal !important;\n hyphens: unset !important;\n margin-bottom: $spacer-2 !important;\n box-shadow: $box-shadow !important;\n}\n\n.plotly-notifier .notifier-close {\n color: $gray-400 !important;\n transition: $transition-base !important;\n &:hover {\n color: $foreground !important;\n }\n}\n\n.chart-wrapper {\n background: $chart-bg;\n\n .plot-container {\n .cartesianlayer text {\n user-select: none;\n }\n\n .hovertext path,\n .axistext path {\n stroke: none !important;\n }\n\n .axistext path {\n fill: $gray-600 !important;\n box-shadow: 4px 4px $black;\n }\n\n .zoomlayer .zoombox {\n fill: rgba(0, 0, 0, 50%) !important;\n }\n\n .zoomlayer .zoombox-corners {\n fill: $white;\n stroke: $gray-900;\n }\n }\n\n // Tooltip arrow\n .js-plotly-plot .plotly [data-title]::before {\n border-color: transparent transparent $tooltip-bg;\n\n // Make the arrow appear above the box shadow of the body\n z-index: 1002;\n }\n // Tooltip body\n .js-plotly-plot .plotly [data-title]::after {\n border-radius: $border-radius;\n background: $tooltip-bg;\n color: $tooltip-color;\n padding: $tooltip-padding-y $tooltip-padding-x;\n box-shadow: $tooltip-box-shadow;\n\n // Already set by plotly, just setting again in case it changes in the future so body shadow appears under arrow tip\n z-index: 1001;\n }\n\n .js-plotly-plot .plotly .modebar {\n //aggressive set as 1001 by plotly, no need for it to be explicitly above anything\n z-index: auto;\n\n .modebar-btn {\n &[data-attr='animation-spin'] {\n svg {\n animation: fa-spin 2s infinite linear;\n }\n }\n\n &[data-attr='fill-active'] {\n svg {\n path {\n fill: $plotly-color-btn-active !important;\n }\n }\n }\n\n &[data-attr='fill-warning'] {\n svg {\n path {\n fill: $warning !important;\n }\n }\n }\n }\n }\n}\n","// Styling overrides for bootstrap\n\n// Override / set color variables\n$red: #f95d84;\n$orange: #f37e3f;\n$yellow: #fcd65b;\n$green: #9edc6f;\n$blue: #76d9e4;\n$purple: #aa9af4;\n\n//Define some UI colors\n$interfacegray: #2d2a2e;\n$interfaceblue: #4878ea;\n$interfacewhite: #f0f0ee; //same as gray-200\n$interfaceblack: #1a171a;\n\n//Define our Gray scale\n$white: $interfacewhite;\n$gray-100: #fcfcfa;\n$gray-200: $interfacewhite;\n$gray-300: #c0bfbf;\n$gray-400: #929192;\n$gray-500: #5b5a5c;\n$gray-600: #555356;\n$gray-700: #403e41;\n$gray-800: #373438;\n$gray-850: #322f33;\n$gray-900: #211f22;\n$black: $interfaceblack;\n$content-bg: $interfacegray;\n$background: $interfaceblack;\n$foreground: $interfacewhite;\n\n//Load colors into map\n$colors: ();\n$colors: map-merge(\n (\n 'red': $red,\n 'orange': $orange,\n 'yellow': $yellow,\n 'green': $green,\n 'blue': $blue,\n 'purple': $purple,\n 'white': $white,\n 'black': $black,\n ),\n $colors\n);\n\n//Set default colors\n$body-bg: $black;\n$body-color: $interfacewhite;\n\n// Set brand colors\n$primary: $interfaceblue;\n$primary-hover: darken($primary, 8%);\n$primary-dark: mix($primary, $content-bg, 25%);\n$primary-light: scale-color($primary, $lightness: -25%);\n$secondary: $gray-500;\n$secondary-hover: darken($secondary, 8%);\n$success: $green;\n$info: $yellow;\n$warning: $orange;\n$danger: $red;\n$danger-hover: darken($danger, 8%);\n$light: $gray-100;\n$mid: $gray-400; //Added a mid color, useful for input styling\n$dark: $gray-800;\n$green-dark: scale-color($green, $lightness: -45%, $saturation: -10%);\n\n$theme-colors: () !default;\n$theme-colors: map-merge(\n (\n 'primary': $primary,\n 'primary-hover': $primary-hover,\n 'primary-light': $primary-light,\n 'primary-dark': $primary-dark,\n 'secondary': $secondary,\n 'success': $success,\n 'info': $info,\n 'warning': $warning,\n 'danger': $danger,\n 'light': $light,\n 'dark': $dark,\n 'mid': $mid,\n 'content-bg': $interfacegray,\n 'background': $interfaceblack,\n 'foreground': $interfacewhite,\n ),\n $theme-colors\n);\n\n$component-active-bg: $primary;\n$theme-color-interval: 9%;\n$yiq-contrasted-threshold: 180;\n\n// Override fonts\n$font-family-sans-serif: 'Fira Sans', -apple-system, blinkmacsystemfont,\n 'Segoe UI', 'Roboto', 'Helvetica Neue', arial, sans-serif; //fira sans then native system ui fallbacks\n$font-family-monospace: 'Fira Mono', menlo, monaco, consolas, 'Liberation Mono',\n 'Courier New', monospace;\n$font-family-base: $font-family-sans-serif;\n\n$headings-font-weight: 400;\n\n//Text overides\n$text-muted: $gray-400;\n\n//Style Selection highlight color\n//so browsers add alpha to your color by default, ignoring opacity 1\n//by setting rgba with 0.99 it tricks browser into thinking there is alpha applied\n$text-select-color: $primary-hover;\n$text-select-color-editor: lighten(\n $gray-700,\n 15%\n); //we lighten it abit to account for that 0.01 loss, and because it needs some anyways.\n\n//Grid variables, same value as default just making easily accessible\n$grid-gutter-width: 30px;\n\n//Visual Overrides\n$border-radius: 4px;\n$box-shadow: 0 0.1rem 1rem rgba($black, 45%); //because our UI is so dark, we need darker default shadows\n$box-shadow-900: 0 0.1rem 1rem rgba(0, 0, 0, 45%); //darkest shadow for $black popups over $black UI\n\n//Override Btn\n$btn-border-radius: 4rem;\n$btn-padding-x: 1.5rem;\n$btn-transition: color 0.12s ease-in-out, background-color 0.12s ease-in-out,\n border-color 0.12s ease-in-out, box-shadow 0.12s ease-in-out; //default 0.15 is too long\n$btn-border-width: 2px;\n\n//Override Inputs\n$input-bg: $gray-600;\n$input-disabled-bg: $gray-800;\n$input-color: $foreground;\n$input-border-color: $gray-400;\n$input-placeholder-color: $gray-400;\n$input-focus-border-color: rgba($primary, 85%);\n\n$input-btn-focus-width: 0.2rem;\n$input-btn-focus-color: rgba($component-active-bg, 35%);\n$input-btn-focus-box-shadow: 0 0 0 $input-btn-focus-width $input-btn-focus-color;\n\n//checkbox\n$custom-control-indicator-bg: $gray-600;\n$custom-control-indicator-bg-size: 75% 75%;\n$custom-control-indicator-disabled-bg: $gray-800;\n$custom-control-indicator-checked-disabled-bg: $gray-800;\n$custom-control-label-disabled-color: $gray-400;\n\n//Custom Select\n$custom-select-indicator-color: $gray-400;\n$custom-select-bg-size: 16px 16px;\n//dhSort icon encoded\n$custom-select-indicator: str-replace(\n url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill='#{$custom-select-indicator-color}' d='M4 7l-.4-.8 4-3.7h.8l4 3.7-.4.8H4zm0 2l-.4.8 4 3.7h.8l4-3.7L12 9H4z'/%3E%3C/svg%3E\"),\n '#',\n '%23'\n);\n$custom-select-focus-box-shadow: $input-btn-focus-box-shadow;\n$custom-select-disabled-color: darken($gray-400, 5%);\n$custom-select-disabled-bg: $gray-800;\n\n//modal\n$modal-content-bg: $gray-200;\n$modal-content-border-width: 0;\n$modal-md: 550px;\n\n// Toast notification\n$toast-bg: $primary-dark;\n$toast-color: $foreground;\n$toast-error-bg: mix($danger, $content-bg, 15%);\n$toast-error-color: $foreground;\n\n//tooltips\n$tooltip-bg: $gray-700;\n$tooltip-color: $foreground;\n$tooltip-box-shadow: 0 0.1rem 1.5rem 0.1rem rgba($black, 80%);\n\n//drowdowns\n$dropdown-bg: $gray-600;\n$dropdown-link-color: $foreground;\n$dropdown-link-hover-color: $foreground;\n$dropdown-link-hover-bg: $primary;\n$dropdown-divider-bg: $gray-700;\n\n//context menus\n$contextmenu-bg: $gray-600;\n$contextmenu-color: $foreground;\n$contextmenu-disabled-color: $text-muted;\n$contextmenu-keyboard-selected-bg: rgba($primary, 50%);\n$contextmenu-selected-bg: $primary;\n$contextmenu-selected-color: $foreground;\n\n//links\n$link-color: $gray-400;\n$link-hover-color: $foreground;\n\n//progress-bar\n$progress-bg: $gray-600;\n$progress-border-radius: 1rem;\n\n// Set global options\n$enable-shadows: false;\n$enable-gradients: false;\n$enable-print-styles: false; //I don't think anyone should expect to \"print\" this app.\n\n// Transition times\n$transition: 0.15s;\n$transition-mid: 0.2s;\n$transition-long: 0.3s;\n$transition-slow: 0.6s;\n\n//form-validation icon, uses vsWarning icon encoded here as svg\n$form-feedback-icon-invalid-color: theme-color('danger');\n$form-feedback-icon-invalid: str-replace(\n url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16'%3E%3Cg fill='none'%3E%3Cg fill='#{$form-feedback-icon-invalid-color}'%3E%3Cpath d='M7.56 1h.88l6.54 12.26-.44.74H1.44L1 13.26 7.56 1zM8 2.28 2.28 13H13.7L8 2.28zM8.625 12v-1h-1.25v1h1.25zm-1.25-2V6h1.25v4h-1.25z'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E \"),\n '#',\n '%23'\n);\n"]}
package/dist/Chart.js ADDED
@@ -0,0 +1,518 @@
1
+ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
2
+ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
3
+ function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
4
+ function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return typeof key === "symbol" ? key : String(key); }
5
+ function _toPrimitive(input, hint) { if (typeof input !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (typeof res !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
6
+ import React, { Component } from 'react';
7
+ import deepEqual from 'deep-equal';
8
+ import memoize from 'memoize-one';
9
+ import { vsLoading, dhGraphLineDown, dhWarningFilled } from '@deephaven/icons';
10
+ import { Formatter, FormatterUtils, DateUtils } from '@deephaven/jsapi-utils';
11
+ import Log from '@deephaven/log';
12
+ import createPlotlyComponent from 'react-plotly.js/factory.js';
13
+ import Plotly from "./plotly/Plotly.js";
14
+ import ChartModel from "./ChartModel.js";
15
+ import ChartUtils from "./ChartUtils.js";
16
+ import "./Chart.css";
17
+ var log = Log.module('Chart');
18
+ export class Chart extends Component {
19
+ /**
20
+ * Convert a font awesome icon definition to a plotly icon definition
21
+ * @param faIcon The icon to convert
22
+ */
23
+ static convertIcon(faIcon) {
24
+ var [width,,,, path] = faIcon.icon;
25
+ // By default the icons are flipped upside down, so we need to add our own transform
26
+ // https://github.com/plotly/plotly.js/issues/1335
27
+ var stringPath = "".concat(path);
28
+ return {
29
+ width,
30
+ path: stringPath,
31
+ ascent: width,
32
+ descent: 0,
33
+ transform: "matrix(1, 0, 0, 1, 0, 0)"
34
+ };
35
+ }
36
+ static downsampleButtonTitle(isDownsampleInProgress, isDownsamplingDisabled) {
37
+ if (isDownsampleInProgress) {
38
+ return 'Downsampling in progress...';
39
+ }
40
+ return isDownsamplingDisabled ? 'Downsampling disabled, click to enable' : 'Downsampling enabled, click to disable';
41
+ }
42
+ static downsampleButtonAttr(isDownsampleInProgress, isDownsamplingDisabled) {
43
+ if (isDownsampleInProgress) {
44
+ return 'animation-spin';
45
+ }
46
+ return isDownsamplingDisabled ? undefined : 'fill-active';
47
+ }
48
+ constructor(props) {
49
+ super(props);
50
+ _defineProperty(this, "currentSeries", void 0);
51
+ _defineProperty(this, "PlotComponent", void 0);
52
+ _defineProperty(this, "plot", void 0);
53
+ _defineProperty(this, "plotWrapper", void 0);
54
+ _defineProperty(this, "columnFormats", void 0);
55
+ _defineProperty(this, "dateTimeFormatterOptions", void 0);
56
+ _defineProperty(this, "decimalFormatOptions", void 0);
57
+ _defineProperty(this, "integerFormatOptions", void 0);
58
+ _defineProperty(this, "rect", void 0);
59
+ _defineProperty(this, "ranges", void 0);
60
+ _defineProperty(this, "isSubscribed", void 0);
61
+ _defineProperty(this, "isLoadedFired", void 0);
62
+ _defineProperty(this, "getCachedConfig", memoize((downsamplingError, isDownsampleFinished, isDownsampleInProgress, isDownsamplingDisabled, data) => {
63
+ var customButtons = [];
64
+ var hasDownsampleError = Boolean(downsamplingError);
65
+ if (hasDownsampleError) {
66
+ customButtons.push({
67
+ name: "Downsampling failed: ".concat(downsamplingError),
68
+ title: 'Downsampling failed',
69
+ click: () => undefined,
70
+ icon: Chart.convertIcon(dhWarningFilled),
71
+ attr: 'fill-warning'
72
+ });
73
+ }
74
+ if (isDownsampleFinished || isDownsampleInProgress || isDownsamplingDisabled || hasDownsampleError) {
75
+ var name = Chart.downsampleButtonTitle(isDownsampleInProgress, isDownsamplingDisabled);
76
+ var attr = Chart.downsampleButtonAttr(isDownsampleInProgress, isDownsamplingDisabled);
77
+ var icon = isDownsampleInProgress ? vsLoading : dhGraphLineDown;
78
+ customButtons.push({
79
+ name,
80
+ title: 'Downsampling status',
81
+ icon: Chart.convertIcon(icon),
82
+ click: this.handleDownsampleClick,
83
+ attr
84
+ });
85
+ }
86
+ var has2D = data.some(_ref => {
87
+ var {
88
+ type
89
+ } = _ref;
90
+ return type != null && !type.includes('3d');
91
+ });
92
+ var has3D = data.some(_ref2 => {
93
+ var {
94
+ type
95
+ } = _ref2;
96
+ return type != null && type.includes('3d');
97
+ });
98
+ var buttons2D = ['zoomIn2d', 'zoomOut2d', 'autoScale2d', 'resetScale2d'];
99
+ var buttons3D = ['orbitRotation', 'tableRotation', 'resetCameraDefault3d'];
100
+ return {
101
+ displaylogo: false,
102
+ // Display the mode bar if there's an error or downsampling so user can see progress
103
+ // Yes, the value is a boolean or the string 'hover': https://github.com/plotly/plotly.js/blob/master/src/plot_api/plot_config.js#L249
104
+ displayModeBar:
105
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
106
+ isDownsampleInProgress || hasDownsampleError ? true : 'hover',
107
+ // Each array gets grouped together in the mode bar
108
+ modeBarButtons: [customButtons, ['toImage'], ['zoom2d', 'pan2d'],
109
+ // These work the same for both 2d and 3d
110
+ [...(has2D ? buttons2D : []), ...(has3D ? buttons3D : [])]]
111
+ };
112
+ }));
113
+ this.handleAfterPlot = this.handleAfterPlot.bind(this);
114
+ this.handleDownsampleClick = this.handleDownsampleClick.bind(this);
115
+ this.handleModelEvent = this.handleModelEvent.bind(this);
116
+ this.handlePlotUpdate = this.handlePlotUpdate.bind(this);
117
+ this.handleRelayout = this.handleRelayout.bind(this);
118
+ this.handleRestyle = this.handleRestyle.bind(this);
119
+ this.PlotComponent = createPlotlyComponent(props.Plotly);
120
+ this.plot = /*#__PURE__*/React.createRef();
121
+ this.plotWrapper = /*#__PURE__*/React.createRef();
122
+ this.columnFormats = [];
123
+ this.dateTimeFormatterOptions = {};
124
+ this.decimalFormatOptions = {};
125
+ this.integerFormatOptions = {};
126
+ this.isSubscribed = false;
127
+ this.isLoadedFired = false;
128
+ this.currentSeries = 0;
129
+ this.state = {
130
+ data: null,
131
+ downsamplingError: null,
132
+ isDownsampleFinished: false,
133
+ isDownsampleInProgress: false,
134
+ isDownsamplingDisabled: false,
135
+ layout: {
136
+ datarevision: 0
137
+ },
138
+ revision: 0
139
+ };
140
+ }
141
+ componentDidMount() {
142
+ // Need to make sure the model dimensions are up to date before initializing the data
143
+ this.updateDimensions();
144
+ this.updateModelDimensions();
145
+ this.initData();
146
+ this.initFormatter();
147
+ var {
148
+ isActive
149
+ } = this.props;
150
+ if (isActive) {
151
+ this.subscribe();
152
+ }
153
+ }
154
+ componentDidUpdate(prevProps) {
155
+ var {
156
+ isActive,
157
+ settings
158
+ } = this.props;
159
+ this.updateFormatterSettings(settings);
160
+ if (isActive !== prevProps.isActive) {
161
+ if (isActive) {
162
+ this.subscribe();
163
+ } else {
164
+ this.unsubscribe();
165
+ }
166
+ }
167
+ }
168
+ componentWillUnmount() {
169
+ this.unsubscribe();
170
+ }
171
+ getPlotRect() {
172
+ var _this$plotWrapper$cur, _this$plotWrapper$cur2;
173
+ return (_this$plotWrapper$cur = (_this$plotWrapper$cur2 = this.plotWrapper.current) === null || _this$plotWrapper$cur2 === void 0 ? void 0 : _this$plotWrapper$cur2.getBoundingClientRect()) !== null && _this$plotWrapper$cur !== void 0 ? _this$plotWrapper$cur : null;
174
+ }
175
+ initData() {
176
+ var {
177
+ model
178
+ } = this.props;
179
+ var {
180
+ layout
181
+ } = this.state;
182
+ this.setState({
183
+ data: model.getData(),
184
+ layout: _objectSpread(_objectSpread({}, layout), model.getLayout())
185
+ });
186
+ }
187
+ subscribe() {
188
+ if (this.isSubscribed) {
189
+ return;
190
+ }
191
+ var {
192
+ model
193
+ } = this.props;
194
+ if (!this.rect || this.rect.width === 0 || this.rect.height === 0) {
195
+ log.debug2('Delaying subscription until model dimensions are set');
196
+ return;
197
+ }
198
+ model.subscribe(this.handleModelEvent);
199
+ this.isSubscribed = true;
200
+ }
201
+ unsubscribe() {
202
+ if (!this.isSubscribed) {
203
+ return;
204
+ }
205
+ var {
206
+ model
207
+ } = this.props;
208
+ model.unsubscribe(this.handleModelEvent);
209
+ this.isSubscribed = false;
210
+ }
211
+ handleAfterPlot() {
212
+ if (this.plot.current != null) {
213
+ // TODO: Translate whatever Don was doing in plotting.js in the afterplot here so that area graphs show up properly
214
+ }
215
+ }
216
+ handleDownsampleClick() {
217
+ this.setState(_ref3 => {
218
+ var {
219
+ isDownsamplingDisabled
220
+ } = _ref3;
221
+ return {
222
+ downsamplingError: null,
223
+ isDownsampleInProgress: false,
224
+ isDownsampleFinished: false,
225
+ isDownsamplingDisabled: !isDownsamplingDisabled
226
+ };
227
+ }, () => {
228
+ var {
229
+ model
230
+ } = this.props;
231
+ var {
232
+ isDownsamplingDisabled
233
+ } = this.state;
234
+ model.setDownsamplingDisabled(isDownsamplingDisabled);
235
+ });
236
+ }
237
+ handleModelEvent(event) {
238
+ var {
239
+ type,
240
+ detail
241
+ } = event;
242
+ log.debug2('Received data update', type, detail);
243
+ switch (type) {
244
+ case ChartModel.EVENT_UPDATED:
245
+ {
246
+ this.currentSeries += 1;
247
+ this.setState(state => {
248
+ var {
249
+ layout,
250
+ revision
251
+ } = state;
252
+ if (typeof layout.datarevision === 'number') {
253
+ layout.datarevision += 1;
254
+ }
255
+ return {
256
+ data: detail,
257
+ layout,
258
+ revision: revision + 1
259
+ };
260
+ });
261
+ var {
262
+ onUpdate
263
+ } = this.props;
264
+ onUpdate({
265
+ isLoading: !this.isLoadedFired
266
+ });
267
+ break;
268
+ }
269
+ case ChartModel.EVENT_LOADFINISHED:
270
+ {
271
+ var {
272
+ onUpdate: _onUpdate
273
+ } = this.props;
274
+ this.isLoadedFired = true;
275
+ _onUpdate({
276
+ isLoading: false
277
+ });
278
+ break;
279
+ }
280
+ case ChartModel.EVENT_DISCONNECT:
281
+ {
282
+ var {
283
+ onDisconnect
284
+ } = this.props;
285
+ onDisconnect();
286
+ break;
287
+ }
288
+ case ChartModel.EVENT_RECONNECT:
289
+ {
290
+ var {
291
+ onReconnect
292
+ } = this.props;
293
+ onReconnect();
294
+ break;
295
+ }
296
+ case ChartModel.EVENT_DOWNSAMPLESTARTED:
297
+ {
298
+ this.setState({
299
+ isDownsampleFinished: false,
300
+ isDownsampleInProgress: true,
301
+ downsamplingError: null
302
+ });
303
+ break;
304
+ }
305
+ case ChartModel.EVENT_DOWNSAMPLEFINISHED:
306
+ {
307
+ this.setState({
308
+ isDownsampleFinished: true,
309
+ isDownsampleInProgress: false,
310
+ downsamplingError: null
311
+ });
312
+ break;
313
+ }
314
+ case ChartModel.EVENT_DOWNSAMPLENEEDED:
315
+ case ChartModel.EVENT_DOWNSAMPLEFAILED:
316
+ {
317
+ var _detail$message;
318
+ var downsamplingError = (_detail$message = detail.message) !== null && _detail$message !== void 0 ? _detail$message : detail;
319
+ this.setState({
320
+ isDownsampleFinished: false,
321
+ isDownsampleInProgress: false,
322
+ isDownsamplingDisabled: false,
323
+ downsamplingError
324
+ });
325
+ var {
326
+ onError
327
+ } = this.props;
328
+ onError(new Error(downsamplingError));
329
+ break;
330
+ }
331
+ default:
332
+ log.debug('Unknown event type', type, event);
333
+ }
334
+ }
335
+ handlePlotUpdate(figure) {
336
+ // User could have modified zoom/pan here, update the model dimensions
337
+ // We don't need to update the datarevision, as we don't have any data changes
338
+ // until an update comes back from the server anyway
339
+ var {
340
+ layout
341
+ } = figure;
342
+ var ranges = ChartUtils.getLayoutRanges(layout);
343
+ var isRangesChanged = !deepEqual(ranges, this.ranges);
344
+ if (isRangesChanged) {
345
+ this.ranges = ranges;
346
+ this.updateModelDimensions(true);
347
+ }
348
+ }
349
+ handleRelayout(changes) {
350
+ log.debug('handleRelayout', changes);
351
+ if (changes.hiddenlabels != null) {
352
+ var {
353
+ onSettingsChanged
354
+ } = this.props;
355
+ // Pie charts store series visibility in layout.hiddenlabels and trigger relayout on changes
356
+ // Series visibility for other types of charts is handled in handleRestyle
357
+ var hiddenSeries = [...changes.hiddenlabels];
358
+ onSettingsChanged({
359
+ hiddenSeries
360
+ });
361
+ }
362
+ this.updateModelDimensions();
363
+ }
364
+ handleRestyle(_ref4) {
365
+ var [changes, seriesIndexes] = _ref4;
366
+ log.debug('handleRestyle', changes, seriesIndexes);
367
+ if (Object.keys(changes).includes('visible')) {
368
+ var {
369
+ data
370
+ } = this.state;
371
+ var {
372
+ onSettingsChanged
373
+ } = this.props;
374
+ if (data != null) {
375
+ var hiddenSeries = data.reduce((acc, _ref5) => {
376
+ var {
377
+ name,
378
+ visible
379
+ } = _ref5;
380
+ return name != null && visible === 'legendonly' ? [...acc, name] : acc;
381
+ }, []);
382
+ onSettingsChanged({
383
+ hiddenSeries
384
+ });
385
+ }
386
+ }
387
+ }
388
+
389
+ /**
390
+ * Update the models dimensions and ranges.
391
+ * Note that this will update it all whether the plot size changes OR the range
392
+ * the user is looking at has changed (eg. panning/zooming).
393
+ * Could update each independently, but doing them at the same time keeps the
394
+ * ChartModel API a bit cleaner.
395
+ * @param force Force a change even if the chart dimensions haven't changed (eg. after pan/zoom)
396
+ */
397
+ updateModelDimensions() {
398
+ var force = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
399
+ var rect = this.getPlotRect();
400
+ if (!rect) {
401
+ log.warn('Unable to get plotting rect');
402
+ return;
403
+ }
404
+ var isRectChanged = !this.rect || this.rect.width !== rect.width || this.rect.height !== rect.height;
405
+ if (isRectChanged || force) {
406
+ this.rect = rect;
407
+ var {
408
+ isActive,
409
+ model
410
+ } = this.props;
411
+ model.setDimensions(rect);
412
+ // We may need to resubscribe if dimensions were too small before
413
+ if (isActive) {
414
+ this.subscribe();
415
+ }
416
+ }
417
+ }
418
+ initFormatter() {
419
+ var {
420
+ settings
421
+ } = this.props;
422
+ this.updateFormatterSettings(settings);
423
+ }
424
+ updateFormatterSettings(settings) {
425
+ var columnFormats = FormatterUtils.getColumnFormats(settings);
426
+ var dateTimeFormatterOptions = FormatterUtils.getDateTimeFormatterOptions(settings);
427
+ var {
428
+ decimalFormatOptions = {},
429
+ integerFormatOptions = {}
430
+ } = settings;
431
+ if (!deepEqual(this.columnFormats, columnFormats) || !deepEqual(this.dateTimeFormatterOptions, dateTimeFormatterOptions) || !deepEqual(this.decimalFormatOptions, decimalFormatOptions) || !deepEqual(this.integerFormatOptions, integerFormatOptions)) {
432
+ this.columnFormats = FormatterUtils.getColumnFormats(settings);
433
+ this.dateTimeFormatterOptions = dateTimeFormatterOptions;
434
+ this.decimalFormatOptions = decimalFormatOptions;
435
+ this.integerFormatOptions = integerFormatOptions;
436
+ this.updateFormatter();
437
+ }
438
+ }
439
+ updateFormatter() {
440
+ var {
441
+ model
442
+ } = this.props;
443
+ var formatter = new Formatter(model.dh, this.columnFormats, this.dateTimeFormatterOptions, this.decimalFormatOptions, this.integerFormatOptions);
444
+ model.setFormatter(formatter);
445
+ }
446
+ updateDimensions() {
447
+ var rect = this.getPlotRect();
448
+ var {
449
+ Plotly: PlotlyProp
450
+ } = this.props;
451
+ if (this.plot.current != null && rect != null && rect.width > 0 && rect.height > 0) {
452
+ // Call relayout to resize avoiding the debouncing plotly does
453
+ // https://github.com/plotly/plotly.js/issues/2769#issuecomment-402099552
454
+ PlotlyProp.relayout(this.plot.current.el, {
455
+ autosize: true
456
+ }).catch(e => {
457
+ log.debug('Unable to resize, promise rejected', e);
458
+ });
459
+ }
460
+ }
461
+ render() {
462
+ var {
463
+ PlotComponent
464
+ } = this;
465
+ var {
466
+ data,
467
+ downsamplingError,
468
+ isDownsampleFinished,
469
+ isDownsampleInProgress,
470
+ isDownsamplingDisabled,
471
+ layout,
472
+ revision
473
+ } = this.state;
474
+ var config = this.getCachedConfig(downsamplingError, isDownsampleFinished, isDownsampleInProgress, isDownsamplingDisabled, data !== null && data !== void 0 ? data : []);
475
+ var isPlotShown = data != null;
476
+ return /*#__PURE__*/React.createElement("div", {
477
+ className: "h-100 w-100 chart-wrapper",
478
+ ref: this.plotWrapper
479
+ }, isPlotShown && /*#__PURE__*/React.createElement(PlotComponent
480
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
481
+ // @ts-ignore
482
+ , {
483
+ ref: this.plot,
484
+ data: data,
485
+ layout: layout,
486
+ revision: revision,
487
+ config: config,
488
+ onAfterPlot: this.handleAfterPlot,
489
+ onError: log.error,
490
+ onRelayout: this.handleRelayout,
491
+ onUpdate: this.handlePlotUpdate,
492
+ onRestyle: this.handleRestyle,
493
+ useResizeHandler: true,
494
+ style: {
495
+ height: '100%',
496
+ width: '100%'
497
+ }
498
+ }));
499
+ }
500
+ }
501
+ _defineProperty(Chart, "defaultProps", {
502
+ isActive: true,
503
+ settings: {
504
+ timeZone: 'America/New_York',
505
+ defaultDateTimeFormat: DateUtils.FULL_DATE_FORMAT,
506
+ showTimeZone: false,
507
+ showTSeparator: true,
508
+ formatter: []
509
+ },
510
+ Plotly,
511
+ onDisconnect: () => undefined,
512
+ onReconnect: () => undefined,
513
+ onUpdate: () => undefined,
514
+ onError: () => undefined,
515
+ onSettingsChanged: () => undefined
516
+ });
517
+ export default Chart;
518
+ //# sourceMappingURL=Chart.js.map