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