sea-chart 2.0.42 → 2.0.44
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/components/color-popover/color-rules/rule-filters/number-input.js +2 -2
- package/dist/components/drill-down-settings/drill-down-fields-popover/index.js +2 -2
- package/dist/components/tooltip/index.js +11 -4
- package/dist/constants/index.js +8 -3
- package/dist/context.js +10 -7
- package/dist/model/base-model.js +4 -0
- package/dist/model/combination.js +4 -0
- package/dist/model/horizontal-bar.js +4 -0
- package/dist/model/horizontal-group-bar.js +5 -1
- package/dist/model/stacked-horizontal-bar.js +4 -0
- package/dist/settings/advance-bar-settings/style-settings.js +24 -7
- package/dist/settings/bar-settings/style-settings.js +24 -7
- package/dist/settings/combination-settings/style-settings.js +35 -10
- package/dist/settings/time-comparison-settings/style-settings.js +24 -7
- package/dist/settings/widgets/axis-title-font-settings/index.js +39 -0
- package/dist/utils/cell-format-utils.js +2 -2
- package/dist/utils/chart-utils/base-utils.js +49 -13
- package/dist/utils/chart-utils/original-data-utils/basic-chart-calculator.js +4 -3
- package/dist/utils/chart-utils/original-data-utils/mirror-calculator.js +3 -3
- package/dist/utils/chart-utils/original-data-utils/pivot-table-calculator.js +2 -2
- package/dist/utils/chart-utils/sql-statistics-utils.js +64 -18
- package/dist/utils/row-record-utils.js +21 -5
- package/dist/utils/sql/column-2-sql-column.js +2 -0
- package/dist/view/index.css +0 -17
- package/dist/view/wrapper/area-group.js +14 -25
- package/dist/view/wrapper/area.js +14 -27
- package/dist/view/wrapper/bar-compare.js +10 -15
- package/dist/view/wrapper/bar-custom-stack.js +19 -81
- package/dist/view/wrapper/bar-group.js +15 -50
- package/dist/view/wrapper/bar-stack.js +12 -40
- package/dist/view/wrapper/bar.js +10 -23
- package/dist/view/wrapper/basic-number-card.js +9 -2
- package/dist/view/wrapper/chart-component.js +461 -76
- package/dist/view/wrapper/combination.js +17 -29
- package/dist/view/wrapper/completeness-group.js +13 -59
- package/dist/view/wrapper/completeness.js +14 -60
- package/dist/view/wrapper/dashboard.js +8 -14
- package/dist/view/wrapper/funnel.js +6 -18
- package/dist/view/wrapper/heat-map.js +80 -50
- package/dist/view/wrapper/horizontal-bar-group.js +14 -25
- package/dist/view/wrapper/horizontal-bar-stack.js +16 -61
- package/dist/view/wrapper/horizontal-bar.js +10 -25
- package/dist/view/wrapper/index.js +3 -0
- package/dist/view/wrapper/line-group.js +11 -21
- package/dist/view/wrapper/line.js +11 -23
- package/dist/view/wrapper/map-bubble.js +9 -14
- package/dist/view/wrapper/map-world-bubble.js +9 -14
- package/dist/view/wrapper/map-world.js +9 -14
- package/dist/view/wrapper/map.js +9 -13
- package/dist/view/wrapper/mirror.js +7 -20
- package/dist/view/wrapper/pie.js +9 -12
- package/dist/view/wrapper/ring.js +10 -13
- package/dist/view/wrapper/scatter.js +13 -23
- package/dist/view/wrapper/table/pivot-table-display-name.js +2 -2
- package/dist/view/wrapper/table-element/components/formatter.js +2 -2
- package/dist/view/wrapper/table-element/components/records-body.js +8 -2
- package/dist/view/wrapper/table-element/components/records.js +2 -4
- package/dist/view/wrapper/treemap.js +8 -18
- package/dist/view/wrapper/trend.js +3 -2
- package/package.json +2 -2
|
@@ -4,7 +4,7 @@ import * as d3 from 'd3';
|
|
|
4
4
|
import { cloneDeep, debounce } from 'lodash-es';
|
|
5
5
|
import { getTableById, getTableColumnByKey } from 'dtable-utils';
|
|
6
6
|
import { BaseUtils, formatXAxisLabel } from '../../utils';
|
|
7
|
-
import { CHART_TYPE, CHART_SUMMARY_TYPE, LABEL_POSITION_TYPE, CHART_THEME_COLOR, EMPTY_NAME, THEME_NAME_MAP, CHART_STYLE_COLORS } from '../../constants';
|
|
7
|
+
import { CHART_TYPE, CHART_SUMMARY_TYPE, LABEL_POSITION_TYPE, CHART_THEME_COLOR, EMPTY_NAME, THEME_NAME_MAP, CHART_STYLE_COLORS, DEFAULT_AXIS_LABEL_FONT_COLOR, DEFAULT_AXIS_LABEL_FONT_COLOR_DARK, DEFAULT_AXIS_LABEL_FONT_SIZE } from '../../constants';
|
|
8
8
|
import { FILL_BORDER_COLOR_MAP } from '../../constants/style';
|
|
9
9
|
import intl from '../../intl';
|
|
10
10
|
import '../../assets/css/sea-chart-d3-tooltip.css';
|
|
@@ -25,12 +25,23 @@ export default class ChartComponent extends Component {
|
|
|
25
25
|
this.destroyChart();
|
|
26
26
|
this.createChart();
|
|
27
27
|
this.drawChart();
|
|
28
|
-
if (this.needRenderAxisLabel) {
|
|
29
|
-
this.renderAxisLabel(this.props.chart, this.props.tables);
|
|
30
|
-
}
|
|
31
28
|
}, 300);
|
|
32
29
|
this.destroyChart = () => {
|
|
33
30
|
this.chart && this.chart.node() && this.chart.node().remove();
|
|
31
|
+
this.container && this.setAxisTitlePadding(this.container, {
|
|
32
|
+
left: null,
|
|
33
|
+
bottom: null,
|
|
34
|
+
right: null
|
|
35
|
+
});
|
|
36
|
+
this._clipMaskByRect.clear();
|
|
37
|
+
this._defs = null;
|
|
38
|
+
};
|
|
39
|
+
this.toggleRecords = function (statisticRecord) {
|
|
40
|
+
if (!statisticRecord) return;
|
|
41
|
+
for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
|
|
42
|
+
args[_key - 1] = arguments[_key];
|
|
43
|
+
}
|
|
44
|
+
_this.props.toggleRecords && _this.props.toggleRecords(statisticRecord, ...args);
|
|
34
45
|
};
|
|
35
46
|
this.getTitle = (tables, table_id, yAxisType, yAxisKey) => {
|
|
36
47
|
return yAxisType === CHART_SUMMARY_TYPE.COUNT ? intl.get('Amount') : this.getAxisLabel(tables, table_id, yAxisKey);
|
|
@@ -44,6 +55,30 @@ export default class ChartComponent extends Component {
|
|
|
44
55
|
const column = this.getColumn(tables, tableId, columnKey);
|
|
45
56
|
return column.name || '';
|
|
46
57
|
};
|
|
58
|
+
this.getAxisTitleHeight = fontSize => {
|
|
59
|
+
const safeFontSize = Number(fontSize) || DEFAULT_AXIS_LABEL_FONT_SIZE;
|
|
60
|
+
return Math.max(this.axisTitleMinHeight, safeFontSize + 4);
|
|
61
|
+
};
|
|
62
|
+
this.setAxisTitlePadding = function (chartContainer) {
|
|
63
|
+
let {
|
|
64
|
+
left = null,
|
|
65
|
+
bottom = null,
|
|
66
|
+
right = null
|
|
67
|
+
} = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
68
|
+
if (!chartContainer) return;
|
|
69
|
+
chartContainer.style.paddingLeft = left != null ? `${left}px` : '';
|
|
70
|
+
chartContainer.style.paddingBottom = bottom != null ? `${bottom}px` : '';
|
|
71
|
+
chartContainer.style.paddingRight = right != null ? `${right}px` : '';
|
|
72
|
+
};
|
|
73
|
+
this.getRotatedAxisTitleTransform = function (containerHeight, titleHeight) {
|
|
74
|
+
let placement = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'left';
|
|
75
|
+
const translateX = containerHeight / 2 - titleHeight / 2;
|
|
76
|
+
const translateY = containerHeight / 2 - titleHeight / 2;
|
|
77
|
+
if (placement === 'right') {
|
|
78
|
+
return `translate(${translateX}px, ${translateY}px) rotate(-90deg)`;
|
|
79
|
+
}
|
|
80
|
+
return `translate(-${translateX}px, ${translateY}px) rotate(-90deg)`;
|
|
81
|
+
};
|
|
47
82
|
this.initChart = function (container, id) {
|
|
48
83
|
let initConfig = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
49
84
|
const {
|
|
@@ -61,6 +96,8 @@ export default class ChartComponent extends Component {
|
|
|
61
96
|
const height = customHeight ? customHeight : containerHeight - marginBottom;
|
|
62
97
|
_this.chart = d3.create('svg').attr('id', id).attr('width', width).attr('height', height).attr('viewBox', [0, 0, width, height]);
|
|
63
98
|
_this.container.appendChild(_this.chart.node());
|
|
99
|
+
_this._defs = null;
|
|
100
|
+
_this._clipMaskByRect = new Map();
|
|
64
101
|
_this.chartBoundingClientRect = {
|
|
65
102
|
...JSON.parse(JSON.stringify(_this.chart.node().getBoundingClientRect())),
|
|
66
103
|
...initConfig,
|
|
@@ -68,6 +105,12 @@ export default class ChartComponent extends Component {
|
|
|
68
105
|
height
|
|
69
106
|
};
|
|
70
107
|
};
|
|
108
|
+
this.getDefs = () => {
|
|
109
|
+
if (!this._defs || !this._defs.node() || !this._defs.node().isConnected) {
|
|
110
|
+
this._defs = this.chart.append('defs').attr('class', 'sea-chart-defs');
|
|
111
|
+
}
|
|
112
|
+
return this._defs;
|
|
113
|
+
};
|
|
71
114
|
this.initDefs = () => {
|
|
72
115
|
if (this.container) {
|
|
73
116
|
// add Mask
|
|
@@ -222,23 +265,38 @@ export default class ChartComponent extends Component {
|
|
|
222
265
|
y_axis_summary_type,
|
|
223
266
|
type,
|
|
224
267
|
title_name,
|
|
268
|
+
x_axis_label_font_size,
|
|
269
|
+
x_axis_label_font_color,
|
|
270
|
+
y_axis_label_font_size,
|
|
271
|
+
y_axis_label_font_color,
|
|
225
272
|
// left axis - combination chart
|
|
226
273
|
show_y_axis_left_label,
|
|
227
274
|
y_axis_left_label_position,
|
|
228
275
|
y_axis_left_summary_type,
|
|
229
276
|
y_axis_left_summary_column,
|
|
277
|
+
y_axis_left_label_font_size,
|
|
278
|
+
y_axis_left_label_font_color,
|
|
230
279
|
// right axis - combination chart
|
|
231
280
|
show_y_axis_right_label,
|
|
232
281
|
y_axis_right_label_position,
|
|
233
282
|
y_axis_right_summary_type,
|
|
234
|
-
y_axis_right_summary_column
|
|
283
|
+
y_axis_right_summary_column,
|
|
284
|
+
y_axis_right_label_font_size,
|
|
285
|
+
y_axis_right_label_font_color
|
|
235
286
|
} = chart.config;
|
|
236
287
|
if (y_axis_summary_column_key) {
|
|
237
288
|
y_axis_column_key = y_axis_summary_column_key;
|
|
238
289
|
}
|
|
239
290
|
const table = getTableById(tables, table_id);
|
|
240
|
-
|
|
241
|
-
|
|
291
|
+
const defaultTextColor = this.globalTheme === THEME_NAME_MAP.DARK ? DEFAULT_AXIS_LABEL_FONT_COLOR_DARK : DEFAULT_AXIS_LABEL_FONT_COLOR;
|
|
292
|
+
const xColor = x_axis_label_font_color || defaultTextColor;
|
|
293
|
+
const xFontSize = x_axis_label_font_size || DEFAULT_AXIS_LABEL_FONT_SIZE;
|
|
294
|
+
const yColor = y_axis_label_font_color || defaultTextColor;
|
|
295
|
+
const yFontSize = y_axis_label_font_size || DEFAULT_AXIS_LABEL_FONT_SIZE;
|
|
296
|
+
const yLeftColor = y_axis_left_label_font_color || defaultTextColor;
|
|
297
|
+
const yLeftFontSize = y_axis_left_label_font_size || DEFAULT_AXIS_LABEL_FONT_SIZE;
|
|
298
|
+
const yRightColor = y_axis_right_label_font_color || defaultTextColor;
|
|
299
|
+
const yRightFontSize = y_axis_right_label_font_size || DEFAULT_AXIS_LABEL_FONT_SIZE;
|
|
242
300
|
|
|
243
301
|
// xAxis
|
|
244
302
|
const xAxisID = `chart-x-axis-label_${chart.id}`;
|
|
@@ -246,17 +304,18 @@ export default class ChartComponent extends Component {
|
|
|
246
304
|
const {
|
|
247
305
|
width: containerWidth
|
|
248
306
|
} = this.chartBoundingClientRect;
|
|
307
|
+
const xTitleHeight = this.getAxisTitleHeight(xFontSize);
|
|
249
308
|
if (!xLabel && x_axis_show_label) {
|
|
250
309
|
const div = document.createElement('div');
|
|
251
310
|
div.id = xAxisID;
|
|
252
311
|
div.className = 'chart-axis-label';
|
|
253
312
|
const column = getTableColumnByKey(table, x_axis_column_key);
|
|
254
313
|
div.innerHTML = `${column ? column.name : ''}`;
|
|
255
|
-
div.setAttribute('style', `color:${
|
|
314
|
+
div.setAttribute('style', `color:${xColor}; font-size:${xFontSize}px; width: ${containerWidth}px; height: ${xTitleHeight}px; line-height: ${xTitleHeight}px; text-align: ${x_axis_label_position}; position: absolute; bottom: 0;`);
|
|
256
315
|
chartContainer.appendChild(div);
|
|
257
316
|
}
|
|
258
317
|
if (xLabel && x_axis_show_label) {
|
|
259
|
-
xLabel.setAttribute('style', `color:${
|
|
318
|
+
xLabel.setAttribute('style', `color:${xColor}; font-size:${xFontSize}px; width: ${containerWidth}px; height: ${xTitleHeight}px; line-height: ${xTitleHeight}px; text-align: ${x_axis_label_position}; position: absolute; bottom: 0;`);
|
|
260
319
|
}
|
|
261
320
|
if (xLabel && !x_axis_show_label) {
|
|
262
321
|
xLabel.parentNode.removeChild(xLabel);
|
|
@@ -265,7 +324,7 @@ export default class ChartComponent extends Component {
|
|
|
265
324
|
// yAxis
|
|
266
325
|
const yAxisID = `chart-y-axis-label_${chart.id}`;
|
|
267
326
|
const yLabel = chartContainer.querySelector(`#${yAxisID}`);
|
|
268
|
-
const
|
|
327
|
+
const yTitleHeight = this.getAxisTitleHeight(yFontSize);
|
|
269
328
|
if (!yLabel && y_axis_show_label) {
|
|
270
329
|
const div = document.createElement('div');
|
|
271
330
|
div.id = yAxisID;
|
|
@@ -286,7 +345,7 @@ export default class ChartComponent extends Component {
|
|
|
286
345
|
let textAlign = 'center';
|
|
287
346
|
if (y_axis_label_position === LABEL_POSITION_TYPE.BOTTOM) textAlign = 'left';
|
|
288
347
|
if (y_axis_label_position === LABEL_POSITION_TYPE.TOP) textAlign = 'right';
|
|
289
|
-
div.setAttribute('style', `color:${
|
|
348
|
+
div.setAttribute('style', `color:${yColor}; font-size:${yFontSize}px; position: absolute; width: ${containerHeight}px; height: ${yTitleHeight}px; line-height: ${yTitleHeight}px; text-align: ${textAlign}; top: 0; left: 0; transform: ${this.getRotatedAxisTitleTransform(containerHeight, yTitleHeight)}`);
|
|
290
349
|
chartContainer.appendChild(div);
|
|
291
350
|
}
|
|
292
351
|
if (yLabel && y_axis_show_label) {
|
|
@@ -296,7 +355,7 @@ export default class ChartComponent extends Component {
|
|
|
296
355
|
let textAlign = 'center';
|
|
297
356
|
if (y_axis_label_position === LABEL_POSITION_TYPE.BOTTOM) textAlign = 'left';
|
|
298
357
|
if (y_axis_label_position === LABEL_POSITION_TYPE.TOP) textAlign = 'right';
|
|
299
|
-
yLabel.setAttribute('style', `color:${
|
|
358
|
+
yLabel.setAttribute('style', `color:${yColor}; font-size:${yFontSize}px; position: absolute; width: ${containerHeight}px; height: ${yTitleHeight}px; line-height: ${yTitleHeight}px; text-align: ${textAlign}; top: 0; left: 0; transform: ${this.getRotatedAxisTitleTransform(containerHeight, yTitleHeight)}`);
|
|
300
359
|
}
|
|
301
360
|
if (yLabel && !y_axis_show_label) {
|
|
302
361
|
yLabel.parentNode.removeChild(yLabel);
|
|
@@ -305,6 +364,7 @@ export default class ChartComponent extends Component {
|
|
|
305
364
|
// yAxis(left) - combination chart
|
|
306
365
|
const yAxisLeftID = `chart-y-axis-left-label_${chart.id}`;
|
|
307
366
|
const yAxisLeftLabel = chartContainer.querySelector(`#${yAxisLeftID}`);
|
|
367
|
+
const yLeftTitleHeight = this.getAxisTitleHeight(yLeftFontSize);
|
|
308
368
|
if (!yAxisLeftLabel && show_y_axis_left_label) {
|
|
309
369
|
const div = document.createElement('div');
|
|
310
370
|
div.id = yAxisLeftID;
|
|
@@ -319,7 +379,7 @@ export default class ChartComponent extends Component {
|
|
|
319
379
|
let textAlign = 'center';
|
|
320
380
|
if (y_axis_left_label_position === LABEL_POSITION_TYPE.BOTTOM) textAlign = 'left';
|
|
321
381
|
if (y_axis_left_label_position === LABEL_POSITION_TYPE.TOP) textAlign = 'right';
|
|
322
|
-
div.setAttribute('style', `color:${
|
|
382
|
+
div.setAttribute('style', `color:${yLeftColor}; font-size:${yLeftFontSize}px; position: absolute; width: ${containerHeight}px; height: ${yLeftTitleHeight}px; line-height: ${yLeftTitleHeight}px; text-align: ${textAlign}; top: 0; left: 0; transform: ${this.getRotatedAxisTitleTransform(containerHeight, yLeftTitleHeight)}`);
|
|
323
383
|
chartContainer.appendChild(div);
|
|
324
384
|
}
|
|
325
385
|
if (yAxisLeftLabel && show_y_axis_left_label) {
|
|
@@ -327,7 +387,7 @@ export default class ChartComponent extends Component {
|
|
|
327
387
|
let textAlign = 'center';
|
|
328
388
|
if (y_axis_left_label_position === 'bottom') textAlign = 'left';
|
|
329
389
|
if (y_axis_left_label_position === 'top') textAlign = 'right';
|
|
330
|
-
yAxisLeftLabel.setAttribute('style', `color:${
|
|
390
|
+
yAxisLeftLabel.setAttribute('style', `color:${yLeftColor}; font-size:${yLeftFontSize}px; position: absolute; width: ${containerHeight}px; height: ${yLeftTitleHeight}px; line-height: ${yLeftTitleHeight}px; text-align: ${textAlign}; top: 0; left: 0; transform: ${this.getRotatedAxisTitleTransform(containerHeight, yLeftTitleHeight)}`);
|
|
331
391
|
}
|
|
332
392
|
if (yAxisLeftLabel && !show_y_axis_left_label) {
|
|
333
393
|
yAxisLeftLabel.parentNode.removeChild(yAxisLeftLabel);
|
|
@@ -336,6 +396,7 @@ export default class ChartComponent extends Component {
|
|
|
336
396
|
// yAxis(right) - combination chart
|
|
337
397
|
const yAxisRightID = `chart-y-axis-right-label_${chart.id}`;
|
|
338
398
|
const yAxisRightLabel = chartContainer.querySelector(`#${yAxisRightID}`);
|
|
399
|
+
const yRightTitleHeight = this.getAxisTitleHeight(yRightFontSize);
|
|
339
400
|
if (!yAxisRightLabel && show_y_axis_right_label) {
|
|
340
401
|
const div = document.createElement('div');
|
|
341
402
|
div.id = yAxisRightID;
|
|
@@ -350,7 +411,7 @@ export default class ChartComponent extends Component {
|
|
|
350
411
|
let textAlign = 'center';
|
|
351
412
|
if (y_axis_right_label_position === LABEL_POSITION_TYPE.BOTTOM) textAlign = 'left';
|
|
352
413
|
if (y_axis_right_label_position === LABEL_POSITION_TYPE.TOP) textAlign = 'right';
|
|
353
|
-
div.setAttribute('style', `color:${
|
|
414
|
+
div.setAttribute('style', `color:${yRightColor}; font-size:${yRightFontSize}px; position: absolute; width: ${containerHeight}px; height: ${yRightTitleHeight}px; line-height: ${yRightTitleHeight}px; text-align: ${textAlign}; top: 0; right: 0; transform: ${this.getRotatedAxisTitleTransform(containerHeight, yRightTitleHeight, 'right')}`);
|
|
354
415
|
chartContainer.appendChild(div);
|
|
355
416
|
}
|
|
356
417
|
if (yAxisRightLabel && show_y_axis_right_label) {
|
|
@@ -358,11 +419,16 @@ export default class ChartComponent extends Component {
|
|
|
358
419
|
let textAlign = 'center';
|
|
359
420
|
if (y_axis_right_label_position === 'bottom') textAlign = 'left';
|
|
360
421
|
if (y_axis_right_label_position === 'top') textAlign = 'right';
|
|
361
|
-
yAxisRightLabel.setAttribute('style', `color:${
|
|
422
|
+
yAxisRightLabel.setAttribute('style', `color:${yRightColor}; font-size:${yRightFontSize}px; position: absolute; width: ${containerHeight}px; height: ${yRightTitleHeight}px; line-height: ${yRightTitleHeight}px; text-align: ${textAlign}; top: 0; right: 0; transform: ${this.getRotatedAxisTitleTransform(containerHeight, yRightTitleHeight, 'right')}`);
|
|
362
423
|
}
|
|
363
424
|
if (yAxisRightLabel && !show_y_axis_right_label) {
|
|
364
425
|
yAxisRightLabel.parentNode.removeChild(yAxisRightLabel);
|
|
365
426
|
}
|
|
427
|
+
this.setAxisTitlePadding(chartContainer, {
|
|
428
|
+
left: y_axis_show_label ? yTitleHeight : show_y_axis_left_label ? yLeftTitleHeight : null,
|
|
429
|
+
right: show_y_axis_right_label ? yRightTitleHeight : null,
|
|
430
|
+
bottom: x_axis_show_label ? xTitleHeight : null
|
|
431
|
+
});
|
|
366
432
|
};
|
|
367
433
|
this.renderHorizontalLabel = (chart, tables, chartContainer) => {
|
|
368
434
|
if (!this.chart || !chart) return;
|
|
@@ -374,15 +440,24 @@ export default class ChartComponent extends Component {
|
|
|
374
440
|
horizontal_axis_label_position,
|
|
375
441
|
vertical_axis_label_position,
|
|
376
442
|
show_vertical_axis_label,
|
|
377
|
-
show_horizontal_axis_label
|
|
443
|
+
show_horizontal_axis_label,
|
|
444
|
+
horizontal_axis_label_font_size,
|
|
445
|
+
horizontal_axis_label_font_color,
|
|
446
|
+
vertical_axis_label_font_size,
|
|
447
|
+
vertical_axis_label_font_color
|
|
378
448
|
} = chart.config;
|
|
379
449
|
const table = getTableById(tables, table_id);
|
|
380
|
-
const
|
|
450
|
+
const defaultTextColor = this.globalTheme === THEME_NAME_MAP.DARK ? DEFAULT_AXIS_LABEL_FONT_COLOR_DARK : DEFAULT_AXIS_LABEL_FONT_COLOR;
|
|
451
|
+
const xColor = horizontal_axis_label_font_color || defaultTextColor;
|
|
452
|
+
const xFontSize = horizontal_axis_label_font_size || DEFAULT_AXIS_LABEL_FONT_SIZE;
|
|
453
|
+
const yColor = vertical_axis_label_font_color || defaultTextColor;
|
|
454
|
+
const yFontSize = vertical_axis_label_font_size || DEFAULT_AXIS_LABEL_FONT_SIZE;
|
|
381
455
|
const xAxisID = `chart-x-axis-label_${chart.id}`;
|
|
382
456
|
const xLabel = chartContainer.querySelector(`#${xAxisID}`);
|
|
383
457
|
const {
|
|
384
458
|
width: containerWidth
|
|
385
459
|
} = this.chartBoundingClientRect;
|
|
460
|
+
const xTitleHeight = this.getAxisTitleHeight(xFontSize);
|
|
386
461
|
if (!xLabel && show_horizontal_axis_label) {
|
|
387
462
|
const div = document.createElement('div');
|
|
388
463
|
div.id = xAxisID;
|
|
@@ -393,18 +468,18 @@ export default class ChartComponent extends Component {
|
|
|
393
468
|
const column = getTableColumnByKey(table, horizontal_axis_column_key);
|
|
394
469
|
div.innerHTML = `${column ? column.name : ''}`;
|
|
395
470
|
}
|
|
396
|
-
div.setAttribute('style', `color:${
|
|
471
|
+
div.setAttribute('style', `color:${xColor}; font-size:${xFontSize}px; width: ${containerWidth}px; height: ${xTitleHeight}px; line-height: ${xTitleHeight}px; text-align: ${horizontal_axis_label_position}; position: absolute`);
|
|
397
472
|
chartContainer.appendChild(div);
|
|
398
473
|
}
|
|
399
474
|
if (xLabel && show_horizontal_axis_label) {
|
|
400
|
-
xLabel.setAttribute('style', `color:${
|
|
475
|
+
xLabel.setAttribute('style', `color:${xColor}; font-size:${xFontSize}px; width: ${containerWidth}px; height: ${xTitleHeight}px; line-height: ${xTitleHeight}px; text-align: ${horizontal_axis_label_position}; position: absolute`);
|
|
401
476
|
}
|
|
402
477
|
if (xLabel && !show_horizontal_axis_label) {
|
|
403
478
|
xLabel.parentNode.removeChild(xLabel);
|
|
404
479
|
}
|
|
405
480
|
const yAxisID = `chart-y-axis-label_${chart.id}`;
|
|
406
481
|
const yLabel = chartContainer.querySelector(`#${yAxisID}`);
|
|
407
|
-
const
|
|
482
|
+
const yTitleHeight = this.getAxisTitleHeight(yFontSize);
|
|
408
483
|
if (!yLabel && show_vertical_axis_label) {
|
|
409
484
|
const div = document.createElement('div');
|
|
410
485
|
div.id = yAxisID;
|
|
@@ -417,30 +492,33 @@ export default class ChartComponent extends Component {
|
|
|
417
492
|
let textAlign = 'center';
|
|
418
493
|
if (vertical_axis_label_position === LABEL_POSITION_TYPE.BOTTOM) textAlign = 'left';
|
|
419
494
|
if (vertical_axis_label_position === LABEL_POSITION_TYPE.TOP) textAlign = 'right';
|
|
420
|
-
div.setAttribute('style', `color:${
|
|
495
|
+
div.setAttribute('style', `color:${yColor}; font-size:${yFontSize}px; position: absolute; width: ${containerHeight}px; height: ${yTitleHeight}px; line-height: ${yTitleHeight}px; text-align: ${textAlign}; top: 0; left: 0; transform: ${this.getRotatedAxisTitleTransform(containerHeight, yTitleHeight)}`);
|
|
421
496
|
chartContainer.appendChild(div);
|
|
422
497
|
}
|
|
423
|
-
if (yLabel &&
|
|
498
|
+
if (yLabel && show_vertical_axis_label) {
|
|
424
499
|
const {
|
|
425
500
|
height: containerHeight
|
|
426
501
|
} = this.chartBoundingClientRect;
|
|
427
502
|
let textAlign = 'center';
|
|
428
503
|
if (vertical_axis_label_position === LABEL_POSITION_TYPE.BOTTOM) textAlign = 'left';
|
|
429
504
|
if (vertical_axis_label_position === LABEL_POSITION_TYPE.TOP) textAlign = 'right';
|
|
430
|
-
yLabel.setAttribute('style', `color:${
|
|
505
|
+
yLabel.setAttribute('style', `color:${yColor}; font-size:${yFontSize}px; position: absolute; width: ${containerHeight}px; height: ${yTitleHeight}px; line-height: ${yTitleHeight}px; text-align: ${textAlign}; top: 0; left: 0; transform: ${this.getRotatedAxisTitleTransform(containerHeight, yTitleHeight)}`);
|
|
431
506
|
}
|
|
432
|
-
if (yLabel && !
|
|
507
|
+
if (yLabel && !show_vertical_axis_label) {
|
|
433
508
|
yLabel.parentNode.removeChild(yLabel);
|
|
434
509
|
}
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
return !!(chart && chart.config && chart.config.show_horizontal_axis_label);
|
|
510
|
+
this.setAxisTitlePadding(chartContainer, {
|
|
511
|
+
left: show_vertical_axis_label ? yTitleHeight : null,
|
|
512
|
+
bottom: show_horizontal_axis_label ? xTitleHeight : null,
|
|
513
|
+
right: null
|
|
514
|
+
});
|
|
441
515
|
};
|
|
442
516
|
this.formatterLegendName = name => {
|
|
443
|
-
if (
|
|
517
|
+
if (typeof name !== 'string') {
|
|
518
|
+
if (!name && typeof name !== 'number') return intl.get(EMPTY_NAME);
|
|
519
|
+
return intl.get(String(name)) || String(name);
|
|
520
|
+
}
|
|
521
|
+
if (name.trim() === 'undefined' || name.trim() === 'null' || name.trim() === '') {
|
|
444
522
|
return intl.get(EMPTY_NAME);
|
|
445
523
|
} else if (name === '_Others') {
|
|
446
524
|
return intl.get('Others');
|
|
@@ -476,8 +554,9 @@ export default class ChartComponent extends Component {
|
|
|
476
554
|
};
|
|
477
555
|
|
|
478
556
|
// sort legend data and format data
|
|
479
|
-
|
|
480
|
-
|
|
557
|
+
const clonedData = cloneDeep(data);
|
|
558
|
+
clonedData.forEach(item => item[legendName] = String(item[legendName]));
|
|
559
|
+
const legendData = BaseUtils.sortDataByGroupName(clonedData, legendName, groupColumn, chart);
|
|
481
560
|
const {
|
|
482
561
|
width: chartWidth,
|
|
483
562
|
height: chartHeight,
|
|
@@ -965,18 +1044,6 @@ export default class ChartComponent extends Component {
|
|
|
965
1044
|
}
|
|
966
1045
|
return statisticNewData;
|
|
967
1046
|
};
|
|
968
|
-
this.isShowXAxisLabel = chart => {
|
|
969
|
-
return !!(chart && chart.config && chart.config.x_axis_show_label);
|
|
970
|
-
};
|
|
971
|
-
this.isShowYAxisLabel = chart => {
|
|
972
|
-
return !!(chart && chart.config && chart.config.y_axis_show_label);
|
|
973
|
-
};
|
|
974
|
-
this.isShowYAxisLeftLabel = chart => {
|
|
975
|
-
return !!(chart && chart.config && chart.config.show_y_axis_left_label);
|
|
976
|
-
};
|
|
977
|
-
this.isShowYAxisRightLabel = chart => {
|
|
978
|
-
return !!(chart && chart.config && chart.config.show_y_axis_right_label);
|
|
979
|
-
};
|
|
980
1047
|
this.getThemeColors = function () {
|
|
981
1048
|
let themeColors = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
|
|
982
1049
|
let theme = arguments.length > 1 ? arguments[1] : undefined;
|
|
@@ -1065,7 +1132,7 @@ export default class ChartComponent extends Component {
|
|
|
1065
1132
|
allGroup.forEach(g => {
|
|
1066
1133
|
const rects = Array.from(g.children).filter(item => item.tagName !== 'text');
|
|
1067
1134
|
rects.forEach(item => {
|
|
1068
|
-
d3.select(item).transition().duration(this.
|
|
1135
|
+
d3.select(item).transition().duration(this.interactionDuration).attr('opacity', 1);
|
|
1069
1136
|
if ([CHART_TYPE.PIE, CHART_TYPE.RING].includes(chartType)) {
|
|
1070
1137
|
d3.select(item).attr('stroke-width', 2);
|
|
1071
1138
|
}
|
|
@@ -1077,7 +1144,7 @@ export default class ChartComponent extends Component {
|
|
|
1077
1144
|
const rects = Array.from(g.children).filter(item => item.tagName !== 'text');
|
|
1078
1145
|
rects.forEach(item => {
|
|
1079
1146
|
if (item.getAttribute('data-groupName') !== curGroupName) {
|
|
1080
|
-
d3.selectAll([item]).transition().duration(this.
|
|
1147
|
+
d3.selectAll([item]).transition().duration(this.interactionDuration).attr('opacity', 0.3);
|
|
1081
1148
|
} else {
|
|
1082
1149
|
if ([CHART_TYPE.PIE, CHART_TYPE.RING].includes(chartType)) {
|
|
1083
1150
|
d3.select(item).attr('stroke-width', 0.5);
|
|
@@ -1087,37 +1154,222 @@ export default class ChartComponent extends Component {
|
|
|
1087
1154
|
});
|
|
1088
1155
|
}
|
|
1089
1156
|
};
|
|
1090
|
-
// Use clipPath to make rectangle rounded corners
|
|
1091
1157
|
this.addClipPath = _ref9 => {
|
|
1092
1158
|
let {
|
|
1093
1159
|
rect,
|
|
1094
|
-
parentNode,
|
|
1095
1160
|
attr,
|
|
1096
|
-
rectId,
|
|
1097
1161
|
borderRadiusVal
|
|
1098
1162
|
} = _ref9;
|
|
1163
|
+
return this.addRoundedClip(rect, attr === 'x' ? 'x' : 'y', null, borderRadiusVal);
|
|
1164
|
+
};
|
|
1165
|
+
this.addRoundedClip = function (rect, orient) {
|
|
1166
|
+
let width = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
|
|
1167
|
+
let radiusOverride = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null;
|
|
1099
1168
|
const {
|
|
1100
1169
|
borderRadius
|
|
1101
|
-
} =
|
|
1102
|
-
const
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1170
|
+
} = _this.chartBoundingClientRect;
|
|
1171
|
+
const x = Number(rect.getAttribute('x'));
|
|
1172
|
+
const y = Number(rect.getAttribute('y'));
|
|
1173
|
+
const w = width != null ? width : Number(rect.getAttribute('width'));
|
|
1174
|
+
const h = Number(rect.getAttribute('height'));
|
|
1175
|
+
const computedRadius = orient === 'x' ? Math.min(h * borderRadius, h / 2, w / 2) : Math.min(w * borderRadius, w / 2, h / 2);
|
|
1176
|
+
const radius = radiusOverride != null ? Math.min(radiusOverride, w / 2, h / 2) : computedRadius;
|
|
1177
|
+
const d = orient === 'x' ? _this.getRightRoundedRectPath(x, y, w, h, radius) : _this.getTopRoundedRectPath(x, y, w, h, radius);
|
|
1178
|
+
const clipId = `rounded-clip-${Math.random().toString(36).slice(2)}`;
|
|
1179
|
+
const path = _this.getDefs().append('clipPath').attr('id', clipId).append('path').attr('class', 'rounded-clip-path').attr('data-x', x).attr('data-y', y).attr('data-width', w).attr('data-height', h).attr('data-radius', radius).attr('data-orient', orient).attr('d', d);
|
|
1180
|
+
d3.select(rect).attr('clip-path', `url(#${clipId})`);
|
|
1181
|
+
_this._clipMaskByRect.set(rect, path.node());
|
|
1182
|
+
return path.node();
|
|
1183
|
+
};
|
|
1184
|
+
this.animateMaskForRect = (rect, orient, baseline, t) => {
|
|
1185
|
+
const path = this._clipMaskByRect && this._clipMaskByRect.get(rect);
|
|
1186
|
+
if (!path) return;
|
|
1187
|
+
const x = Number(path.getAttribute('data-x'));
|
|
1188
|
+
const y = Number(path.getAttribute('data-y'));
|
|
1189
|
+
const width = Number(path.getAttribute('data-width'));
|
|
1190
|
+
const height = Number(path.getAttribute('data-height'));
|
|
1191
|
+
const radius = Number(path.getAttribute('data-radius'));
|
|
1192
|
+
const el = d3.select(path);
|
|
1193
|
+
if (orient === 'x') {
|
|
1194
|
+
const interpX = d3.interpolateNumber(baseline, x);
|
|
1195
|
+
const interpW = d3.interpolateNumber(0, width);
|
|
1196
|
+
el.attr('d', this.getRightRoundedRectPath(baseline, y, 0, height, radius)).transition(t).attrTween('d', () => tt => this.getRightRoundedRectPath(interpX(tt), y, interpW(tt), height, radius));
|
|
1110
1197
|
} else {
|
|
1111
|
-
const
|
|
1112
|
-
const
|
|
1113
|
-
|
|
1114
|
-
const safeBorderRadius = Math.min(borderRadiusVal !== null && borderRadiusVal !== void 0 ? borderRadiusVal : computedBorderRadius, rectWidth / 2, rectHeight / 2);
|
|
1115
|
-
clipRect.attr('rx', safeBorderRadius);
|
|
1116
|
-
clipRect.attr('height', rectHeight + safeBorderRadius);
|
|
1198
|
+
const interpY = d3.interpolateNumber(baseline, y);
|
|
1199
|
+
const interpH = d3.interpolateNumber(0, height);
|
|
1200
|
+
el.attr('d', this.getTopRoundedRectPath(x, baseline, width, 0, radius)).transition(t).attrTween('d', () => tt => this.getTopRoundedRectPath(x, interpY(tt), width, interpH(tt), radius));
|
|
1117
1201
|
}
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1202
|
+
};
|
|
1203
|
+
this.getTopRoundedRectPath = (x, y, width, height, radius) => {
|
|
1204
|
+
const r = Math.min(radius, width / 2, height / 2);
|
|
1205
|
+
if (height <= 0) return `M${x},${y} L${x + width},${y} L${x + width},${y} L${x},${y} Z`;
|
|
1206
|
+
return `M${x},${y + r} Q${x},${y} ${x + r},${y} L${x + width - r},${y} Q${x + width},${y} ${x + width},${y + r} L${x + width},${y + height} L${x},${y + height} Z`;
|
|
1207
|
+
};
|
|
1208
|
+
this.getRightRoundedRectPath = (x, y, width, height, radius) => {
|
|
1209
|
+
const r = Math.min(radius, width / 2, height / 2);
|
|
1210
|
+
if (width <= 0) return `M${x},${y} L${x},${y + height} L${x},${y + height} L${x},${y} Z`;
|
|
1211
|
+
return `M${x},${y} L${x + width - r},${y} Q${x + width},${y} ${x + width},${y + r} L${x + width},${y + height - r} Q${x + width},${y + height} ${x + width - r},${y + height} L${x},${y + height} Z`;
|
|
1212
|
+
};
|
|
1213
|
+
this.animateRectGrowInY = function (selection) {
|
|
1214
|
+
let duration = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : _this.transitionDuration;
|
|
1215
|
+
if (!selection || selection.empty()) return;
|
|
1216
|
+
const self = _this;
|
|
1217
|
+
selection.each(function () {
|
|
1218
|
+
const finalY = Number(this.getAttribute('y'));
|
|
1219
|
+
const finalHeight = Number(this.getAttribute('height'));
|
|
1220
|
+
if (!(finalHeight > 0)) return;
|
|
1221
|
+
const baseline = finalY + finalHeight;
|
|
1222
|
+
const t = d3.transition(self.enterTransitionName).duration(duration).ease(d3.easeCubicOut);
|
|
1223
|
+
d3.select(this).attr('y', baseline).attr('height', 0).transition(t).attr('y', finalY).attr('height', finalHeight);
|
|
1224
|
+
self.animateMaskForRect(this, 'y', baseline, t);
|
|
1225
|
+
});
|
|
1226
|
+
};
|
|
1227
|
+
this.animateStackGrowInY = function (selection) {
|
|
1228
|
+
let groupKey = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : node => node.getAttribute('x');
|
|
1229
|
+
let duration = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : _this.transitionDuration;
|
|
1230
|
+
if (!selection || selection.empty()) return null;
|
|
1231
|
+
const columns = new Map();
|
|
1232
|
+
selection.each(function () {
|
|
1233
|
+
if (!(Number(this.getAttribute('height')) > 0)) return;
|
|
1234
|
+
const key = groupKey(this);
|
|
1235
|
+
if (!columns.has(key)) columns.set(key, []);
|
|
1236
|
+
columns.get(key).push(this);
|
|
1237
|
+
});
|
|
1238
|
+
if (columns.size === 0) return null;
|
|
1239
|
+
const t = d3.transition(_this.enterTransitionName).duration(duration).ease(d3.easeCubicOut);
|
|
1240
|
+
columns.forEach(rects => {
|
|
1241
|
+
let baselineY = -Infinity;
|
|
1242
|
+
rects.forEach(rect => {
|
|
1243
|
+
baselineY = Math.max(baselineY, Number(rect.getAttribute('y')) + Number(rect.getAttribute('height')));
|
|
1244
|
+
});
|
|
1245
|
+
rects.forEach(rect => {
|
|
1246
|
+
const finalY = Number(rect.getAttribute('y'));
|
|
1247
|
+
const finalHeight = Number(rect.getAttribute('height'));
|
|
1248
|
+
d3.select(rect).attr('y', baselineY).attr('height', 0).transition(t).attr('y', finalY).attr('height', finalHeight);
|
|
1249
|
+
_this.animateMaskForRect(rect, 'y', baselineY, t);
|
|
1250
|
+
});
|
|
1251
|
+
});
|
|
1252
|
+
return t;
|
|
1253
|
+
};
|
|
1254
|
+
this.animateRectGrowInX = function (selection) {
|
|
1255
|
+
let duration = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : _this.transitionDuration;
|
|
1256
|
+
if (!selection || selection.empty()) return;
|
|
1257
|
+
const self = _this;
|
|
1258
|
+
selection.each(function () {
|
|
1259
|
+
const finalX = Number(this.getAttribute('x'));
|
|
1260
|
+
const finalWidth = Number(this.getAttribute('width'));
|
|
1261
|
+
if (!(finalWidth > 0)) return;
|
|
1262
|
+
const t = d3.transition(self.enterTransitionName).duration(duration).ease(d3.easeCubicOut);
|
|
1263
|
+
d3.select(this).attr('width', 0).transition(t).attr('width', finalWidth);
|
|
1264
|
+
self.animateMaskForRect(this, 'x', finalX, t);
|
|
1265
|
+
});
|
|
1266
|
+
};
|
|
1267
|
+
this.animateStackGrowInX = function (selection) {
|
|
1268
|
+
let groupKey = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : node => node.getAttribute('y');
|
|
1269
|
+
let duration = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : _this.transitionDuration;
|
|
1270
|
+
if (!selection || selection.empty()) return null;
|
|
1271
|
+
const rows = new Map();
|
|
1272
|
+
selection.each(function () {
|
|
1273
|
+
if (!(Number(this.getAttribute('width')) > 0)) return;
|
|
1274
|
+
const key = groupKey(this);
|
|
1275
|
+
if (!rows.has(key)) rows.set(key, []);
|
|
1276
|
+
rows.get(key).push(this);
|
|
1277
|
+
});
|
|
1278
|
+
if (rows.size === 0) return null;
|
|
1279
|
+
const t = d3.transition(_this.enterTransitionName).duration(duration).ease(d3.easeCubicOut);
|
|
1280
|
+
rows.forEach(rects => {
|
|
1281
|
+
let baselineX = Infinity;
|
|
1282
|
+
rects.forEach(rect => {
|
|
1283
|
+
baselineX = Math.min(baselineX, Number(rect.getAttribute('x')));
|
|
1284
|
+
});
|
|
1285
|
+
rects.forEach(rect => {
|
|
1286
|
+
const finalX = Number(rect.getAttribute('x'));
|
|
1287
|
+
const finalWidth = Number(rect.getAttribute('width'));
|
|
1288
|
+
d3.select(rect).attr('x', baselineX).attr('width', 0).transition(t).attr('x', finalX).attr('width', finalWidth);
|
|
1289
|
+
_this.animateMaskForRect(rect, 'x', baselineX, t);
|
|
1290
|
+
});
|
|
1291
|
+
});
|
|
1292
|
+
return t;
|
|
1293
|
+
};
|
|
1294
|
+
this.animateArcGrowIn = function (selection, arc) {
|
|
1295
|
+
let duration = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : _this.transitionDuration;
|
|
1296
|
+
if (!selection || selection.empty()) return;
|
|
1297
|
+
const transitionName = _this.enterTransitionName;
|
|
1298
|
+
selection.each(function (d) {
|
|
1299
|
+
const path = d3.select(this);
|
|
1300
|
+
const interpolate = d3.interpolate({
|
|
1301
|
+
startAngle: d.startAngle,
|
|
1302
|
+
endAngle: d.startAngle,
|
|
1303
|
+
padAngle: d.padAngle
|
|
1304
|
+
}, {
|
|
1305
|
+
startAngle: d.startAngle,
|
|
1306
|
+
endAngle: d.endAngle,
|
|
1307
|
+
padAngle: d.padAngle
|
|
1308
|
+
});
|
|
1309
|
+
path.attr('d', arc(interpolate(0))).transition(transitionName).duration(duration).ease(d3.easeCubicOut).attrTween('d', () => t => arc(interpolate(t)));
|
|
1310
|
+
});
|
|
1311
|
+
};
|
|
1312
|
+
this.animatePathDrawIn = function (selection) {
|
|
1313
|
+
let duration = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : _this.transitionDuration;
|
|
1314
|
+
if (!selection || selection.empty()) return;
|
|
1315
|
+
const transitionName = _this.enterTransitionName;
|
|
1316
|
+
selection.each(function () {
|
|
1317
|
+
const path = d3.select(this);
|
|
1318
|
+
let totalLength = 0;
|
|
1319
|
+
try {
|
|
1320
|
+
totalLength = this.getTotalLength();
|
|
1321
|
+
} catch (e) {
|
|
1322
|
+
totalLength = 0;
|
|
1323
|
+
}
|
|
1324
|
+
if (!(totalLength > 0)) return;
|
|
1325
|
+
path.attr('stroke-dasharray', `${totalLength} ${totalLength}`).attr('stroke-dashoffset', totalLength).transition(transitionName).duration(duration).ease(d3.easeLinear).attr('stroke-dashoffset', 0).on('end', function () {
|
|
1326
|
+
d3.select(this).attr('stroke-dasharray', null).attr('stroke-dashoffset', null);
|
|
1327
|
+
});
|
|
1328
|
+
});
|
|
1329
|
+
};
|
|
1330
|
+
this.animateRevealInX = function (selection, width) {
|
|
1331
|
+
let duration = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : _this.transitionDuration;
|
|
1332
|
+
if (!selection || selection.empty()) return;
|
|
1333
|
+
const {
|
|
1334
|
+
height: chartHeight
|
|
1335
|
+
} = _this.chartBoundingClientRect;
|
|
1336
|
+
const clipId = `reveal-clip-${Math.random().toString(36).slice(2)}`;
|
|
1337
|
+
const clipPath = _this.getDefs().append('clipPath').attr('id', clipId);
|
|
1338
|
+
const clipRect = clipPath.append('rect').attr('x', 0).attr('y', 0).attr('width', 0).attr('height', chartHeight);
|
|
1339
|
+
selection.attr('clip-path', `url(#${clipId})`);
|
|
1340
|
+
clipRect.transition(_this.enterTransitionName).duration(duration).ease(d3.easeLinear).attr('width', width).on('end', () => {
|
|
1341
|
+
selection.attr('clip-path', null);
|
|
1342
|
+
clipPath.remove();
|
|
1343
|
+
});
|
|
1344
|
+
};
|
|
1345
|
+
this.animateFadeIn = function (selection) {
|
|
1346
|
+
let duration = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : _this.transitionDuration;
|
|
1347
|
+
let delay = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
|
|
1348
|
+
let finalOpacity = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null;
|
|
1349
|
+
if (!selection || selection.empty()) return;
|
|
1350
|
+
const transitionName = _this.enterTransitionName;
|
|
1351
|
+
selection.each(function () {
|
|
1352
|
+
const el = d3.select(this);
|
|
1353
|
+
let target = finalOpacity;
|
|
1354
|
+
if (target == null) {
|
|
1355
|
+
const orig = this.getAttribute('opacity');
|
|
1356
|
+
const parsed = orig === null || orig === '' ? 1 : Number(orig);
|
|
1357
|
+
target = Number.isNaN(parsed) ? 1 : parsed;
|
|
1358
|
+
}
|
|
1359
|
+
if (!(target > 0)) return;
|
|
1360
|
+
el.attr('opacity', 0).transition(transitionName).duration(duration).delay(delay).ease(d3.easeLinear).attr('opacity', target);
|
|
1361
|
+
});
|
|
1362
|
+
};
|
|
1363
|
+
this.animateCircleZoomIn = function (selection) {
|
|
1364
|
+
let duration = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : _this.transitionDuration;
|
|
1365
|
+
if (!selection || selection.empty()) return;
|
|
1366
|
+
const transitionName = _this.enterTransitionName;
|
|
1367
|
+
selection.each(function () {
|
|
1368
|
+
const circle = d3.select(this);
|
|
1369
|
+
const finalR = Number(this.getAttribute('r')) || 0;
|
|
1370
|
+
if (!(finalR > 0)) return;
|
|
1371
|
+
circle.attr('r', 0).transition(transitionName).duration(duration).ease(d3.easeCubicOut).attr('r', finalR);
|
|
1372
|
+
});
|
|
1121
1373
|
};
|
|
1122
1374
|
this.drawYaxis = function (g, theme) {
|
|
1123
1375
|
let rightAxisOffset = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
|
|
@@ -1131,33 +1383,92 @@ export default class ChartComponent extends Component {
|
|
|
1131
1383
|
// add text
|
|
1132
1384
|
g.selectAll('text').attr('font-size', theme.fontSize);
|
|
1133
1385
|
g.selectAll('text').attr('fill', theme.textColor);
|
|
1386
|
+
_this.thinYAxisTicks(g);
|
|
1134
1387
|
_this.checkTextOverflow(g.selectAll('text').nodes());
|
|
1135
1388
|
|
|
1136
1389
|
// line
|
|
1137
1390
|
g.selectAll('line').node() && g.selectAll('line').node().remove(); // delete the first line
|
|
1138
|
-
g.selectAll('.tick line').clone().attr('x2', chartWidth -
|
|
1391
|
+
g.selectAll('.tick line').clone().attr('x2', chartWidth - _this.getYAxisTranslateX() - insertPadding - rightAxisOffset).attr('stroke', theme.gridColor).attr('stroke-dasharray', '8,3');
|
|
1139
1392
|
|
|
1140
1393
|
// update g translateX
|
|
1141
|
-
g.attr('transform', `translate(${
|
|
1394
|
+
g.attr('transform', `translate(${_this.getYAxisTranslateX()}, 0)`);
|
|
1395
|
+
};
|
|
1396
|
+
this.thinYAxisTicks = g => {
|
|
1397
|
+
const ticks = g.selectAll('.tick').nodes();
|
|
1398
|
+
if (ticks.length <= 2) return;
|
|
1399
|
+
const visibleTicks = ticks.map((tick, index) => {
|
|
1400
|
+
const text = d3.select(tick).select('text').node();
|
|
1401
|
+
if (!text) return null;
|
|
1402
|
+
const {
|
|
1403
|
+
top,
|
|
1404
|
+
bottom
|
|
1405
|
+
} = text.getBoundingClientRect();
|
|
1406
|
+
return {
|
|
1407
|
+
tick,
|
|
1408
|
+
index,
|
|
1409
|
+
top,
|
|
1410
|
+
bottom
|
|
1411
|
+
};
|
|
1412
|
+
}).filter(Boolean).sort((a, b) => a.top - b.top);
|
|
1413
|
+
const keptTicks = [];
|
|
1414
|
+
let prevBottom = -Infinity;
|
|
1415
|
+
visibleTicks.forEach(_ref10 => {
|
|
1416
|
+
let {
|
|
1417
|
+
tick,
|
|
1418
|
+
index,
|
|
1419
|
+
top,
|
|
1420
|
+
bottom
|
|
1421
|
+
} = _ref10;
|
|
1422
|
+
const shouldKeepFirstTick = index === 0;
|
|
1423
|
+
const shouldKeepLastTick = index === ticks.length - 1;
|
|
1424
|
+
const hasEnoughSpace = top > prevBottom + this.yAxisTickLabelGap;
|
|
1425
|
+
if (shouldKeepLastTick) {
|
|
1426
|
+
keptTicks.forEach(keptTick => {
|
|
1427
|
+
if (keptTick.bottom + this.yAxisTickLabelGap >= top) {
|
|
1428
|
+
d3.select(keptTick.tick).attr('opacity', 0);
|
|
1429
|
+
}
|
|
1430
|
+
});
|
|
1431
|
+
d3.select(tick).attr('opacity', 1);
|
|
1432
|
+
return;
|
|
1433
|
+
}
|
|
1434
|
+
if (shouldKeepFirstTick || hasEnoughSpace) {
|
|
1435
|
+
d3.select(tick).attr('opacity', 1);
|
|
1436
|
+
keptTicks.push({
|
|
1437
|
+
tick,
|
|
1438
|
+
bottom
|
|
1439
|
+
});
|
|
1440
|
+
prevBottom = bottom;
|
|
1441
|
+
return;
|
|
1442
|
+
}
|
|
1443
|
+
d3.select(tick).attr('opacity', 0);
|
|
1444
|
+
});
|
|
1142
1445
|
};
|
|
1143
1446
|
this.checkTextOverflow = allTextEl => {
|
|
1144
1447
|
const {
|
|
1145
1448
|
insertPadding
|
|
1146
1449
|
} = this.chartBoundingClientRect;
|
|
1147
1450
|
const allTextWidth = allTextEl.map(item => {
|
|
1451
|
+
const tick = item.parentNode;
|
|
1452
|
+
if (tick && Number(tick.getAttribute('opacity')) === 0) return 0;
|
|
1148
1453
|
const {
|
|
1149
1454
|
width
|
|
1150
1455
|
} = item.getBoundingClientRect();
|
|
1151
1456
|
return width;
|
|
1152
1457
|
});
|
|
1153
|
-
const maxTextWidth = Math.max(...allTextWidth);
|
|
1458
|
+
const maxTextWidth = Math.max(...allTextWidth, 0);
|
|
1154
1459
|
this.horizontalOverflowOffset = 0;
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
const offset =
|
|
1460
|
+
const requiredLeftSpace = maxTextWidth + 3;
|
|
1461
|
+
if (requiredLeftSpace > insertPadding) {
|
|
1462
|
+
const offset = requiredLeftSpace - insertPadding;
|
|
1158
1463
|
this.horizontalOverflowOffset = offset;
|
|
1159
1464
|
}
|
|
1160
1465
|
};
|
|
1466
|
+
this.getYAxisTranslateX = () => {
|
|
1467
|
+
const {
|
|
1468
|
+
insertPadding
|
|
1469
|
+
} = this.chartBoundingClientRect;
|
|
1470
|
+
return insertPadding + this.horizontalOverflowOffset;
|
|
1471
|
+
};
|
|
1161
1472
|
this.checkTickOverlap = (g, axis) => {
|
|
1162
1473
|
const allTicks = g.selectAll('.tick').nodes();
|
|
1163
1474
|
if (axis === 'yAxis') {
|
|
@@ -1309,10 +1620,84 @@ export default class ChartComponent extends Component {
|
|
|
1309
1620
|
const annotationWrapper = contentWrapper.insert('g', ':first-child').attr('class', 'vertical-annotation-wrapper');
|
|
1310
1621
|
annotationWrapper.append('line').attr('x1', x).attr('y1', insertPadding + marginTop).attr('x2', x).attr('y2', chartHeight - insertPadding).attr('stroke', theme.XAxisColor);
|
|
1311
1622
|
};
|
|
1623
|
+
this.setLegendForHeatMap = _ref11 => {
|
|
1624
|
+
let {
|
|
1625
|
+
exampleColors,
|
|
1626
|
+
themeColors
|
|
1627
|
+
} = _ref11;
|
|
1628
|
+
const legendOffsetY = 3;
|
|
1629
|
+
const legendItemTextWidth = 32;
|
|
1630
|
+
const legendItemWidth = 12;
|
|
1631
|
+
const legendItemHeight = 12;
|
|
1632
|
+
const legendItemGap = 3;
|
|
1633
|
+
const legendItemRadius = 2;
|
|
1634
|
+
const legendWrapper = this.chart.append('g').attr('class', 'legend-heat-map-wrapper').attr('transform', `translate(0, ${legendOffsetY})`);
|
|
1635
|
+
legendWrapper.append('text').attr('y', 10).attr('fill', themeColors.textColor).attr('font-size', 12).attr('font-weight', 'bold').text(intl.get('Less'));
|
|
1636
|
+
exampleColors.forEach((color, index) => {
|
|
1637
|
+
legendWrapper.append('rect').attr('x', legendItemTextWidth + index * legendItemWidth + index * legendItemGap).attr('width', legendItemWidth).attr('height', legendItemHeight).attr('rx', legendItemRadius).attr('fill', color).attr('stroke', FILL_BORDER_COLOR_MAP[color]).attr('stroke-width', 1);
|
|
1638
|
+
});
|
|
1639
|
+
legendWrapper.append('text').attr('x', 182).attr('y', 10).attr('fill', themeColors.textColor).attr('font-size', 12).attr('font-weight', 'bold').text(intl.get('More'));
|
|
1640
|
+
};
|
|
1641
|
+
this.setContinuousLegend = _ref12 => {
|
|
1642
|
+
var _this$chart$node2;
|
|
1643
|
+
let {
|
|
1644
|
+
previewType,
|
|
1645
|
+
theme,
|
|
1646
|
+
colorRange = [],
|
|
1647
|
+
legendDirection,
|
|
1648
|
+
legendSize,
|
|
1649
|
+
legendTextRange,
|
|
1650
|
+
bubbleColor,
|
|
1651
|
+
type
|
|
1652
|
+
} = _ref12;
|
|
1653
|
+
const {
|
|
1654
|
+
width: chartWidth,
|
|
1655
|
+
height: chartHeight,
|
|
1656
|
+
insertPadding
|
|
1657
|
+
} = this.chartBoundingClientRect;
|
|
1658
|
+
const legendRectWidth = legendDirection === 'vertical' ? 12 : Math.min(legendSize * 100, chartWidth - insertPadding * 2);
|
|
1659
|
+
const legendRectHeight = legendDirection === 'vertical' ? Math.min(legendSize * 100, chartHeight - insertPadding * 2) : 12;
|
|
1660
|
+
const legendTextOffset = 2;
|
|
1661
|
+
const legendTextHeightSpace = legendDirection === 'vertical' ? 0 : 14 + legendTextOffset;
|
|
1662
|
+
if (![CHART_TYPE.MAP_BUBBLE, CHART_TYPE.WORLD_MAP_BUBBLE].includes(type)) {
|
|
1663
|
+
var _this$chart$node;
|
|
1664
|
+
const gradient = this.chart.append('defs').attr('class', 'linear-gradient-wrapper').append('linearGradient').attr("id", `gradient-${(_this$chart$node = this.chart.node()) === null || _this$chart$node === void 0 ? void 0 : _this$chart$node.id}-${previewType}`).attr("x1", '0%').attr("y1", '0%').attr("x2", legendDirection === 'vertical' ? '0%' : '100%').attr("y2", legendDirection === 'vertical' ? '100%' : '0%');
|
|
1665
|
+
gradient.append('stop').attr('offset', '0%').attr('stop-color', `${colorRange[0]}`);
|
|
1666
|
+
gradient.append('stop').attr('offset', '50%').attr('stop-color', `${colorRange[4]}`);
|
|
1667
|
+
gradient.append('stop').attr('offset', '100%').attr('stop-color', `${colorRange[8]}`);
|
|
1668
|
+
}
|
|
1669
|
+
const continuousLegendWrapper = this.chart.append('g').attr('class', 'legend-continuous-wrapper').attr('transform', `translate(0, ${chartHeight - legendRectHeight - legendTextHeightSpace})`);
|
|
1670
|
+
continuousLegendWrapper.append('rect').attr('width', legendRectWidth).attr('height', legendRectHeight).attr('fill', [CHART_TYPE.MAP_BUBBLE, CHART_TYPE.WORLD_MAP_BUBBLE].includes(type) ? bubbleColor : `url(#gradient-${(_this$chart$node2 = this.chart.node()) === null || _this$chart$node2 === void 0 ? void 0 : _this$chart$node2.id}-${previewType})`).call(g => {
|
|
1671
|
+
if ([CHART_TYPE.MAP_BUBBLE, CHART_TYPE.WORLD_MAP_BUBBLE].includes(type)) {
|
|
1672
|
+
continuousLegendWrapper.append('polygon').attr('points', `0,0 ${legendRectWidth - 0.5},0 0,${legendRectHeight - 0.5}`).attr('fill', '#fff').attr('stroke', '#fff');
|
|
1673
|
+
}
|
|
1674
|
+
});
|
|
1675
|
+
continuousLegendWrapper.append('text').attr('class', 'range-start').attr('stroke', '#fff').attr('stroke-width', 1).attr('paint-order', 'stroke').attr('fill', theme.labelColor).text(legendTextRange[0]).call(g => {
|
|
1676
|
+
const {
|
|
1677
|
+
height
|
|
1678
|
+
} = g.node().getBoundingClientRect();
|
|
1679
|
+
g.attr('x', legendDirection === 'vertical' ? legendRectWidth + legendTextOffset : legendTextOffset);
|
|
1680
|
+
g.attr('y', legendDirection === 'vertical' ? height : height + legendRectHeight);
|
|
1681
|
+
});
|
|
1682
|
+
continuousLegendWrapper.append('text').attr('class', 'range-end').attr('stroke', '#fff').attr('stroke-width', 1).attr('paint-order', 'stroke').attr('fill', theme.labelColor).text(legendTextRange[1]).call(g => {
|
|
1683
|
+
const {
|
|
1684
|
+
width,
|
|
1685
|
+
height
|
|
1686
|
+
} = g.node().getBoundingClientRect();
|
|
1687
|
+
g.attr('x', legendDirection === 'vertical' ? legendRectWidth + legendTextOffset : legendRectWidth - width);
|
|
1688
|
+
g.attr('y', legendDirection === 'vertical' ? legendRectHeight - legendTextOffset : height + legendRectHeight);
|
|
1689
|
+
});
|
|
1690
|
+
};
|
|
1312
1691
|
this.initLabelStroke(props === null || props === void 0 ? void 0 : props.globalTheme);
|
|
1313
1692
|
this.chartBoundingClientRect = {};
|
|
1314
|
-
this.transitionDuration =
|
|
1693
|
+
this.transitionDuration = 450;
|
|
1694
|
+
this.interactionDuration = 150;
|
|
1315
1695
|
this.areaTransitionDuration = 200;
|
|
1696
|
+
this.yAxisTickLabelGap = 4;
|
|
1697
|
+
this.axisTitleMinHeight = 20;
|
|
1698
|
+
this.enterTransitionName = 'enter';
|
|
1699
|
+
this._defs = null;
|
|
1700
|
+
this._clipMaskByRect = new Map();
|
|
1316
1701
|
}
|
|
1317
1702
|
componentDidMount() {
|
|
1318
1703
|
window.addEventListener('resize', this.handleResize);
|