@deephaven/chart 0.38.1-beta.3 → 0.38.1-beta.5
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/ChartModelFactory.d.ts +7 -4
- package/dist/ChartModelFactory.d.ts.map +1 -1
- package/dist/ChartModelFactory.js +13 -11
- package/dist/ChartModelFactory.js.map +1 -1
- package/dist/ChartUtils.d.ts +157 -154
- package/dist/ChartUtils.d.ts.map +1 -1
- package/dist/ChartUtils.js +669 -607
- package/dist/ChartUtils.js.map +1 -1
- package/dist/FigureChartModel.d.ts +7 -4
- package/dist/FigureChartModel.d.ts.map +1 -1
- package/dist/FigureChartModel.js +28 -12
- package/dist/FigureChartModel.js.map +1 -1
- package/dist/MockChartModel.d.ts +3 -3
- package/dist/MockChartModel.d.ts.map +1 -1
- package/dist/MockChartModel.js +6 -6
- package/dist/MockChartModel.js.map +1 -1
- package/package.json +10 -9
package/dist/ChartUtils.js
CHANGED
|
@@ -5,12 +5,10 @@ function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return typ
|
|
|
5
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
6
|
import Log from '@deephaven/log';
|
|
7
7
|
import { TableUtils } from '@deephaven/jsapi-utils';
|
|
8
|
-
import dh from '@deephaven/jsapi-shim';
|
|
9
8
|
import set from 'lodash.set';
|
|
10
9
|
import { assertNotNull } from '@deephaven/utils';
|
|
11
10
|
import ChartTheme from "./ChartTheme.js";
|
|
12
11
|
var log = Log.module('ChartUtils');
|
|
13
|
-
var DAYS = Object.freeze(dh.calendar.DayOfWeek.values());
|
|
14
12
|
var BUSINESS_COLUMN_TYPE = 'io.deephaven.time.DateTime';
|
|
15
13
|
var MILLIS_PER_HOUR = 3600000;
|
|
16
14
|
var NANOS_PER_MILLI = 1000000;
|
|
@@ -27,168 +25,6 @@ function isRangedPlotlyAxis(value) {
|
|
|
27
25
|
return value != null && value.range != null && (value.autorange === false || value.autorange === undefined);
|
|
28
26
|
}
|
|
29
27
|
class ChartUtils {
|
|
30
|
-
/**
|
|
31
|
-
* Converts the Iris plot style into a plotly chart type
|
|
32
|
-
* @param plotStyle The plotStyle to use, see dh.plot.SeriesPlotStyle
|
|
33
|
-
* @param isBusinessTime If the plot is using business time for an axis
|
|
34
|
-
*/
|
|
35
|
-
static getPlotlyChartType(plotStyle, isBusinessTime) {
|
|
36
|
-
switch (plotStyle) {
|
|
37
|
-
case dh.plot.SeriesPlotStyle.SCATTER:
|
|
38
|
-
// scattergl mode is more performant, but doesn't support the rangebreaks we need for businessTime calendars
|
|
39
|
-
return !isBusinessTime ? 'scattergl' : 'scatter';
|
|
40
|
-
case dh.plot.SeriesPlotStyle.LINE:
|
|
41
|
-
// There is also still some artifacting bugs with scattergl: https://github.com/plotly/plotly.js/issues/3522
|
|
42
|
-
// The artifacting only occurs on line plots, which we can draw with fairly decent performance using SVG paths
|
|
43
|
-
// Once the above plotly issue is fixed, scattergl should be used here (when !isBusinessTime)
|
|
44
|
-
return 'scatter';
|
|
45
|
-
case dh.plot.SeriesPlotStyle.BAR:
|
|
46
|
-
case dh.plot.SeriesPlotStyle.STACKED_BAR:
|
|
47
|
-
return 'bar';
|
|
48
|
-
case dh.plot.SeriesPlotStyle.PIE:
|
|
49
|
-
return 'pie';
|
|
50
|
-
case dh.plot.SeriesPlotStyle.TREEMAP:
|
|
51
|
-
return 'treemap';
|
|
52
|
-
case dh.plot.SeriesPlotStyle.HISTOGRAM:
|
|
53
|
-
return 'histogram';
|
|
54
|
-
case dh.plot.SeriesPlotStyle.OHLC:
|
|
55
|
-
return 'ohlc';
|
|
56
|
-
default:
|
|
57
|
-
return undefined;
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* Converts the Iris plot style into a plotly chart mode
|
|
63
|
-
* @param plotStyle The plotStyle to use, see dh.plot.SeriesPlotStyle.*
|
|
64
|
-
* @param areLinesVisible Whether lines are visible or not
|
|
65
|
-
* @param areShapesVisible Whether shapes are visible or not
|
|
66
|
-
*/
|
|
67
|
-
static getPlotlyChartMode(plotStyle, areLinesVisible, areShapesVisible) {
|
|
68
|
-
var modes = new Set();
|
|
69
|
-
switch (plotStyle) {
|
|
70
|
-
case dh.plot.SeriesPlotStyle.SCATTER:
|
|
71
|
-
// Default to only showing shapes in scatter plots
|
|
72
|
-
if (areLinesVisible !== null && areLinesVisible !== void 0 ? areLinesVisible : false) {
|
|
73
|
-
modes.add(ChartUtils.MODE_LINES);
|
|
74
|
-
}
|
|
75
|
-
if (areShapesVisible !== null && areShapesVisible !== void 0 ? areShapesVisible : true) {
|
|
76
|
-
modes.add(ChartUtils.MODE_MARKERS);
|
|
77
|
-
}
|
|
78
|
-
break;
|
|
79
|
-
case dh.plot.SeriesPlotStyle.LINE:
|
|
80
|
-
// Default to only showing lines in line series
|
|
81
|
-
if (areLinesVisible !== null && areLinesVisible !== void 0 ? areLinesVisible : true) {
|
|
82
|
-
modes.add(ChartUtils.MODE_LINES);
|
|
83
|
-
}
|
|
84
|
-
if (areShapesVisible !== null && areShapesVisible !== void 0 ? areShapesVisible : false) {
|
|
85
|
-
modes.add(ChartUtils.MODE_MARKERS);
|
|
86
|
-
}
|
|
87
|
-
break;
|
|
88
|
-
default:
|
|
89
|
-
break;
|
|
90
|
-
}
|
|
91
|
-
return modes.size > 0 ? [...modes].join('+') : undefined;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* Get the property to set on the series data for plotly
|
|
96
|
-
* @param plotStyle The plot style of the series
|
|
97
|
-
* @param sourceType The source type for the series
|
|
98
|
-
*/
|
|
99
|
-
static getPlotlyProperty(plotStyle, sourceType) {
|
|
100
|
-
switch (plotStyle) {
|
|
101
|
-
case dh.plot.SeriesPlotStyle.PIE:
|
|
102
|
-
switch (sourceType) {
|
|
103
|
-
case dh.plot.SourceType.X:
|
|
104
|
-
return 'labels';
|
|
105
|
-
case dh.plot.SourceType.Y:
|
|
106
|
-
return 'values';
|
|
107
|
-
default:
|
|
108
|
-
break;
|
|
109
|
-
}
|
|
110
|
-
break;
|
|
111
|
-
case dh.plot.SeriesPlotStyle.OHLC:
|
|
112
|
-
switch (sourceType) {
|
|
113
|
-
case dh.plot.SourceType.TIME:
|
|
114
|
-
return 'x';
|
|
115
|
-
default:
|
|
116
|
-
break;
|
|
117
|
-
}
|
|
118
|
-
break;
|
|
119
|
-
case dh.plot.SeriesPlotStyle.TREEMAP:
|
|
120
|
-
switch (sourceType) {
|
|
121
|
-
case dh.plot.SourceType.X:
|
|
122
|
-
return 'ids';
|
|
123
|
-
case dh.plot.SourceType.Y:
|
|
124
|
-
return 'values';
|
|
125
|
-
case dh.plot.SourceType.LABEL:
|
|
126
|
-
return 'labels';
|
|
127
|
-
case dh.plot.SourceType.PARENT:
|
|
128
|
-
return 'parents';
|
|
129
|
-
case dh.plot.SourceType.COLOR:
|
|
130
|
-
return 'marker.colors';
|
|
131
|
-
default:
|
|
132
|
-
break;
|
|
133
|
-
}
|
|
134
|
-
break;
|
|
135
|
-
default:
|
|
136
|
-
break;
|
|
137
|
-
}
|
|
138
|
-
switch (sourceType) {
|
|
139
|
-
case dh.plot.SourceType.X:
|
|
140
|
-
return 'x';
|
|
141
|
-
case dh.plot.SourceType.Y:
|
|
142
|
-
return 'y';
|
|
143
|
-
case dh.plot.SourceType.Z:
|
|
144
|
-
return 'z';
|
|
145
|
-
case dh.plot.SourceType.X_LOW:
|
|
146
|
-
return 'xLow';
|
|
147
|
-
case dh.plot.SourceType.X_HIGH:
|
|
148
|
-
return 'xHigh';
|
|
149
|
-
case dh.plot.SourceType.Y_LOW:
|
|
150
|
-
return 'yLow';
|
|
151
|
-
case dh.plot.SourceType.Y_HIGH:
|
|
152
|
-
return 'yHigh';
|
|
153
|
-
case dh.plot.SourceType.TIME:
|
|
154
|
-
return 'time';
|
|
155
|
-
case dh.plot.SourceType.OPEN:
|
|
156
|
-
return 'open';
|
|
157
|
-
case dh.plot.SourceType.HIGH:
|
|
158
|
-
return 'high';
|
|
159
|
-
case dh.plot.SourceType.LOW:
|
|
160
|
-
return 'low';
|
|
161
|
-
case dh.plot.SourceType.CLOSE:
|
|
162
|
-
return 'close';
|
|
163
|
-
case dh.plot.SourceType.SHAPE:
|
|
164
|
-
return 'shape';
|
|
165
|
-
case dh.plot.SourceType.SIZE:
|
|
166
|
-
return 'size';
|
|
167
|
-
case dh.plot.SourceType.LABEL:
|
|
168
|
-
return 'label';
|
|
169
|
-
case dh.plot.SourceType.COLOR:
|
|
170
|
-
return 'color';
|
|
171
|
-
case dh.plot.SourceType.PARENT:
|
|
172
|
-
return 'parent';
|
|
173
|
-
case dh.plot.SourceType.HOVER_TEXT:
|
|
174
|
-
return 'hovertext';
|
|
175
|
-
case dh.plot.SourceType.TEXT:
|
|
176
|
-
return 'text';
|
|
177
|
-
default:
|
|
178
|
-
throw new Error("Unrecognized source type: ".concat(sourceType));
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
static getPlotlySeriesOrientation(series) {
|
|
182
|
-
var _sources$, _sources$$axis;
|
|
183
|
-
var {
|
|
184
|
-
sources
|
|
185
|
-
} = series;
|
|
186
|
-
if (sources.length === 2 && ((_sources$ = sources[0]) === null || _sources$ === void 0 ? void 0 : (_sources$$axis = _sources$.axis) === null || _sources$$axis === void 0 ? void 0 : _sources$$axis.type) === dh.plot.AxisType.Y) {
|
|
187
|
-
return ChartUtils.ORIENTATION.HORIZONTAL;
|
|
188
|
-
}
|
|
189
|
-
return ChartUtils.ORIENTATION.VERTICAL;
|
|
190
|
-
}
|
|
191
|
-
|
|
192
28
|
/**
|
|
193
29
|
* Generate the plotly error bar data from the passed in data.
|
|
194
30
|
* Iris passes in the values as absolute, plotly needs them as relative.
|
|
@@ -208,20 +44,6 @@ class ChartUtils {
|
|
|
208
44
|
arrayminus
|
|
209
45
|
};
|
|
210
46
|
}
|
|
211
|
-
static getPlotlyDateFormat(formatter, columnType, formatPattern) {
|
|
212
|
-
var tickformat = formatPattern == null ? undefined : formatPattern.replace('%', '%%').replace(/S{9}/g, '%9f').replace(/S{8}/g, '%8f').replace(/S{7}/g, '%7f').replace(/S{6}/g, '%6f').replace(/S{5}/g, '%5f').replace(/S{4}/g, '%4f').replace(/S{3}/g, '%3f').replace(/S{2}/g, '%2f').replace(/S{1}/g, '%1f').replace(/y{4}/g, '%Y').replace(/y{2}/g, '%y').replace(/M{4}/g, '%B').replace(/M{3}/g, '%b').replace(/M{2}/g, '%m').replace(/M{1}/g, '%-m').replace(/E{4,}/g, '%A').replace(/E{1,}/g, '%a').replace(/d{2}/g, '%d').replace(/([^%]|^)d{1}/g, '$1%-d').replace(/H{2}/g, '%H').replace(/h{2}/g, '%I').replace(/h{1}/g, '%-I').replace(/m{2}/g, '%M').replace(/s{2}/g, '%S').replace("'T'", 'T').replace(' z', ''); // timezone added as suffix if necessary
|
|
213
|
-
|
|
214
|
-
var ticksuffix;
|
|
215
|
-
var dataFormatter = formatter === null || formatter === void 0 ? void 0 : formatter.getColumnTypeFormatter(columnType);
|
|
216
|
-
if (dataFormatter != null && isDateTimeColumnFormatter(dataFormatter) && dataFormatter.dhTimeZone != null && dataFormatter.showTimeZone) {
|
|
217
|
-
ticksuffix = dh.i18n.DateTimeFormat.format(' z', new Date(), dataFormatter.dhTimeZone);
|
|
218
|
-
}
|
|
219
|
-
return {
|
|
220
|
-
tickformat,
|
|
221
|
-
ticksuffix,
|
|
222
|
-
automargin: true
|
|
223
|
-
};
|
|
224
|
-
}
|
|
225
47
|
static convertNumberPrefix(prefix) {
|
|
226
48
|
return prefix.replace(/\u00A4\u00A4/g, 'USD').replace(/\u00A4/g, '$');
|
|
227
49
|
}
|
|
@@ -260,42 +82,6 @@ class ChartUtils {
|
|
|
260
82
|
};
|
|
261
83
|
}
|
|
262
84
|
|
|
263
|
-
/**
|
|
264
|
-
* Gets the plotly axis formatting information from the source passed in
|
|
265
|
-
* @param source The Source to get the formatter information from
|
|
266
|
-
* @param formatter The current formatter for formatting data
|
|
267
|
-
*/
|
|
268
|
-
static getPlotlyAxisFormat(source) {
|
|
269
|
-
var formatter = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
|
|
270
|
-
var {
|
|
271
|
-
axis,
|
|
272
|
-
columnType
|
|
273
|
-
} = source;
|
|
274
|
-
var {
|
|
275
|
-
formatPattern
|
|
276
|
-
} = axis;
|
|
277
|
-
var axisFormat = null;
|
|
278
|
-
if (TableUtils.isDateType(columnType)) {
|
|
279
|
-
axisFormat = ChartUtils.getPlotlyDateFormat(formatter, columnType, formatPattern);
|
|
280
|
-
axisFormat = ChartUtils.addTickSpacing(axisFormat, axis, true);
|
|
281
|
-
} else if (TableUtils.isNumberType(columnType)) {
|
|
282
|
-
axisFormat = ChartUtils.getPlotlyNumberFormat(formatter, columnType, formatPattern);
|
|
283
|
-
axisFormat = ChartUtils.addTickSpacing(axisFormat, axis, false);
|
|
284
|
-
}
|
|
285
|
-
if (axis.formatType === dh.plot.AxisFormatType.CATEGORY) {
|
|
286
|
-
if (axisFormat) {
|
|
287
|
-
axisFormat.type = 'category';
|
|
288
|
-
} else {
|
|
289
|
-
axisFormat = {
|
|
290
|
-
type: 'category',
|
|
291
|
-
tickformat: undefined,
|
|
292
|
-
ticksuffix: undefined
|
|
293
|
-
};
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
return axisFormat;
|
|
297
|
-
}
|
|
298
|
-
|
|
299
85
|
/**
|
|
300
86
|
* Adds tick spacing for an axis that has gapBetweenMajorTicks defined.
|
|
301
87
|
*
|
|
@@ -354,34 +140,457 @@ class ChartUtils {
|
|
|
354
140
|
if (settings != null && settings.hiddenSeries != null && settings.hiddenSeries.includes(name)) {
|
|
355
141
|
return 'legendonly';
|
|
356
142
|
}
|
|
357
|
-
return true;
|
|
143
|
+
return true;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Get hidden labels array from chart settings
|
|
148
|
+
* @param settings Chart settings
|
|
149
|
+
* @returns Array of hidden series names
|
|
150
|
+
*/
|
|
151
|
+
static getHiddenLabels(settings) {
|
|
152
|
+
if (settings !== null && settings !== void 0 && settings.hiddenSeries) {
|
|
153
|
+
return [...settings.hiddenSeries];
|
|
154
|
+
}
|
|
155
|
+
return [];
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Create a default series data object. Apply styling to the object afterward.
|
|
160
|
+
* @returns A simple series data object with no styling
|
|
161
|
+
*/
|
|
162
|
+
static makeSeriesData(type, mode, name, showLegend) {
|
|
163
|
+
var orientation = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : ChartUtils.ORIENTATION.VERTICAL;
|
|
164
|
+
return {
|
|
165
|
+
type,
|
|
166
|
+
mode,
|
|
167
|
+
name,
|
|
168
|
+
orientation,
|
|
169
|
+
showlegend: showLegend !== null && showLegend !== void 0 ? showLegend : undefined
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Get the Plotly marker symbol for the provided Deephaven shape
|
|
175
|
+
* Deephaven shapes: https://deephaven.io/enterprise/docs/plotting/visual-formatting/#point-formatting
|
|
176
|
+
* Plotly shapes: https://plotly.com/javascript/reference/scattergl/#scattergl-marker-symbol
|
|
177
|
+
* Table of plotly shapes: https://plotly.com/python/marker-style/#custom-marker-symbols
|
|
178
|
+
* @param deephavenShape Deephaven shape to get the marker symbol for
|
|
179
|
+
*/
|
|
180
|
+
static getMarkerSymbol(deephavenShape) {
|
|
181
|
+
switch (deephavenShape) {
|
|
182
|
+
case 'SQUARE':
|
|
183
|
+
return 'square';
|
|
184
|
+
case 'CIRCLE':
|
|
185
|
+
return 'circle';
|
|
186
|
+
case 'DIAMOND':
|
|
187
|
+
return 'diamond';
|
|
188
|
+
case 'UP_TRIANGLE':
|
|
189
|
+
return 'triangle-up';
|
|
190
|
+
case 'DOWN_TRIANGLE':
|
|
191
|
+
return 'triangle-down';
|
|
192
|
+
case 'RIGHT_TRIANGLE':
|
|
193
|
+
return 'triangle-right';
|
|
194
|
+
case 'LEFT_TRIANGLE':
|
|
195
|
+
return 'triangle-left';
|
|
196
|
+
// There don't seem to be any plotly equivalents for ellipse or rectangles
|
|
197
|
+
// Rectangles could be `line-ew`, `line-ns`, or `hourglass` and `bowtie` instead?
|
|
198
|
+
// Ellipse could be `asterisk` or `diamond-wide` instead?
|
|
199
|
+
// Just throw an error, we've already got a bunch of types.
|
|
200
|
+
case 'ELLIPSE':
|
|
201
|
+
case 'HORIZONTAL_RECTANGLE':
|
|
202
|
+
case 'VERTICAL_RECTANGLE':
|
|
203
|
+
default:
|
|
204
|
+
throw new Error("Unrecognized shape ".concat(deephavenShape));
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Get all axes for a given `Figure`. Iterates through all charts axes and concatenates them.
|
|
210
|
+
* @param figure Figure to get all axes for
|
|
211
|
+
*/
|
|
212
|
+
static getAllAxes(figure) {
|
|
213
|
+
return figure.charts.reduce((axes, chart) => [...axes, ...chart.axes], []);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Retrieve the chart that contains the passed in series from the figure
|
|
218
|
+
* @param figure The figure to retrieve the chart from
|
|
219
|
+
* @param series The series to get the chart for
|
|
220
|
+
*/
|
|
221
|
+
static getChartForSeries(figure, series) {
|
|
222
|
+
var {
|
|
223
|
+
charts
|
|
224
|
+
} = figure;
|
|
225
|
+
for (var i = 0; i < charts.length; i += 1) {
|
|
226
|
+
var _chart = charts[i];
|
|
227
|
+
for (var j = 0; j < _chart.series.length; j += 1) {
|
|
228
|
+
if (series === _chart.series[j]) {
|
|
229
|
+
return _chart;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
return null;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Get an object mapping axis to their ranges
|
|
238
|
+
* @param layout The plotly layout object to get the ranges from
|
|
239
|
+
* @returns An object mapping the axis name to it's range
|
|
240
|
+
*/
|
|
241
|
+
static getLayoutRanges(layout) {
|
|
242
|
+
var ranges = {};
|
|
243
|
+
var keys = Object.keys(layout).filter(key => key.indexOf('axis') >= 0);
|
|
244
|
+
for (var i = 0; i < keys.length; i += 1) {
|
|
245
|
+
var key = keys[i];
|
|
246
|
+
var value = layout[key];
|
|
247
|
+
if (isRangedPlotlyAxis(value)) {
|
|
248
|
+
// Only want to add the range if it's not autoranged
|
|
249
|
+
ranges[key] = [...value.range];
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
return ranges;
|
|
253
|
+
}
|
|
254
|
+
static getAxisLayoutProperty(axisProperty, axisIndex) {
|
|
255
|
+
var axisIndexString = axisIndex > 0 ? "".concat(axisIndex + 1) : '';
|
|
256
|
+
return "".concat(axisProperty !== null && axisProperty !== void 0 ? axisProperty : '', "axis").concat(axisIndexString);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Converts an open or close period to a declimal. e.g '09:30" to 9.5
|
|
261
|
+
*
|
|
262
|
+
* @param period the open or close value of the period
|
|
263
|
+
*/
|
|
264
|
+
static periodToDecimal(period) {
|
|
265
|
+
var values = period.split(':');
|
|
266
|
+
return Number(values[0]) + Number(values[1]) / 60;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* Groups an array and returns a map
|
|
271
|
+
* @param array The object to group
|
|
272
|
+
* @param property The property name to group by
|
|
273
|
+
* @returns A map containing the items grouped by their values for the property
|
|
274
|
+
*/
|
|
275
|
+
static groupArray(array, property) {
|
|
276
|
+
return array.reduce((result, item) => {
|
|
277
|
+
var _result$get;
|
|
278
|
+
var key = item[property];
|
|
279
|
+
var group = (_result$get = result.get(key)) !== null && _result$get !== void 0 ? _result$get : [];
|
|
280
|
+
group.push(item);
|
|
281
|
+
result.set(key, group);
|
|
282
|
+
return result;
|
|
283
|
+
}, new Map());
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Parses the colorway property of a theme and returns an array of colors
|
|
288
|
+
* Theme could have a single string with space separated colors or an array of strings representing the colorway
|
|
289
|
+
* @param theme The theme to get colorway from
|
|
290
|
+
* @returns Colorway array for the theme
|
|
291
|
+
*/
|
|
292
|
+
static getColorwayFromTheme() {
|
|
293
|
+
var theme = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ChartTheme;
|
|
294
|
+
var colorway = [];
|
|
295
|
+
if (theme.colorway) {
|
|
296
|
+
if (Array.isArray(theme.colorway)) {
|
|
297
|
+
colorway = theme.colorway;
|
|
298
|
+
} else if (typeof theme.colorway === 'string') {
|
|
299
|
+
colorway = theme.colorway.split(' ');
|
|
300
|
+
} else {
|
|
301
|
+
log.warn("Unable to handle colorway property: ".concat(theme.colorway));
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
return colorway;
|
|
305
|
+
}
|
|
306
|
+
static titleFromSettings(settings) {
|
|
307
|
+
var {
|
|
308
|
+
series,
|
|
309
|
+
xAxis,
|
|
310
|
+
title = "".concat((series !== null && series !== void 0 ? series : []).join(', '), " by ").concat(xAxis)
|
|
311
|
+
} = settings;
|
|
312
|
+
return title;
|
|
313
|
+
}
|
|
314
|
+
constructor(dh) {
|
|
315
|
+
_defineProperty(this, "dh", void 0);
|
|
316
|
+
_defineProperty(this, "daysOfWeek", void 0);
|
|
317
|
+
this.dh = dh;
|
|
318
|
+
this.daysOfWeek = Object.freeze(dh.calendar.DayOfWeek.values());
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* Retrieve the axis formats from the provided figure.
|
|
323
|
+
* Currently defaults to just the x/y axes.
|
|
324
|
+
* @param figure The figure to get the axis formats for
|
|
325
|
+
* @param formatter The formatter to use when getting the axis format
|
|
326
|
+
* @returns A map of axis layout property names to axis formats
|
|
327
|
+
*/
|
|
328
|
+
getAxisFormats(figure, formatter) {
|
|
329
|
+
var _this = this;
|
|
330
|
+
var axisFormats = new Map();
|
|
331
|
+
var nullFormat = {
|
|
332
|
+
tickformat: null,
|
|
333
|
+
ticksuffix: null
|
|
334
|
+
};
|
|
335
|
+
var allAxes = ChartUtils.getAllAxes(figure);
|
|
336
|
+
var axisTypeMap = ChartUtils.groupArray(allAxes, 'type');
|
|
337
|
+
var {
|
|
338
|
+
charts
|
|
339
|
+
} = figure;
|
|
340
|
+
for (var i = 0; i < charts.length; i += 1) {
|
|
341
|
+
var _chart2 = charts[i];
|
|
342
|
+
for (var j = 0; j < _chart2.series.length; j += 1) {
|
|
343
|
+
var series = _chart2.series[j];
|
|
344
|
+
var {
|
|
345
|
+
sources
|
|
346
|
+
} = series;
|
|
347
|
+
var axisSources = sources.filter(source => source.axis);
|
|
348
|
+
var _loop = function _loop() {
|
|
349
|
+
var source = axisSources[k];
|
|
350
|
+
var {
|
|
351
|
+
axis
|
|
352
|
+
} = source;
|
|
353
|
+
var {
|
|
354
|
+
type: axisType
|
|
355
|
+
} = axis;
|
|
356
|
+
var typeAxes = axisTypeMap.get(axisType);
|
|
357
|
+
assertNotNull(typeAxes);
|
|
358
|
+
var axisIndex = typeAxes.indexOf(axis);
|
|
359
|
+
var axisProperty = _this.getAxisPropertyName(axisType);
|
|
360
|
+
if (axisProperty != null) {
|
|
361
|
+
var axisLayoutProperty = ChartUtils.getAxisLayoutProperty(axisProperty, axisIndex);
|
|
362
|
+
if (axisFormats.has(axisLayoutProperty)) {
|
|
363
|
+
log.debug("".concat(axisLayoutProperty, " already added."));
|
|
364
|
+
} else {
|
|
365
|
+
log.debug("Adding ".concat(axisLayoutProperty, " to axisFormats."));
|
|
366
|
+
var axisFormat = _this.getPlotlyAxisFormat(source, formatter);
|
|
367
|
+
if (axisFormat === null) {
|
|
368
|
+
axisFormats.set(axisLayoutProperty, nullFormat);
|
|
369
|
+
} else {
|
|
370
|
+
axisFormats.set(axisLayoutProperty, axisFormat);
|
|
371
|
+
var {
|
|
372
|
+
businessCalendar
|
|
373
|
+
} = axis;
|
|
374
|
+
if (businessCalendar != null) {
|
|
375
|
+
var rangebreaks = [];
|
|
376
|
+
var {
|
|
377
|
+
businessPeriods,
|
|
378
|
+
businessDays,
|
|
379
|
+
holidays,
|
|
380
|
+
timeZone: calendarTimeZone
|
|
381
|
+
} = businessCalendar;
|
|
382
|
+
var typeFormatter = formatter === null || formatter === void 0 ? void 0 : formatter.getColumnTypeFormatter(BUSINESS_COLUMN_TYPE);
|
|
383
|
+
var formatterTimeZone;
|
|
384
|
+
if (isDateTimeColumnFormatter(typeFormatter)) {
|
|
385
|
+
formatterTimeZone = typeFormatter.dhTimeZone;
|
|
386
|
+
}
|
|
387
|
+
var timeZoneDiff = formatterTimeZone ? (calendarTimeZone.standardOffset - formatterTimeZone.standardOffset) / 60 : 0;
|
|
388
|
+
if (holidays.length > 0) {
|
|
389
|
+
rangebreaks.push(..._this.createRangeBreakValuesFromHolidays(holidays, calendarTimeZone, formatterTimeZone));
|
|
390
|
+
}
|
|
391
|
+
businessPeriods.forEach(period => rangebreaks.push({
|
|
392
|
+
pattern: 'hour',
|
|
393
|
+
bounds: [ChartUtils.periodToDecimal(period.close) + timeZoneDiff, ChartUtils.periodToDecimal(period.open) + timeZoneDiff]
|
|
394
|
+
}));
|
|
395
|
+
// If there are seven business days, then there is no weekend
|
|
396
|
+
if (businessDays.length < _this.daysOfWeek.length) {
|
|
397
|
+
_this.createBoundsFromDays(businessDays).forEach(weekendBounds => rangebreaks.push({
|
|
398
|
+
pattern: 'day of week',
|
|
399
|
+
bounds: weekendBounds
|
|
400
|
+
}));
|
|
401
|
+
}
|
|
402
|
+
axisFormat.rangebreaks = rangebreaks;
|
|
403
|
+
}
|
|
404
|
+
if (axisFormats.size === _chart2.axes.length) {
|
|
405
|
+
return {
|
|
406
|
+
v: axisFormats
|
|
407
|
+
};
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
};
|
|
413
|
+
for (var k = 0; k < axisSources.length; k += 1) {
|
|
414
|
+
var _ret = _loop();
|
|
415
|
+
if (typeof _ret === "object") return _ret.v;
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
return axisFormats;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
/**
|
|
423
|
+
* Converts the Iris plot style into a plotly chart type
|
|
424
|
+
* @param plotStyle The plotStyle to use, see dh.plot.SeriesPlotStyle
|
|
425
|
+
* @param isBusinessTime If the plot is using business time for an axis
|
|
426
|
+
*/
|
|
427
|
+
getPlotlyChartType(plotStyle, isBusinessTime) {
|
|
428
|
+
var {
|
|
429
|
+
dh
|
|
430
|
+
} = this;
|
|
431
|
+
switch (plotStyle) {
|
|
432
|
+
case dh.plot.SeriesPlotStyle.SCATTER:
|
|
433
|
+
// scattergl mode is more performant, but doesn't support the rangebreaks we need for businessTime calendars
|
|
434
|
+
return !isBusinessTime ? 'scattergl' : 'scatter';
|
|
435
|
+
case dh.plot.SeriesPlotStyle.LINE:
|
|
436
|
+
// There is also still some artifacting bugs with scattergl: https://github.com/plotly/plotly.js/issues/3522
|
|
437
|
+
// The artifacting only occurs on line plots, which we can draw with fairly decent performance using SVG paths
|
|
438
|
+
// Once the above plotly issue is fixed, scattergl should be used here (when !isBusinessTime)
|
|
439
|
+
return 'scatter';
|
|
440
|
+
case dh.plot.SeriesPlotStyle.BAR:
|
|
441
|
+
case dh.plot.SeriesPlotStyle.STACKED_BAR:
|
|
442
|
+
return 'bar';
|
|
443
|
+
case dh.plot.SeriesPlotStyle.PIE:
|
|
444
|
+
return 'pie';
|
|
445
|
+
case dh.plot.SeriesPlotStyle.TREEMAP:
|
|
446
|
+
return 'treemap';
|
|
447
|
+
case dh.plot.SeriesPlotStyle.HISTOGRAM:
|
|
448
|
+
return 'histogram';
|
|
449
|
+
case dh.plot.SeriesPlotStyle.OHLC:
|
|
450
|
+
return 'ohlc';
|
|
451
|
+
default:
|
|
452
|
+
return undefined;
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
/**
|
|
457
|
+
* Converts the Iris plot style into a plotly chart mode
|
|
458
|
+
* @param plotStyle The plotStyle to use, see dh.plot.SeriesPlotStyle.*
|
|
459
|
+
* @param areLinesVisible Whether lines are visible or not
|
|
460
|
+
* @param areShapesVisible Whether shapes are visible or not
|
|
461
|
+
*/
|
|
462
|
+
getPlotlyChartMode(plotStyle, areLinesVisible, areShapesVisible) {
|
|
463
|
+
var {
|
|
464
|
+
dh
|
|
465
|
+
} = this;
|
|
466
|
+
var modes = new Set();
|
|
467
|
+
switch (plotStyle) {
|
|
468
|
+
case dh.plot.SeriesPlotStyle.SCATTER:
|
|
469
|
+
// Default to only showing shapes in scatter plots
|
|
470
|
+
if (areLinesVisible !== null && areLinesVisible !== void 0 ? areLinesVisible : false) {
|
|
471
|
+
modes.add(ChartUtils.MODE_LINES);
|
|
472
|
+
}
|
|
473
|
+
if (areShapesVisible !== null && areShapesVisible !== void 0 ? areShapesVisible : true) {
|
|
474
|
+
modes.add(ChartUtils.MODE_MARKERS);
|
|
475
|
+
}
|
|
476
|
+
break;
|
|
477
|
+
case dh.plot.SeriesPlotStyle.LINE:
|
|
478
|
+
// Default to only showing lines in line series
|
|
479
|
+
if (areLinesVisible !== null && areLinesVisible !== void 0 ? areLinesVisible : true) {
|
|
480
|
+
modes.add(ChartUtils.MODE_LINES);
|
|
481
|
+
}
|
|
482
|
+
if (areShapesVisible !== null && areShapesVisible !== void 0 ? areShapesVisible : false) {
|
|
483
|
+
modes.add(ChartUtils.MODE_MARKERS);
|
|
484
|
+
}
|
|
485
|
+
break;
|
|
486
|
+
default:
|
|
487
|
+
break;
|
|
488
|
+
}
|
|
489
|
+
return modes.size > 0 ? [...modes].join('+') : undefined;
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
/**
|
|
493
|
+
* Get the property to set on the series data for plotly
|
|
494
|
+
* @param plotStyle The plot style of the series
|
|
495
|
+
* @param sourceType The source type for the series
|
|
496
|
+
*/
|
|
497
|
+
getPlotlyProperty(plotStyle, sourceType) {
|
|
498
|
+
var {
|
|
499
|
+
dh
|
|
500
|
+
} = this;
|
|
501
|
+
switch (plotStyle) {
|
|
502
|
+
case dh.plot.SeriesPlotStyle.PIE:
|
|
503
|
+
switch (sourceType) {
|
|
504
|
+
case dh.plot.SourceType.X:
|
|
505
|
+
return 'labels';
|
|
506
|
+
case dh.plot.SourceType.Y:
|
|
507
|
+
return 'values';
|
|
508
|
+
default:
|
|
509
|
+
break;
|
|
510
|
+
}
|
|
511
|
+
break;
|
|
512
|
+
case dh.plot.SeriesPlotStyle.OHLC:
|
|
513
|
+
switch (sourceType) {
|
|
514
|
+
case dh.plot.SourceType.TIME:
|
|
515
|
+
return 'x';
|
|
516
|
+
default:
|
|
517
|
+
break;
|
|
518
|
+
}
|
|
519
|
+
break;
|
|
520
|
+
case dh.plot.SeriesPlotStyle.TREEMAP:
|
|
521
|
+
switch (sourceType) {
|
|
522
|
+
case dh.plot.SourceType.X:
|
|
523
|
+
return 'ids';
|
|
524
|
+
case dh.plot.SourceType.Y:
|
|
525
|
+
return 'values';
|
|
526
|
+
case dh.plot.SourceType.LABEL:
|
|
527
|
+
return 'labels';
|
|
528
|
+
case dh.plot.SourceType.PARENT:
|
|
529
|
+
return 'parents';
|
|
530
|
+
case dh.plot.SourceType.COLOR:
|
|
531
|
+
return 'marker.colors';
|
|
532
|
+
default:
|
|
533
|
+
break;
|
|
534
|
+
}
|
|
535
|
+
break;
|
|
536
|
+
default:
|
|
537
|
+
break;
|
|
538
|
+
}
|
|
539
|
+
switch (sourceType) {
|
|
540
|
+
case dh.plot.SourceType.X:
|
|
541
|
+
return 'x';
|
|
542
|
+
case dh.plot.SourceType.Y:
|
|
543
|
+
return 'y';
|
|
544
|
+
case dh.plot.SourceType.Z:
|
|
545
|
+
return 'z';
|
|
546
|
+
case dh.plot.SourceType.X_LOW:
|
|
547
|
+
return 'xLow';
|
|
548
|
+
case dh.plot.SourceType.X_HIGH:
|
|
549
|
+
return 'xHigh';
|
|
550
|
+
case dh.plot.SourceType.Y_LOW:
|
|
551
|
+
return 'yLow';
|
|
552
|
+
case dh.plot.SourceType.Y_HIGH:
|
|
553
|
+
return 'yHigh';
|
|
554
|
+
case dh.plot.SourceType.TIME:
|
|
555
|
+
return 'time';
|
|
556
|
+
case dh.plot.SourceType.OPEN:
|
|
557
|
+
return 'open';
|
|
558
|
+
case dh.plot.SourceType.HIGH:
|
|
559
|
+
return 'high';
|
|
560
|
+
case dh.plot.SourceType.LOW:
|
|
561
|
+
return 'low';
|
|
562
|
+
case dh.plot.SourceType.CLOSE:
|
|
563
|
+
return 'close';
|
|
564
|
+
case dh.plot.SourceType.SHAPE:
|
|
565
|
+
return 'shape';
|
|
566
|
+
case dh.plot.SourceType.SIZE:
|
|
567
|
+
return 'size';
|
|
568
|
+
case dh.plot.SourceType.LABEL:
|
|
569
|
+
return 'label';
|
|
570
|
+
case dh.plot.SourceType.COLOR:
|
|
571
|
+
return 'color';
|
|
572
|
+
case dh.plot.SourceType.PARENT:
|
|
573
|
+
return 'parent';
|
|
574
|
+
case dh.plot.SourceType.HOVER_TEXT:
|
|
575
|
+
return 'hovertext';
|
|
576
|
+
case dh.plot.SourceType.TEXT:
|
|
577
|
+
return 'text';
|
|
578
|
+
default:
|
|
579
|
+
throw new Error("Unrecognized source type: ".concat(sourceType));
|
|
580
|
+
}
|
|
358
581
|
}
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
582
|
+
getPlotlySeriesOrientation(series) {
|
|
583
|
+
var _sources$, _sources$$axis;
|
|
584
|
+
var {
|
|
585
|
+
dh
|
|
586
|
+
} = this;
|
|
587
|
+
var {
|
|
588
|
+
sources
|
|
589
|
+
} = series;
|
|
590
|
+
if (sources.length === 2 && ((_sources$ = sources[0]) === null || _sources$ === void 0 ? void 0 : (_sources$$axis = _sources$.axis) === null || _sources$$axis === void 0 ? void 0 : _sources$$axis.type) === dh.plot.AxisType.Y) {
|
|
591
|
+
return ChartUtils.ORIENTATION.HORIZONTAL;
|
|
368
592
|
}
|
|
369
|
-
return
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
/**
|
|
373
|
-
* Create a default series data object. Apply styling to the object afterward.
|
|
374
|
-
* @returns A simple series data object with no styling
|
|
375
|
-
*/
|
|
376
|
-
static makeSeriesData(type, mode, name, showLegend) {
|
|
377
|
-
var orientation = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : ChartUtils.ORIENTATION.VERTICAL;
|
|
378
|
-
return {
|
|
379
|
-
type,
|
|
380
|
-
mode,
|
|
381
|
-
name,
|
|
382
|
-
orientation,
|
|
383
|
-
showlegend: showLegend !== null && showLegend !== void 0 ? showLegend : undefined
|
|
384
|
-
};
|
|
593
|
+
return ChartUtils.ORIENTATION.VERTICAL;
|
|
385
594
|
}
|
|
386
595
|
|
|
387
596
|
/**
|
|
@@ -392,7 +601,7 @@ class ChartUtils {
|
|
|
392
601
|
* @param theme The theme properties for the plot. See ChartTheme.js for an example
|
|
393
602
|
* @returns The series data (trace) object for use with plotly.
|
|
394
603
|
*/
|
|
395
|
-
|
|
604
|
+
makeSeriesDataFromSeries(series, axisTypeMap, seriesVisibility) {
|
|
396
605
|
var showLegend = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null;
|
|
397
606
|
var theme = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : ChartTheme;
|
|
398
607
|
var {
|
|
@@ -410,15 +619,15 @@ class ChartUtils {
|
|
|
410
619
|
var _source$axis;
|
|
411
620
|
return (_source$axis = source.axis) === null || _source$axis === void 0 ? void 0 : _source$axis.businessCalendar;
|
|
412
621
|
});
|
|
413
|
-
var type =
|
|
414
|
-
var mode =
|
|
415
|
-
var orientation =
|
|
622
|
+
var type = this.getChartType(plotStyle, isBusinessTime);
|
|
623
|
+
var mode = this.getPlotlyChartMode(plotStyle, isLinesVisible !== null && isLinesVisible !== void 0 ? isLinesVisible : undefined, isShapesVisible !== null && isShapesVisible !== void 0 ? isShapesVisible : undefined);
|
|
624
|
+
var orientation = this.getPlotlySeriesOrientation(series);
|
|
416
625
|
var seriesData = ChartUtils.makeSeriesData(type, mode, name, showLegend, orientation);
|
|
417
|
-
|
|
418
|
-
|
|
626
|
+
this.addSourcesToSeriesData(seriesData, plotStyle, sources, axisTypeMap);
|
|
627
|
+
this.addStylingToSeriesData(seriesData, plotStyle, theme, lineColor, shapeColor, shape, shapeSize, seriesVisibility);
|
|
419
628
|
return seriesData;
|
|
420
629
|
}
|
|
421
|
-
|
|
630
|
+
addSourcesToSeriesData(seriesDataParam, plotStyle, sources, axisTypeMap) {
|
|
422
631
|
var seriesData = seriesDataParam;
|
|
423
632
|
for (var k = 0; k < sources.length; k += 1) {
|
|
424
633
|
var source = sources[k];
|
|
@@ -426,9 +635,9 @@ class ChartUtils {
|
|
|
426
635
|
axis: _axis,
|
|
427
636
|
type: sourceType
|
|
428
637
|
} = source;
|
|
429
|
-
var dataAttributeName =
|
|
638
|
+
var dataAttributeName = this.getPlotlyProperty(plotStyle, sourceType);
|
|
430
639
|
set(seriesData, dataAttributeName, []);
|
|
431
|
-
var axisProperty = _axis != null ?
|
|
640
|
+
var axisProperty = _axis != null ? this.getAxisPropertyName(_axis.type) : null;
|
|
432
641
|
if (axisProperty != null) {
|
|
433
642
|
var axes = axisTypeMap.get(_axis.type);
|
|
434
643
|
if (axes) {
|
|
@@ -439,13 +648,16 @@ class ChartUtils {
|
|
|
439
648
|
}
|
|
440
649
|
}
|
|
441
650
|
}
|
|
442
|
-
|
|
651
|
+
addStylingToSeriesData(seriesDataParam, plotStyle) {
|
|
443
652
|
var theme = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : ChartTheme;
|
|
444
653
|
var lineColor = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null;
|
|
445
654
|
var shapeColor = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : null;
|
|
446
655
|
var shape = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : null;
|
|
447
656
|
var shapeSize = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : null;
|
|
448
657
|
var seriesVisibility = arguments.length > 7 && arguments[7] !== undefined ? arguments[7] : null;
|
|
658
|
+
var {
|
|
659
|
+
dh
|
|
660
|
+
} = this;
|
|
449
661
|
var seriesData = seriesDataParam;
|
|
450
662
|
// Add some empty objects so we can fill them in later with details without checking for existence
|
|
451
663
|
seriesData.marker = {
|
|
@@ -531,231 +743,58 @@ class ChartUtils {
|
|
|
531
743
|
seriesData.visible = seriesVisibility;
|
|
532
744
|
}
|
|
533
745
|
}
|
|
534
|
-
|
|
535
|
-
/**
|
|
536
|
-
* Get the Plotly marker symbol for the provided Deephaven shape
|
|
537
|
-
* Deephaven shapes: https://deephaven.io/enterprise/docs/plotting/visual-formatting/#point-formatting
|
|
538
|
-
* Plotly shapes: https://plotly.com/javascript/reference/scattergl/#scattergl-marker-symbol
|
|
539
|
-
* Table of plotly shapes: https://plotly.com/python/marker-style/#custom-marker-symbols
|
|
540
|
-
* @param deephavenShape Deephaven shape to get the marker symbol for
|
|
541
|
-
*/
|
|
542
|
-
static getMarkerSymbol(deephavenShape) {
|
|
543
|
-
switch (deephavenShape) {
|
|
544
|
-
case 'SQUARE':
|
|
545
|
-
return 'square';
|
|
546
|
-
case 'CIRCLE':
|
|
547
|
-
return 'circle';
|
|
548
|
-
case 'DIAMOND':
|
|
549
|
-
return 'diamond';
|
|
550
|
-
case 'UP_TRIANGLE':
|
|
551
|
-
return 'triangle-up';
|
|
552
|
-
case 'DOWN_TRIANGLE':
|
|
553
|
-
return 'triangle-down';
|
|
554
|
-
case 'RIGHT_TRIANGLE':
|
|
555
|
-
return 'triangle-right';
|
|
556
|
-
case 'LEFT_TRIANGLE':
|
|
557
|
-
return 'triangle-left';
|
|
558
|
-
// There don't seem to be any plotly equivalents for ellipse or rectangles
|
|
559
|
-
// Rectangles could be `line-ew`, `line-ns`, or `hourglass` and `bowtie` instead?
|
|
560
|
-
// Ellipse could be `asterisk` or `diamond-wide` instead?
|
|
561
|
-
// Just throw an error, we've already got a bunch of types.
|
|
562
|
-
case 'ELLIPSE':
|
|
563
|
-
case 'HORIZONTAL_RECTANGLE':
|
|
564
|
-
case 'VERTICAL_RECTANGLE':
|
|
565
|
-
default:
|
|
566
|
-
throw new Error("Unrecognized shape ".concat(deephavenShape));
|
|
567
|
-
}
|
|
568
|
-
}
|
|
569
|
-
|
|
570
|
-
/**
|
|
571
|
-
* Retrieve the axis formats from the provided figure.
|
|
572
|
-
* Currently defaults to just the x/y axes.
|
|
573
|
-
* @param figure The figure to get the axis formats for
|
|
574
|
-
* @param formatter The formatter to use when getting the axis format
|
|
575
|
-
* @returns A map of axis layout property names to axis formats
|
|
576
|
-
*/
|
|
577
|
-
static getAxisFormats(figure, formatter) {
|
|
578
|
-
var axisFormats = new Map();
|
|
579
|
-
var nullFormat = {
|
|
580
|
-
tickformat: null,
|
|
581
|
-
ticksuffix: null
|
|
582
|
-
};
|
|
583
|
-
var allAxes = ChartUtils.getAllAxes(figure);
|
|
584
|
-
var axisTypeMap = ChartUtils.groupArray(allAxes, 'type');
|
|
746
|
+
getChartType(plotStyle, isBusinessTime) {
|
|
585
747
|
var {
|
|
586
|
-
|
|
587
|
-
} =
|
|
588
|
-
for (var i = 0; i < charts.length; i += 1) {
|
|
589
|
-
var _chart = charts[i];
|
|
590
|
-
for (var j = 0; j < _chart.series.length; j += 1) {
|
|
591
|
-
var series = _chart.series[j];
|
|
592
|
-
var {
|
|
593
|
-
sources
|
|
594
|
-
} = series;
|
|
595
|
-
var axisSources = sources.filter(source => source.axis);
|
|
596
|
-
var _loop = function _loop() {
|
|
597
|
-
var source = axisSources[k];
|
|
598
|
-
var {
|
|
599
|
-
axis
|
|
600
|
-
} = source;
|
|
601
|
-
var {
|
|
602
|
-
type: axisType
|
|
603
|
-
} = axis;
|
|
604
|
-
var typeAxes = axisTypeMap.get(axisType);
|
|
605
|
-
assertNotNull(typeAxes);
|
|
606
|
-
var axisIndex = typeAxes.indexOf(axis);
|
|
607
|
-
var axisProperty = ChartUtils.getAxisPropertyName(axisType);
|
|
608
|
-
if (axisProperty != null) {
|
|
609
|
-
var axisLayoutProperty = ChartUtils.getAxisLayoutProperty(axisProperty, axisIndex);
|
|
610
|
-
if (axisFormats.has(axisLayoutProperty)) {
|
|
611
|
-
log.debug("".concat(axisLayoutProperty, " already added."));
|
|
612
|
-
} else {
|
|
613
|
-
log.debug("Adding ".concat(axisLayoutProperty, " to axisFormats."));
|
|
614
|
-
var axisFormat = ChartUtils.getPlotlyAxisFormat(source, formatter);
|
|
615
|
-
if (axisFormat === null) {
|
|
616
|
-
axisFormats.set(axisLayoutProperty, nullFormat);
|
|
617
|
-
} else {
|
|
618
|
-
axisFormats.set(axisLayoutProperty, axisFormat);
|
|
619
|
-
var {
|
|
620
|
-
businessCalendar
|
|
621
|
-
} = axis;
|
|
622
|
-
if (businessCalendar != null) {
|
|
623
|
-
var rangebreaks = [];
|
|
624
|
-
var {
|
|
625
|
-
businessPeriods,
|
|
626
|
-
businessDays,
|
|
627
|
-
holidays,
|
|
628
|
-
timeZone: calendarTimeZone
|
|
629
|
-
} = businessCalendar;
|
|
630
|
-
var typeFormatter = formatter === null || formatter === void 0 ? void 0 : formatter.getColumnTypeFormatter(BUSINESS_COLUMN_TYPE);
|
|
631
|
-
var formatterTimeZone;
|
|
632
|
-
if (isDateTimeColumnFormatter(typeFormatter)) {
|
|
633
|
-
formatterTimeZone = typeFormatter.dhTimeZone;
|
|
634
|
-
}
|
|
635
|
-
var timeZoneDiff = formatterTimeZone ? (calendarTimeZone.standardOffset - formatterTimeZone.standardOffset) / 60 : 0;
|
|
636
|
-
if (holidays.length > 0) {
|
|
637
|
-
rangebreaks.push(...ChartUtils.createRangeBreakValuesFromHolidays(holidays, calendarTimeZone, formatterTimeZone));
|
|
638
|
-
}
|
|
639
|
-
businessPeriods.forEach(period => rangebreaks.push({
|
|
640
|
-
pattern: 'hour',
|
|
641
|
-
bounds: [ChartUtils.periodToDecimal(period.close) + timeZoneDiff, ChartUtils.periodToDecimal(period.open) + timeZoneDiff]
|
|
642
|
-
}));
|
|
643
|
-
// If there are seven business days, then there is no weekend
|
|
644
|
-
if (businessDays.length < DAYS.length) {
|
|
645
|
-
ChartUtils.createBoundsFromDays(businessDays).forEach(weekendBounds => rangebreaks.push({
|
|
646
|
-
pattern: 'day of week',
|
|
647
|
-
bounds: weekendBounds
|
|
648
|
-
}));
|
|
649
|
-
}
|
|
650
|
-
axisFormat.rangebreaks = rangebreaks;
|
|
651
|
-
}
|
|
652
|
-
if (axisFormats.size === _chart.axes.length) {
|
|
653
|
-
return {
|
|
654
|
-
v: axisFormats
|
|
655
|
-
};
|
|
656
|
-
}
|
|
657
|
-
}
|
|
658
|
-
}
|
|
659
|
-
}
|
|
660
|
-
};
|
|
661
|
-
for (var k = 0; k < axisSources.length; k += 1) {
|
|
662
|
-
var _ret = _loop();
|
|
663
|
-
if (typeof _ret === "object") return _ret.v;
|
|
664
|
-
}
|
|
665
|
-
}
|
|
666
|
-
}
|
|
667
|
-
return axisFormats;
|
|
668
|
-
}
|
|
669
|
-
static getChartType(plotStyle, isBusinessTime) {
|
|
748
|
+
dh
|
|
749
|
+
} = this;
|
|
670
750
|
switch (plotStyle) {
|
|
671
751
|
case dh.plot.SeriesPlotStyle.HISTOGRAM:
|
|
672
752
|
// When reading data from the `Figure`, it already provides bins and values, so rather than using
|
|
673
753
|
// plot.ly to calculate the bins and sum values, just convert it to a bar chart
|
|
674
754
|
return 'bar';
|
|
675
755
|
default:
|
|
676
|
-
return
|
|
677
|
-
}
|
|
678
|
-
}
|
|
679
|
-
|
|
680
|
-
/**
|
|
681
|
-
* Return the plotly axis property name
|
|
682
|
-
* @param axisType The axis type to get the property name for
|
|
683
|
-
*/
|
|
684
|
-
static getAxisPropertyName(axisType) {
|
|
685
|
-
switch (axisType) {
|
|
686
|
-
case dh.plot.AxisType.X:
|
|
687
|
-
return 'x';
|
|
688
|
-
case dh.plot.AxisType.Y:
|
|
689
|
-
return 'y';
|
|
690
|
-
default:
|
|
691
|
-
return null;
|
|
692
|
-
}
|
|
693
|
-
}
|
|
694
|
-
|
|
695
|
-
/**
|
|
696
|
-
* Returns the plotly "side" value for the provided axis position
|
|
697
|
-
* @param axisPosition The Iris AxisPosition of the axis
|
|
698
|
-
*/
|
|
699
|
-
static getAxisSide(axisPosition) {
|
|
700
|
-
switch (axisPosition) {
|
|
701
|
-
case dh.plot.AxisPosition.BOTTOM:
|
|
702
|
-
return 'bottom';
|
|
703
|
-
case dh.plot.AxisPosition.TOP:
|
|
704
|
-
return 'top';
|
|
705
|
-
case dh.plot.AxisPosition.LEFT:
|
|
706
|
-
return 'left';
|
|
707
|
-
case dh.plot.AxisPosition.RIGHT:
|
|
708
|
-
return 'right';
|
|
709
|
-
default:
|
|
710
|
-
return undefined;
|
|
756
|
+
return this.getPlotlyChartType(plotStyle, isBusinessTime);
|
|
711
757
|
}
|
|
712
758
|
}
|
|
713
|
-
|
|
714
|
-
/**
|
|
715
|
-
*
|
|
716
|
-
* @param
|
|
717
|
-
*/
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
charts
|
|
730
|
-
} = figure;
|
|
731
|
-
for (var i = 0; i < charts.length; i += 1) {
|
|
732
|
-
var _chart2 = charts[i];
|
|
733
|
-
for (var j = 0; j < _chart2.series.length; j += 1) {
|
|
734
|
-
if (series === _chart2.series[j]) {
|
|
735
|
-
return _chart2;
|
|
736
|
-
}
|
|
737
|
-
}
|
|
759
|
+
|
|
760
|
+
/**
|
|
761
|
+
* Return the plotly axis property name
|
|
762
|
+
* @param axisType The axis type to get the property name for
|
|
763
|
+
*/
|
|
764
|
+
getAxisPropertyName(axisType) {
|
|
765
|
+
var {
|
|
766
|
+
dh
|
|
767
|
+
} = this;
|
|
768
|
+
switch (axisType) {
|
|
769
|
+
case dh.plot.AxisType.X:
|
|
770
|
+
return 'x';
|
|
771
|
+
case dh.plot.AxisType.Y:
|
|
772
|
+
return 'y';
|
|
773
|
+
default:
|
|
774
|
+
return null;
|
|
738
775
|
}
|
|
739
|
-
return null;
|
|
740
776
|
}
|
|
741
777
|
|
|
742
778
|
/**
|
|
743
|
-
*
|
|
744
|
-
* @param
|
|
745
|
-
* @returns An object mapping the axis name to it's range
|
|
779
|
+
* Returns the plotly "side" value for the provided axis position
|
|
780
|
+
* @param axisPosition The Iris AxisPosition of the axis
|
|
746
781
|
*/
|
|
747
|
-
|
|
748
|
-
var
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
782
|
+
getAxisSide(axisPosition) {
|
|
783
|
+
var {
|
|
784
|
+
dh
|
|
785
|
+
} = this;
|
|
786
|
+
switch (axisPosition) {
|
|
787
|
+
case dh.plot.AxisPosition.BOTTOM:
|
|
788
|
+
return 'bottom';
|
|
789
|
+
case dh.plot.AxisPosition.TOP:
|
|
790
|
+
return 'top';
|
|
791
|
+
case dh.plot.AxisPosition.LEFT:
|
|
792
|
+
return 'left';
|
|
793
|
+
case dh.plot.AxisPosition.RIGHT:
|
|
794
|
+
return 'right';
|
|
795
|
+
default:
|
|
796
|
+
return undefined;
|
|
757
797
|
}
|
|
758
|
-
return ranges;
|
|
759
798
|
}
|
|
760
799
|
|
|
761
800
|
/**
|
|
@@ -767,7 +806,7 @@ class ChartUtils {
|
|
|
767
806
|
* @param plotHeight Height of the plot in pixels
|
|
768
807
|
* @param theme Theme used for displaying the plot
|
|
769
808
|
*/
|
|
770
|
-
|
|
809
|
+
updateFigureAxes(layoutParam, figure, chartAxisRangeParser) {
|
|
771
810
|
var plotWidth = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 0;
|
|
772
811
|
var plotHeight = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 0;
|
|
773
812
|
var theme = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : ChartTheme;
|
|
@@ -776,13 +815,16 @@ class ChartUtils {
|
|
|
776
815
|
for (var i = 0; i < figure.charts.length; i += 1) {
|
|
777
816
|
var _chart3 = figure.charts[i];
|
|
778
817
|
var axisRangeParser = chartAxisRangeParser === null || chartAxisRangeParser === void 0 ? void 0 : chartAxisRangeParser(_chart3);
|
|
779
|
-
var bounds =
|
|
780
|
-
|
|
818
|
+
var bounds = this.getChartBounds(figure, _chart3, plotWidth, plotHeight);
|
|
819
|
+
this.updateLayoutAxes(layout, _chart3.axes, figureAxes, plotWidth, plotHeight, bounds, axisRangeParser, theme);
|
|
781
820
|
}
|
|
782
|
-
|
|
821
|
+
this.removeStaleAxes(layout, figureAxes);
|
|
783
822
|
}
|
|
784
|
-
|
|
823
|
+
getChartBounds(figure, chart, plotWidth, plotHeight) {
|
|
785
824
|
var _axisPositionMap$get;
|
|
825
|
+
var {
|
|
826
|
+
dh
|
|
827
|
+
} = this;
|
|
786
828
|
var {
|
|
787
829
|
cols,
|
|
788
830
|
rows
|
|
@@ -820,6 +862,62 @@ class ChartUtils {
|
|
|
820
862
|
}
|
|
821
863
|
return bounds;
|
|
822
864
|
}
|
|
865
|
+
getPlotlyDateFormat(formatter, columnType, formatPattern) {
|
|
866
|
+
var {
|
|
867
|
+
dh
|
|
868
|
+
} = this;
|
|
869
|
+
var tickformat = formatPattern == null ? undefined : formatPattern.replace('%', '%%').replace(/S{9}/g, '%9f').replace(/S{8}/g, '%8f').replace(/S{7}/g, '%7f').replace(/S{6}/g, '%6f').replace(/S{5}/g, '%5f').replace(/S{4}/g, '%4f').replace(/S{3}/g, '%3f').replace(/S{2}/g, '%2f').replace(/S{1}/g, '%1f').replace(/y{4}/g, '%Y').replace(/y{2}/g, '%y').replace(/M{4}/g, '%B').replace(/M{3}/g, '%b').replace(/M{2}/g, '%m').replace(/M{1}/g, '%-m').replace(/E{4,}/g, '%A').replace(/E{1,}/g, '%a').replace(/d{2}/g, '%d').replace(/([^%]|^)d{1}/g, '$1%-d').replace(/H{2}/g, '%H').replace(/h{2}/g, '%I').replace(/h{1}/g, '%-I').replace(/m{2}/g, '%M').replace(/s{2}/g, '%S').replace("'T'", 'T').replace(' z', ''); // timezone added as suffix if necessary
|
|
870
|
+
|
|
871
|
+
var ticksuffix;
|
|
872
|
+
var dataFormatter = formatter === null || formatter === void 0 ? void 0 : formatter.getColumnTypeFormatter(columnType);
|
|
873
|
+
if (dataFormatter != null && isDateTimeColumnFormatter(dataFormatter) && dataFormatter.dhTimeZone != null && dataFormatter.showTimeZone) {
|
|
874
|
+
ticksuffix = dh.i18n.DateTimeFormat.format(' z', new Date(), dataFormatter.dhTimeZone);
|
|
875
|
+
}
|
|
876
|
+
return {
|
|
877
|
+
tickformat,
|
|
878
|
+
ticksuffix,
|
|
879
|
+
automargin: true
|
|
880
|
+
};
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
/**
|
|
884
|
+
* Gets the plotly axis formatting information from the source passed in
|
|
885
|
+
* @param source The Source to get the formatter information from
|
|
886
|
+
* @param formatter The current formatter for formatting data
|
|
887
|
+
*/
|
|
888
|
+
getPlotlyAxisFormat(source) {
|
|
889
|
+
var formatter = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
|
|
890
|
+
var {
|
|
891
|
+
dh
|
|
892
|
+
} = this;
|
|
893
|
+
var {
|
|
894
|
+
axis,
|
|
895
|
+
columnType
|
|
896
|
+
} = source;
|
|
897
|
+
var {
|
|
898
|
+
formatPattern
|
|
899
|
+
} = axis;
|
|
900
|
+
var axisFormat = null;
|
|
901
|
+
if (TableUtils.isDateType(columnType)) {
|
|
902
|
+
axisFormat = this.getPlotlyDateFormat(formatter, columnType, formatPattern);
|
|
903
|
+
axisFormat = ChartUtils.addTickSpacing(axisFormat, axis, true);
|
|
904
|
+
} else if (TableUtils.isNumberType(columnType)) {
|
|
905
|
+
axisFormat = ChartUtils.getPlotlyNumberFormat(formatter, columnType, formatPattern);
|
|
906
|
+
axisFormat = ChartUtils.addTickSpacing(axisFormat, axis, false);
|
|
907
|
+
}
|
|
908
|
+
if (axis.formatType === dh.plot.AxisFormatType.CATEGORY) {
|
|
909
|
+
if (axisFormat) {
|
|
910
|
+
axisFormat.type = 'category';
|
|
911
|
+
} else {
|
|
912
|
+
axisFormat = {
|
|
913
|
+
type: 'category',
|
|
914
|
+
tickformat: undefined,
|
|
915
|
+
ticksuffix: undefined
|
|
916
|
+
};
|
|
917
|
+
}
|
|
918
|
+
}
|
|
919
|
+
return axisFormat;
|
|
920
|
+
}
|
|
823
921
|
|
|
824
922
|
/**
|
|
825
923
|
* Updates the axes positions and sizes in the layout object provided.
|
|
@@ -834,7 +932,7 @@ class ChartUtils {
|
|
|
834
932
|
* @param bounds The bounds for this set of axes
|
|
835
933
|
* @param axisRangeParser A function to retrieve the range parser for a given axis
|
|
836
934
|
*/
|
|
837
|
-
|
|
935
|
+
updateLayoutAxes(layoutParam, chartAxes, figureAxes) {
|
|
838
936
|
var plotWidth = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 0;
|
|
839
937
|
var plotHeight = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 0;
|
|
840
938
|
var bounds = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : {
|
|
@@ -845,6 +943,9 @@ class ChartUtils {
|
|
|
845
943
|
};
|
|
846
944
|
var axisRangeParser = arguments.length > 6 ? arguments[6] : undefined;
|
|
847
945
|
var theme = arguments.length > 7 && arguments[7] !== undefined ? arguments[7] : ChartTheme;
|
|
946
|
+
var {
|
|
947
|
+
dh
|
|
948
|
+
} = this;
|
|
848
949
|
var xAxisSize = plotWidth > 0 ? Math.max(ChartUtils.MIN_AXIS_SIZE, Math.min(ChartUtils.AXIS_SIZE_PX / plotHeight, ChartUtils.MAX_AXIS_SIZE)) : ChartUtils.DEFAULT_AXIS_SIZE;
|
|
849
950
|
var yAxisSize = plotHeight > 0 ? Math.max(ChartUtils.MIN_AXIS_SIZE, Math.min(ChartUtils.AXIS_SIZE_PX / plotWidth, ChartUtils.MAX_AXIS_SIZE)) : ChartUtils.DEFAULT_AXIS_SIZE;
|
|
850
951
|
var layout = layoutParam;
|
|
@@ -854,7 +955,7 @@ class ChartUtils {
|
|
|
854
955
|
var figureAxisTypeMap = ChartUtils.groupArray(figureAxes, 'type');
|
|
855
956
|
for (var j = 0; j < axisTypes.length; j += 1) {
|
|
856
957
|
var axisType = axisTypes[j];
|
|
857
|
-
var axisProperty =
|
|
958
|
+
var axisProperty = this.getAxisPropertyName(axisType);
|
|
858
959
|
if (axisProperty != null) {
|
|
859
960
|
var typeAxes = axisTypeMap.get(axisType);
|
|
860
961
|
var figureTypeAxes = figureAxisTypeMap.get(axisType);
|
|
@@ -867,11 +968,11 @@ class ChartUtils {
|
|
|
867
968
|
var figureAxisIndex = figureTypeAxes.indexOf(_axis2);
|
|
868
969
|
var axisLayoutProperty = ChartUtils.getAxisLayoutProperty(axisProperty, figureAxisIndex);
|
|
869
970
|
if (layout[axisLayoutProperty] == null) {
|
|
870
|
-
layout[axisLayoutProperty] =
|
|
971
|
+
layout[axisLayoutProperty] = this.makeLayoutAxis(axisType, theme);
|
|
871
972
|
}
|
|
872
973
|
var layoutAxis = layout[axisLayoutProperty];
|
|
873
974
|
if (layoutAxis != null) {
|
|
874
|
-
|
|
975
|
+
this.updateLayoutAxis(layoutAxis, _axis2, chartAxisIndex, axisPositionMap, xAxisSize, yAxisSize, bounds);
|
|
875
976
|
var {
|
|
876
977
|
range: _range,
|
|
877
978
|
autorange
|
|
@@ -895,7 +996,7 @@ class ChartUtils {
|
|
|
895
996
|
* @param layoutParam Layout object to remove stale axes from
|
|
896
997
|
* @param axes All axes in the figure
|
|
897
998
|
*/
|
|
898
|
-
|
|
999
|
+
removeStaleAxes(layoutParam, axes) {
|
|
899
1000
|
var layout = layoutParam;
|
|
900
1001
|
var figureAxisTypeMap = ChartUtils.groupArray(axes, 'type');
|
|
901
1002
|
var figureAxisTypes = [...figureAxisTypeMap.keys()];
|
|
@@ -905,7 +1006,7 @@ class ChartUtils {
|
|
|
905
1006
|
assertNotNull(typeAxes);
|
|
906
1007
|
var axisIndex = typeAxes.length;
|
|
907
1008
|
// Delete any axes that may no longer exist
|
|
908
|
-
var axisProperty =
|
|
1009
|
+
var axisProperty = this.getAxisPropertyName(axisType);
|
|
909
1010
|
if (axisProperty != null) {
|
|
910
1011
|
var axisLayoutProperty = ChartUtils.getAxisLayoutProperty(axisProperty, axisIndex);
|
|
911
1012
|
while (layout[axisLayoutProperty] != null) {
|
|
@@ -916,10 +1017,6 @@ class ChartUtils {
|
|
|
916
1017
|
}
|
|
917
1018
|
}
|
|
918
1019
|
}
|
|
919
|
-
static getAxisLayoutProperty(axisProperty, axisIndex) {
|
|
920
|
-
var axisIndexString = axisIndex > 0 ? "".concat(axisIndex + 1) : '';
|
|
921
|
-
return "".concat(axisProperty !== null && axisProperty !== void 0 ? axisProperty : '', "axis").concat(axisIndexString);
|
|
922
|
-
}
|
|
923
1020
|
|
|
924
1021
|
/**
|
|
925
1022
|
* Updates the layout axis object in place
|
|
@@ -930,8 +1027,11 @@ class ChartUtils {
|
|
|
930
1027
|
* @param axisSize The size of each axis in percent
|
|
931
1028
|
* @param bounds The bounds of the axes domains
|
|
932
1029
|
*/
|
|
933
|
-
|
|
1030
|
+
updateLayoutAxis(layoutAxisParam, axis, axisIndex, axisPositionMap, xAxisSize, yAxisSize, bounds) {
|
|
934
1031
|
var _axis$label;
|
|
1032
|
+
var {
|
|
1033
|
+
dh
|
|
1034
|
+
} = this;
|
|
935
1035
|
var isYAxis = axis.type === dh.plot.AxisType.Y;
|
|
936
1036
|
var axisSize = isYAxis ? yAxisSize : xAxisSize;
|
|
937
1037
|
var layoutAxis = layoutAxisParam;
|
|
@@ -948,10 +1048,10 @@ class ChartUtils {
|
|
|
948
1048
|
if (axis.log) {
|
|
949
1049
|
layoutAxis.type = 'log';
|
|
950
1050
|
}
|
|
951
|
-
layoutAxis.side =
|
|
1051
|
+
layoutAxis.side = this.getAxisSide(axis.position);
|
|
952
1052
|
if (axisIndex > 0) {
|
|
953
|
-
var
|
|
954
|
-
layoutAxis.overlaying = (
|
|
1053
|
+
var _this$getAxisProperty, _axisPositionMap$get2;
|
|
1054
|
+
layoutAxis.overlaying = (_this$getAxisProperty = this.getAxisPropertyName(axis.type)) !== null && _this$getAxisProperty !== void 0 ? _this$getAxisProperty : undefined;
|
|
955
1055
|
var positionAxes = (_axisPositionMap$get2 = axisPositionMap.get(axis.position)) !== null && _axisPositionMap$get2 !== void 0 ? _axisPositionMap$get2 : [];
|
|
956
1056
|
var sideIndex = positionAxes.indexOf(axis);
|
|
957
1057
|
if (sideIndex > 0) {
|
|
@@ -981,16 +1081,6 @@ class ChartUtils {
|
|
|
981
1081
|
}
|
|
982
1082
|
}
|
|
983
1083
|
|
|
984
|
-
/**
|
|
985
|
-
* Converts an open or close period to a declimal. e.g '09:30" to 9.5
|
|
986
|
-
*
|
|
987
|
-
* @param period the open or close value of the period
|
|
988
|
-
*/
|
|
989
|
-
static periodToDecimal(period) {
|
|
990
|
-
var values = period.split(':');
|
|
991
|
-
return Number(values[0]) + Number(values[1]) / 60;
|
|
992
|
-
}
|
|
993
|
-
|
|
994
1084
|
/**
|
|
995
1085
|
* Creates range break bounds for plotly from business days.
|
|
996
1086
|
* For example a standard business week of ['MONDAY','TUESDAY','WEDNESDAY','THURSDAY','FRIDAY']
|
|
@@ -999,14 +1089,14 @@ class ChartUtils {
|
|
|
999
1089
|
*
|
|
1000
1090
|
* @param businessDays the days to display on the x-axis
|
|
1001
1091
|
*/
|
|
1002
|
-
|
|
1003
|
-
var businessDaysInt = businessDays.map(day =>
|
|
1004
|
-
var nonBusinessDaysInt =
|
|
1092
|
+
createBoundsFromDays(businessDays) {
|
|
1093
|
+
var businessDaysInt = businessDays.map(day => this.daysOfWeek.indexOf(day));
|
|
1094
|
+
var nonBusinessDaysInt = this.daysOfWeek.filter(day => !businessDays.includes(day)).map(day => this.daysOfWeek.indexOf(day));
|
|
1005
1095
|
// These are the days when business reopens (e.g. Monday after a weekend)
|
|
1006
1096
|
var reopenDays = new Set();
|
|
1007
1097
|
nonBusinessDaysInt.forEach(closed => {
|
|
1008
|
-
for (var i = closed + 1; i < closed +
|
|
1009
|
-
var adjustedDay = i %
|
|
1098
|
+
for (var i = closed + 1; i < closed + this.daysOfWeek.length; i += 1) {
|
|
1099
|
+
var adjustedDay = i % this.daysOfWeek.length;
|
|
1010
1100
|
if (businessDaysInt.includes(adjustedDay)) {
|
|
1011
1101
|
reopenDays.add(adjustedDay);
|
|
1012
1102
|
break;
|
|
@@ -1016,8 +1106,8 @@ class ChartUtils {
|
|
|
1016
1106
|
var boundsArray = [];
|
|
1017
1107
|
// For each reopen day, find the furthest previous closed day
|
|
1018
1108
|
reopenDays.forEach(open => {
|
|
1019
|
-
for (var i = open - 1; i > open -
|
|
1020
|
-
var adjustedDay = i < 0 ? i +
|
|
1109
|
+
for (var i = open - 1; i > open - this.daysOfWeek.length; i -= 1) {
|
|
1110
|
+
var adjustedDay = i < 0 ? i + this.daysOfWeek.length : i;
|
|
1021
1111
|
if (businessDaysInt.includes(adjustedDay)) {
|
|
1022
1112
|
var closedDay = (adjustedDay + 1) % 7;
|
|
1023
1113
|
boundsArray.push([closedDay, open]);
|
|
@@ -1035,14 +1125,14 @@ class ChartUtils {
|
|
|
1035
1125
|
* @param calendarTimeZone the time zone for the business calendar
|
|
1036
1126
|
* @param formatterTimeZone the time zone for the formatter
|
|
1037
1127
|
*/
|
|
1038
|
-
|
|
1128
|
+
createRangeBreakValuesFromHolidays(holidays, calendarTimeZone, formatterTimeZone) {
|
|
1039
1129
|
var fullHolidays = [];
|
|
1040
1130
|
var partialHolidays = [];
|
|
1041
1131
|
holidays.forEach(holiday => {
|
|
1042
1132
|
if (holiday.businessPeriods.length > 0) {
|
|
1043
|
-
partialHolidays.push(...
|
|
1133
|
+
partialHolidays.push(...this.createPartialHoliday(holiday, calendarTimeZone, formatterTimeZone));
|
|
1044
1134
|
} else {
|
|
1045
|
-
fullHolidays.push(
|
|
1135
|
+
fullHolidays.push(this.createFullHoliday(holiday, calendarTimeZone, formatterTimeZone));
|
|
1046
1136
|
}
|
|
1047
1137
|
});
|
|
1048
1138
|
return [{
|
|
@@ -1057,8 +1147,8 @@ class ChartUtils {
|
|
|
1057
1147
|
* @param calendarTimeZone the time zone for the business calendar
|
|
1058
1148
|
* @param formatterTimeZone the time zone for the formatter
|
|
1059
1149
|
*/
|
|
1060
|
-
|
|
1061
|
-
return
|
|
1150
|
+
createFullHoliday(holiday, calendarTimeZone, formatterTimeZone) {
|
|
1151
|
+
return this.adjustDateForTimeZone("".concat(holiday.date.toString(), " 00:00:00.000000"), calendarTimeZone, formatterTimeZone);
|
|
1062
1152
|
}
|
|
1063
1153
|
|
|
1064
1154
|
/**
|
|
@@ -1069,7 +1159,7 @@ class ChartUtils {
|
|
|
1069
1159
|
* @param calendarTimeZone the time zone for the business calendar
|
|
1070
1160
|
* @param formatterTimeZone the time zone for the formatter
|
|
1071
1161
|
*/
|
|
1072
|
-
|
|
1162
|
+
createPartialHoliday(holiday, calendarTimeZone, formatterTimeZone) {
|
|
1073
1163
|
// If a holiday has business periods {open1, close1} and {open2, close2}
|
|
1074
1164
|
// This will generate range breaks for:
|
|
1075
1165
|
// closed from 00:00 to open1
|
|
@@ -1089,7 +1179,7 @@ class ChartUtils {
|
|
|
1089
1179
|
var endClose = closedPeriods[i + 1];
|
|
1090
1180
|
// Skip over any periods where start and close are the same (zero hours)
|
|
1091
1181
|
if (startClose !== endClose) {
|
|
1092
|
-
var values = [
|
|
1182
|
+
var values = [this.adjustDateForTimeZone("".concat(dateString, " ").concat(startClose, ":00.000000"), calendarTimeZone, formatterTimeZone)];
|
|
1093
1183
|
var dvalue = MILLIS_PER_HOUR * (ChartUtils.periodToDecimal(endClose) - ChartUtils.periodToDecimal(startClose));
|
|
1094
1184
|
rangeBreaks.push({
|
|
1095
1185
|
values,
|
|
@@ -1107,35 +1197,77 @@ class ChartUtils {
|
|
|
1107
1197
|
* @param calendarTimeZone the time zone for the business calendar
|
|
1108
1198
|
* @param formatterTimeZone the time zone for the formatter
|
|
1109
1199
|
*/
|
|
1110
|
-
|
|
1200
|
+
adjustDateForTimeZone(dateString, calendarTimeZone, formatterTimeZone) {
|
|
1111
1201
|
if (formatterTimeZone && formatterTimeZone.standardOffset !== calendarTimeZone.standardOffset) {
|
|
1112
|
-
return
|
|
1202
|
+
return this.unwrapValue(this.wrapValue(dateString, BUSINESS_COLUMN_TYPE, calendarTimeZone), formatterTimeZone);
|
|
1113
1203
|
}
|
|
1114
1204
|
return dateString;
|
|
1115
1205
|
}
|
|
1116
1206
|
|
|
1117
1207
|
/**
|
|
1118
|
-
*
|
|
1119
|
-
*
|
|
1120
|
-
*
|
|
1121
|
-
*
|
|
1208
|
+
* Creates the Figure settings from the Chart Builder settings
|
|
1209
|
+
* This should be deprecated at some point, and have Chart Builder create the figure settings directly.
|
|
1210
|
+
* This logic will still need to exist to translate existing charts, but could be part of a migration script
|
|
1211
|
+
* to translate the data.
|
|
1212
|
+
* Change when we decide to add more functionality to the Chart Builder.
|
|
1213
|
+
* @param settings The chart builder settings
|
|
1214
|
+
* @param settings.title The title for this figure
|
|
1215
|
+
* @param settings.xAxis The name of the column to use for the x-axis
|
|
1216
|
+
* @param settings.series The name of the columns to use for the series of this figure
|
|
1217
|
+
* @param settings.type The plot style for this figure
|
|
1122
1218
|
*/
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
}
|
|
1219
|
+
makeFigureSettings(settings, table) {
|
|
1220
|
+
var {
|
|
1221
|
+
dh
|
|
1222
|
+
} = this;
|
|
1223
|
+
var {
|
|
1224
|
+
series,
|
|
1225
|
+
xAxis: settingsAxis,
|
|
1226
|
+
type
|
|
1227
|
+
} = settings;
|
|
1228
|
+
var title = ChartUtils.titleFromSettings(settings);
|
|
1229
|
+
var xAxis = {
|
|
1230
|
+
formatType: "".concat(dh.plot.AxisFormatType.NUMBER),
|
|
1231
|
+
type: "".concat(dh.plot.AxisType.X),
|
|
1232
|
+
position: "".concat(dh.plot.AxisPosition.BOTTOM)
|
|
1233
|
+
};
|
|
1234
|
+
var yAxis = {
|
|
1235
|
+
formatType: "".concat(dh.plot.AxisFormatType.NUMBER),
|
|
1236
|
+
type: "".concat(dh.plot.AxisType.Y),
|
|
1237
|
+
position: "".concat(dh.plot.AxisPosition.LEFT)
|
|
1238
|
+
};
|
|
1239
|
+
return {
|
|
1240
|
+
charts: [{
|
|
1241
|
+
chartType: "".concat(dh.plot.ChartType.XY),
|
|
1242
|
+
axes: [xAxis, yAxis],
|
|
1243
|
+
series: (series !== null && series !== void 0 ? series : []).map(name => ({
|
|
1244
|
+
plotStyle: "".concat(type),
|
|
1245
|
+
name,
|
|
1246
|
+
dataSources: [{
|
|
1247
|
+
type: "".concat(dh.plot.SourceType.X),
|
|
1248
|
+
columnName: settingsAxis !== null && settingsAxis !== void 0 ? settingsAxis : '',
|
|
1249
|
+
axis: xAxis,
|
|
1250
|
+
table
|
|
1251
|
+
}, {
|
|
1252
|
+
type: "".concat(dh.plot.SourceType.Y),
|
|
1253
|
+
columnName: name,
|
|
1254
|
+
axis: yAxis,
|
|
1255
|
+
table
|
|
1256
|
+
}]
|
|
1257
|
+
}))
|
|
1258
|
+
}],
|
|
1259
|
+
title
|
|
1260
|
+
};
|
|
1132
1261
|
}
|
|
1133
1262
|
|
|
1134
1263
|
/**
|
|
1135
1264
|
* Unwraps a value provided from API to a value plotly can understand
|
|
1136
1265
|
* Eg. Unwraps DateWrapper, LongWrapper objects.
|
|
1137
1266
|
*/
|
|
1138
|
-
|
|
1267
|
+
unwrapValue(value, timeZone) {
|
|
1268
|
+
var {
|
|
1269
|
+
dh
|
|
1270
|
+
} = this;
|
|
1139
1271
|
if (value != null) {
|
|
1140
1272
|
if (isDateWrapper(value)) {
|
|
1141
1273
|
return dh.i18n.DateTimeFormat.format(ChartUtils.DATE_FORMAT, value, timeZone);
|
|
@@ -1153,8 +1285,11 @@ class ChartUtils {
|
|
|
1153
1285
|
* @param columnType The type of column this value is from
|
|
1154
1286
|
* @param timeZone The time zone if applicable
|
|
1155
1287
|
*/
|
|
1156
|
-
|
|
1288
|
+
wrapValue(value, columnType) {
|
|
1157
1289
|
var timeZone = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
|
|
1290
|
+
var {
|
|
1291
|
+
dh
|
|
1292
|
+
} = this;
|
|
1158
1293
|
if (TableUtils.isDateType(columnType) && typeof value === 'string') {
|
|
1159
1294
|
// Need to limit the format to the actual length of the string range set in plotly
|
|
1160
1295
|
// Otherwise parse will fail
|
|
@@ -1177,8 +1312,11 @@ class ChartUtils {
|
|
|
1177
1312
|
}
|
|
1178
1313
|
return value;
|
|
1179
1314
|
}
|
|
1180
|
-
|
|
1315
|
+
makeLayoutAxis(type) {
|
|
1181
1316
|
var theme = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : ChartTheme;
|
|
1317
|
+
var {
|
|
1318
|
+
dh
|
|
1319
|
+
} = this;
|
|
1182
1320
|
var axis = {
|
|
1183
1321
|
automargin: true,
|
|
1184
1322
|
gridcolor: theme.gridcolor,
|
|
@@ -1212,29 +1350,11 @@ class ChartUtils {
|
|
|
1212
1350
|
}
|
|
1213
1351
|
return axis;
|
|
1214
1352
|
}
|
|
1215
|
-
|
|
1216
|
-
/**
|
|
1217
|
-
* Parses the colorway property of a theme and returns an array of colors
|
|
1218
|
-
* Theme could have a single string with space separated colors or an array of strings representing the colorway
|
|
1219
|
-
* @param theme The theme to get colorway from
|
|
1220
|
-
* @returns Colorway array for the theme
|
|
1221
|
-
*/
|
|
1222
|
-
static getColorwayFromTheme() {
|
|
1223
|
-
var theme = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ChartTheme;
|
|
1224
|
-
var colorway = [];
|
|
1225
|
-
if (theme.colorway) {
|
|
1226
|
-
if (Array.isArray(theme.colorway)) {
|
|
1227
|
-
colorway = theme.colorway;
|
|
1228
|
-
} else if (typeof theme.colorway === 'string') {
|
|
1229
|
-
colorway = theme.colorway.split(' ');
|
|
1230
|
-
} else {
|
|
1231
|
-
log.warn("Unable to handle colorway property: ".concat(theme.colorway));
|
|
1232
|
-
}
|
|
1233
|
-
}
|
|
1234
|
-
return colorway;
|
|
1235
|
-
}
|
|
1236
|
-
static makeDefaultLayout() {
|
|
1353
|
+
makeDefaultLayout() {
|
|
1237
1354
|
var theme = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ChartTheme;
|
|
1355
|
+
var {
|
|
1356
|
+
dh
|
|
1357
|
+
} = this;
|
|
1238
1358
|
var layout = _objectSpread(_objectSpread({}, theme), {}, {
|
|
1239
1359
|
autosize: true,
|
|
1240
1360
|
colorway: ChartUtils.getColorwayFromTheme(theme),
|
|
@@ -1255,8 +1375,8 @@ class ChartUtils {
|
|
|
1255
1375
|
}
|
|
1256
1376
|
},
|
|
1257
1377
|
margin: _objectSpread({}, ChartUtils.DEFAULT_MARGIN),
|
|
1258
|
-
xaxis:
|
|
1259
|
-
yaxis:
|
|
1378
|
+
xaxis: this.makeLayoutAxis(dh.plot.AxisType.X, theme),
|
|
1379
|
+
yaxis: this.makeLayoutAxis(dh.plot.AxisType.Y, theme)
|
|
1260
1380
|
});
|
|
1261
1381
|
layout.datarevision = 0;
|
|
1262
1382
|
return layout;
|
|
@@ -1266,72 +1386,14 @@ class ChartUtils {
|
|
|
1266
1386
|
* Hydrate settings from a JSONable object
|
|
1267
1387
|
* @param settings Dehydrated settings
|
|
1268
1388
|
*/
|
|
1269
|
-
|
|
1389
|
+
hydrateSettings(settings) {
|
|
1390
|
+
var {
|
|
1391
|
+
dh
|
|
1392
|
+
} = this;
|
|
1270
1393
|
return _objectSpread(_objectSpread({}, settings), {}, {
|
|
1271
1394
|
type: settings.type != null ? dh.plot.SeriesPlotStyle[settings.type] : undefined
|
|
1272
1395
|
});
|
|
1273
1396
|
}
|
|
1274
|
-
static titleFromSettings(settings) {
|
|
1275
|
-
var {
|
|
1276
|
-
series,
|
|
1277
|
-
xAxis,
|
|
1278
|
-
title = "".concat((series !== null && series !== void 0 ? series : []).join(', '), " by ").concat(xAxis)
|
|
1279
|
-
} = settings;
|
|
1280
|
-
return title;
|
|
1281
|
-
}
|
|
1282
|
-
|
|
1283
|
-
/**
|
|
1284
|
-
* Creates the Figure settings from the Chart Builder settings
|
|
1285
|
-
* This should be deprecated at some point, and have Chart Builder create the figure settings directly.
|
|
1286
|
-
* This logic will still need to exist to translate existing charts, but could be part of a migration script
|
|
1287
|
-
* to translate the data.
|
|
1288
|
-
* Change when we decide to add more functionality to the Chart Builder.
|
|
1289
|
-
* @param settings The chart builder settings
|
|
1290
|
-
* @param settings.title The title for this figure
|
|
1291
|
-
* @param settings.xAxis The name of the column to use for the x-axis
|
|
1292
|
-
* @param settings.series The name of the columns to use for the series of this figure
|
|
1293
|
-
* @param settings.type The plot style for this figure
|
|
1294
|
-
*/
|
|
1295
|
-
static makeFigureSettings(settings, table) {
|
|
1296
|
-
var {
|
|
1297
|
-
series,
|
|
1298
|
-
xAxis: settingsAxis,
|
|
1299
|
-
type
|
|
1300
|
-
} = settings;
|
|
1301
|
-
var title = ChartUtils.titleFromSettings(settings);
|
|
1302
|
-
var xAxis = {
|
|
1303
|
-
formatType: "".concat(dh.plot.AxisFormatType.NUMBER),
|
|
1304
|
-
type: "".concat(dh.plot.AxisType.X),
|
|
1305
|
-
position: "".concat(dh.plot.AxisPosition.BOTTOM)
|
|
1306
|
-
};
|
|
1307
|
-
var yAxis = {
|
|
1308
|
-
formatType: "".concat(dh.plot.AxisFormatType.NUMBER),
|
|
1309
|
-
type: "".concat(dh.plot.AxisType.Y),
|
|
1310
|
-
position: "".concat(dh.plot.AxisPosition.LEFT)
|
|
1311
|
-
};
|
|
1312
|
-
return {
|
|
1313
|
-
charts: [{
|
|
1314
|
-
chartType: "".concat(dh.plot.ChartType.XY),
|
|
1315
|
-
axes: [xAxis, yAxis],
|
|
1316
|
-
series: (series !== null && series !== void 0 ? series : []).map(name => ({
|
|
1317
|
-
plotStyle: "".concat(type),
|
|
1318
|
-
name,
|
|
1319
|
-
dataSources: [{
|
|
1320
|
-
type: "".concat(dh.plot.SourceType.X),
|
|
1321
|
-
columnName: settingsAxis !== null && settingsAxis !== void 0 ? settingsAxis : '',
|
|
1322
|
-
axis: xAxis,
|
|
1323
|
-
table
|
|
1324
|
-
}, {
|
|
1325
|
-
type: "".concat(dh.plot.SourceType.Y),
|
|
1326
|
-
columnName: name,
|
|
1327
|
-
axis: yAxis,
|
|
1328
|
-
table
|
|
1329
|
-
}]
|
|
1330
|
-
}))
|
|
1331
|
-
}],
|
|
1332
|
-
title
|
|
1333
|
-
};
|
|
1334
|
-
}
|
|
1335
1397
|
}
|
|
1336
1398
|
_defineProperty(ChartUtils, "DEFAULT_AXIS_SIZE", 0.15);
|
|
1337
1399
|
_defineProperty(ChartUtils, "MIN_AXIS_SIZE", 0.025);
|