@deephaven/chart 0.5.1 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/Chart.d.ts +16 -37
- package/dist/Chart.d.ts.map +1 -1
- package/dist/Chart.js +419 -454
- package/dist/Chart.js.map +1 -1
- package/dist/ChartModel.js +121 -156
- package/dist/ChartModel.js.map +1 -1
- package/dist/ChartModelFactory.js +51 -99
- package/dist/ChartModelFactory.js.map +1 -1
- package/dist/ChartTestUtils.js +76 -113
- package/dist/ChartTestUtils.js.map +1 -1
- package/dist/ChartTheme.js.map +1 -1
- package/dist/ChartUtils.js +1083 -1169
- package/dist/ChartUtils.js.map +1 -1
- package/dist/FigureChartModel.js +447 -566
- package/dist/FigureChartModel.js.map +1 -1
- package/dist/MockChartModel.js +176 -226
- package/dist/MockChartModel.js.map +1 -1
- package/dist/index.js +6 -6
- package/dist/index.js.map +1 -1
- package/dist/plotly/Plot.js +1 -1
- package/dist/plotly/Plot.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +17 -21
package/dist/ChartUtils.js
CHANGED
|
@@ -2,1318 +2,1232 @@ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (O
|
|
|
2
2
|
|
|
3
3
|
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
|
|
4
4
|
|
|
5
|
-
function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
|
|
6
|
-
|
|
7
|
-
function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); }
|
|
8
|
-
|
|
9
|
-
function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
|
|
10
|
-
|
|
11
|
-
function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && Symbol.iterator in Object(iter)) return Array.from(iter); }
|
|
12
|
-
|
|
13
|
-
function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); }
|
|
14
|
-
|
|
15
|
-
function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
|
|
16
|
-
|
|
17
|
-
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
|
|
18
|
-
|
|
19
|
-
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
|
|
20
|
-
|
|
21
|
-
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
|
|
22
|
-
|
|
23
|
-
function _iterableToArrayLimit(arr, i) { if (typeof Symbol === "undefined" || !(Symbol.iterator in Object(arr))) return; var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; }
|
|
24
|
-
|
|
25
|
-
function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
|
|
26
|
-
|
|
27
|
-
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
|
28
|
-
|
|
29
|
-
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
|
|
30
|
-
|
|
31
|
-
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
|
|
32
|
-
|
|
33
5
|
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
|
34
6
|
|
|
35
7
|
import Log from '@deephaven/log';
|
|
36
8
|
import { TableUtils } from '@deephaven/iris-grid';
|
|
37
9
|
import dh from '@deephaven/jsapi-shim';
|
|
38
|
-
import ChartTheme from
|
|
10
|
+
import ChartTheme from "./ChartTheme.js";
|
|
39
11
|
var log = Log.module('ChartUtils');
|
|
40
12
|
var DAYS = Object.freeze(dh.calendar.DayOfWeek.values());
|
|
41
13
|
var BUSINESS_COLUMN_TYPE = 'io.deephaven.db.tables.utils.DBDateTime';
|
|
42
14
|
var MILLIS_PER_HOUR = 3600000;
|
|
43
15
|
var NANOS_PER_MILLI = 1000000;
|
|
44
16
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
17
|
+
class ChartUtils {
|
|
18
|
+
/**
|
|
19
|
+
* Converts the Iris plot style into a plotly chart type
|
|
20
|
+
* @param {String} plotStyle The plotStyle to use, see dh.plot.SeriesPlotStyle
|
|
21
|
+
* @param {boolean} isBusinessTime If the plot is using business time for an axis
|
|
22
|
+
*/
|
|
23
|
+
static getPlotlyChartType(plotStyle, isBusinessTime) {
|
|
24
|
+
switch (plotStyle) {
|
|
25
|
+
case dh.plot.SeriesPlotStyle.SCATTER:
|
|
26
|
+
// scattergl mode is more performant, but doesn't support the rangebreaks we need for businessTime calendars
|
|
27
|
+
return !isBusinessTime ? 'scattergl' : 'scatter';
|
|
28
|
+
|
|
29
|
+
case dh.plot.SeriesPlotStyle.LINE:
|
|
30
|
+
// There is also still some artifacting bugs with scattergl: https://github.com/plotly/plotly.js/issues/3522
|
|
31
|
+
// The artifacting only occurs on line plots, which we can draw with fairly decent performance using SVG paths
|
|
32
|
+
// Once the above plotly issue is fixed, scattergl should be used here (when !isBusinessTime)
|
|
33
|
+
return 'scatter';
|
|
34
|
+
|
|
35
|
+
case dh.plot.SeriesPlotStyle.BAR:
|
|
36
|
+
case dh.plot.SeriesPlotStyle.STACKED_BAR:
|
|
37
|
+
return 'bar';
|
|
38
|
+
|
|
39
|
+
case dh.plot.SeriesPlotStyle.PIE:
|
|
40
|
+
return 'pie';
|
|
41
|
+
|
|
42
|
+
case dh.plot.SeriesPlotStyle.HISTOGRAM:
|
|
43
|
+
return 'histogram';
|
|
44
|
+
|
|
45
|
+
case dh.plot.SeriesPlotStyle.OHLC:
|
|
46
|
+
return 'ohlc';
|
|
47
|
+
|
|
48
|
+
default:
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
48
51
|
}
|
|
52
|
+
/**
|
|
53
|
+
* Converts the Iris plot style into a plotly chart mode
|
|
54
|
+
* @param {String} plotStyle The plotStyle to use, see dh.plot.SeriesPlotStyle.*
|
|
55
|
+
*/
|
|
49
56
|
|
|
50
|
-
_createClass(ChartUtils, null, [{
|
|
51
|
-
key: "getPlotlyChartType",
|
|
52
|
-
value:
|
|
53
|
-
/**
|
|
54
|
-
* Converts the Iris plot style into a plotly chart type
|
|
55
|
-
* @param {String} plotStyle The plotStyle to use, see dh.plot.SeriesPlotStyle
|
|
56
|
-
* @param {boolean} isBusinessTime If the plot is using business time for an axis
|
|
57
|
-
*/
|
|
58
|
-
function getPlotlyChartType(plotStyle, isBusinessTime) {
|
|
59
|
-
switch (plotStyle) {
|
|
60
|
-
case dh.plot.SeriesPlotStyle.SCATTER:
|
|
61
|
-
// scattergl mode is more performant, but doesn't support the rangebreaks we need for businessTime calendars
|
|
62
|
-
return !isBusinessTime ? 'scattergl' : 'scatter';
|
|
63
|
-
|
|
64
|
-
case dh.plot.SeriesPlotStyle.LINE:
|
|
65
|
-
// There is also still some artifacting bugs with scattergl: https://github.com/plotly/plotly.js/issues/3522
|
|
66
|
-
// The artifacting only occurs on line plots, which we can draw with fairly decent performance using SVG paths
|
|
67
|
-
// Once the above plotly issue is fixed, scattergl should be used here (when !isBusinessTime)
|
|
68
|
-
return 'scatter';
|
|
69
|
-
|
|
70
|
-
case dh.plot.SeriesPlotStyle.BAR:
|
|
71
|
-
case dh.plot.SeriesPlotStyle.STACKED_BAR:
|
|
72
|
-
return 'bar';
|
|
73
|
-
|
|
74
|
-
case dh.plot.SeriesPlotStyle.PIE:
|
|
75
|
-
return 'pie';
|
|
76
|
-
|
|
77
|
-
case dh.plot.SeriesPlotStyle.HISTOGRAM:
|
|
78
|
-
return 'histogram';
|
|
79
|
-
|
|
80
|
-
case dh.plot.SeriesPlotStyle.OHLC:
|
|
81
|
-
return 'ohlc';
|
|
82
|
-
|
|
83
|
-
default:
|
|
84
|
-
return null;
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
/**
|
|
88
|
-
* Converts the Iris plot style into a plotly chart mode
|
|
89
|
-
* @param {String} plotStyle The plotStyle to use, see dh.plot.SeriesPlotStyle.*
|
|
90
|
-
*/
|
|
91
|
-
|
|
92
|
-
}, {
|
|
93
|
-
key: "getPlotlyChartMode",
|
|
94
|
-
value: function getPlotlyChartMode(plotStyle) {
|
|
95
|
-
switch (plotStyle) {
|
|
96
|
-
case dh.plot.SeriesPlotStyle.SCATTER:
|
|
97
|
-
return 'markers';
|
|
98
|
-
|
|
99
|
-
case dh.plot.SeriesPlotStyle.LINE:
|
|
100
|
-
return 'lines';
|
|
101
|
-
|
|
102
|
-
default:
|
|
103
|
-
return null;
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
/**
|
|
107
|
-
* Get the property to set on the series data for plotly
|
|
108
|
-
* @param {dh.plot.SeriesPlotStyle} plotStyle The plot style of the series
|
|
109
|
-
* @param {dh.plot.SourceType} sourceType The source type for the series
|
|
110
|
-
*/
|
|
111
|
-
|
|
112
|
-
}, {
|
|
113
|
-
key: "getPlotlyProperty",
|
|
114
|
-
value: function getPlotlyProperty(plotStyle, sourceType) {
|
|
115
|
-
switch (plotStyle) {
|
|
116
|
-
case dh.plot.SeriesPlotStyle.PIE:
|
|
117
|
-
switch (sourceType) {
|
|
118
|
-
case dh.plot.SourceType.X:
|
|
119
|
-
return 'labels';
|
|
120
|
-
|
|
121
|
-
case dh.plot.SourceType.Y:
|
|
122
|
-
return 'values';
|
|
123
|
-
|
|
124
|
-
default:
|
|
125
|
-
break;
|
|
126
|
-
}
|
|
127
57
|
|
|
128
|
-
|
|
58
|
+
static getPlotlyChartMode(plotStyle) {
|
|
59
|
+
switch (plotStyle) {
|
|
60
|
+
case dh.plot.SeriesPlotStyle.SCATTER:
|
|
61
|
+
return 'markers';
|
|
129
62
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
case dh.plot.SourceType.TIME:
|
|
133
|
-
return 'x';
|
|
63
|
+
case dh.plot.SeriesPlotStyle.LINE:
|
|
64
|
+
return 'lines';
|
|
134
65
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
66
|
+
default:
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Get the property to set on the series data for plotly
|
|
72
|
+
* @param {dh.plot.SeriesPlotStyle} plotStyle The plot style of the series
|
|
73
|
+
* @param {dh.plot.SourceType} sourceType The source type for the series
|
|
74
|
+
*/
|
|
138
75
|
|
|
139
|
-
break;
|
|
140
76
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
77
|
+
static getPlotlyProperty(plotStyle, sourceType) {
|
|
78
|
+
switch (plotStyle) {
|
|
79
|
+
case dh.plot.SeriesPlotStyle.PIE:
|
|
80
|
+
switch (sourceType) {
|
|
81
|
+
case dh.plot.SourceType.X:
|
|
82
|
+
return 'labels';
|
|
144
83
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
return 'x';
|
|
84
|
+
case dh.plot.SourceType.Y:
|
|
85
|
+
return 'values';
|
|
148
86
|
|
|
149
|
-
|
|
150
|
-
|
|
87
|
+
default:
|
|
88
|
+
break;
|
|
89
|
+
}
|
|
151
90
|
|
|
152
|
-
|
|
153
|
-
return 'z';
|
|
91
|
+
break;
|
|
154
92
|
|
|
155
|
-
|
|
156
|
-
|
|
93
|
+
case dh.plot.SeriesPlotStyle.OHLC:
|
|
94
|
+
switch (sourceType) {
|
|
95
|
+
case dh.plot.SourceType.TIME:
|
|
96
|
+
return 'x';
|
|
157
97
|
|
|
158
|
-
|
|
159
|
-
|
|
98
|
+
default:
|
|
99
|
+
break;
|
|
100
|
+
}
|
|
160
101
|
|
|
161
|
-
|
|
162
|
-
return 'yLow';
|
|
102
|
+
break;
|
|
163
103
|
|
|
164
|
-
|
|
165
|
-
|
|
104
|
+
default:
|
|
105
|
+
break;
|
|
106
|
+
}
|
|
166
107
|
|
|
167
|
-
|
|
168
|
-
|
|
108
|
+
switch (sourceType) {
|
|
109
|
+
case dh.plot.SourceType.X:
|
|
110
|
+
return 'x';
|
|
169
111
|
|
|
170
|
-
|
|
171
|
-
|
|
112
|
+
case dh.plot.SourceType.Y:
|
|
113
|
+
return 'y';
|
|
172
114
|
|
|
173
|
-
|
|
174
|
-
|
|
115
|
+
case dh.plot.SourceType.Z:
|
|
116
|
+
return 'z';
|
|
175
117
|
|
|
176
|
-
|
|
177
|
-
|
|
118
|
+
case dh.plot.SourceType.X_LOW:
|
|
119
|
+
return 'xLow';
|
|
178
120
|
|
|
179
|
-
|
|
180
|
-
|
|
121
|
+
case dh.plot.SourceType.X_HIGH:
|
|
122
|
+
return 'xHigh';
|
|
181
123
|
|
|
182
|
-
|
|
183
|
-
|
|
124
|
+
case dh.plot.SourceType.Y_LOW:
|
|
125
|
+
return 'yLow';
|
|
184
126
|
|
|
185
|
-
|
|
186
|
-
|
|
127
|
+
case dh.plot.SourceType.Y_HIGH:
|
|
128
|
+
return 'yHigh';
|
|
187
129
|
|
|
188
|
-
|
|
189
|
-
|
|
130
|
+
case dh.plot.SourceType.TIME:
|
|
131
|
+
return 'time';
|
|
190
132
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
}, {
|
|
196
|
-
key: "getPlotlySeriesOrientation",
|
|
197
|
-
value: function getPlotlySeriesOrientation(series) {
|
|
198
|
-
var sources = series.sources;
|
|
133
|
+
case dh.plot.SourceType.OPEN:
|
|
134
|
+
return 'open';
|
|
199
135
|
|
|
200
|
-
|
|
201
|
-
return
|
|
202
|
-
}
|
|
136
|
+
case dh.plot.SourceType.HIGH:
|
|
137
|
+
return 'high';
|
|
203
138
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
/**
|
|
207
|
-
* Generate the plotly error bar data from the passed in data.
|
|
208
|
-
* Iris passes in the values as absolute, plotly needs them as relative.
|
|
209
|
-
* @param {Array[Number]} x The main data array
|
|
210
|
-
* @param {Array[Number]} xLow The absolute low values
|
|
211
|
-
* @param {Array[Number]} xHigh
|
|
212
|
-
*
|
|
213
|
-
* @returns {Object} The error_x object required by plotly, or null if none is required
|
|
214
|
-
*/
|
|
215
|
-
|
|
216
|
-
}, {
|
|
217
|
-
key: "getPlotlyErrorBars",
|
|
218
|
-
value: function getPlotlyErrorBars(x, xLow, xHigh) {
|
|
219
|
-
var array = xHigh.map(function (value, i) {
|
|
220
|
-
return value - x[i];
|
|
221
|
-
});
|
|
222
|
-
var arrayminus = xLow.map(function (value, i) {
|
|
223
|
-
return x[i] - value;
|
|
224
|
-
});
|
|
225
|
-
return {
|
|
226
|
-
type: 'data',
|
|
227
|
-
symmetric: false,
|
|
228
|
-
array: array,
|
|
229
|
-
arrayminus: arrayminus
|
|
230
|
-
};
|
|
231
|
-
}
|
|
232
|
-
}, {
|
|
233
|
-
key: "getPlotlyDateFormat",
|
|
234
|
-
value: function getPlotlyDateFormat(formatter, columnType, formatPattern) {
|
|
235
|
-
var tickformat = formatPattern == null ? null : 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
|
|
139
|
+
case dh.plot.SourceType.LOW:
|
|
140
|
+
return 'low';
|
|
236
141
|
|
|
237
|
-
|
|
238
|
-
|
|
142
|
+
case dh.plot.SourceType.CLOSE:
|
|
143
|
+
return 'shape';
|
|
239
144
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
}
|
|
145
|
+
case dh.plot.SourceType.SIZE:
|
|
146
|
+
return 'size';
|
|
243
147
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
value: function convertNumberPrefix(prefix) {
|
|
253
|
-
return prefix.replace(/\u00A4\u00A4/g, 'USD').replace(/\u00A4/g, '$');
|
|
254
|
-
}
|
|
255
|
-
}, {
|
|
256
|
-
key: "getPlotlyNumberFormat",
|
|
257
|
-
value: function getPlotlyNumberFormat(formatter, columnType, formatPattern) {
|
|
258
|
-
if (!formatPattern) {
|
|
259
|
-
return null;
|
|
260
|
-
} // We translate java formatting: https://docs.oracle.com/javase/7/docs/api/java/text/DecimalFormat.html
|
|
261
|
-
// Into d3 number formatting: https://github.com/d3/d3-format
|
|
262
|
-
// We can't translate number formatting exactly, but should be able to translate the most common cases
|
|
263
|
-
// First split it into the subpatterns; currently only handling the positive subpattern, ignoring the rest
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
var subpatterns = formatPattern.split(';');
|
|
267
|
-
|
|
268
|
-
var _subpatterns$0$match = subpatterns[0].match(/^([^#,0.]*)([#,]*)([0,]*)(\.?)(0*)(#*)(E?0*)(%?)(.*)/),
|
|
269
|
-
_subpatterns$0$match2 = _slicedToArray(_subpatterns$0$match, 10),
|
|
270
|
-
prefix = _subpatterns$0$match2[1],
|
|
271
|
-
placeholderDigits = _subpatterns$0$match2[2],
|
|
272
|
-
zeroDigits = _subpatterns$0$match2[3],
|
|
273
|
-
decimalDigits = _subpatterns$0$match2[5],
|
|
274
|
-
optionalDecimalDigits = _subpatterns$0$match2[6],
|
|
275
|
-
numberType = _subpatterns$0$match2[7],
|
|
276
|
-
percentSign = _subpatterns$0$match2[8],
|
|
277
|
-
suffix = _subpatterns$0$match2[9];
|
|
278
|
-
|
|
279
|
-
var paddingLength = zeroDigits.replace(',', '').length;
|
|
280
|
-
var isCommaSeparated = placeholderDigits.indexOf(',') >= 0 || zeroDigits.indexOf(',') >= 0;
|
|
281
|
-
var comma = isCommaSeparated ? ',' : '';
|
|
282
|
-
var plotlyNumberType = numberType ? 'e' : 'f';
|
|
283
|
-
var type = percentSign || plotlyNumberType;
|
|
284
|
-
var decimalLength = decimalDigits.length + optionalDecimalDigits.length; // IDS-4565 Plotly uses an older version of d3 which doesn't support the trim option or negative brackets
|
|
285
|
-
// If plotly updates it's d3 version, this should be re-enabled
|
|
286
|
-
// const trimOption = optionalDecimalDigits.length > 0 ? '~' : '';
|
|
287
|
-
|
|
288
|
-
var trimOption = '';
|
|
289
|
-
var tickformat = "0".concat(paddingLength).concat(comma, ".").concat(decimalLength).concat(trimOption).concat(type);
|
|
290
|
-
var tickprefix = ChartUtils.convertNumberPrefix(prefix); // prefix and suffix are processed the same
|
|
291
|
-
|
|
292
|
-
var ticksuffix = ChartUtils.convertNumberPrefix(suffix);
|
|
293
|
-
return {
|
|
294
|
-
tickformat: tickformat,
|
|
295
|
-
tickprefix: tickprefix,
|
|
296
|
-
ticksuffix: ticksuffix,
|
|
297
|
-
automargin: true
|
|
298
|
-
};
|
|
148
|
+
case dh.plot.SourceType.LABEL:
|
|
149
|
+
return 'label';
|
|
150
|
+
|
|
151
|
+
case dh.plot.SourceType.COLOR:
|
|
152
|
+
return 'color';
|
|
153
|
+
|
|
154
|
+
default:
|
|
155
|
+
throw new Error('Unrecognized source type', sourceType);
|
|
299
156
|
}
|
|
300
|
-
|
|
301
|
-
* Gets the plotly axis formatting information from the source passed in
|
|
302
|
-
* @param {dh.plot.Source} source The Source to get the formatter information from
|
|
303
|
-
* @param {Formatter} formatter The current formatter for formatting data
|
|
304
|
-
*/
|
|
305
|
-
|
|
306
|
-
}, {
|
|
307
|
-
key: "getPlotlyAxisFormat",
|
|
308
|
-
value: function getPlotlyAxisFormat(source) {
|
|
309
|
-
var formatter = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
|
|
310
|
-
var axis = source.axis,
|
|
311
|
-
columnType = source.columnType;
|
|
312
|
-
var formatPattern = axis.formatPattern;
|
|
313
|
-
var axisFormat = null;
|
|
314
|
-
|
|
315
|
-
if (TableUtils.isDateType(columnType)) {
|
|
316
|
-
axisFormat = ChartUtils.getPlotlyDateFormat(formatter, columnType, formatPattern);
|
|
317
|
-
axisFormat = ChartUtils.addTickSpacing(axisFormat, axis, true);
|
|
318
|
-
} else if (TableUtils.isNumberType(columnType)) {
|
|
319
|
-
axisFormat = ChartUtils.getPlotlyNumberFormat(formatter, columnType, formatPattern);
|
|
320
|
-
axisFormat = ChartUtils.addTickSpacing(axisFormat, axis, false);
|
|
321
|
-
}
|
|
157
|
+
}
|
|
322
158
|
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
axisFormat = {
|
|
328
|
-
type: 'category',
|
|
329
|
-
tickformat: null,
|
|
330
|
-
ticksuffix: null
|
|
331
|
-
};
|
|
332
|
-
}
|
|
333
|
-
}
|
|
159
|
+
static getPlotlySeriesOrientation(series) {
|
|
160
|
+
var {
|
|
161
|
+
sources
|
|
162
|
+
} = series;
|
|
334
163
|
|
|
335
|
-
|
|
164
|
+
if (sources.length === 2 && sources[0].axis.type === dh.plot.AxisType.Y) {
|
|
165
|
+
return ChartUtils.ORIENTATION.HORIZONTAL;
|
|
336
166
|
}
|
|
337
|
-
/**
|
|
338
|
-
* Adds tick spacing for an axis that has gapBetweenMajorTicks defined.
|
|
339
|
-
*
|
|
340
|
-
* @param {object} axisFormat the current axis format, may be null
|
|
341
|
-
* @param {object} axis the current axis
|
|
342
|
-
* @param {boolean} isDateType indicates if the columns is a date type
|
|
343
|
-
*/
|
|
344
|
-
|
|
345
|
-
}, {
|
|
346
|
-
key: "addTickSpacing",
|
|
347
|
-
value: function addTickSpacing(axisFormat, axis, isDateType) {
|
|
348
|
-
var gapBetweenMajorTicks = axis.gapBetweenMajorTicks;
|
|
349
|
-
|
|
350
|
-
if (gapBetweenMajorTicks > 0) {
|
|
351
|
-
var updatedFormat = axisFormat || {};
|
|
352
|
-
var tickSpacing = gapBetweenMajorTicks;
|
|
353
|
-
|
|
354
|
-
if (isDateType) {
|
|
355
|
-
// Need to convert from nanoseconds to milliseconds
|
|
356
|
-
tickSpacing = gapBetweenMajorTicks / NANOS_PER_MILLI;
|
|
357
|
-
}
|
|
358
167
|
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
168
|
+
return ChartUtils.ORIENTATION.VERTICAL;
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Generate the plotly error bar data from the passed in data.
|
|
172
|
+
* Iris passes in the values as absolute, plotly needs them as relative.
|
|
173
|
+
* @param {Array[Number]} x The main data array
|
|
174
|
+
* @param {Array[Number]} xLow The absolute low values
|
|
175
|
+
* @param {Array[Number]} xHigh
|
|
176
|
+
*
|
|
177
|
+
* @returns {Object} The error_x object required by plotly, or null if none is required
|
|
178
|
+
*/
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
static getPlotlyErrorBars(x, xLow, xHigh) {
|
|
182
|
+
var array = xHigh.map((value, i) => value - x[i]);
|
|
183
|
+
var arrayminus = xLow.map((value, i) => x[i] - value);
|
|
184
|
+
return {
|
|
185
|
+
type: 'data',
|
|
186
|
+
symmetric: false,
|
|
187
|
+
array,
|
|
188
|
+
arrayminus
|
|
189
|
+
};
|
|
190
|
+
}
|
|
362
191
|
|
|
192
|
+
static getPlotlyDateFormat(formatter, columnType, formatPattern) {
|
|
193
|
+
var tickformat = formatPattern == null ? null : 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
|
|
363
194
|
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
return updatedFormat;
|
|
367
|
-
}
|
|
195
|
+
var ticksuffix = null;
|
|
196
|
+
var dataFormatter = formatter.getColumnTypeFormatter(columnType);
|
|
368
197
|
|
|
369
|
-
|
|
198
|
+
if (dataFormatter.dhTimeZone != null && dataFormatter.showTimeZone) {
|
|
199
|
+
ticksuffix = dh.i18n.DateTimeFormat.format(' z', new Date(), dataFormatter.dhTimeZone);
|
|
370
200
|
}
|
|
371
|
-
/**
|
|
372
|
-
* Retrieve the data source for a given axis in a chart
|
|
373
|
-
* @param {dh.plot.Chart} chart The chart to get the source for
|
|
374
|
-
* @param {dh.plot.Axis} axis The axis to find the source for
|
|
375
|
-
* @returns {dh.plot.Source} The first source matching this axis
|
|
376
|
-
*/
|
|
377
|
-
|
|
378
|
-
}, {
|
|
379
|
-
key: "getSourceForAxis",
|
|
380
|
-
value: function getSourceForAxis(chart, axis) {
|
|
381
|
-
for (var i = 0; i < chart.series.length; i += 1) {
|
|
382
|
-
var series = chart.series[i];
|
|
383
|
-
|
|
384
|
-
for (var j = 0; j < series.sources.length; j += 1) {
|
|
385
|
-
var source = series.sources[j];
|
|
386
|
-
|
|
387
|
-
if (source.axis === axis) {
|
|
388
|
-
return source;
|
|
389
|
-
}
|
|
390
|
-
}
|
|
391
|
-
}
|
|
392
201
|
|
|
202
|
+
return {
|
|
203
|
+
tickformat,
|
|
204
|
+
ticksuffix,
|
|
205
|
+
automargin: true
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
static convertNumberPrefix(prefix) {
|
|
210
|
+
return prefix.replace(/\u00A4\u00A4/g, 'USD').replace(/\u00A4/g, '$');
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
static getPlotlyNumberFormat(formatter, columnType, formatPattern) {
|
|
214
|
+
if (!formatPattern) {
|
|
393
215
|
return null;
|
|
216
|
+
} // We translate java formatting: https://docs.oracle.com/javase/7/docs/api/java/text/DecimalFormat.html
|
|
217
|
+
// Into d3 number formatting: https://github.com/d3/d3-format
|
|
218
|
+
// We can't translate number formatting exactly, but should be able to translate the most common cases
|
|
219
|
+
// First split it into the subpatterns; currently only handling the positive subpattern, ignoring the rest
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
var subpatterns = formatPattern.split(';');
|
|
223
|
+
var [, prefix, placeholderDigits, zeroDigits,, decimalDigits, optionalDecimalDigits, numberType, percentSign, suffix] = subpatterns[0].match(/^([^#,0.]*)([#,]*)([0,]*)(\.?)(0*)(#*)(E?0*)(%?)(.*)/);
|
|
224
|
+
var paddingLength = zeroDigits.replace(',', '').length;
|
|
225
|
+
var isCommaSeparated = placeholderDigits.indexOf(',') >= 0 || zeroDigits.indexOf(',') >= 0;
|
|
226
|
+
var comma = isCommaSeparated ? ',' : '';
|
|
227
|
+
var plotlyNumberType = numberType ? 'e' : 'f';
|
|
228
|
+
var type = percentSign || plotlyNumberType;
|
|
229
|
+
var decimalLength = decimalDigits.length + optionalDecimalDigits.length; // IDS-4565 Plotly uses an older version of d3 which doesn't support the trim option or negative brackets
|
|
230
|
+
// If plotly updates it's d3 version, this should be re-enabled
|
|
231
|
+
// const trimOption = optionalDecimalDigits.length > 0 ? '~' : '';
|
|
232
|
+
|
|
233
|
+
var trimOption = '';
|
|
234
|
+
var tickformat = "0".concat(paddingLength).concat(comma, ".").concat(decimalLength).concat(trimOption).concat(type);
|
|
235
|
+
var tickprefix = ChartUtils.convertNumberPrefix(prefix); // prefix and suffix are processed the same
|
|
236
|
+
|
|
237
|
+
var ticksuffix = ChartUtils.convertNumberPrefix(suffix);
|
|
238
|
+
return {
|
|
239
|
+
tickformat,
|
|
240
|
+
tickprefix,
|
|
241
|
+
ticksuffix,
|
|
242
|
+
automargin: true
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* Gets the plotly axis formatting information from the source passed in
|
|
247
|
+
* @param {dh.plot.Source} source The Source to get the formatter information from
|
|
248
|
+
* @param {Formatter} formatter The current formatter for formatting data
|
|
249
|
+
*/
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
static getPlotlyAxisFormat(source) {
|
|
253
|
+
var formatter = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
|
|
254
|
+
var {
|
|
255
|
+
axis,
|
|
256
|
+
columnType
|
|
257
|
+
} = source;
|
|
258
|
+
var {
|
|
259
|
+
formatPattern
|
|
260
|
+
} = axis;
|
|
261
|
+
var axisFormat = null;
|
|
262
|
+
|
|
263
|
+
if (TableUtils.isDateType(columnType)) {
|
|
264
|
+
axisFormat = ChartUtils.getPlotlyDateFormat(formatter, columnType, formatPattern);
|
|
265
|
+
axisFormat = ChartUtils.addTickSpacing(axisFormat, axis, true);
|
|
266
|
+
} else if (TableUtils.isNumberType(columnType)) {
|
|
267
|
+
axisFormat = ChartUtils.getPlotlyNumberFormat(formatter, columnType, formatPattern);
|
|
268
|
+
axisFormat = ChartUtils.addTickSpacing(axisFormat, axis, false);
|
|
394
269
|
}
|
|
395
|
-
/**
|
|
396
|
-
* Get visibility setting for the series object
|
|
397
|
-
* @param {string} name The series name to get the visibility for
|
|
398
|
-
* @param {object} settings Chart settings
|
|
399
|
-
* @returns {boolean|string} True for visible series and 'legendonly' for hidden
|
|
400
|
-
*/
|
|
401
|
-
|
|
402
|
-
}, {
|
|
403
|
-
key: "getSeriesVisibility",
|
|
404
|
-
value: function getSeriesVisibility(name, settings) {
|
|
405
|
-
var _settings$hiddenSerie;
|
|
406
|
-
|
|
407
|
-
if (settings !== null && settings !== void 0 && (_settings$hiddenSerie = settings.hiddenSeries) !== null && _settings$hiddenSerie !== void 0 && _settings$hiddenSerie.includes(name)) {
|
|
408
|
-
return 'legendonly';
|
|
409
|
-
}
|
|
410
270
|
|
|
411
|
-
|
|
271
|
+
if (axis.formatType === dh.plot.AxisFormatType.CATEGORY) {
|
|
272
|
+
if (axisFormat) {
|
|
273
|
+
axisFormat.type = 'category';
|
|
274
|
+
} else {
|
|
275
|
+
axisFormat = {
|
|
276
|
+
type: 'category',
|
|
277
|
+
tickformat: null,
|
|
278
|
+
ticksuffix: null
|
|
279
|
+
};
|
|
280
|
+
}
|
|
412
281
|
}
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
282
|
+
|
|
283
|
+
return axisFormat;
|
|
284
|
+
}
|
|
285
|
+
/**
|
|
286
|
+
* Adds tick spacing for an axis that has gapBetweenMajorTicks defined.
|
|
287
|
+
*
|
|
288
|
+
* @param {object} axisFormat the current axis format, may be null
|
|
289
|
+
* @param {object} axis the current axis
|
|
290
|
+
* @param {boolean} isDateType indicates if the columns is a date type
|
|
291
|
+
*/
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
static addTickSpacing(axisFormat, axis, isDateType) {
|
|
295
|
+
var {
|
|
296
|
+
gapBetweenMajorTicks
|
|
297
|
+
} = axis;
|
|
298
|
+
|
|
299
|
+
if (gapBetweenMajorTicks > 0) {
|
|
300
|
+
var updatedFormat = axisFormat || {};
|
|
301
|
+
var tickSpacing = gapBetweenMajorTicks;
|
|
302
|
+
|
|
303
|
+
if (isDateType) {
|
|
304
|
+
// Need to convert from nanoseconds to milliseconds
|
|
305
|
+
tickSpacing = gapBetweenMajorTicks / NANOS_PER_MILLI;
|
|
424
306
|
}
|
|
425
307
|
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
key: "makeSeriesData",
|
|
435
|
-
value: function makeSeriesData(type, mode, name) {
|
|
436
|
-
var orientation = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : ChartUtils.ORIENTATION.VERTICAL;
|
|
437
|
-
return {
|
|
438
|
-
type: type,
|
|
439
|
-
mode: mode,
|
|
440
|
-
name: name,
|
|
441
|
-
orientation: orientation
|
|
442
|
-
};
|
|
443
|
-
}
|
|
444
|
-
/**
|
|
445
|
-
* Create a data series (trace) for use with plotly
|
|
446
|
-
* @param {dh.plot.Series} series The series to create the series data with
|
|
447
|
-
* @param {Map<dh.plot.AxisType, dh.plot.Axis[]>} axisTypeMap The map of axes grouped by type
|
|
448
|
-
* @param {boolean|string} seriesVisibility Visibility setting for the series
|
|
449
|
-
* @returns {Object} The series data (trace) object for use with plotly.
|
|
450
|
-
*/
|
|
451
|
-
|
|
452
|
-
}, {
|
|
453
|
-
key: "makeSeriesDataFromSeries",
|
|
454
|
-
value: function makeSeriesDataFromSeries(series, axisTypeMap, seriesVisibility) {
|
|
455
|
-
var name = series.name,
|
|
456
|
-
plotStyle = series.plotStyle,
|
|
457
|
-
lineColor = series.lineColor,
|
|
458
|
-
shapeColor = series.shapeColor,
|
|
459
|
-
sources = series.sources;
|
|
460
|
-
var isBusinessTime = sources.some(function (source) {
|
|
461
|
-
return source.axis.businessCalendar;
|
|
462
|
-
});
|
|
463
|
-
var type = ChartUtils.getChartType(plotStyle, isBusinessTime);
|
|
464
|
-
var mode = ChartUtils.getPlotlyChartMode(plotStyle);
|
|
465
|
-
var orientation = ChartUtils.getPlotlySeriesOrientation(series);
|
|
466
|
-
var seriesData = ChartUtils.makeSeriesData(type, mode, name, orientation);
|
|
467
|
-
ChartUtils.addSourcesToSeriesData(seriesData, plotStyle, sources, axisTypeMap);
|
|
468
|
-
ChartUtils.addStylingToSeriesData(seriesData, plotStyle, lineColor, shapeColor, seriesVisibility);
|
|
469
|
-
return seriesData;
|
|
308
|
+
if (axis.log) {
|
|
309
|
+
tickSpacing = Math.log(tickSpacing);
|
|
310
|
+
} // Note that tickmode defaults to 'auto'
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
updatedFormat.tickmode = 'linear';
|
|
314
|
+
updatedFormat.dtick = tickSpacing;
|
|
315
|
+
return updatedFormat;
|
|
470
316
|
}
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
317
|
+
|
|
318
|
+
return axisFormat;
|
|
319
|
+
}
|
|
320
|
+
/**
|
|
321
|
+
* Retrieve the data source for a given axis in a chart
|
|
322
|
+
* @param {dh.plot.Chart} chart The chart to get the source for
|
|
323
|
+
* @param {dh.plot.Axis} axis The axis to find the source for
|
|
324
|
+
* @returns {dh.plot.Source} The first source matching this axis
|
|
325
|
+
*/
|
|
326
|
+
|
|
327
|
+
|
|
328
|
+
static getSourceForAxis(chart, axis) {
|
|
329
|
+
for (var i = 0; i < chart.series.length; i += 1) {
|
|
330
|
+
var series = chart.series[i];
|
|
331
|
+
|
|
332
|
+
for (var j = 0; j < series.sources.length; j += 1) {
|
|
333
|
+
var source = series.sources[j];
|
|
334
|
+
|
|
335
|
+
if (source.axis === axis) {
|
|
336
|
+
return source;
|
|
489
337
|
}
|
|
490
338
|
}
|
|
491
339
|
}
|
|
492
|
-
}, {
|
|
493
|
-
key: "addStylingToSeriesData",
|
|
494
|
-
value: function addStylingToSeriesData(seriesDataParam, plotStyle) {
|
|
495
|
-
var lineColor = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
|
|
496
|
-
var shapeColor = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null;
|
|
497
|
-
var seriesVisibility = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : null;
|
|
498
|
-
var seriesData = seriesDataParam; // Add some empty objects so we can fill them in later with details without checking for existence
|
|
499
340
|
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
341
|
+
return null;
|
|
342
|
+
}
|
|
343
|
+
/**
|
|
344
|
+
* Get visibility setting for the series object
|
|
345
|
+
* @param {string} name The series name to get the visibility for
|
|
346
|
+
* @param {object} settings Chart settings
|
|
347
|
+
* @returns {boolean|string} True for visible series and 'legendonly' for hidden
|
|
348
|
+
*/
|
|
503
349
|
|
|
504
|
-
seriesData.line = {
|
|
505
|
-
width: 1 // default line width for lines, should eventually be able to override
|
|
506
350
|
|
|
507
|
-
|
|
351
|
+
static getSeriesVisibility(name, settings) {
|
|
352
|
+
var _settings$hiddenSerie;
|
|
508
353
|
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
354
|
+
if (settings !== null && settings !== void 0 && (_settings$hiddenSerie = settings.hiddenSeries) !== null && _settings$hiddenSerie !== void 0 && _settings$hiddenSerie.includes(name)) {
|
|
355
|
+
return 'legendonly';
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
return true;
|
|
359
|
+
}
|
|
360
|
+
/**
|
|
361
|
+
* Get hidden labels array from chart settings
|
|
362
|
+
* @param {object} settings Chart settings
|
|
363
|
+
* @returns {string[]} Array of hidden series names
|
|
364
|
+
*/
|
|
365
|
+
|
|
366
|
+
|
|
367
|
+
static getHiddenLabels(settings) {
|
|
368
|
+
if (settings !== null && settings !== void 0 && settings.hiddenSeries) {
|
|
369
|
+
return [...settings.hiddenSeries];
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
return [];
|
|
373
|
+
}
|
|
374
|
+
/**
|
|
375
|
+
* Create a default series data object. Apply styling to the object afterward.
|
|
376
|
+
* @returns {Object} A simple series data object with no styling
|
|
377
|
+
*/
|
|
378
|
+
|
|
379
|
+
|
|
380
|
+
static makeSeriesData(type, mode, name) {
|
|
381
|
+
var orientation = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : ChartUtils.ORIENTATION.VERTICAL;
|
|
382
|
+
return {
|
|
383
|
+
type,
|
|
384
|
+
mode,
|
|
385
|
+
name,
|
|
386
|
+
orientation
|
|
387
|
+
};
|
|
388
|
+
}
|
|
389
|
+
/**
|
|
390
|
+
* Create a data series (trace) for use with plotly
|
|
391
|
+
* @param {dh.plot.Series} series The series to create the series data with
|
|
392
|
+
* @param {Map<dh.plot.AxisType, dh.plot.Axis[]>} axisTypeMap The map of axes grouped by type
|
|
393
|
+
* @param {boolean|string} seriesVisibility Visibility setting for the series
|
|
394
|
+
* @returns {Object} The series data (trace) object for use with plotly.
|
|
395
|
+
*/
|
|
396
|
+
|
|
397
|
+
|
|
398
|
+
static makeSeriesDataFromSeries(series, axisTypeMap, seriesVisibility) {
|
|
399
|
+
var {
|
|
400
|
+
name,
|
|
401
|
+
plotStyle,
|
|
402
|
+
lineColor,
|
|
403
|
+
shapeColor,
|
|
404
|
+
sources
|
|
405
|
+
} = series;
|
|
406
|
+
var isBusinessTime = sources.some(source => source.axis.businessCalendar);
|
|
407
|
+
var type = ChartUtils.getChartType(plotStyle, isBusinessTime);
|
|
408
|
+
var mode = ChartUtils.getPlotlyChartMode(plotStyle);
|
|
409
|
+
var orientation = ChartUtils.getPlotlySeriesOrientation(series);
|
|
410
|
+
var seriesData = ChartUtils.makeSeriesData(type, mode, name, orientation);
|
|
411
|
+
ChartUtils.addSourcesToSeriesData(seriesData, plotStyle, sources, axisTypeMap);
|
|
412
|
+
ChartUtils.addStylingToSeriesData(seriesData, plotStyle, lineColor, shapeColor, seriesVisibility);
|
|
413
|
+
return seriesData;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
static addSourcesToSeriesData(seriesDataParam, plotStyle, sources, axisTypeMap) {
|
|
417
|
+
var seriesData = seriesDataParam;
|
|
418
|
+
|
|
419
|
+
for (var k = 0; k < sources.length; k += 1) {
|
|
420
|
+
var source = sources[k];
|
|
421
|
+
var {
|
|
422
|
+
axis,
|
|
423
|
+
type: sourceType
|
|
424
|
+
} = source;
|
|
425
|
+
var dataAttributeName = ChartUtils.getPlotlyProperty(plotStyle, sourceType);
|
|
426
|
+
seriesData[dataAttributeName] = [];
|
|
427
|
+
var axisProperty = ChartUtils.getAxisPropertyName(axis.type);
|
|
428
|
+
var axes = axisTypeMap.get(axis.type);
|
|
429
|
+
var axisIndex = axes.indexOf(axis);
|
|
430
|
+
|
|
431
|
+
if (axisProperty != null) {
|
|
432
|
+
var axisIndexString = axisIndex > 0 ? "".concat(axisIndex + 1) : '';
|
|
433
|
+
seriesData["".concat(axisProperty, "axis")] = "".concat(axisProperty).concat(axisIndexString);
|
|
539
434
|
}
|
|
435
|
+
}
|
|
436
|
+
}
|
|
540
437
|
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
438
|
+
static addStylingToSeriesData(seriesDataParam, plotStyle) {
|
|
439
|
+
var lineColor = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
|
|
440
|
+
var shapeColor = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null;
|
|
441
|
+
var seriesVisibility = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : null;
|
|
442
|
+
var seriesData = seriesDataParam; // Add some empty objects so we can fill them in later with details without checking for existence
|
|
443
|
+
|
|
444
|
+
seriesData.marker = {
|
|
445
|
+
line: {}
|
|
446
|
+
}; // border line width on markers
|
|
447
|
+
|
|
448
|
+
seriesData.line = {
|
|
449
|
+
width: 1 // default line width for lines, should eventually be able to override
|
|
450
|
+
|
|
451
|
+
};
|
|
452
|
+
|
|
453
|
+
if (plotStyle === dh.plot.SeriesPlotStyle.AREA) {
|
|
454
|
+
seriesData.fill = 'tozeroy';
|
|
455
|
+
} else if (plotStyle === dh.plot.SeriesPlotStyle.STACKED_AREA) {
|
|
456
|
+
seriesData.stackgroup = 'stack';
|
|
457
|
+
} else if (plotStyle === dh.plot.SeriesPlotStyle.STEP) {
|
|
458
|
+
seriesData.line.shape = 'hv'; // plot.ly horizontal then vertical step styling
|
|
459
|
+
} else if (plotStyle === dh.plot.SeriesPlotStyle.HISTOGRAM) {
|
|
460
|
+
// The default histfunc in plotly is 'count', but the data passed up from the API provides explicit x/y values and bins
|
|
461
|
+
// Since it's converted to bar, just set the widths of each bar
|
|
462
|
+
seriesData.width = [];
|
|
463
|
+
Object.assign(seriesData.marker.line, {
|
|
464
|
+
color: ChartTheme.paper_bgcolor,
|
|
465
|
+
width: 1
|
|
466
|
+
});
|
|
467
|
+
} else if (plotStyle === dh.plot.SeriesPlotStyle.OHLC) {
|
|
468
|
+
seriesData.increasing = {
|
|
469
|
+
line: {
|
|
470
|
+
color: ChartTheme.ohlc_increasing
|
|
471
|
+
}
|
|
472
|
+
};
|
|
473
|
+
seriesData.decreasing = {
|
|
474
|
+
line: {
|
|
475
|
+
color: ChartTheme.ohlc_decreasing
|
|
546
476
|
}
|
|
477
|
+
};
|
|
478
|
+
} else if (plotStyle === dh.plot.SeriesPlotStyle.PIE) {
|
|
479
|
+
seriesData.textinfo = 'label+percent';
|
|
480
|
+
seriesData.outsidetextfont = {
|
|
481
|
+
color: ChartTheme.title_color
|
|
482
|
+
};
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
if (lineColor != null) {
|
|
486
|
+
if (plotStyle === dh.plot.SeriesPlotStyle.BAR) {
|
|
487
|
+
seriesData.marker.color = lineColor;
|
|
488
|
+
} else {
|
|
489
|
+
seriesData.line.color = lineColor;
|
|
547
490
|
}
|
|
491
|
+
}
|
|
548
492
|
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
493
|
+
if (shapeColor != null) {
|
|
494
|
+
seriesData.marker.color = shapeColor;
|
|
495
|
+
} // Skipping pie charts
|
|
496
|
+
// Pie slice visibility is configured in chart layout instead of series data
|
|
553
497
|
|
|
554
498
|
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
}
|
|
499
|
+
if (seriesVisibility != null && plotStyle !== dh.plot.SeriesPlotStyle.PIE) {
|
|
500
|
+
seriesData.visible = seriesVisibility;
|
|
558
501
|
}
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
ChartUtils.createBoundsFromDays(businessDays).forEach(function (weekendBounds) {
|
|
633
|
-
return axisFormat.rangebreaks.push({
|
|
634
|
-
pattern: 'day of week',
|
|
635
|
-
bounds: weekendBounds
|
|
636
|
-
});
|
|
637
|
-
});
|
|
638
|
-
}
|
|
502
|
+
}
|
|
503
|
+
/**
|
|
504
|
+
* Retrieve the axis formats from the provided figure.
|
|
505
|
+
* Currently defaults to just the x/y axes.
|
|
506
|
+
* @param {dh.plot.Figure} figure The figure to get the axis formats for
|
|
507
|
+
* @param {Formatter} formatter The formatter to use when getting the axis format
|
|
508
|
+
* @returns {Map<string, object>} A map of axis layout property names to axis formats
|
|
509
|
+
*/
|
|
510
|
+
|
|
511
|
+
|
|
512
|
+
static getAxisFormats(figure, formatter) {
|
|
513
|
+
var axisFormats = new Map();
|
|
514
|
+
var nullFormat = {
|
|
515
|
+
tickformat: null,
|
|
516
|
+
ticksuffix: null
|
|
517
|
+
};
|
|
518
|
+
var {
|
|
519
|
+
charts
|
|
520
|
+
} = figure;
|
|
521
|
+
|
|
522
|
+
for (var i = 0; i < charts.length; i += 1) {
|
|
523
|
+
var chart = charts[i];
|
|
524
|
+
var axisTypeMap = ChartUtils.groupArray(chart.axes, 'type');
|
|
525
|
+
|
|
526
|
+
for (var j = 0; j < chart.series.length; j += 1) {
|
|
527
|
+
var series = chart.series[j];
|
|
528
|
+
var {
|
|
529
|
+
sources
|
|
530
|
+
} = series;
|
|
531
|
+
|
|
532
|
+
for (var k = 0; k < sources.length; k += 1) {
|
|
533
|
+
var source = sources[k];
|
|
534
|
+
var {
|
|
535
|
+
axis
|
|
536
|
+
} = source;
|
|
537
|
+
var {
|
|
538
|
+
type: axisType
|
|
539
|
+
} = axis;
|
|
540
|
+
var typeAxes = axisTypeMap.get(axisType);
|
|
541
|
+
var axisIndex = typeAxes.indexOf(axis);
|
|
542
|
+
var axisProperty = ChartUtils.getAxisPropertyName(axisType);
|
|
543
|
+
var axisLayoutProperty = ChartUtils.getAxisLayoutProperty(axisProperty, axisIndex);
|
|
544
|
+
|
|
545
|
+
if (axisFormats.has(axisLayoutProperty)) {
|
|
546
|
+
log.debug("".concat(axisLayoutProperty, " already added."));
|
|
547
|
+
} else {
|
|
548
|
+
var _ret = function () {
|
|
549
|
+
log.debug("Adding ".concat(axisLayoutProperty, " to axisFormats."));
|
|
550
|
+
var axisFormat = ChartUtils.getPlotlyAxisFormat(source, formatter);
|
|
551
|
+
|
|
552
|
+
if (axisFormat === null) {
|
|
553
|
+
axisFormats.set(axisLayoutProperty, nullFormat);
|
|
554
|
+
} else {
|
|
555
|
+
axisFormats.set(axisLayoutProperty, axisFormat);
|
|
556
|
+
var {
|
|
557
|
+
businessCalendar
|
|
558
|
+
} = axis;
|
|
559
|
+
|
|
560
|
+
if (businessCalendar) {
|
|
561
|
+
var _formatter$getColumnT;
|
|
562
|
+
|
|
563
|
+
axisFormat.rangebreaks = [];
|
|
564
|
+
var {
|
|
565
|
+
businessPeriods,
|
|
566
|
+
businessDays,
|
|
567
|
+
holidays,
|
|
568
|
+
timeZone: calendarTimeZone
|
|
569
|
+
} = businessCalendar;
|
|
570
|
+
var formatterTimeZone = formatter === null || formatter === void 0 ? void 0 : (_formatter$getColumnT = formatter.getColumnTypeFormatter(BUSINESS_COLUMN_TYPE)) === null || _formatter$getColumnT === void 0 ? void 0 : _formatter$getColumnT.dhTimeZone;
|
|
571
|
+
var timeZoneDiff = formatterTimeZone ? (calendarTimeZone.standardOffset - formatterTimeZone.standardOffset) / 60 : 0;
|
|
572
|
+
|
|
573
|
+
if (holidays.length > 0) {
|
|
574
|
+
axisFormat.rangebreaks.push(...ChartUtils.createRangeBreakValuesFromHolidays(holidays, calendarTimeZone, formatterTimeZone));
|
|
639
575
|
}
|
|
640
576
|
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
577
|
+
businessPeriods.forEach(period => axisFormat.rangebreaks.push({
|
|
578
|
+
pattern: 'hour',
|
|
579
|
+
bounds: [ChartUtils.periodToDecimal(period.close) + timeZoneDiff, ChartUtils.periodToDecimal(period.open) + timeZoneDiff]
|
|
580
|
+
})); // If there are seven business days, then there is no weekend
|
|
581
|
+
|
|
582
|
+
if (businessDays.length < DAYS.length) {
|
|
583
|
+
ChartUtils.createBoundsFromDays(businessDays).forEach(weekendBounds => axisFormat.rangebreaks.push({
|
|
584
|
+
pattern: 'day of week',
|
|
585
|
+
bounds: weekendBounds
|
|
586
|
+
}));
|
|
645
587
|
}
|
|
646
588
|
}
|
|
647
|
-
}();
|
|
648
589
|
|
|
649
|
-
|
|
650
|
-
|
|
590
|
+
if (axisFormats.size === chart.axes.length) {
|
|
591
|
+
return {
|
|
592
|
+
v: axisFormats
|
|
593
|
+
};
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
}();
|
|
597
|
+
|
|
598
|
+
if (typeof _ret === "object") return _ret.v;
|
|
651
599
|
}
|
|
652
600
|
}
|
|
653
601
|
}
|
|
654
|
-
|
|
655
|
-
return axisFormats;
|
|
656
602
|
}
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
603
|
+
|
|
604
|
+
return axisFormats;
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
static getChartType(plotStyle, isBusinessTime) {
|
|
608
|
+
switch (plotStyle) {
|
|
609
|
+
case dh.plot.SeriesPlotStyle.HISTOGRAM:
|
|
610
|
+
// When reading data from the `Figure`, it already provides bins and values, so rather than using
|
|
611
|
+
// plot.ly to calculate the bins and sum values, just convert it to a bar chart
|
|
612
|
+
return 'bar';
|
|
613
|
+
|
|
614
|
+
default:
|
|
615
|
+
return ChartUtils.getPlotlyChartType(plotStyle, isBusinessTime);
|
|
669
616
|
}
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
}
|
|
617
|
+
}
|
|
618
|
+
/**
|
|
619
|
+
* Return the plotly axis property name
|
|
620
|
+
* @param {dh.plot.AxisType} axisType The axis type to get the property name for
|
|
621
|
+
*/
|
|
622
|
+
|
|
623
|
+
|
|
624
|
+
static getAxisPropertyName(axisType) {
|
|
625
|
+
switch (axisType) {
|
|
626
|
+
case dh.plot.AxisType.X:
|
|
627
|
+
return 'x';
|
|
628
|
+
|
|
629
|
+
case dh.plot.AxisType.Y:
|
|
630
|
+
return 'y';
|
|
631
|
+
|
|
632
|
+
default:
|
|
633
|
+
return null;
|
|
688
634
|
}
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
635
|
+
}
|
|
636
|
+
/**
|
|
637
|
+
* Returns the plotly "side" value for the provided axis position
|
|
638
|
+
* @param {dh.plot.AxisPosition} axisPosition The Iris AxisPosition of the axis
|
|
639
|
+
*/
|
|
693
640
|
|
|
694
|
-
}, {
|
|
695
|
-
key: "getAxisSide",
|
|
696
|
-
value: function getAxisSide(axisPosition) {
|
|
697
|
-
switch (axisPosition) {
|
|
698
|
-
case dh.plot.AxisPosition.BOTTOM:
|
|
699
|
-
return 'bottom';
|
|
700
641
|
|
|
701
|
-
|
|
702
|
-
|
|
642
|
+
static getAxisSide(axisPosition) {
|
|
643
|
+
switch (axisPosition) {
|
|
644
|
+
case dh.plot.AxisPosition.BOTTOM:
|
|
645
|
+
return 'bottom';
|
|
703
646
|
|
|
704
|
-
|
|
705
|
-
|
|
647
|
+
case dh.plot.AxisPosition.TOP:
|
|
648
|
+
return 'top';
|
|
706
649
|
|
|
707
|
-
|
|
708
|
-
|
|
650
|
+
case dh.plot.AxisPosition.LEFT:
|
|
651
|
+
return 'left';
|
|
709
652
|
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
}
|
|
713
|
-
}
|
|
714
|
-
/**
|
|
715
|
-
* Retrieve the chart that contains the passed in series from the figure
|
|
716
|
-
* @param {dh.plot.Figure} figure The figure to retrieve the chart from
|
|
717
|
-
* @param {dh.plot.Series} series The series to get the chart for
|
|
718
|
-
*/
|
|
719
|
-
|
|
720
|
-
}, {
|
|
721
|
-
key: "getChartForSeries",
|
|
722
|
-
value: function getChartForSeries(figure, series) {
|
|
723
|
-
var charts = figure.charts;
|
|
724
|
-
|
|
725
|
-
for (var i = 0; i < charts.length; i += 1) {
|
|
726
|
-
var chart = charts[i];
|
|
727
|
-
|
|
728
|
-
for (var j = 0; j < chart.series.length; j += 1) {
|
|
729
|
-
if (series === chart.series[j]) {
|
|
730
|
-
return chart;
|
|
731
|
-
}
|
|
732
|
-
}
|
|
733
|
-
}
|
|
653
|
+
case dh.plot.AxisPosition.RIGHT:
|
|
654
|
+
return 'right';
|
|
734
655
|
|
|
735
|
-
|
|
656
|
+
default:
|
|
657
|
+
return null;
|
|
736
658
|
}
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
}, {
|
|
744
|
-
key: "getLayoutRanges",
|
|
745
|
-
value: function getLayoutRanges(layout) {
|
|
746
|
-
var ranges = {};
|
|
747
|
-
var keys = Object.keys(layout).filter(function (key) {
|
|
748
|
-
return key.indexOf('axis') >= 0;
|
|
749
|
-
});
|
|
659
|
+
}
|
|
660
|
+
/**
|
|
661
|
+
* Retrieve the chart that contains the passed in series from the figure
|
|
662
|
+
* @param {dh.plot.Figure} figure The figure to retrieve the chart from
|
|
663
|
+
* @param {dh.plot.Series} series The series to get the chart for
|
|
664
|
+
*/
|
|
750
665
|
|
|
751
|
-
for (var i = 0; i < keys.length; i += 1) {
|
|
752
|
-
var key = keys[i];
|
|
753
666
|
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
}
|
|
667
|
+
static getChartForSeries(figure, series) {
|
|
668
|
+
var {
|
|
669
|
+
charts
|
|
670
|
+
} = figure;
|
|
759
671
|
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
/**
|
|
763
|
-
* Updates the axes positions and sizes in the layout object provided.
|
|
764
|
-
* If the axis did not exist in the layout previously, it is created and added.
|
|
765
|
-
* Any axis that no longer exists in axes is removed.
|
|
766
|
-
* With Downsampling enabled, will also update the range on the axis itself as appropriate
|
|
767
|
-
* @param {object} layoutParam The layout object to update
|
|
768
|
-
* @param {dh.plot.Axis[]} axes The axes to update the layout with
|
|
769
|
-
* @param {number} plotWidth The width of the plot to calculate the axis sizes for
|
|
770
|
-
* @param {number} plotHeight The height of the plot to calculate the axis sizes for
|
|
771
|
-
* @param {func} getRangeParser A function to retrieve the range parser for a given axis
|
|
772
|
-
*/
|
|
773
|
-
|
|
774
|
-
}, {
|
|
775
|
-
key: "updateLayoutAxes",
|
|
776
|
-
value: function updateLayoutAxes(layoutParam, axes) {
|
|
777
|
-
var plotWidth = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
|
|
778
|
-
var plotHeight = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 0;
|
|
779
|
-
var getRangeParser = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : null;
|
|
780
|
-
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;
|
|
781
|
-
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; // Adjust the bounds based on where the legend is
|
|
782
|
-
// For now, always assume the legend is shown on the right
|
|
783
|
-
|
|
784
|
-
var bounds = {
|
|
785
|
-
left: 0,
|
|
786
|
-
bottom: 0,
|
|
787
|
-
top: 1,
|
|
788
|
-
right: 1
|
|
789
|
-
};
|
|
790
|
-
var axisPositionMap = ChartUtils.groupArray(axes, 'position');
|
|
791
|
-
var rightAxes = axisPositionMap.get(dh.plot.AxisPosition.RIGHT) || [];
|
|
672
|
+
for (var i = 0; i < charts.length; i += 1) {
|
|
673
|
+
var chart = charts[i];
|
|
792
674
|
|
|
793
|
-
|
|
794
|
-
if (
|
|
795
|
-
|
|
796
|
-
} else {
|
|
797
|
-
bounds.right = 1 - ChartUtils.DEFAULT_AXIS_SIZE;
|
|
675
|
+
for (var j = 0; j < chart.series.length; j += 1) {
|
|
676
|
+
if (series === chart.series[j]) {
|
|
677
|
+
return chart;
|
|
798
678
|
}
|
|
799
679
|
}
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
return null;
|
|
683
|
+
}
|
|
684
|
+
/**
|
|
685
|
+
* Get an object mapping axis to their ranges
|
|
686
|
+
* @param {object} layout The plotly layout object to get the ranges from
|
|
687
|
+
* @returns {object} An object mapping the axis name to it's range
|
|
688
|
+
*/
|
|
800
689
|
|
|
801
|
-
var layout = layoutParam;
|
|
802
|
-
var axisTypeMap = ChartUtils.groupArray(axes, 'type');
|
|
803
690
|
|
|
804
|
-
|
|
691
|
+
static getLayoutRanges(layout) {
|
|
692
|
+
var ranges = {};
|
|
693
|
+
var keys = Object.keys(layout).filter(key => key.indexOf('axis') >= 0);
|
|
805
694
|
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
var axisProperty = ChartUtils.getAxisPropertyName(axisType);
|
|
695
|
+
for (var i = 0; i < keys.length; i += 1) {
|
|
696
|
+
var key = keys[i];
|
|
809
697
|
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
698
|
+
if (layout[key] && layout[key].range && !layout[key].autorange) {
|
|
699
|
+
// Only want to add the range if it's not autoranged
|
|
700
|
+
ranges[key] = [...layout[key].range];
|
|
701
|
+
}
|
|
702
|
+
}
|
|
815
703
|
|
|
816
|
-
|
|
817
|
-
|
|
704
|
+
return ranges;
|
|
705
|
+
}
|
|
706
|
+
/**
|
|
707
|
+
* Updates the axes positions and sizes in the layout object provided.
|
|
708
|
+
* If the axis did not exist in the layout previously, it is created and added.
|
|
709
|
+
* Any axis that no longer exists in axes is removed.
|
|
710
|
+
* With Downsampling enabled, will also update the range on the axis itself as appropriate
|
|
711
|
+
* @param {object} layoutParam The layout object to update
|
|
712
|
+
* @param {dh.plot.Axis[]} axes The axes to update the layout with
|
|
713
|
+
* @param {number} plotWidth The width of the plot to calculate the axis sizes for
|
|
714
|
+
* @param {number} plotHeight The height of the plot to calculate the axis sizes for
|
|
715
|
+
* @param {func} getRangeParser A function to retrieve the range parser for a given axis
|
|
716
|
+
*/
|
|
717
|
+
|
|
718
|
+
|
|
719
|
+
static updateLayoutAxes(layoutParam, axes) {
|
|
720
|
+
var plotWidth = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
|
|
721
|
+
var plotHeight = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 0;
|
|
722
|
+
var getRangeParser = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : null;
|
|
723
|
+
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;
|
|
724
|
+
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; // Adjust the bounds based on where the legend is
|
|
725
|
+
// For now, always assume the legend is shown on the right
|
|
726
|
+
|
|
727
|
+
var bounds = {
|
|
728
|
+
left: 0,
|
|
729
|
+
bottom: 0,
|
|
730
|
+
top: 1,
|
|
731
|
+
right: 1
|
|
732
|
+
};
|
|
733
|
+
var axisPositionMap = ChartUtils.groupArray(axes, 'position');
|
|
734
|
+
var rightAxes = axisPositionMap.get(dh.plot.AxisPosition.RIGHT) || [];
|
|
735
|
+
|
|
736
|
+
if (rightAxes.length > 0) {
|
|
737
|
+
if (plotWidth > 0) {
|
|
738
|
+
bounds.right = 1 - Math.max(0, Math.min(ChartUtils.LEGEND_WIDTH_PX / plotWidth, ChartUtils.MAX_LEGEND_SIZE));
|
|
739
|
+
} else {
|
|
740
|
+
bounds.right = 1 - ChartUtils.DEFAULT_AXIS_SIZE;
|
|
741
|
+
}
|
|
742
|
+
}
|
|
818
743
|
|
|
819
|
-
|
|
744
|
+
var layout = layoutParam;
|
|
745
|
+
var axisTypeMap = ChartUtils.groupArray(axes, 'type');
|
|
746
|
+
var axisTypes = [...axisTypeMap.keys()];
|
|
820
747
|
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
748
|
+
for (var j = 0; j < axisTypes.length; j += 1) {
|
|
749
|
+
var axisType = axisTypes[j];
|
|
750
|
+
var axisProperty = ChartUtils.getAxisPropertyName(axisType);
|
|
824
751
|
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
752
|
+
if (axisProperty != null) {
|
|
753
|
+
var typeAxes = axisTypeMap.get(axisType);
|
|
754
|
+
var isYAxis = axisType === dh.plot.AxisType.Y;
|
|
755
|
+
var plotSize = isYAxis ? plotHeight : plotWidth;
|
|
756
|
+
var axisIndex = 0;
|
|
829
757
|
|
|
830
|
-
|
|
831
|
-
|
|
758
|
+
for (axisIndex = 0; axisIndex < typeAxes.length; axisIndex += 1) {
|
|
759
|
+
var axis = typeAxes[axisIndex];
|
|
832
760
|
|
|
833
|
-
|
|
834
|
-
_rangeParser2 = _slicedToArray(_rangeParser, 2),
|
|
835
|
-
rangeStart = _rangeParser2[0],
|
|
836
|
-
rangeEnd = _rangeParser2[1];
|
|
761
|
+
var _axisLayoutProperty = ChartUtils.getAxisLayoutProperty(axisProperty, axisIndex);
|
|
837
762
|
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
} else {
|
|
841
|
-
axis.range(plotSize);
|
|
842
|
-
}
|
|
763
|
+
if (layout[_axisLayoutProperty] == null) {
|
|
764
|
+
layout[_axisLayoutProperty] = ChartUtils.makeLayoutAxis(axisType);
|
|
843
765
|
}
|
|
844
766
|
|
|
845
|
-
var
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
767
|
+
var layoutAxis = layout[_axisLayoutProperty];
|
|
768
|
+
ChartUtils.updateLayoutAxis(layoutAxis, axis, axisIndex, axisPositionMap, xAxisSize, yAxisSize, bounds);
|
|
769
|
+
var {
|
|
770
|
+
range,
|
|
771
|
+
autorange
|
|
772
|
+
} = layoutAxis;
|
|
773
|
+
|
|
774
|
+
if (getRangeParser && range && !autorange) {
|
|
775
|
+
var rangeParser = getRangeParser(axis);
|
|
776
|
+
var [rangeStart, rangeEnd] = rangeParser(range);
|
|
777
|
+
log.debug('Setting downsample range', plotSize, rangeStart, rangeEnd);
|
|
778
|
+
axis.range(plotSize, rangeStart, rangeEnd);
|
|
779
|
+
} else {
|
|
780
|
+
axis.range(plotSize);
|
|
851
781
|
}
|
|
852
782
|
}
|
|
783
|
+
|
|
784
|
+
var axisLayoutProperty = ChartUtils.getAxisLayoutProperty(axisProperty, axisIndex);
|
|
785
|
+
|
|
786
|
+
while (layout[axisLayoutProperty] != null) {
|
|
787
|
+
delete layout[axisLayoutProperty];
|
|
788
|
+
axisIndex += 1;
|
|
789
|
+
axisLayoutProperty = ChartUtils.getAxisLayoutProperty(axisProperty, axisIndex);
|
|
790
|
+
}
|
|
853
791
|
}
|
|
854
792
|
}
|
|
855
|
-
}
|
|
856
|
-
key: "getAxisLayoutProperty",
|
|
857
|
-
value: function getAxisLayoutProperty(axisProperty, axisIndex) {
|
|
858
|
-
var axisIndexString = axisIndex > 0 ? "".concat(axisIndex + 1) : '';
|
|
859
|
-
return "".concat(axisProperty, "axis").concat(axisIndexString);
|
|
860
|
-
}
|
|
861
|
-
/**
|
|
862
|
-
* Updates the layout axis object in place
|
|
863
|
-
* @param {object} layoutAxisParam The plotly layout axis param
|
|
864
|
-
* @param {dh.plot.Axis} axis The Iris Axis to update the plotly layout with
|
|
865
|
-
* @param {number} axisIndex The type index for this axis
|
|
866
|
-
* @param {Map<dh.plot.AxisPosition, dh.plot.Axis>} axisPositionMap All the axes mapped by position
|
|
867
|
-
* @param {number} axisSize The size of each axis in percent
|
|
868
|
-
* @param {object} bounds The bounds of the axes domains
|
|
869
|
-
*/
|
|
870
|
-
|
|
871
|
-
}, {
|
|
872
|
-
key: "updateLayoutAxis",
|
|
873
|
-
value: function updateLayoutAxis(layoutAxisParam, axis, axisIndex, axisPositionMap, xAxisSize, yAxisSize, bounds) {
|
|
874
|
-
var isYAxis = axis.type === dh.plot.AxisType.Y;
|
|
875
|
-
var axisSize = isYAxis ? yAxisSize : xAxisSize;
|
|
876
|
-
var layoutAxis = layoutAxisParam;
|
|
877
|
-
layoutAxis.title.text = axis.label;
|
|
793
|
+
}
|
|
878
794
|
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
795
|
+
static getAxisLayoutProperty(axisProperty, axisIndex) {
|
|
796
|
+
var axisIndexString = axisIndex > 0 ? "".concat(axisIndex + 1) : '';
|
|
797
|
+
return "".concat(axisProperty, "axis").concat(axisIndexString);
|
|
798
|
+
}
|
|
799
|
+
/**
|
|
800
|
+
* Updates the layout axis object in place
|
|
801
|
+
* @param {object} layoutAxisParam The plotly layout axis param
|
|
802
|
+
* @param {dh.plot.Axis} axis The Iris Axis to update the plotly layout with
|
|
803
|
+
* @param {number} axisIndex The type index for this axis
|
|
804
|
+
* @param {Map<dh.plot.AxisPosition, dh.plot.Axis>} axisPositionMap All the axes mapped by position
|
|
805
|
+
* @param {number} axisSize The size of each axis in percent
|
|
806
|
+
* @param {object} bounds The bounds of the axes domains
|
|
807
|
+
*/
|
|
808
|
+
|
|
809
|
+
|
|
810
|
+
static updateLayoutAxis(layoutAxisParam, axis, axisIndex, axisPositionMap, xAxisSize, yAxisSize, bounds) {
|
|
811
|
+
var isYAxis = axis.type === dh.plot.AxisType.Y;
|
|
812
|
+
var axisSize = isYAxis ? yAxisSize : xAxisSize;
|
|
813
|
+
var layoutAxis = layoutAxisParam;
|
|
814
|
+
layoutAxis.title.text = axis.label;
|
|
815
|
+
|
|
816
|
+
if (axis.log) {
|
|
817
|
+
layoutAxis.type = 'log';
|
|
818
|
+
}
|
|
882
819
|
|
|
883
|
-
|
|
820
|
+
layoutAxis.side = ChartUtils.getAxisSide(axis.position);
|
|
884
821
|
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
822
|
+
if (axisIndex > 0) {
|
|
823
|
+
layoutAxis.overlaying = ChartUtils.getAxisPropertyName(axis.type);
|
|
824
|
+
var positionAxes = axisPositionMap.get(axis.position);
|
|
825
|
+
var sideIndex = positionAxes.indexOf(axis);
|
|
889
826
|
|
|
890
|
-
|
|
891
|
-
|
|
827
|
+
if (sideIndex > 0) {
|
|
828
|
+
layoutAxis.anchor = 'free';
|
|
892
829
|
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
}
|
|
830
|
+
if (axis.position === dh.plot.AxisPosition.RIGHT) {
|
|
831
|
+
layoutAxis.position = bounds.right + (sideIndex - positionAxes.length + 1) * axisSize;
|
|
832
|
+
} else if (axis.position === dh.plot.AxisPosition.TOP) {
|
|
833
|
+
layoutAxis.position = bounds.top + (sideIndex - positionAxes.length + 1) * axisSize;
|
|
834
|
+
} else if (axis.position === dh.plot.AxisPosition.BOTTOM) {
|
|
835
|
+
layoutAxis.position = bounds.bottom + (positionAxes.length - sideIndex + 1) * axisSize;
|
|
836
|
+
} else if (axis.position === dh.plot.AxisPosition.LEFT) {
|
|
837
|
+
layoutAxis.position = bounds.left + (positionAxes.length - sideIndex + 1) * axisSize;
|
|
902
838
|
}
|
|
903
|
-
} else if (axis.type === dh.plot.AxisType.X) {
|
|
904
|
-
var leftAxes = axisPositionMap.get(dh.plot.AxisPosition.LEFT) || [];
|
|
905
|
-
var rightAxes = axisPositionMap.get(dh.plot.AxisPosition.RIGHT) || [];
|
|
906
|
-
var left = Math.max(bounds.left, bounds.left + (leftAxes.length - 1) * yAxisSize);
|
|
907
|
-
var right = Math.min(bounds.right - (rightAxes.length - 1) * yAxisSize, bounds.right);
|
|
908
|
-
layoutAxis.domain = [left, right];
|
|
909
|
-
} else if (axis.type === dh.plot.AxisType.Y) {
|
|
910
|
-
var bottomAxes = axisPositionMap.get(dh.plot.AxisPosition.BOTTOM) || [];
|
|
911
|
-
var topAxes = axisPositionMap.get(dh.plot.AxisPosition.TOP) || [];
|
|
912
|
-
var bottom = Math.max(bounds.bottom, bounds.bottom + (bottomAxes.length - 1) * xAxisSize);
|
|
913
|
-
var top = Math.min(bounds.top - (topAxes.length - 1) * xAxisSize, bounds.top);
|
|
914
|
-
layoutAxis.domain = [bottom, top];
|
|
915
839
|
}
|
|
840
|
+
} else if (axis.type === dh.plot.AxisType.X) {
|
|
841
|
+
var leftAxes = axisPositionMap.get(dh.plot.AxisPosition.LEFT) || [];
|
|
842
|
+
var rightAxes = axisPositionMap.get(dh.plot.AxisPosition.RIGHT) || [];
|
|
843
|
+
var left = Math.max(bounds.left, bounds.left + (leftAxes.length - 1) * yAxisSize);
|
|
844
|
+
var right = Math.min(bounds.right - (rightAxes.length - 1) * yAxisSize, bounds.right);
|
|
845
|
+
layoutAxis.domain = [left, right];
|
|
846
|
+
} else if (axis.type === dh.plot.AxisType.Y) {
|
|
847
|
+
var bottomAxes = axisPositionMap.get(dh.plot.AxisPosition.BOTTOM) || [];
|
|
848
|
+
var topAxes = axisPositionMap.get(dh.plot.AxisPosition.TOP) || [];
|
|
849
|
+
var bottom = Math.max(bounds.bottom, bounds.bottom + (bottomAxes.length - 1) * xAxisSize);
|
|
850
|
+
var top = Math.min(bounds.top - (topAxes.length - 1) * xAxisSize, bounds.top);
|
|
851
|
+
layoutAxis.domain = [bottom, top];
|
|
916
852
|
}
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
}, {
|
|
924
|
-
key: "periodToDecimal",
|
|
925
|
-
value: function periodToDecimal(period) {
|
|
926
|
-
var values = period.split(':');
|
|
927
|
-
return Number(values[0]) + Number(values[1] / 60);
|
|
928
|
-
}
|
|
929
|
-
/**
|
|
930
|
-
* Creates range break bounds for plotly from business days.
|
|
931
|
-
* For example a standard business week of ['MONDAY','TUESDAY','WEDNESDAY','THURSDAY','FRIDAY']
|
|
932
|
-
* will result in [[6,1]] meaning close on Saturday and open on Monday.
|
|
933
|
-
* If you remove Wednesday from the array, then you get two closures [[6, 1], [3, 4]]
|
|
934
|
-
*
|
|
935
|
-
* @param {Array} businessDays the days to display on the x-axis
|
|
936
|
-
*/
|
|
937
|
-
|
|
938
|
-
}, {
|
|
939
|
-
key: "createBoundsFromDays",
|
|
940
|
-
value: function createBoundsFromDays(businessDays) {
|
|
941
|
-
var businessDaysInt = businessDays.map(function (day) {
|
|
942
|
-
return DAYS.indexOf(day);
|
|
943
|
-
});
|
|
944
|
-
var nonBusinessDaysInt = DAYS.filter(function (day) {
|
|
945
|
-
return !businessDays.includes(day);
|
|
946
|
-
}).map(function (day) {
|
|
947
|
-
return DAYS.indexOf(day);
|
|
948
|
-
}); // These are the days when business reopens (e.g. Monday after a weekend)
|
|
949
|
-
|
|
950
|
-
var reopenDays = new Set();
|
|
951
|
-
nonBusinessDaysInt.forEach(function (closed) {
|
|
952
|
-
for (var i = closed + 1; i < closed + DAYS.length; i += 1) {
|
|
953
|
-
var adjustedDay = i % DAYS.length;
|
|
954
|
-
|
|
955
|
-
if (businessDaysInt.includes(adjustedDay)) {
|
|
956
|
-
reopenDays.add(adjustedDay);
|
|
957
|
-
break;
|
|
958
|
-
}
|
|
959
|
-
}
|
|
960
|
-
});
|
|
961
|
-
var boundsArray = []; // For each reopen day, find the furthest previous closed day
|
|
853
|
+
}
|
|
854
|
+
/**
|
|
855
|
+
* Converts an open or close period to a declimal. e.g '09:30" to 9.5
|
|
856
|
+
*
|
|
857
|
+
* @param {String} period the open or close value of the period
|
|
858
|
+
*/
|
|
962
859
|
|
|
963
|
-
reopenDays.forEach(function (open) {
|
|
964
|
-
for (var i = open - 1; i > open - DAYS.length; i -= 1) {
|
|
965
|
-
var adjustedDay = i < 0 ? i + DAYS.length : i;
|
|
966
860
|
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
var
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
if (
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
fullHolidays.push(ChartUtils.createFullHoliday(holiday, calendarTimeZone, formatterTimeZone));
|
|
994
|
-
}
|
|
995
|
-
});
|
|
996
|
-
return [{
|
|
997
|
-
values: fullHolidays
|
|
998
|
-
}].concat(partialHolidays);
|
|
999
|
-
}
|
|
1000
|
-
/**
|
|
1001
|
-
* Creates the range break value for a full holiday. A full holiday is day that has no business periods.
|
|
1002
|
-
*
|
|
1003
|
-
* @param {Holiday} holiday the full holiday
|
|
1004
|
-
* @param {TimeZone} calendarTimeZone the time zone for the business calendar
|
|
1005
|
-
* @param {TimeZone} formatterTimeZone the time zone for the formatter
|
|
1006
|
-
*/
|
|
1007
|
-
|
|
1008
|
-
}, {
|
|
1009
|
-
key: "createFullHoliday",
|
|
1010
|
-
value: function createFullHoliday(holiday, calendarTimeZone, formatterTimeZone) {
|
|
1011
|
-
return ChartUtils.adjustDateForTimeZone("".concat(holiday.date.toString(), " 00:00:00.000000"), calendarTimeZone, formatterTimeZone);
|
|
1012
|
-
}
|
|
1013
|
-
/**
|
|
1014
|
-
* Creates the range break for a partial holiday. A partial holiday is holiday with business periods
|
|
1015
|
-
* that are different than the default business periods.
|
|
1016
|
-
*
|
|
1017
|
-
* @param {Holiday} holiday the partial holiday
|
|
1018
|
-
* @param {TimeZone} calendarTimeZone the time zone for the business calendar
|
|
1019
|
-
* @param {TimeZone} formatterTimeZone the time zone for the formatter
|
|
1020
|
-
*/
|
|
1021
|
-
|
|
1022
|
-
}, {
|
|
1023
|
-
key: "createPartialHoliday",
|
|
1024
|
-
value: function createPartialHoliday(holiday, calendarTimeZone, formatterTimeZone) {
|
|
1025
|
-
// If a holiday has business periods {open1, close1} and {open2, close2}
|
|
1026
|
-
// This will generate range breaks for:
|
|
1027
|
-
// closed from 00:00 to open1
|
|
1028
|
-
// closed from close1 to open2
|
|
1029
|
-
// closed from close2 to 23:59:59.999999
|
|
1030
|
-
var dateString = holiday.date.toString();
|
|
1031
|
-
var closedPeriods = ['00:00'];
|
|
1032
|
-
holiday.businessPeriods.forEach(function (period) {
|
|
1033
|
-
closedPeriods.push(period.open);
|
|
1034
|
-
closedPeriods.push(period.close);
|
|
1035
|
-
}); // To go up to 23:59:59.999999, we calculate the dvalue using 24 - close
|
|
1036
|
-
|
|
1037
|
-
closedPeriods.push('24:00');
|
|
1038
|
-
var rangeBreaks = [];
|
|
1039
|
-
|
|
1040
|
-
for (var i = 0; i < closedPeriods.length; i += 2) {
|
|
1041
|
-
var startClose = closedPeriods[i];
|
|
1042
|
-
var endClose = closedPeriods[i + 1]; // Skip over any periods where start and close are the same (zero hours)
|
|
1043
|
-
|
|
1044
|
-
if (startClose !== endClose) {
|
|
1045
|
-
var values = [ChartUtils.adjustDateForTimeZone("".concat(dateString, " ").concat(startClose, ":00.000000"), calendarTimeZone, formatterTimeZone)];
|
|
1046
|
-
var dvalue = MILLIS_PER_HOUR * (ChartUtils.periodToDecimal(endClose) - ChartUtils.periodToDecimal(startClose));
|
|
1047
|
-
rangeBreaks.push({
|
|
1048
|
-
values: values,
|
|
1049
|
-
dvalue: dvalue
|
|
1050
|
-
});
|
|
861
|
+
static periodToDecimal(period) {
|
|
862
|
+
var values = period.split(':');
|
|
863
|
+
return Number(values[0]) + Number(values[1] / 60);
|
|
864
|
+
}
|
|
865
|
+
/**
|
|
866
|
+
* Creates range break bounds for plotly from business days.
|
|
867
|
+
* For example a standard business week of ['MONDAY','TUESDAY','WEDNESDAY','THURSDAY','FRIDAY']
|
|
868
|
+
* will result in [[6,1]] meaning close on Saturday and open on Monday.
|
|
869
|
+
* If you remove Wednesday from the array, then you get two closures [[6, 1], [3, 4]]
|
|
870
|
+
*
|
|
871
|
+
* @param {Array} businessDays the days to display on the x-axis
|
|
872
|
+
*/
|
|
873
|
+
|
|
874
|
+
|
|
875
|
+
static createBoundsFromDays(businessDays) {
|
|
876
|
+
var businessDaysInt = businessDays.map(day => DAYS.indexOf(day));
|
|
877
|
+
var nonBusinessDaysInt = DAYS.filter(day => !businessDays.includes(day)).map(day => DAYS.indexOf(day)); // These are the days when business reopens (e.g. Monday after a weekend)
|
|
878
|
+
|
|
879
|
+
var reopenDays = new Set();
|
|
880
|
+
nonBusinessDaysInt.forEach(closed => {
|
|
881
|
+
for (var i = closed + 1; i < closed + DAYS.length; i += 1) {
|
|
882
|
+
var adjustedDay = i % DAYS.length;
|
|
883
|
+
|
|
884
|
+
if (businessDaysInt.includes(adjustedDay)) {
|
|
885
|
+
reopenDays.add(adjustedDay);
|
|
886
|
+
break;
|
|
1051
887
|
}
|
|
1052
888
|
}
|
|
889
|
+
});
|
|
890
|
+
var boundsArray = []; // For each reopen day, find the furthest previous closed day
|
|
1053
891
|
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
}, {
|
|
1065
|
-
key: "adjustDateForTimeZone",
|
|
1066
|
-
value: function adjustDateForTimeZone(dateString, calendarTimeZone, formatterTimeZone) {
|
|
1067
|
-
if (formatterTimeZone && formatterTimeZone.standardOffset !== calendarTimeZone.standardOffset) {
|
|
1068
|
-
return ChartUtils.unwrapValue(ChartUtils.wrapValue(dateString, BUSINESS_COLUMN_TYPE, calendarTimeZone), formatterTimeZone);
|
|
892
|
+
reopenDays.forEach(open => {
|
|
893
|
+
for (var i = open - 1; i > open - DAYS.length; i -= 1) {
|
|
894
|
+
var adjustedDay = i < 0 ? i + DAYS.length : i;
|
|
895
|
+
|
|
896
|
+
if (businessDaysInt.includes(adjustedDay)) {
|
|
897
|
+
var closedDay = (adjustedDay + 1) % 7;
|
|
898
|
+
boundsArray.push([closedDay, open]);
|
|
899
|
+
break;
|
|
900
|
+
}
|
|
1069
901
|
}
|
|
902
|
+
});
|
|
903
|
+
return boundsArray;
|
|
904
|
+
}
|
|
905
|
+
/**
|
|
906
|
+
* Creates an array of range breaks for all holidays.
|
|
907
|
+
*
|
|
908
|
+
* @param {Array} holidays an array of holidays
|
|
909
|
+
* @param {TimeZone} calendarTimeZone the time zone for the business calendar
|
|
910
|
+
* @param {TimeZone} formatterTimeZone the time zone for the formatter
|
|
911
|
+
*/
|
|
912
|
+
|
|
913
|
+
|
|
914
|
+
static createRangeBreakValuesFromHolidays(holidays, calendarTimeZone, formatterTimeZone) {
|
|
915
|
+
var fullHolidays = [];
|
|
916
|
+
var partialHolidays = [];
|
|
917
|
+
holidays.forEach(holiday => {
|
|
918
|
+
if (holiday.businessPeriods.length > 0) {
|
|
919
|
+
partialHolidays.push(...ChartUtils.createPartialHoliday(holiday, calendarTimeZone, formatterTimeZone));
|
|
920
|
+
} else {
|
|
921
|
+
fullHolidays.push(ChartUtils.createFullHoliday(holiday, calendarTimeZone, formatterTimeZone));
|
|
922
|
+
}
|
|
923
|
+
});
|
|
924
|
+
return [{
|
|
925
|
+
values: fullHolidays
|
|
926
|
+
}, ...partialHolidays];
|
|
927
|
+
}
|
|
928
|
+
/**
|
|
929
|
+
* Creates the range break value for a full holiday. A full holiday is day that has no business periods.
|
|
930
|
+
*
|
|
931
|
+
* @param {Holiday} holiday the full holiday
|
|
932
|
+
* @param {TimeZone} calendarTimeZone the time zone for the business calendar
|
|
933
|
+
* @param {TimeZone} formatterTimeZone the time zone for the formatter
|
|
934
|
+
*/
|
|
1070
935
|
|
|
1071
|
-
|
|
936
|
+
|
|
937
|
+
static createFullHoliday(holiday, calendarTimeZone, formatterTimeZone) {
|
|
938
|
+
return ChartUtils.adjustDateForTimeZone("".concat(holiday.date.toString(), " 00:00:00.000000"), calendarTimeZone, formatterTimeZone);
|
|
939
|
+
}
|
|
940
|
+
/**
|
|
941
|
+
* Creates the range break for a partial holiday. A partial holiday is holiday with business periods
|
|
942
|
+
* that are different than the default business periods.
|
|
943
|
+
*
|
|
944
|
+
* @param {Holiday} holiday the partial holiday
|
|
945
|
+
* @param {TimeZone} calendarTimeZone the time zone for the business calendar
|
|
946
|
+
* @param {TimeZone} formatterTimeZone the time zone for the formatter
|
|
947
|
+
*/
|
|
948
|
+
|
|
949
|
+
|
|
950
|
+
static createPartialHoliday(holiday, calendarTimeZone, formatterTimeZone) {
|
|
951
|
+
// If a holiday has business periods {open1, close1} and {open2, close2}
|
|
952
|
+
// This will generate range breaks for:
|
|
953
|
+
// closed from 00:00 to open1
|
|
954
|
+
// closed from close1 to open2
|
|
955
|
+
// closed from close2 to 23:59:59.999999
|
|
956
|
+
var dateString = holiday.date.toString();
|
|
957
|
+
var closedPeriods = ['00:00'];
|
|
958
|
+
holiday.businessPeriods.forEach(period => {
|
|
959
|
+
closedPeriods.push(period.open);
|
|
960
|
+
closedPeriods.push(period.close);
|
|
961
|
+
}); // To go up to 23:59:59.999999, we calculate the dvalue using 24 - close
|
|
962
|
+
|
|
963
|
+
closedPeriods.push('24:00');
|
|
964
|
+
var rangeBreaks = [];
|
|
965
|
+
|
|
966
|
+
for (var i = 0; i < closedPeriods.length; i += 2) {
|
|
967
|
+
var startClose = closedPeriods[i];
|
|
968
|
+
var endClose = closedPeriods[i + 1]; // Skip over any periods where start and close are the same (zero hours)
|
|
969
|
+
|
|
970
|
+
if (startClose !== endClose) {
|
|
971
|
+
var values = [ChartUtils.adjustDateForTimeZone("".concat(dateString, " ").concat(startClose, ":00.000000"), calendarTimeZone, formatterTimeZone)];
|
|
972
|
+
var dvalue = MILLIS_PER_HOUR * (ChartUtils.periodToDecimal(endClose) - ChartUtils.periodToDecimal(startClose));
|
|
973
|
+
rangeBreaks.push({
|
|
974
|
+
values,
|
|
975
|
+
dvalue
|
|
976
|
+
});
|
|
977
|
+
}
|
|
1072
978
|
}
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
return result;
|
|
1089
|
-
}, new Map());
|
|
979
|
+
|
|
980
|
+
return rangeBreaks;
|
|
981
|
+
}
|
|
982
|
+
/**
|
|
983
|
+
* Adjusts a date string from the calendar time zone to the formatter time zone.
|
|
984
|
+
*
|
|
985
|
+
* @param {string} dateString the date string
|
|
986
|
+
* @param {TimeZone} calendarTimeZone the time zone for the business calendar
|
|
987
|
+
* @param {TimeZone} formatterTimeZone the time zone for the formatter
|
|
988
|
+
*/
|
|
989
|
+
|
|
990
|
+
|
|
991
|
+
static adjustDateForTimeZone(dateString, calendarTimeZone, formatterTimeZone) {
|
|
992
|
+
if (formatterTimeZone && formatterTimeZone.standardOffset !== calendarTimeZone.standardOffset) {
|
|
993
|
+
return ChartUtils.unwrapValue(ChartUtils.wrapValue(dateString, BUSINESS_COLUMN_TYPE, calendarTimeZone), formatterTimeZone);
|
|
1090
994
|
}
|
|
1091
|
-
/**
|
|
1092
|
-
* Update
|
|
1093
|
-
*/
|
|
1094
|
-
|
|
1095
|
-
}, {
|
|
1096
|
-
key: "updateRanges",
|
|
1097
|
-
value: function updateRanges() {}
|
|
1098
|
-
/**
|
|
1099
|
-
* Unwraps a value provided from API to a value plotly can understand
|
|
1100
|
-
* Eg. Unwraps DateWrapper, LongWrapper objects.
|
|
1101
|
-
*/
|
|
1102
|
-
|
|
1103
|
-
}, {
|
|
1104
|
-
key: "unwrapValue",
|
|
1105
|
-
value: function unwrapValue(value) {
|
|
1106
|
-
var timeZone = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
|
|
1107
|
-
|
|
1108
|
-
if (value != null) {
|
|
1109
|
-
if (value.asDate) {
|
|
1110
|
-
return dh.i18n.DateTimeFormat.format(ChartUtils.DATE_FORMAT, value, timeZone);
|
|
1111
|
-
}
|
|
1112
995
|
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
996
|
+
return dateString;
|
|
997
|
+
}
|
|
998
|
+
/**
|
|
999
|
+
* Groups an array and returns a map
|
|
1000
|
+
* @param {object[]} array The object to group
|
|
1001
|
+
* @param {string} property The property name to group by
|
|
1002
|
+
* @returns {Map<object, object>} A map containing the items grouped by their values for the property
|
|
1003
|
+
*/
|
|
1004
|
+
|
|
1005
|
+
|
|
1006
|
+
static groupArray(array, property) {
|
|
1007
|
+
return array.reduce((result, item) => {
|
|
1008
|
+
var key = item[property];
|
|
1009
|
+
var group = result.get(key) || [];
|
|
1010
|
+
group.push(item);
|
|
1011
|
+
result.set(key, group);
|
|
1012
|
+
return result;
|
|
1013
|
+
}, new Map());
|
|
1014
|
+
}
|
|
1015
|
+
/**
|
|
1016
|
+
* Update
|
|
1017
|
+
*/
|
|
1018
|
+
|
|
1019
|
+
|
|
1020
|
+
static updateRanges() {}
|
|
1021
|
+
/**
|
|
1022
|
+
* Unwraps a value provided from API to a value plotly can understand
|
|
1023
|
+
* Eg. Unwraps DateWrapper, LongWrapper objects.
|
|
1024
|
+
*/
|
|
1025
|
+
|
|
1026
|
+
|
|
1027
|
+
static unwrapValue(value) {
|
|
1028
|
+
var timeZone = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
|
|
1029
|
+
|
|
1030
|
+
if (value != null) {
|
|
1031
|
+
if (value.asDate) {
|
|
1032
|
+
return dh.i18n.DateTimeFormat.format(ChartUtils.DATE_FORMAT, value, timeZone);
|
|
1116
1033
|
}
|
|
1117
1034
|
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
/**
|
|
1121
|
-
*
|
|
1122
|
-
* @param {any} value The value to wrap up
|
|
1123
|
-
* @param {string} columnType The type of column this value is from
|
|
1124
|
-
* @param {dh.i18n.TimeZone} timeZone The time zone if applicable
|
|
1125
|
-
*/
|
|
1126
|
-
|
|
1127
|
-
}, {
|
|
1128
|
-
key: "wrapValue",
|
|
1129
|
-
value: function wrapValue(value, columnType) {
|
|
1130
|
-
var timeZone = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
|
|
1131
|
-
|
|
1132
|
-
if (TableUtils.isDateType(columnType) && typeof value === 'string') {
|
|
1133
|
-
// Need to limit the format to the actual length of the string range set in plotly
|
|
1134
|
-
// Otherwise parse will fail
|
|
1135
|
-
var text = value;
|
|
1136
|
-
var format = ChartUtils.DATE_FORMAT.substr(0, value.length);
|
|
1137
|
-
var date = dh.i18n.DateTimeFormat.parse(format, text);
|
|
1138
|
-
|
|
1139
|
-
if (!timeZone) {
|
|
1140
|
-
return date;
|
|
1141
|
-
} // IDS-5994 Due to date parsing, time zone, and daylight savings shenanigans, we need
|
|
1142
|
-
// to pass the actual offset with the time to have it parse correctly.
|
|
1143
|
-
// However, the offset can change based on the date because of Daylight Savings
|
|
1144
|
-
// So we end up parsing the date multiple times. And curse daylight savings.
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
var tzFormat = "".concat(format, " Z");
|
|
1148
|
-
var estimatedOffset = dh.i18n.DateTimeFormat.format('Z', date, timeZone);
|
|
1149
|
-
var estimatedDate = dh.i18n.DateTimeFormat.parse(tzFormat, "".concat(text, " ").concat(estimatedOffset));
|
|
1150
|
-
var offset = dh.i18n.DateTimeFormat.format('Z', estimatedDate, timeZone);
|
|
1151
|
-
return dh.i18n.DateTimeFormat.parse(tzFormat, "".concat(text, " ").concat(offset));
|
|
1035
|
+
if (value.asNumber) {
|
|
1036
|
+
return value.asNumber();
|
|
1152
1037
|
}
|
|
1038
|
+
}
|
|
1153
1039
|
|
|
1154
|
-
|
|
1040
|
+
return value;
|
|
1041
|
+
}
|
|
1042
|
+
/**
|
|
1043
|
+
*
|
|
1044
|
+
* @param {any} value The value to wrap up
|
|
1045
|
+
* @param {string} columnType The type of column this value is from
|
|
1046
|
+
* @param {dh.i18n.TimeZone} timeZone The time zone if applicable
|
|
1047
|
+
*/
|
|
1048
|
+
|
|
1049
|
+
|
|
1050
|
+
static wrapValue(value, columnType) {
|
|
1051
|
+
var timeZone = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
|
|
1052
|
+
|
|
1053
|
+
if (TableUtils.isDateType(columnType) && typeof value === 'string') {
|
|
1054
|
+
// Need to limit the format to the actual length of the string range set in plotly
|
|
1055
|
+
// Otherwise parse will fail
|
|
1056
|
+
var text = value;
|
|
1057
|
+
var format = ChartUtils.DATE_FORMAT.substr(0, value.length);
|
|
1058
|
+
var date = dh.i18n.DateTimeFormat.parse(format, text);
|
|
1059
|
+
|
|
1060
|
+
if (!timeZone) {
|
|
1061
|
+
return date;
|
|
1062
|
+
} // IDS-5994 Due to date parsing, time zone, and daylight savings shenanigans, we need
|
|
1063
|
+
// to pass the actual offset with the time to have it parse correctly.
|
|
1064
|
+
// However, the offset can change based on the date because of Daylight Savings
|
|
1065
|
+
// So we end up parsing the date multiple times. And curse daylight savings.
|
|
1066
|
+
|
|
1067
|
+
|
|
1068
|
+
var tzFormat = "".concat(format, " Z");
|
|
1069
|
+
var estimatedOffset = dh.i18n.DateTimeFormat.format('Z', date, timeZone);
|
|
1070
|
+
var estimatedDate = dh.i18n.DateTimeFormat.parse(tzFormat, "".concat(text, " ").concat(estimatedOffset));
|
|
1071
|
+
var offset = dh.i18n.DateTimeFormat.format('Z', estimatedDate, timeZone);
|
|
1072
|
+
return dh.i18n.DateTimeFormat.parse(tzFormat, "".concat(text, " ").concat(offset));
|
|
1155
1073
|
}
|
|
1156
|
-
}, {
|
|
1157
|
-
key: "makeLayoutAxis",
|
|
1158
|
-
value: function makeLayoutAxis(type) {
|
|
1159
|
-
var axis = {
|
|
1160
|
-
automargin: true,
|
|
1161
|
-
gridcolor: ChartTheme.gridcolor,
|
|
1162
|
-
linecolor: ChartTheme.linecolor,
|
|
1163
|
-
rangeslider: {
|
|
1164
|
-
visible: false
|
|
1165
|
-
},
|
|
1166
|
-
showline: true,
|
|
1167
|
-
ticklen: 5,
|
|
1168
|
-
// act as padding, can't find a tick padding
|
|
1169
|
-
tickcolor: ChartTheme.paper_bgcolor,
|
|
1170
|
-
// hide ticks as padding
|
|
1171
|
-
tickfont: {
|
|
1172
|
-
color: ChartTheme.zerolinecolor
|
|
1173
|
-
},
|
|
1174
|
-
title: {
|
|
1175
|
-
font: {
|
|
1176
|
-
color: ChartTheme.title_color
|
|
1177
|
-
}
|
|
1178
|
-
}
|
|
1179
|
-
};
|
|
1180
1074
|
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
showgrid: true
|
|
1184
|
-
});
|
|
1185
|
-
} else if (type === dh.plot.AxisType.Y) {
|
|
1186
|
-
Object.assign(axis, {
|
|
1187
|
-
zerolinecolor: ChartTheme.zerolinecolor,
|
|
1188
|
-
zerolinewidth: 2
|
|
1189
|
-
});
|
|
1190
|
-
}
|
|
1075
|
+
return value;
|
|
1076
|
+
}
|
|
1191
1077
|
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1078
|
+
static makeLayoutAxis(type) {
|
|
1079
|
+
var axis = {
|
|
1080
|
+
automargin: true,
|
|
1081
|
+
gridcolor: ChartTheme.gridcolor,
|
|
1082
|
+
linecolor: ChartTheme.linecolor,
|
|
1083
|
+
rangeslider: {
|
|
1084
|
+
visible: false
|
|
1085
|
+
},
|
|
1086
|
+
showline: true,
|
|
1087
|
+
ticklen: 5,
|
|
1088
|
+
// act as padding, can't find a tick padding
|
|
1089
|
+
tickcolor: ChartTheme.paper_bgcolor,
|
|
1090
|
+
// hide ticks as padding
|
|
1091
|
+
tickfont: {
|
|
1092
|
+
color: ChartTheme.zerolinecolor
|
|
1093
|
+
},
|
|
1094
|
+
title: {
|
|
1200
1095
|
font: {
|
|
1201
|
-
|
|
1202
|
-
}
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
color: ChartTheme.title_color
|
|
1206
|
-
},
|
|
1207
|
-
yanchor: 'top',
|
|
1208
|
-
pad: _objectSpread({}, ChartUtils.DEFAULT_TITLE_PADDING),
|
|
1209
|
-
y: 1,
|
|
1210
|
-
text: 'Untitled'
|
|
1211
|
-
},
|
|
1212
|
-
legend: {
|
|
1213
|
-
font: {
|
|
1214
|
-
color: ChartTheme.title_color
|
|
1215
|
-
}
|
|
1216
|
-
},
|
|
1217
|
-
margin: _objectSpread({}, ChartUtils.DEFAULT_MARGIN),
|
|
1218
|
-
xaxis: ChartUtils.makeLayoutAxis(dh.plot.AxisType.X),
|
|
1219
|
-
yaxis: ChartUtils.makeLayoutAxis(dh.plot.AxisType.Y)
|
|
1220
|
-
});
|
|
1096
|
+
color: ChartTheme.title_color
|
|
1097
|
+
}
|
|
1098
|
+
}
|
|
1099
|
+
};
|
|
1221
1100
|
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
/**
|
|
1226
|
-
* Dehydrate settings so they can be JSONified
|
|
1227
|
-
* @param {object} settings Chart builder settings
|
|
1228
|
-
*/
|
|
1229
|
-
|
|
1230
|
-
}, {
|
|
1231
|
-
key: "dehydrateSettings",
|
|
1232
|
-
value: function dehydrateSettings(settings) {
|
|
1233
|
-
return _objectSpread(_objectSpread({}, settings), {}, {
|
|
1234
|
-
type: "".concat(settings.type)
|
|
1101
|
+
if (type === dh.plot.AxisType.X) {
|
|
1102
|
+
Object.assign(axis, {
|
|
1103
|
+
showgrid: true
|
|
1235
1104
|
});
|
|
1236
|
-
}
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
*/
|
|
1241
|
-
|
|
1242
|
-
}, {
|
|
1243
|
-
key: "hydrateSettings",
|
|
1244
|
-
value: function hydrateSettings(settings) {
|
|
1245
|
-
return _objectSpread(_objectSpread({}, settings), {}, {
|
|
1246
|
-
type: dh.plot.SeriesPlotStyle[settings.type]
|
|
1105
|
+
} else if (type === dh.plot.AxisType.Y) {
|
|
1106
|
+
Object.assign(axis, {
|
|
1107
|
+
zerolinecolor: ChartTheme.zerolinecolor,
|
|
1108
|
+
zerolinewidth: 2
|
|
1247
1109
|
});
|
|
1248
1110
|
}
|
|
1249
|
-
}, {
|
|
1250
|
-
key: "titleFromSettings",
|
|
1251
|
-
value: function titleFromSettings(settings) {
|
|
1252
|
-
var series = settings.series,
|
|
1253
|
-
xAxis = settings.xAxis,
|
|
1254
|
-
_settings$title = settings.title,
|
|
1255
|
-
title = _settings$title === void 0 ? "".concat(series.join(', '), " by ").concat(xAxis) : _settings$title;
|
|
1256
|
-
return title;
|
|
1257
|
-
}
|
|
1258
|
-
/**
|
|
1259
|
-
* Creates the Figure settings from the Chart Builder settings
|
|
1260
|
-
* This should be deprecated at some point, and have Chart Builder create the figure settings directly.
|
|
1261
|
-
* This logic will still need to exist to translate existing charts, but could be part of a migration script
|
|
1262
|
-
* to translate the data.
|
|
1263
|
-
* Change when we decide to add more functionality to the Chart Builder.
|
|
1264
|
-
* @param {object} settings The chart builder settings
|
|
1265
|
-
* @param {string} settings.title The title for this figure
|
|
1266
|
-
* @param {string} settings.xAxis The name of the column to use for the x-axis
|
|
1267
|
-
* @param {string[]} settings.series The name of the columns to use for the series of this figure
|
|
1268
|
-
* @param {dh.plot.SeriesPlotStyle} settings.type The plot style for this figure
|
|
1269
|
-
*/
|
|
1270
|
-
|
|
1271
|
-
}, {
|
|
1272
|
-
key: "makeFigureSettings",
|
|
1273
|
-
value: function makeFigureSettings(settings, table) {
|
|
1274
|
-
var series = settings.series,
|
|
1275
|
-
settingsAxis = settings.xAxis,
|
|
1276
|
-
type = settings.type;
|
|
1277
|
-
var title = ChartUtils.titleFromSettings(settings);
|
|
1278
|
-
var xAxis = {
|
|
1279
|
-
formatType: "".concat(dh.plot.AxisFormatType.NUMBER),
|
|
1280
|
-
type: "".concat(dh.plot.AxisType.X),
|
|
1281
|
-
position: "".concat(dh.plot.AxisPosition.BOTTOM)
|
|
1282
|
-
};
|
|
1283
|
-
var yAxis = {
|
|
1284
|
-
formatType: "".concat(dh.plot.AxisFormatType.NUMBER),
|
|
1285
|
-
type: "".concat(dh.plot.AxisType.Y),
|
|
1286
|
-
position: "".concat(dh.plot.AxisPosition.LEFT)
|
|
1287
|
-
};
|
|
1288
|
-
return {
|
|
1289
|
-
charts: [{
|
|
1290
|
-
chartType: "".concat(dh.plot.ChartType.XY),
|
|
1291
|
-
axes: [xAxis, yAxis],
|
|
1292
|
-
series: series.map(function (name) {
|
|
1293
|
-
return {
|
|
1294
|
-
plotStyle: "".concat(type),
|
|
1295
|
-
name: name,
|
|
1296
|
-
dataSources: [{
|
|
1297
|
-
type: "".concat(dh.plot.SourceType.X),
|
|
1298
|
-
columnName: settingsAxis,
|
|
1299
|
-
axis: xAxis,
|
|
1300
|
-
table: table
|
|
1301
|
-
}, {
|
|
1302
|
-
type: "".concat(dh.plot.SourceType.Y),
|
|
1303
|
-
columnName: name,
|
|
1304
|
-
axis: yAxis,
|
|
1305
|
-
table: table
|
|
1306
|
-
}]
|
|
1307
|
-
};
|
|
1308
|
-
})
|
|
1309
|
-
}],
|
|
1310
|
-
title: title
|
|
1311
|
-
};
|
|
1312
|
-
}
|
|
1313
|
-
}]);
|
|
1314
1111
|
|
|
1315
|
-
|
|
1316
|
-
}
|
|
1112
|
+
return axis;
|
|
1113
|
+
}
|
|
1114
|
+
|
|
1115
|
+
static makeDefaultLayout() {
|
|
1116
|
+
var layout = _objectSpread(_objectSpread({}, ChartTheme), {}, {
|
|
1117
|
+
autosize: true,
|
|
1118
|
+
colorway: ChartTheme.colorway ? ChartTheme.colorway.split(' ') : [],
|
|
1119
|
+
font: {
|
|
1120
|
+
family: "'Fira Sans', sans-serif"
|
|
1121
|
+
},
|
|
1122
|
+
title: {
|
|
1123
|
+
font: {
|
|
1124
|
+
color: ChartTheme.title_color
|
|
1125
|
+
},
|
|
1126
|
+
yanchor: 'top',
|
|
1127
|
+
pad: _objectSpread({}, ChartUtils.DEFAULT_TITLE_PADDING),
|
|
1128
|
+
y: 1,
|
|
1129
|
+
text: 'Untitled'
|
|
1130
|
+
},
|
|
1131
|
+
legend: {
|
|
1132
|
+
font: {
|
|
1133
|
+
color: ChartTheme.title_color
|
|
1134
|
+
}
|
|
1135
|
+
},
|
|
1136
|
+
margin: _objectSpread({}, ChartUtils.DEFAULT_MARGIN),
|
|
1137
|
+
xaxis: ChartUtils.makeLayoutAxis(dh.plot.AxisType.X),
|
|
1138
|
+
yaxis: ChartUtils.makeLayoutAxis(dh.plot.AxisType.Y)
|
|
1139
|
+
});
|
|
1140
|
+
|
|
1141
|
+
layout.datarevision = 0;
|
|
1142
|
+
return layout;
|
|
1143
|
+
}
|
|
1144
|
+
/**
|
|
1145
|
+
* Dehydrate settings so they can be JSONified
|
|
1146
|
+
* @param {object} settings Chart builder settings
|
|
1147
|
+
*/
|
|
1148
|
+
|
|
1149
|
+
|
|
1150
|
+
static dehydrateSettings(settings) {
|
|
1151
|
+
return _objectSpread(_objectSpread({}, settings), {}, {
|
|
1152
|
+
type: "".concat(settings.type)
|
|
1153
|
+
});
|
|
1154
|
+
}
|
|
1155
|
+
/**
|
|
1156
|
+
* Hydrate settings from a JSONable object
|
|
1157
|
+
* @param {object} settings Dehydrated settings
|
|
1158
|
+
*/
|
|
1159
|
+
|
|
1160
|
+
|
|
1161
|
+
static hydrateSettings(settings) {
|
|
1162
|
+
return _objectSpread(_objectSpread({}, settings), {}, {
|
|
1163
|
+
type: dh.plot.SeriesPlotStyle[settings.type]
|
|
1164
|
+
});
|
|
1165
|
+
}
|
|
1166
|
+
|
|
1167
|
+
static titleFromSettings(settings) {
|
|
1168
|
+
var {
|
|
1169
|
+
series,
|
|
1170
|
+
xAxis,
|
|
1171
|
+
title = "".concat(series.join(', '), " by ").concat(xAxis)
|
|
1172
|
+
} = settings;
|
|
1173
|
+
return title;
|
|
1174
|
+
}
|
|
1175
|
+
/**
|
|
1176
|
+
* Creates the Figure settings from the Chart Builder settings
|
|
1177
|
+
* This should be deprecated at some point, and have Chart Builder create the figure settings directly.
|
|
1178
|
+
* This logic will still need to exist to translate existing charts, but could be part of a migration script
|
|
1179
|
+
* to translate the data.
|
|
1180
|
+
* Change when we decide to add more functionality to the Chart Builder.
|
|
1181
|
+
* @param {object} settings The chart builder settings
|
|
1182
|
+
* @param {string} settings.title The title for this figure
|
|
1183
|
+
* @param {string} settings.xAxis The name of the column to use for the x-axis
|
|
1184
|
+
* @param {string[]} settings.series The name of the columns to use for the series of this figure
|
|
1185
|
+
* @param {dh.plot.SeriesPlotStyle} settings.type The plot style for this figure
|
|
1186
|
+
*/
|
|
1187
|
+
|
|
1188
|
+
|
|
1189
|
+
static makeFigureSettings(settings, table) {
|
|
1190
|
+
var {
|
|
1191
|
+
series,
|
|
1192
|
+
xAxis: settingsAxis,
|
|
1193
|
+
type
|
|
1194
|
+
} = settings;
|
|
1195
|
+
var title = ChartUtils.titleFromSettings(settings);
|
|
1196
|
+
var xAxis = {
|
|
1197
|
+
formatType: "".concat(dh.plot.AxisFormatType.NUMBER),
|
|
1198
|
+
type: "".concat(dh.plot.AxisType.X),
|
|
1199
|
+
position: "".concat(dh.plot.AxisPosition.BOTTOM)
|
|
1200
|
+
};
|
|
1201
|
+
var yAxis = {
|
|
1202
|
+
formatType: "".concat(dh.plot.AxisFormatType.NUMBER),
|
|
1203
|
+
type: "".concat(dh.plot.AxisType.Y),
|
|
1204
|
+
position: "".concat(dh.plot.AxisPosition.LEFT)
|
|
1205
|
+
};
|
|
1206
|
+
return {
|
|
1207
|
+
charts: [{
|
|
1208
|
+
chartType: "".concat(dh.plot.ChartType.XY),
|
|
1209
|
+
axes: [xAxis, yAxis],
|
|
1210
|
+
series: series.map(name => ({
|
|
1211
|
+
plotStyle: "".concat(type),
|
|
1212
|
+
name,
|
|
1213
|
+
dataSources: [{
|
|
1214
|
+
type: "".concat(dh.plot.SourceType.X),
|
|
1215
|
+
columnName: settingsAxis,
|
|
1216
|
+
axis: xAxis,
|
|
1217
|
+
table
|
|
1218
|
+
}, {
|
|
1219
|
+
type: "".concat(dh.plot.SourceType.Y),
|
|
1220
|
+
columnName: name,
|
|
1221
|
+
axis: yAxis,
|
|
1222
|
+
table
|
|
1223
|
+
}]
|
|
1224
|
+
}))
|
|
1225
|
+
}],
|
|
1226
|
+
title
|
|
1227
|
+
};
|
|
1228
|
+
}
|
|
1229
|
+
|
|
1230
|
+
}
|
|
1317
1231
|
|
|
1318
1232
|
_defineProperty(ChartUtils, "DEFAULT_AXIS_SIZE", 0.15);
|
|
1319
1233
|
|