@hrforte/react-pivottable 1.0.0 → 1.1.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/PivotTable.js +72 -0
- package/dist/PivotTable.js.map +1 -0
- package/dist/PivotTableUI.js +1846 -0
- package/dist/PivotTableUI.js.map +1 -0
- package/dist/PlotlyRenderers.js +822 -0
- package/dist/PlotlyRenderers.js.map +1 -0
- package/dist/TableRenderers.js +1066 -0
- package/dist/TableRenderers.js.map +1 -0
- package/dist/Utilities.js +1476 -0
- package/dist/Utilities.js.map +1 -0
- package/dist/__tests__/Utilities-test.js +571 -0
- package/dist/__tests__/Utilities-test.js.map +1 -0
- package/dist/pivottable.css +377 -0
- package/package.json +4 -14
|
@@ -0,0 +1,822 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
|
|
7
|
+
var _createClass = function () { 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); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
|
|
8
|
+
|
|
9
|
+
exports.default = createPlotlyRenderers;
|
|
10
|
+
|
|
11
|
+
var _react = require('react');
|
|
12
|
+
|
|
13
|
+
var _react2 = _interopRequireDefault(_react);
|
|
14
|
+
|
|
15
|
+
var _propTypes = require('prop-types');
|
|
16
|
+
|
|
17
|
+
var _propTypes2 = _interopRequireDefault(_propTypes);
|
|
18
|
+
|
|
19
|
+
var _Utilities = require('./Utilities');
|
|
20
|
+
|
|
21
|
+
var _TableRenderers = require('./TableRenderers');
|
|
22
|
+
|
|
23
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
24
|
+
|
|
25
|
+
function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
|
|
26
|
+
|
|
27
|
+
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; }
|
|
28
|
+
|
|
29
|
+
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
|
30
|
+
|
|
31
|
+
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
|
|
32
|
+
|
|
33
|
+
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
|
|
34
|
+
|
|
35
|
+
var CHART_WIDTH_RATIO = 1.5; // Ratio to scale down from full window width
|
|
36
|
+
var CHART_HEIGHT_RATIO = 1.4; // Ratio to scale down from full window height
|
|
37
|
+
var CHART_HEIGHT_OFFSET = 50; // Fixed offset to subtract from height calculation
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
// ============================================================================
|
|
41
|
+
// Helper Functions
|
|
42
|
+
// ============================================================================
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Ensures keys array is not empty by adding an empty array if needed
|
|
46
|
+
*/
|
|
47
|
+
function ensureNonEmptyKeys(keys) {
|
|
48
|
+
return keys.length > 0 ? keys : [[]];
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Combines category and datum labels into a single display label
|
|
53
|
+
*/
|
|
54
|
+
function combineCategoryLabels(categoryKey, datumKey) {
|
|
55
|
+
var categoryLabel = categoryKey.join(' ') || '';
|
|
56
|
+
var datumLabel = datumKey.join(' ') || '';
|
|
57
|
+
|
|
58
|
+
// if (categoryLabel && datumLabel) {
|
|
59
|
+
// return `${categoryLabel} - ${datumLabel}`;
|
|
60
|
+
// }
|
|
61
|
+
return categoryLabel || datumLabel || ' ';
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Builds axis title from row and column titles
|
|
66
|
+
*/
|
|
67
|
+
function buildAxisTitle(categoryTitle, datumTitle) {
|
|
68
|
+
var defaultTitle = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'Categories';
|
|
69
|
+
|
|
70
|
+
if (categoryTitle && datumTitle) {
|
|
71
|
+
return categoryTitle + ' - ' + datumTitle;
|
|
72
|
+
}
|
|
73
|
+
return categoryTitle || datumTitle || defaultTitle;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Collects aggregation values and labels across all categories
|
|
78
|
+
*/
|
|
79
|
+
function collectAggregationData(pivotData, categoryKeys, datumKeys, aggregationKey) {
|
|
80
|
+
var values = [];
|
|
81
|
+
var labels = [];
|
|
82
|
+
|
|
83
|
+
var _iteratorNormalCompletion = true;
|
|
84
|
+
var _didIteratorError = false;
|
|
85
|
+
var _iteratorError = undefined;
|
|
86
|
+
|
|
87
|
+
try {
|
|
88
|
+
for (var _iterator = categoryKeys[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
|
|
89
|
+
var categoryKey = _step.value;
|
|
90
|
+
var _iteratorNormalCompletion2 = true;
|
|
91
|
+
var _didIteratorError2 = false;
|
|
92
|
+
var _iteratorError2 = undefined;
|
|
93
|
+
|
|
94
|
+
try {
|
|
95
|
+
for (var _iterator2 = datumKeys[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
|
|
96
|
+
var datumKey = _step2.value;
|
|
97
|
+
|
|
98
|
+
var val = parseFloat(pivotData.getAggregator(categoryKey, datumKey, aggregationKey).value());
|
|
99
|
+
values.push(isFinite(val) ? val : null);
|
|
100
|
+
labels.push(combineCategoryLabels(categoryKey, datumKey));
|
|
101
|
+
}
|
|
102
|
+
} catch (err) {
|
|
103
|
+
_didIteratorError2 = true;
|
|
104
|
+
_iteratorError2 = err;
|
|
105
|
+
} finally {
|
|
106
|
+
try {
|
|
107
|
+
if (!_iteratorNormalCompletion2 && _iterator2.return) {
|
|
108
|
+
_iterator2.return();
|
|
109
|
+
}
|
|
110
|
+
} finally {
|
|
111
|
+
if (_didIteratorError2) {
|
|
112
|
+
throw _iteratorError2;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
} catch (err) {
|
|
118
|
+
_didIteratorError = true;
|
|
119
|
+
_iteratorError = err;
|
|
120
|
+
} finally {
|
|
121
|
+
try {
|
|
122
|
+
if (!_iteratorNormalCompletion && _iterator.return) {
|
|
123
|
+
_iterator.return();
|
|
124
|
+
}
|
|
125
|
+
} finally {
|
|
126
|
+
if (_didIteratorError) {
|
|
127
|
+
throw _iteratorError;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return { values: values, labels: labels };
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Calculates chart dimensions
|
|
137
|
+
*/
|
|
138
|
+
function getChartDimensions() {
|
|
139
|
+
var rowMultiplier = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1;
|
|
140
|
+
|
|
141
|
+
return {
|
|
142
|
+
width: window.innerWidth / CHART_WIDTH_RATIO,
|
|
143
|
+
height: (window.innerHeight / CHART_HEIGHT_RATIO - CHART_HEIGHT_OFFSET) * rowMultiplier
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Creates common renderer props
|
|
149
|
+
*/
|
|
150
|
+
function createRendererProps() {
|
|
151
|
+
return {
|
|
152
|
+
defaultProps: Object.assign({}, _Utilities.PivotData.defaultProps, {
|
|
153
|
+
plotlyOptions: {},
|
|
154
|
+
plotlyConfig: {}
|
|
155
|
+
}),
|
|
156
|
+
propTypes: Object.assign({}, _Utilities.PivotData.propTypes, {
|
|
157
|
+
plotlyOptions: _propTypes2.default.object,
|
|
158
|
+
plotlyConfig: _propTypes2.default.object,
|
|
159
|
+
onRendererUpdate: _propTypes2.default.func
|
|
160
|
+
})
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Determines chart rendering strategy based on trace options
|
|
166
|
+
*/
|
|
167
|
+
function getChartRenderingStrategy(traceOptions) {
|
|
168
|
+
if (traceOptions.type === 'pie') {
|
|
169
|
+
return 'pie-totals';
|
|
170
|
+
}
|
|
171
|
+
if (traceOptions.mode && traceOptions.mode.includes('lines')) {
|
|
172
|
+
return 'category-data';
|
|
173
|
+
}
|
|
174
|
+
// Bar, area, scatter charts also need category data
|
|
175
|
+
return 'category-data';
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// ============================================================================
|
|
179
|
+
// Renderer Factory Functions
|
|
180
|
+
// ============================================================================
|
|
181
|
+
|
|
182
|
+
function makeRenderer(PlotlyComponent) {
|
|
183
|
+
var traceOptions = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
184
|
+
var layoutOptions = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
185
|
+
var transpose = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
|
|
186
|
+
|
|
187
|
+
var Renderer = function (_React$PureComponent) {
|
|
188
|
+
_inherits(Renderer, _React$PureComponent);
|
|
189
|
+
|
|
190
|
+
function Renderer() {
|
|
191
|
+
_classCallCheck(this, Renderer);
|
|
192
|
+
|
|
193
|
+
return _possibleConstructorReturn(this, (Renderer.__proto__ || Object.getPrototypeOf(Renderer)).apply(this, arguments));
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
_createClass(Renderer, [{
|
|
197
|
+
key: 'render',
|
|
198
|
+
value: function render() {
|
|
199
|
+
var _this2 = this;
|
|
200
|
+
|
|
201
|
+
var pivotData = new _Utilities.PivotData(this.props);
|
|
202
|
+
var rowKeys = pivotData.getRowKeys();
|
|
203
|
+
var colKeys = pivotData.getColKeys();
|
|
204
|
+
var traceKeys = ensureNonEmptyKeys(transpose ? colKeys : rowKeys);
|
|
205
|
+
var datumKeys = ensureNonEmptyKeys(transpose ? rowKeys : colKeys);
|
|
206
|
+
|
|
207
|
+
var primaryAggregation = pivotData.getPrimaryAggregation();
|
|
208
|
+
var fallbackAggregator = Object.keys(this.props.aggregators)[0] || 'Value';
|
|
209
|
+
var aggregatorName = primaryAggregation && primaryAggregation.aggregatorName || fallbackAggregator;
|
|
210
|
+
var aggregationVals = primaryAggregation && primaryAggregation.vals || [];
|
|
211
|
+
var fullAggName = primaryAggregation && primaryAggregation.label || (aggregationVals.length ? aggregatorName + ' of ' + aggregationVals.join(', ') : aggregatorName);
|
|
212
|
+
|
|
213
|
+
var data = traceKeys.map(function (traceKey) {
|
|
214
|
+
var values = [];
|
|
215
|
+
var labels = [];
|
|
216
|
+
var textValues = [];
|
|
217
|
+
|
|
218
|
+
var _iteratorNormalCompletion3 = true;
|
|
219
|
+
var _didIteratorError3 = false;
|
|
220
|
+
var _iteratorError3 = undefined;
|
|
221
|
+
|
|
222
|
+
try {
|
|
223
|
+
for (var _iterator3 = datumKeys[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
|
|
224
|
+
var datumKey = _step3.value;
|
|
225
|
+
|
|
226
|
+
var aggregator = pivotData.getAggregator(transpose ? datumKey : traceKey, transpose ? traceKey : datumKey);
|
|
227
|
+
var val = parseFloat(aggregator.value());
|
|
228
|
+
// Get cell formatting from plotlyOptions (similar to tableOptions)
|
|
229
|
+
var cellFormatting = _this2.props.plotlyOptions && _this2.props.plotlyOptions.cellFormatting || null;
|
|
230
|
+
|
|
231
|
+
// Apply cell formatting to the formatted value
|
|
232
|
+
var finalFormattedValue = (0, _TableRenderers.applyCellFormatting)(aggregator.value(), cellFormatting, aggregator.format.bind(aggregator), aggregatorName);
|
|
233
|
+
values.push(isFinite(val) ? val : null);
|
|
234
|
+
labels.push(datumKey.join('-') || ' ');
|
|
235
|
+
textValues.push(finalFormattedValue);
|
|
236
|
+
}
|
|
237
|
+
} catch (err) {
|
|
238
|
+
_didIteratorError3 = true;
|
|
239
|
+
_iteratorError3 = err;
|
|
240
|
+
} finally {
|
|
241
|
+
try {
|
|
242
|
+
if (!_iteratorNormalCompletion3 && _iterator3.return) {
|
|
243
|
+
_iterator3.return();
|
|
244
|
+
}
|
|
245
|
+
} finally {
|
|
246
|
+
if (_didIteratorError3) {
|
|
247
|
+
throw _iteratorError3;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
var trace = {
|
|
253
|
+
name: traceKey.join('-') || fullAggName,
|
|
254
|
+
text: textValues
|
|
255
|
+
};
|
|
256
|
+
|
|
257
|
+
if (traceOptions.type === 'pie') {
|
|
258
|
+
trace.values = values;
|
|
259
|
+
trace.labels = labels.length > 1 ? labels : [fullAggName];
|
|
260
|
+
trace.hovertemplate = '<b>%{label}</b><br>' + fullAggName + '<br><b>%{value}</b><extra></extra>';
|
|
261
|
+
trace.textinfo = 'value';
|
|
262
|
+
trace.textposition = 'inside';
|
|
263
|
+
} else {
|
|
264
|
+
trace.x = transpose ? values : labels;
|
|
265
|
+
trace.y = transpose ? labels : values;
|
|
266
|
+
trace.hovertemplate = transpose ? '<b>%{y}</b><br>' + fullAggName + '<br><b>%{x}</b><extra></extra>' : '<b>%{x}</b><br>' + fullAggName + '<br><b>%{y}</b><extra></extra>';
|
|
267
|
+
|
|
268
|
+
// Configure text display based on chart type
|
|
269
|
+
if (traceOptions.type === 'bar') {
|
|
270
|
+
trace.textposition = traceOptions.orientation === 'h' ? 'middle right' : 'outside';
|
|
271
|
+
trace.textmode = 'text';
|
|
272
|
+
} else if (traceOptions.mode && traceOptions.mode.includes('lines')) {
|
|
273
|
+
trace.textposition = 'top center';
|
|
274
|
+
trace.textmode = 'lines+markers+text'; // Show text on markers for line charts
|
|
275
|
+
} else if (traceOptions.mode === 'markers') {
|
|
276
|
+
trace.textposition = 'middle right';
|
|
277
|
+
trace.textmode = 'text+markers'; // Show text with markers
|
|
278
|
+
} else if (traceOptions.stackgroup) {
|
|
279
|
+
trace.textposition = 'middle center';
|
|
280
|
+
trace.textmode = 'text';
|
|
281
|
+
} else {
|
|
282
|
+
trace.textposition = 'outside';
|
|
283
|
+
trace.textmode = 'text';
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
return Object.assign(trace, traceOptions);
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
var titleText = fullAggName;
|
|
291
|
+
var hAxisTitle = transpose ? this.props.rows.join('-') : this.props.cols.join('-');
|
|
292
|
+
var groupByTitle = transpose ? this.props.cols.join('-') : this.props.rows.join('-');
|
|
293
|
+
if (hAxisTitle !== '') {
|
|
294
|
+
titleText += ' vs ' + hAxisTitle;
|
|
295
|
+
}
|
|
296
|
+
if (groupByTitle !== '') {
|
|
297
|
+
titleText += ' by ' + groupByTitle;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
var dimensions = getChartDimensions();
|
|
301
|
+
var layout = {
|
|
302
|
+
title: titleText,
|
|
303
|
+
hovermode: 'closest',
|
|
304
|
+
width: dimensions.width,
|
|
305
|
+
height: dimensions.height
|
|
306
|
+
};
|
|
307
|
+
|
|
308
|
+
if (traceOptions.type === 'pie') {
|
|
309
|
+
var columns = Math.ceil(Math.sqrt(data.length));
|
|
310
|
+
var rows = Math.ceil(data.length / columns);
|
|
311
|
+
layout.grid = { columns: columns, rows: rows };
|
|
312
|
+
data.forEach(function (d, i) {
|
|
313
|
+
d.domain = {
|
|
314
|
+
row: Math.floor(i / columns),
|
|
315
|
+
column: i - columns * Math.floor(i / columns)
|
|
316
|
+
};
|
|
317
|
+
if (data.length > 1) {
|
|
318
|
+
d.title = d.name;
|
|
319
|
+
}
|
|
320
|
+
});
|
|
321
|
+
if (data[0].labels.length === 1) {
|
|
322
|
+
layout.showlegend = false;
|
|
323
|
+
}
|
|
324
|
+
} else {
|
|
325
|
+
layout.xaxis = {
|
|
326
|
+
title: transpose ? fullAggName : null,
|
|
327
|
+
automargin: true
|
|
328
|
+
};
|
|
329
|
+
layout.yaxis = {
|
|
330
|
+
title: transpose ? null : fullAggName,
|
|
331
|
+
automargin: true
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
return _react2.default.createElement(PlotlyComponent, {
|
|
336
|
+
data: data,
|
|
337
|
+
layout: Object.assign(layout, layoutOptions, this.props.plotlyOptions),
|
|
338
|
+
config: this.props.plotlyConfig,
|
|
339
|
+
onUpdate: this.props.onRendererUpdate
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
}]);
|
|
343
|
+
|
|
344
|
+
return Renderer;
|
|
345
|
+
}(_react2.default.PureComponent);
|
|
346
|
+
|
|
347
|
+
var rendererProps = createRendererProps();
|
|
348
|
+
Renderer.defaultProps = rendererProps.defaultProps;
|
|
349
|
+
Renderer.propTypes = rendererProps.propTypes;
|
|
350
|
+
|
|
351
|
+
return Renderer;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
/**
|
|
355
|
+
* Creates a pie chart trace showing category-level breakdown for a single aggregation
|
|
356
|
+
*/
|
|
357
|
+
function createPieCategoryTrace(pivotData, aggregation, categoryKeys, datumKeys, subplotIndex, traceOptions) {
|
|
358
|
+
var cellFormatting = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : null;
|
|
359
|
+
|
|
360
|
+
var values = [];
|
|
361
|
+
var labels = [];
|
|
362
|
+
|
|
363
|
+
var _iteratorNormalCompletion4 = true;
|
|
364
|
+
var _didIteratorError4 = false;
|
|
365
|
+
var _iteratorError4 = undefined;
|
|
366
|
+
|
|
367
|
+
try {
|
|
368
|
+
for (var _iterator4 = categoryKeys[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) {
|
|
369
|
+
var categoryKey = _step4.value;
|
|
370
|
+
var _iteratorNormalCompletion6 = true;
|
|
371
|
+
var _didIteratorError6 = false;
|
|
372
|
+
var _iteratorError6 = undefined;
|
|
373
|
+
|
|
374
|
+
try {
|
|
375
|
+
for (var _iterator6 = datumKeys[Symbol.iterator](), _step6; !(_iteratorNormalCompletion6 = (_step6 = _iterator6.next()).done); _iteratorNormalCompletion6 = true) {
|
|
376
|
+
var datumKey = _step6.value;
|
|
377
|
+
|
|
378
|
+
var aggregator = pivotData.getAggregator(categoryKey, datumKey, aggregation.key);
|
|
379
|
+
var val = parseFloat(aggregator.value());
|
|
380
|
+
if (isFinite(val) && val !== null) {
|
|
381
|
+
values.push(val);
|
|
382
|
+
labels.push(combineCategoryLabels(categoryKey, datumKey));
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
} catch (err) {
|
|
386
|
+
_didIteratorError6 = true;
|
|
387
|
+
_iteratorError6 = err;
|
|
388
|
+
} finally {
|
|
389
|
+
try {
|
|
390
|
+
if (!_iteratorNormalCompletion6 && _iterator6.return) {
|
|
391
|
+
_iterator6.return();
|
|
392
|
+
}
|
|
393
|
+
} finally {
|
|
394
|
+
if (_didIteratorError6) {
|
|
395
|
+
throw _iteratorError6;
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
} catch (err) {
|
|
401
|
+
_didIteratorError4 = true;
|
|
402
|
+
_iteratorError4 = err;
|
|
403
|
+
} finally {
|
|
404
|
+
try {
|
|
405
|
+
if (!_iteratorNormalCompletion4 && _iterator4.return) {
|
|
406
|
+
_iterator4.return();
|
|
407
|
+
}
|
|
408
|
+
} finally {
|
|
409
|
+
if (_didIteratorError4) {
|
|
410
|
+
throw _iteratorError4;
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
var textValues = [];
|
|
416
|
+
var _iteratorNormalCompletion5 = true;
|
|
417
|
+
var _didIteratorError5 = false;
|
|
418
|
+
var _iteratorError5 = undefined;
|
|
419
|
+
|
|
420
|
+
try {
|
|
421
|
+
for (var _iterator5 = categoryKeys[Symbol.iterator](), _step5; !(_iteratorNormalCompletion5 = (_step5 = _iterator5.next()).done); _iteratorNormalCompletion5 = true) {
|
|
422
|
+
var _categoryKey = _step5.value;
|
|
423
|
+
var _iteratorNormalCompletion7 = true;
|
|
424
|
+
var _didIteratorError7 = false;
|
|
425
|
+
var _iteratorError7 = undefined;
|
|
426
|
+
|
|
427
|
+
try {
|
|
428
|
+
for (var _iterator7 = datumKeys[Symbol.iterator](), _step7; !(_iteratorNormalCompletion7 = (_step7 = _iterator7.next()).done); _iteratorNormalCompletion7 = true) {
|
|
429
|
+
var _datumKey = _step7.value;
|
|
430
|
+
|
|
431
|
+
var _aggregator = pivotData.getAggregator(_categoryKey, _datumKey, aggregation.key);
|
|
432
|
+
|
|
433
|
+
var finalFormattedValue = (0, _TableRenderers.applyCellFormatting)(_aggregator.value(), cellFormatting, _aggregator.format.bind(_aggregator), aggregation.aggregatorName);
|
|
434
|
+
|
|
435
|
+
textValues.push(finalFormattedValue);
|
|
436
|
+
}
|
|
437
|
+
} catch (err) {
|
|
438
|
+
_didIteratorError7 = true;
|
|
439
|
+
_iteratorError7 = err;
|
|
440
|
+
} finally {
|
|
441
|
+
try {
|
|
442
|
+
if (!_iteratorNormalCompletion7 && _iterator7.return) {
|
|
443
|
+
_iterator7.return();
|
|
444
|
+
}
|
|
445
|
+
} finally {
|
|
446
|
+
if (_didIteratorError7) {
|
|
447
|
+
throw _iteratorError7;
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
} catch (err) {
|
|
453
|
+
_didIteratorError5 = true;
|
|
454
|
+
_iteratorError5 = err;
|
|
455
|
+
} finally {
|
|
456
|
+
try {
|
|
457
|
+
if (!_iteratorNormalCompletion5 && _iterator5.return) {
|
|
458
|
+
_iterator5.return();
|
|
459
|
+
}
|
|
460
|
+
} finally {
|
|
461
|
+
if (_didIteratorError5) {
|
|
462
|
+
throw _iteratorError5;
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
var trace = {
|
|
468
|
+
name: aggregation.label || aggregation.key,
|
|
469
|
+
values: values.length > 0 ? values : [0],
|
|
470
|
+
labels: labels.length > 0 ? labels : ['No Data'],
|
|
471
|
+
text: textValues.length > 0 ? textValues : ['No Data'],
|
|
472
|
+
title: {
|
|
473
|
+
text: aggregation.label || aggregation.key
|
|
474
|
+
},
|
|
475
|
+
hovertemplate: '<b>%{label}</b><br>' + (aggregation.label || aggregation.key) + '<br><b>%{text}</b><extra></extra>'
|
|
476
|
+
};
|
|
477
|
+
|
|
478
|
+
var mergedTrace = Object.assign({}, traceOptions, trace);
|
|
479
|
+
mergedTrace.textinfo = 'text';
|
|
480
|
+
mergedTrace.textposition = 'inside';
|
|
481
|
+
|
|
482
|
+
return mergedTrace;
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
/**
|
|
486
|
+
* Creates traces for charts showing category-level data
|
|
487
|
+
*/
|
|
488
|
+
function createCategoryDataTraces(pivotData, aggregations, categoryKeys, datumKeys, groupIndex, traceOptions, plotlyOptions) {
|
|
489
|
+
var traces = [];
|
|
490
|
+
|
|
491
|
+
aggregations.forEach(function (aggregation) {
|
|
492
|
+
var _collectAggregationDa = collectAggregationData(pivotData, categoryKeys, datumKeys, aggregation.key),
|
|
493
|
+
values = _collectAggregationDa.values,
|
|
494
|
+
labels = _collectAggregationDa.labels;
|
|
495
|
+
|
|
496
|
+
// Get formatted text values for display
|
|
497
|
+
|
|
498
|
+
|
|
499
|
+
var textValues = [];
|
|
500
|
+
var _iteratorNormalCompletion8 = true;
|
|
501
|
+
var _didIteratorError8 = false;
|
|
502
|
+
var _iteratorError8 = undefined;
|
|
503
|
+
|
|
504
|
+
try {
|
|
505
|
+
for (var _iterator8 = categoryKeys[Symbol.iterator](), _step8; !(_iteratorNormalCompletion8 = (_step8 = _iterator8.next()).done); _iteratorNormalCompletion8 = true) {
|
|
506
|
+
var categoryKey = _step8.value;
|
|
507
|
+
var _iteratorNormalCompletion9 = true;
|
|
508
|
+
var _didIteratorError9 = false;
|
|
509
|
+
var _iteratorError9 = undefined;
|
|
510
|
+
|
|
511
|
+
try {
|
|
512
|
+
for (var _iterator9 = datumKeys[Symbol.iterator](), _step9; !(_iteratorNormalCompletion9 = (_step9 = _iterator9.next()).done); _iteratorNormalCompletion9 = true) {
|
|
513
|
+
var datumKey = _step9.value;
|
|
514
|
+
|
|
515
|
+
var aggregator = pivotData.getAggregator(categoryKey, datumKey, aggregation.key);
|
|
516
|
+
var finalFormattedValue = (0, _TableRenderers.applyCellFormatting)(aggregator.value(), plotlyOptions && plotlyOptions.cellFormatting, aggregator.format.bind(aggregator), aggregation.aggregatorName);
|
|
517
|
+
textValues.push(finalFormattedValue);
|
|
518
|
+
}
|
|
519
|
+
} catch (err) {
|
|
520
|
+
_didIteratorError9 = true;
|
|
521
|
+
_iteratorError9 = err;
|
|
522
|
+
} finally {
|
|
523
|
+
try {
|
|
524
|
+
if (!_iteratorNormalCompletion9 && _iterator9.return) {
|
|
525
|
+
_iterator9.return();
|
|
526
|
+
}
|
|
527
|
+
} finally {
|
|
528
|
+
if (_didIteratorError9) {
|
|
529
|
+
throw _iteratorError9;
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
} catch (err) {
|
|
535
|
+
_didIteratorError8 = true;
|
|
536
|
+
_iteratorError8 = err;
|
|
537
|
+
} finally {
|
|
538
|
+
try {
|
|
539
|
+
if (!_iteratorNormalCompletion8 && _iterator8.return) {
|
|
540
|
+
_iterator8.return();
|
|
541
|
+
}
|
|
542
|
+
} finally {
|
|
543
|
+
if (_didIteratorError8) {
|
|
544
|
+
throw _iteratorError8;
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
var trace = {
|
|
550
|
+
name: aggregation.label || aggregation.key,
|
|
551
|
+
xaxis: 'x' + (groupIndex + 1),
|
|
552
|
+
yaxis: 'y' + (groupIndex + 1),
|
|
553
|
+
x: labels,
|
|
554
|
+
y: values,
|
|
555
|
+
text: textValues,
|
|
556
|
+
hovertemplate: '<b>%{x}</b><br>' + (aggregation.label || aggregation.key) + '<br><b>%{text}</b><extra></extra>'
|
|
557
|
+
};
|
|
558
|
+
|
|
559
|
+
if (plotlyOptions && plotlyOptions.displayText) {
|
|
560
|
+
|
|
561
|
+
if (traceOptions.type === 'bar') {
|
|
562
|
+
trace.textposition = traceOptions.orientation === 'h' ? 'middle right' : 'outside';
|
|
563
|
+
traceOptions.mode = 'text';
|
|
564
|
+
} else if (traceOptions.mode && traceOptions.mode.includes('lines')) {
|
|
565
|
+
trace.textposition = 'top';
|
|
566
|
+
traceOptions.mode = 'lines+markers+text';
|
|
567
|
+
} else if (traceOptions.mode && traceOptions.mode.includes('markers')) {
|
|
568
|
+
trace.textposition = 'top center';
|
|
569
|
+
traceOptions.mode = 'markers+text';
|
|
570
|
+
} else {
|
|
571
|
+
trace.textposition = 'top center';
|
|
572
|
+
traceOptions.mode = 'text';
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
traces.push(Object.assign(trace, traceOptions));
|
|
577
|
+
});
|
|
578
|
+
|
|
579
|
+
return traces;
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
/**
|
|
583
|
+
* Creates axis configuration for a subplot group
|
|
584
|
+
*/
|
|
585
|
+
function createGroupedSubplotAxes(groupIndex, aggregations, rowsTitle, colsTitle) {
|
|
586
|
+
var _ref;
|
|
587
|
+
|
|
588
|
+
var showXAxisTitle = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : true;
|
|
589
|
+
|
|
590
|
+
var primaryAgg = aggregations[0];
|
|
591
|
+
var aggName = primaryAgg.aggregatorName;
|
|
592
|
+
var xAxisTitle = showXAxisTitle ? buildAxisTitle(rowsTitle, colsTitle) : null;
|
|
593
|
+
|
|
594
|
+
return _ref = {}, _defineProperty(_ref, 'xaxis' + (groupIndex + 1), {
|
|
595
|
+
title: xAxisTitle,
|
|
596
|
+
showticklabels: false,
|
|
597
|
+
automargin: true
|
|
598
|
+
}), _defineProperty(_ref, 'yaxis' + (groupIndex + 1), {
|
|
599
|
+
title: aggName,
|
|
600
|
+
automargin: true
|
|
601
|
+
}), _ref;
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
function makeGroupedRenderer(PlotlyComponent) {
|
|
605
|
+
var traceOptions = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
606
|
+
var layoutOptions = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
607
|
+
|
|
608
|
+
var Renderer = function (_React$PureComponent2) {
|
|
609
|
+
_inherits(Renderer, _React$PureComponent2);
|
|
610
|
+
|
|
611
|
+
function Renderer() {
|
|
612
|
+
_classCallCheck(this, Renderer);
|
|
613
|
+
|
|
614
|
+
return _possibleConstructorReturn(this, (Renderer.__proto__ || Object.getPrototypeOf(Renderer)).apply(this, arguments));
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
_createClass(Renderer, [{
|
|
618
|
+
key: 'render',
|
|
619
|
+
value: function render() {
|
|
620
|
+
var _this4 = this;
|
|
621
|
+
|
|
622
|
+
var pivotData = new _Utilities.PivotData(this.props);
|
|
623
|
+
var renderingStrategy = getChartRenderingStrategy(traceOptions);
|
|
624
|
+
|
|
625
|
+
// For pie charts, treat each aggregation as a separate subplot
|
|
626
|
+
if (renderingStrategy === 'pie-totals') {
|
|
627
|
+
var allAggregations = pivotData.getAggregations();
|
|
628
|
+
|
|
629
|
+
if (allAggregations.length === 0) {
|
|
630
|
+
return _react2.default.createElement(
|
|
631
|
+
'div',
|
|
632
|
+
null,
|
|
633
|
+
'No aggregations to display'
|
|
634
|
+
);
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
var _rowKeys = pivotData.getRowKeys();
|
|
638
|
+
var _colKeys = pivotData.getColKeys();
|
|
639
|
+
var _categoryKeys = ensureNonEmptyKeys(_rowKeys);
|
|
640
|
+
var _datumKeys = ensureNonEmptyKeys(_colKeys);
|
|
641
|
+
|
|
642
|
+
var _data = [];
|
|
643
|
+
var columns = Math.ceil(Math.sqrt(allAggregations.length));
|
|
644
|
+
var _rows = Math.ceil(allAggregations.length / columns);
|
|
645
|
+
var _dimensions = getChartDimensions(_rows);
|
|
646
|
+
|
|
647
|
+
var _layout = {
|
|
648
|
+
title: 'Aggregations',
|
|
649
|
+
grid: { rows: _rows, columns: columns, pattern: 'independent' },
|
|
650
|
+
width: _dimensions.width,
|
|
651
|
+
height: _dimensions.height,
|
|
652
|
+
showlegend: true,
|
|
653
|
+
hovermode: 'closest'
|
|
654
|
+
};
|
|
655
|
+
|
|
656
|
+
// Create a separate subplot for each aggregation
|
|
657
|
+
allAggregations.forEach(function (aggregation, index) {
|
|
658
|
+
var trace = createPieCategoryTrace(pivotData, aggregation, _categoryKeys, _datumKeys, index, traceOptions, _this4.props.plotlyOptions && _this4.props.plotlyOptions.cellFormatting);
|
|
659
|
+
|
|
660
|
+
trace.domain = {
|
|
661
|
+
row: Math.floor(index / columns),
|
|
662
|
+
column: index % columns
|
|
663
|
+
};
|
|
664
|
+
|
|
665
|
+
_data.push(trace);
|
|
666
|
+
});
|
|
667
|
+
|
|
668
|
+
return _react2.default.createElement(PlotlyComponent, {
|
|
669
|
+
data: _data,
|
|
670
|
+
layout: Object.assign(_layout, layoutOptions, this.props.plotlyOptions),
|
|
671
|
+
config: this.props.plotlyConfig,
|
|
672
|
+
onUpdate: this.props.onRendererUpdate
|
|
673
|
+
});
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
// For non-pie charts, group by aggregation type
|
|
677
|
+
var groupedAggregations = pivotData.groupAggregationsByType();
|
|
678
|
+
var groupNames = Object.keys(groupedAggregations);
|
|
679
|
+
|
|
680
|
+
if (groupNames.length === 0) {
|
|
681
|
+
return _react2.default.createElement(
|
|
682
|
+
'div',
|
|
683
|
+
null,
|
|
684
|
+
'No aggregations to display'
|
|
685
|
+
);
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
var rows = groupNames.length;
|
|
689
|
+
|
|
690
|
+
var data = [];
|
|
691
|
+
var dimensions = getChartDimensions(rows);
|
|
692
|
+
var layout = {
|
|
693
|
+
title: 'Grouped Aggregations by Type',
|
|
694
|
+
grid: { rows: rows, columns: 1, pattern: 'independent' },
|
|
695
|
+
width: dimensions.width,
|
|
696
|
+
height: dimensions.height,
|
|
697
|
+
hovermode: 'closest'
|
|
698
|
+
};
|
|
699
|
+
|
|
700
|
+
var rowKeys = pivotData.getRowKeys();
|
|
701
|
+
var colKeys = pivotData.getColKeys();
|
|
702
|
+
var categoryKeys = ensureNonEmptyKeys(rowKeys);
|
|
703
|
+
var datumKeys = ensureNonEmptyKeys(colKeys);
|
|
704
|
+
|
|
705
|
+
groupNames.forEach(function (groupName, groupIndex) {
|
|
706
|
+
var aggregations = groupedAggregations[groupName];
|
|
707
|
+
|
|
708
|
+
var traces = createCategoryDataTraces(pivotData, aggregations, categoryKeys, datumKeys, groupIndex, traceOptions, _this4.props.plotlyOptions);
|
|
709
|
+
data.push.apply(data, _toConsumableArray(traces));
|
|
710
|
+
|
|
711
|
+
Object.assign(layout, createGroupedSubplotAxes(groupIndex, aggregations, _this4.props.rows.join('-'), _this4.props.cols.join('-'), false));
|
|
712
|
+
});
|
|
713
|
+
|
|
714
|
+
return _react2.default.createElement(PlotlyComponent, {
|
|
715
|
+
data: data,
|
|
716
|
+
layout: Object.assign(layout, layoutOptions, this.props.plotlyOptions),
|
|
717
|
+
config: this.props.plotlyConfig,
|
|
718
|
+
onUpdate: this.props.onRendererUpdate
|
|
719
|
+
});
|
|
720
|
+
}
|
|
721
|
+
}]);
|
|
722
|
+
|
|
723
|
+
return Renderer;
|
|
724
|
+
}(_react2.default.PureComponent);
|
|
725
|
+
|
|
726
|
+
var rendererProps = createRendererProps();
|
|
727
|
+
Renderer.defaultProps = rendererProps.defaultProps;
|
|
728
|
+
Renderer.propTypes = rendererProps.propTypes;
|
|
729
|
+
|
|
730
|
+
return Renderer;
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
function makeScatterRenderer(PlotlyComponent) {
|
|
734
|
+
var Renderer = function (_React$PureComponent3) {
|
|
735
|
+
_inherits(Renderer, _React$PureComponent3);
|
|
736
|
+
|
|
737
|
+
function Renderer() {
|
|
738
|
+
_classCallCheck(this, Renderer);
|
|
739
|
+
|
|
740
|
+
return _possibleConstructorReturn(this, (Renderer.__proto__ || Object.getPrototypeOf(Renderer)).apply(this, arguments));
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
_createClass(Renderer, [{
|
|
744
|
+
key: 'render',
|
|
745
|
+
value: function render() {
|
|
746
|
+
var pivotData = new _Utilities.PivotData(this.props);
|
|
747
|
+
var rowKeys = ensureNonEmptyKeys(pivotData.getRowKeys());
|
|
748
|
+
var colKeys = ensureNonEmptyKeys(pivotData.getColKeys());
|
|
749
|
+
|
|
750
|
+
var data = {
|
|
751
|
+
x: [],
|
|
752
|
+
y: [],
|
|
753
|
+
text: [],
|
|
754
|
+
type: 'scatter',
|
|
755
|
+
mode: 'markers+text',
|
|
756
|
+
textposition: 'middle right',
|
|
757
|
+
hovertemplate: '<b>%{x}</b><br>%{y}<br><b>%{text}</b><extra></extra>'
|
|
758
|
+
};
|
|
759
|
+
|
|
760
|
+
// Use forEach instead of map since we're not returning values
|
|
761
|
+
rowKeys.forEach(function (rowKey) {
|
|
762
|
+
colKeys.forEach(function (colKey) {
|
|
763
|
+
var aggregator = pivotData.getAggregator(rowKey, colKey);
|
|
764
|
+
var v = aggregator.value();
|
|
765
|
+
if (v !== null) {
|
|
766
|
+
data.x.push(colKey.join('-'));
|
|
767
|
+
data.y.push(rowKey.join('-'));
|
|
768
|
+
data.text.push(aggregator.format(v));
|
|
769
|
+
}
|
|
770
|
+
});
|
|
771
|
+
});
|
|
772
|
+
|
|
773
|
+
var dimensions = getChartDimensions();
|
|
774
|
+
var layout = {
|
|
775
|
+
title: this.props.rows.join('-') + ' vs ' + this.props.cols.join('-'),
|
|
776
|
+
hovermode: 'closest',
|
|
777
|
+
xaxis: { title: this.props.cols.join('-'), automargin: true },
|
|
778
|
+
yaxis: { title: this.props.rows.join('-'), automargin: true },
|
|
779
|
+
width: dimensions.width,
|
|
780
|
+
height: dimensions.height
|
|
781
|
+
};
|
|
782
|
+
|
|
783
|
+
return _react2.default.createElement(PlotlyComponent, {
|
|
784
|
+
data: [data],
|
|
785
|
+
layout: Object.assign(layout, this.props.plotlyOptions),
|
|
786
|
+
config: this.props.plotlyConfig,
|
|
787
|
+
onUpdate: this.props.onRendererUpdate
|
|
788
|
+
});
|
|
789
|
+
}
|
|
790
|
+
}]);
|
|
791
|
+
|
|
792
|
+
return Renderer;
|
|
793
|
+
}(_react2.default.PureComponent);
|
|
794
|
+
|
|
795
|
+
var rendererProps = createRendererProps();
|
|
796
|
+
Renderer.defaultProps = rendererProps.defaultProps;
|
|
797
|
+
Renderer.propTypes = rendererProps.propTypes;
|
|
798
|
+
|
|
799
|
+
return Renderer;
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
function createPlotlyRenderers(PlotlyComponent) {
|
|
803
|
+
return {
|
|
804
|
+
'Grouped Column Chart': makeRenderer(PlotlyComponent, { type: 'bar' }, { barmode: 'group' }),
|
|
805
|
+
'Stacked Column Chart': makeRenderer(PlotlyComponent, { type: 'bar' }, { barmode: 'relative' }),
|
|
806
|
+
'Grouped Bar Chart': makeRenderer(PlotlyComponent, { type: 'bar', orientation: 'h' }, { barmode: 'group' }, true),
|
|
807
|
+
'Stacked Bar Chart': makeRenderer(PlotlyComponent, { type: 'bar', orientation: 'h' }, { barmode: 'relative' }, true),
|
|
808
|
+
'Line Chart': makeRenderer(PlotlyComponent),
|
|
809
|
+
'Dot Chart': makeRenderer(PlotlyComponent, { mode: 'markers' }, {}, true),
|
|
810
|
+
'Area Chart': makeRenderer(PlotlyComponent, { stackgroup: 1 }),
|
|
811
|
+
'Scatter Chart': makeScatterRenderer(PlotlyComponent),
|
|
812
|
+
'Multiple Pie Chart': makeRenderer(PlotlyComponent, { type: 'pie', scalegroup: 1, hoverinfo: 'label+value', textinfo: 'none' }, {}, true),
|
|
813
|
+
'Grouped Bars by Type': makeGroupedRenderer(PlotlyComponent, { type: 'bar', orientation: 'h' }, { barmode: 'group' }),
|
|
814
|
+
'Grouped Columns by Type': makeGroupedRenderer(PlotlyComponent, { type: 'bar' }, { barmode: 'group' }),
|
|
815
|
+
'Grouped Lines by Type': makeGroupedRenderer(PlotlyComponent, { mode: 'lines+markers' }),
|
|
816
|
+
'Grouped Areas by Type': makeGroupedRenderer(PlotlyComponent, { stackgroup: 1 }),
|
|
817
|
+
'Grouped Scatters by Type': makeGroupedRenderer(PlotlyComponent, { mode: 'markers' }),
|
|
818
|
+
'Grouped Pies by Type': makeGroupedRenderer(PlotlyComponent, { type: 'pie' })
|
|
819
|
+
};
|
|
820
|
+
}
|
|
821
|
+
module.exports = exports['default'];
|
|
822
|
+
//# sourceMappingURL=PlotlyRenderers.js.map
|