sea-chart 2.0.30 → 2.0.32
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/types-dialog/index.js +1 -1
- package/dist/view/wrapper/chart-component.js +70 -31
- package/dist/view/wrapper/dashboard.js +223 -0
- package/dist/view/wrapper/heat-map.js +323 -0
- package/dist/view/wrapper/index.js +21 -0
- package/dist/view/wrapper/mirror.js +320 -0
- package/package.json +1 -1
|
@@ -69,7 +69,7 @@ const TypesDialog = _ref => {
|
|
|
69
69
|
}, [onChange, selectedType, onToggle]);
|
|
70
70
|
const handleFilterTypes = (0, _react.useCallback)(() => {
|
|
71
71
|
if (hideTypeToggle) {
|
|
72
|
-
const newChartTypes = _constants.CHART_TYPES.filter(item => ['Histogram', 'Bar_chart', 'Line_chart', 'Area', 'Pie_chart', 'Scatter_chart', 'Combination_chart', 'Map'].includes(item.name));
|
|
72
|
+
const newChartTypes = _constants.CHART_TYPES.filter(item => ['Histogram', 'Bar_chart', 'Line_chart', 'Area', 'Pie_chart', 'Scatter_chart', 'Combination_chart', 'Map', 'Heat_map', 'Facet_chart', 'Gauge'].includes(item.name));
|
|
73
73
|
return newChartTypes;
|
|
74
74
|
}
|
|
75
75
|
return _constants.CHART_TYPES;
|
|
@@ -12,6 +12,7 @@ var _lodashEs = require("lodash-es");
|
|
|
12
12
|
var _dtableUtils = require("dtable-utils");
|
|
13
13
|
var _utils = require("../../utils");
|
|
14
14
|
var _constants = require("../../constants");
|
|
15
|
+
var _style = require("../../constants/style");
|
|
15
16
|
var _intl = _interopRequireDefault(require("../../intl"));
|
|
16
17
|
require("../../assets/css/sea-chart-d3-tooltip.css");
|
|
17
18
|
class ChartComponent extends _react.Component {
|
|
@@ -59,10 +60,12 @@ class ChartComponent extends _react.Component {
|
|
|
59
60
|
const {
|
|
60
61
|
marginLeft = 0,
|
|
61
62
|
marginRight = 0,
|
|
62
|
-
marginBottom = 0
|
|
63
|
+
marginBottom = 0,
|
|
64
|
+
customWidth,
|
|
65
|
+
customHeight
|
|
63
66
|
} = initConfig;
|
|
64
|
-
const width = containerWidth - marginLeft - marginRight;
|
|
65
|
-
const height = containerHeight - marginBottom;
|
|
67
|
+
const width = customWidth ? customWidth : containerWidth - marginLeft - marginRight;
|
|
68
|
+
const height = customHeight ? customHeight : containerHeight - marginBottom;
|
|
66
69
|
_this.chart = d3.create('svg').attr('id', id).attr('width', width).attr('height', height).attr('viewBox', [0, 0, width, height]);
|
|
67
70
|
_this.container.appendChild(_this.chart.node());
|
|
68
71
|
_this.chartBoundingClientRect = {
|
|
@@ -647,8 +650,31 @@ class ChartComponent extends _react.Component {
|
|
|
647
650
|
return _intl.default.get(name) || name;
|
|
648
651
|
}
|
|
649
652
|
};
|
|
653
|
+
// set legend for heat map
|
|
654
|
+
this.setLegendForHeatMap = _ref => {
|
|
655
|
+
let {
|
|
656
|
+
exampleColors,
|
|
657
|
+
themeColors
|
|
658
|
+
} = _ref;
|
|
659
|
+
const legendOffsetY = 3;
|
|
660
|
+
const legendItemTextWidth = 32;
|
|
661
|
+
const legendItemWidth = 12;
|
|
662
|
+
const legendItemHeight = 12;
|
|
663
|
+
const legendItemGap = 3;
|
|
664
|
+
const legendItemRadius = 2;
|
|
665
|
+
const legendWrapper = this.chart.append('g').attr('class', 'legend-heat-map-wrapper').attr('transform', "translate(0, ".concat(legendOffsetY, ")"));
|
|
666
|
+
|
|
667
|
+
// less
|
|
668
|
+
legendWrapper.append('text').attr('y', 10).attr('fill', themeColors.textColor).attr('font-size', 12).attr('font-weight', 'bold').text(_intl.default.get('Less'));
|
|
669
|
+
// rect
|
|
670
|
+
exampleColors.forEach((color, index) => {
|
|
671
|
+
legendWrapper.append('rect').attr('x', legendItemTextWidth + index * legendItemWidth + index * legendItemGap).attr('width', legendItemWidth).attr('height', legendItemHeight).attr('rx', legendItemRadius).attr('fill', color).attr('stroke', _style.FILL_BORDER_COLOR_MAP[color]).attr('stroke-width', 1);
|
|
672
|
+
});
|
|
673
|
+
// more
|
|
674
|
+
legendWrapper.append('text').attr('x', 182).attr('y', 10).attr('fill', themeColors.textColor).attr('font-size', 12).attr('font-weight', 'bold').text(_intl.default.get('More'));
|
|
675
|
+
};
|
|
650
676
|
// set continuous legend
|
|
651
|
-
this.setContinuousLegend =
|
|
677
|
+
this.setContinuousLegend = _ref2 => {
|
|
652
678
|
var _this$chart$node2;
|
|
653
679
|
let {
|
|
654
680
|
previewType,
|
|
@@ -659,7 +685,7 @@ class ChartComponent extends _react.Component {
|
|
|
659
685
|
legendTextRange,
|
|
660
686
|
bubbleColor,
|
|
661
687
|
type
|
|
662
|
-
} =
|
|
688
|
+
} = _ref2;
|
|
663
689
|
const {
|
|
664
690
|
width: chartWidth,
|
|
665
691
|
height: chartHeight,
|
|
@@ -702,8 +728,8 @@ class ChartComponent extends _react.Component {
|
|
|
702
728
|
});
|
|
703
729
|
};
|
|
704
730
|
// set legend
|
|
705
|
-
this.setLegend =
|
|
706
|
-
var _chart$config, _chart$config2
|
|
731
|
+
this.setLegend = _ref3 => {
|
|
732
|
+
var _chart$config, _chart$config2;
|
|
707
733
|
let {
|
|
708
734
|
legendName,
|
|
709
735
|
theme = _constants.CHART_THEME_COLOR['light'],
|
|
@@ -712,12 +738,12 @@ class ChartComponent extends _react.Component {
|
|
|
712
738
|
colorScale,
|
|
713
739
|
groupColumn,
|
|
714
740
|
chart
|
|
715
|
-
} =
|
|
741
|
+
} = _ref3;
|
|
716
742
|
if (!this.chart) return;
|
|
717
743
|
this.legendConfig = {
|
|
718
|
-
legendRectWidth: (chart === null || chart === void 0 ? void 0 : (_chart$config = chart.config) === null || _chart$config === void 0 ? void 0 : _chart$config.type)
|
|
719
|
-
legendRectHeight: (chart === null || chart === void 0 ? void 0 : (_chart$config2 = chart.config) === null || _chart$config2 === void 0 ? void 0 : _chart$config2.type)
|
|
720
|
-
r: (chart
|
|
744
|
+
legendRectWidth: [_constants.CHART_TYPE.SCATTER, _constants.CHART_TYPE.MIRROR].includes(chart === null || chart === void 0 ? void 0 : (_chart$config = chart.config) === null || _chart$config === void 0 ? void 0 : _chart$config.type) ? 8 : 20,
|
|
745
|
+
legendRectHeight: [_constants.CHART_TYPE.SCATTER, _constants.CHART_TYPE.MIRROR].includes(chart === null || chart === void 0 ? void 0 : (_chart$config2 = chart.config) === null || _chart$config2 === void 0 ? void 0 : _chart$config2.type) ? 8 : 6,
|
|
746
|
+
r: this.getLegendR(chart),
|
|
721
747
|
legendItemPaddingTop: 5,
|
|
722
748
|
legendItemTextPaddingTop: 13,
|
|
723
749
|
legendItemMargin: 20,
|
|
@@ -746,12 +772,13 @@ class ChartComponent extends _react.Component {
|
|
|
746
772
|
// legend offset bottom and When there is only one line of legend, it is displayed in the center (for scatter chart)
|
|
747
773
|
if (bottomLegendSpace) {
|
|
748
774
|
queueMicrotask(() => {
|
|
775
|
+
const {
|
|
776
|
+
width,
|
|
777
|
+
height
|
|
778
|
+
} = legendWrapper.node().getBoundingClientRect();
|
|
749
779
|
let curTranslateX = 0;
|
|
750
|
-
const curTranslateY = bottomLegendSpace ? chartHeight -
|
|
780
|
+
const curTranslateY = bottomLegendSpace ? chartHeight - height : 0;
|
|
751
781
|
if (groupsData.length === 1) {
|
|
752
|
-
const {
|
|
753
|
-
width
|
|
754
|
-
} = legendWrapper.node().getBoundingClientRect();
|
|
755
782
|
curTranslateX = (chartWidth - width - insertPadding * 2) / 2;
|
|
756
783
|
}
|
|
757
784
|
legendWrapper.attr('transform', "translate(".concat(curTranslateX, ",").concat(curTranslateY, ")"));
|
|
@@ -831,14 +858,14 @@ class ChartComponent extends _react.Component {
|
|
|
831
858
|
});
|
|
832
859
|
}
|
|
833
860
|
};
|
|
834
|
-
this.renderLegend =
|
|
861
|
+
this.renderLegend = _ref4 => {
|
|
835
862
|
let {
|
|
836
863
|
legendWrapper,
|
|
837
864
|
groupData,
|
|
838
865
|
colorScale,
|
|
839
866
|
theme,
|
|
840
867
|
text
|
|
841
|
-
} =
|
|
868
|
+
} = _ref4;
|
|
842
869
|
const {
|
|
843
870
|
legendItemPaddingTop,
|
|
844
871
|
legendItemTextPaddingTop,
|
|
@@ -864,15 +891,15 @@ class ChartComponent extends _react.Component {
|
|
|
864
891
|
d3.select(item).remove();
|
|
865
892
|
});
|
|
866
893
|
}
|
|
867
|
-
legendWrapper.selectAll().data(groupData).join('g').attr('data-groupName',
|
|
868
|
-
let [groupName] = _ref4;
|
|
869
|
-
return groupName;
|
|
870
|
-
}).append('rect').attr('width', legendRectWidth).attr('height', legendRectHeight).attr('y', legendItemPaddingTop).attr('rx', r).attr('fill', _ref5 => {
|
|
894
|
+
legendWrapper.selectAll().data(groupData).join('g').attr('data-groupName', _ref5 => {
|
|
871
895
|
let [groupName] = _ref5;
|
|
896
|
+
return groupName;
|
|
897
|
+
}).append('rect').attr('width', legendRectWidth).attr('height', legendRectHeight).attr('y', legendItemPaddingTop).attr('rx', r).attr('fill', _ref6 => {
|
|
898
|
+
let [groupName] = _ref6;
|
|
872
899
|
if (colorScale) return colorScale(groupName);
|
|
873
900
|
return this.colorMap[groupName] || _constants.CHART_STYLE_COLORS[0];
|
|
874
|
-
}).attr('data-text',
|
|
875
|
-
let [groupName] =
|
|
901
|
+
}).attr('data-text', _ref7 => {
|
|
902
|
+
let [groupName] = _ref7;
|
|
876
903
|
return groupName;
|
|
877
904
|
}).call(g => {
|
|
878
905
|
// Add text
|
|
@@ -1078,6 +1105,18 @@ class ChartComponent extends _react.Component {
|
|
|
1078
1105
|
item.name = item['oldName'];
|
|
1079
1106
|
});
|
|
1080
1107
|
};
|
|
1108
|
+
this.getLegendR = chart => {
|
|
1109
|
+
if (!chart) return 3;
|
|
1110
|
+
const {
|
|
1111
|
+
config
|
|
1112
|
+
} = chart;
|
|
1113
|
+
const {
|
|
1114
|
+
type
|
|
1115
|
+
} = config;
|
|
1116
|
+
if (type === _constants.CHART_TYPE.SCATTER) return 4;
|
|
1117
|
+
if (type === _constants.CHART_TYPE.MIRROR) return 0;
|
|
1118
|
+
return 3;
|
|
1119
|
+
};
|
|
1081
1120
|
// theta is pie or ring chart
|
|
1082
1121
|
this.setLegendForTheta = function (legendName) {
|
|
1083
1122
|
let theme = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : _constants.CHART_THEME_COLOR['light'];
|
|
@@ -1372,7 +1411,7 @@ class ChartComponent extends _react.Component {
|
|
|
1372
1411
|
annotationWrapper.append('text').attr('x', chartWidth - insertPadding - 30).attr('y', yScale(goal_value) - 10).attr('fill', '#666').text(goal_label);
|
|
1373
1412
|
});
|
|
1374
1413
|
};
|
|
1375
|
-
this.addLabelToRectTop =
|
|
1414
|
+
this.addLabelToRectTop = _ref8 => {
|
|
1376
1415
|
let {
|
|
1377
1416
|
container,
|
|
1378
1417
|
x,
|
|
@@ -1381,7 +1420,7 @@ class ChartComponent extends _react.Component {
|
|
|
1381
1420
|
theme,
|
|
1382
1421
|
label_font_size,
|
|
1383
1422
|
text
|
|
1384
|
-
} =
|
|
1423
|
+
} = _ref8;
|
|
1385
1424
|
d3.select(container).append('text').attr('stroke', '#fff').attr('stroke-width', 1).attr('paint-order', 'stroke').attr('y', Number(y) - 10).attr('fill', theme.labelColor).attr('font-size', _utils.BaseUtils.getLabelFontSize(label_font_size)).text(text).call(g => {
|
|
1386
1425
|
const {
|
|
1387
1426
|
width
|
|
@@ -1389,7 +1428,7 @@ class ChartComponent extends _react.Component {
|
|
|
1389
1428
|
g.attr('x', Number(x) + Number(xWidth) / 2 - width / 2);
|
|
1390
1429
|
});
|
|
1391
1430
|
};
|
|
1392
|
-
this.addLabelToRectRight =
|
|
1431
|
+
this.addLabelToRectRight = _ref9 => {
|
|
1393
1432
|
let {
|
|
1394
1433
|
container,
|
|
1395
1434
|
x,
|
|
@@ -1399,7 +1438,7 @@ class ChartComponent extends _react.Component {
|
|
|
1399
1438
|
theme,
|
|
1400
1439
|
label_font_size,
|
|
1401
1440
|
text
|
|
1402
|
-
} =
|
|
1441
|
+
} = _ref9;
|
|
1403
1442
|
d3.select(container).append('text').attr('stroke', '#fff').attr('stroke-width', 1).attr('paint-order', 'stroke').attr('x', Number(x) + Number(xWidth) + 10).attr('y', Number(y)).attr('fill', theme.labelColor).attr('dominant-baseline', 'hanging').attr('font-size', _utils.BaseUtils.getLabelFontSize(label_font_size)).text(text).call(g => {
|
|
1404
1443
|
if (g.node()) {
|
|
1405
1444
|
var _g$node;
|
|
@@ -1410,7 +1449,7 @@ class ChartComponent extends _react.Component {
|
|
|
1410
1449
|
}
|
|
1411
1450
|
});
|
|
1412
1451
|
};
|
|
1413
|
-
this.addLabelToRectCenter =
|
|
1452
|
+
this.addLabelToRectCenter = _ref10 => {
|
|
1414
1453
|
let {
|
|
1415
1454
|
chartType,
|
|
1416
1455
|
container,
|
|
@@ -1421,7 +1460,7 @@ class ChartComponent extends _react.Component {
|
|
|
1421
1460
|
theme,
|
|
1422
1461
|
label_font_size,
|
|
1423
1462
|
text
|
|
1424
|
-
} =
|
|
1463
|
+
} = _ref10;
|
|
1425
1464
|
d3.select(container).append('text').attr('stroke', '#fff').attr('stroke-width', 1).attr('paint-order', 'stroke').attr('fill', theme.labelColor).attr('font-size', _utils.BaseUtils.getLabelFontSize(label_font_size)).text(text).call(g => {
|
|
1426
1465
|
const {
|
|
1427
1466
|
width,
|
|
@@ -1463,13 +1502,13 @@ class ChartComponent extends _react.Component {
|
|
|
1463
1502
|
}
|
|
1464
1503
|
};
|
|
1465
1504
|
// Use clipPath to make rectangle rounded corners
|
|
1466
|
-
this.addClipPath =
|
|
1505
|
+
this.addClipPath = _ref11 => {
|
|
1467
1506
|
let {
|
|
1468
1507
|
rect,
|
|
1469
1508
|
parentNode,
|
|
1470
1509
|
attr,
|
|
1471
1510
|
rectId
|
|
1472
|
-
} =
|
|
1511
|
+
} = _ref11;
|
|
1473
1512
|
const {
|
|
1474
1513
|
borderRadius
|
|
1475
1514
|
} = this.chartBoundingClientRect;
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard").default;
|
|
4
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
|
|
5
|
+
Object.defineProperty(exports, "__esModule", {
|
|
6
|
+
value: true
|
|
7
|
+
});
|
|
8
|
+
exports.default = void 0;
|
|
9
|
+
var _react = _interopRequireDefault(require("react"));
|
|
10
|
+
var _propTypes = _interopRequireDefault(require("prop-types"));
|
|
11
|
+
var _lodashEs = require("lodash-es");
|
|
12
|
+
var d3 = _interopRequireWildcard(require("d3"));
|
|
13
|
+
var _constants = require("../../constants");
|
|
14
|
+
var _utils = require("../../utils");
|
|
15
|
+
var _tooltip = _interopRequireDefault(require("../../components/tooltip"));
|
|
16
|
+
var _chartComponent = _interopRequireDefault(require("./chart-component"));
|
|
17
|
+
class Dashboard extends _chartComponent.default {
|
|
18
|
+
constructor(props) {
|
|
19
|
+
super(props);
|
|
20
|
+
this.handleResize = () => {
|
|
21
|
+
this.destroyChart();
|
|
22
|
+
this.createChart();
|
|
23
|
+
this.drawChart();
|
|
24
|
+
};
|
|
25
|
+
this.createChart = () => {
|
|
26
|
+
const {
|
|
27
|
+
chart
|
|
28
|
+
} = this.props;
|
|
29
|
+
const initConfig = {
|
|
30
|
+
insertPadding: 30
|
|
31
|
+
};
|
|
32
|
+
this.initChart(this.container, chart === null || chart === void 0 ? void 0 : chart.id, initConfig);
|
|
33
|
+
};
|
|
34
|
+
this.drawChart = () => {
|
|
35
|
+
const {
|
|
36
|
+
result: data,
|
|
37
|
+
customRender
|
|
38
|
+
} = this.props;
|
|
39
|
+
this.draw(data);
|
|
40
|
+
(0, _utils.isFunction)(customRender) && customRender(this.chart);
|
|
41
|
+
};
|
|
42
|
+
this.draw = data => {
|
|
43
|
+
const {
|
|
44
|
+
width: chartWidth,
|
|
45
|
+
height: chartHeight,
|
|
46
|
+
insertPadding
|
|
47
|
+
} = this.chartBoundingClientRect;
|
|
48
|
+
const value = Number(data) * 100;
|
|
49
|
+
const formatValue = value >= 100 ? 100 : value.toFixed(1);
|
|
50
|
+
const innerRadius = Math.min(chartWidth, chartHeight) / 2 * 0.7;
|
|
51
|
+
const outerRadius = Math.min(chartWidth, chartHeight) / 2 * 0.75;
|
|
52
|
+
const startAngle = -(Math.PI / 2 + 0.5);
|
|
53
|
+
const endAngle = Math.PI / 2 + 0.5;
|
|
54
|
+
|
|
55
|
+
// Ring and Arc
|
|
56
|
+
const arc = d3.arc().innerRadius(innerRadius).outerRadius(outerRadius).startAngle(startAngle).endAngle(endAngle);
|
|
57
|
+
const xScale = d3.scaleLinear().domain([0, 100]).range([startAngle, endAngle]);
|
|
58
|
+
|
|
59
|
+
// Draw Ring
|
|
60
|
+
this.chart.append('g').attr('class', 'content-wrapper').append('path').attr('class', 'completed-path').attr('opacity', 1).attr('fill', '#1890FF').attr('d', () => arc()).call(g => {
|
|
61
|
+
var _g$node$parentNode;
|
|
62
|
+
const {
|
|
63
|
+
width,
|
|
64
|
+
height
|
|
65
|
+
} = (_g$node$parentNode = g.node().parentNode) === null || _g$node$parentNode === void 0 ? void 0 : _g$node$parentNode.getBoundingClientRect();
|
|
66
|
+
const left = width / 2 + insertPadding;
|
|
67
|
+
const top = height / 2 + insertPadding;
|
|
68
|
+
const offsetX = (chartWidth - insertPadding - insertPadding - width) / 2;
|
|
69
|
+
const offsetY = (chartHeight - insertPadding - insertPadding - height) / 2;
|
|
70
|
+
d3.select(g.node().parentNode).attr('transform', "translate(".concat(left + offsetX, ", ").concat(top + offsetY, ")"));
|
|
71
|
+
|
|
72
|
+
// Draw uncompleted path
|
|
73
|
+
if (formatValue < 100) {
|
|
74
|
+
const unCompletedStartAngle = xScale(formatValue);
|
|
75
|
+
this.drawUncompletedPath(g.node().parentNode, innerRadius, outerRadius, unCompletedStartAngle, endAngle);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Draw ticks
|
|
79
|
+
this.drawTicks(left, offsetX, top, offsetY, startAngle, endAngle, arc);
|
|
80
|
+
|
|
81
|
+
// Draw pointer
|
|
82
|
+
this.drawPointer(g.node().parentNode, xScale, formatValue);
|
|
83
|
+
|
|
84
|
+
// Draw total
|
|
85
|
+
this.drawTotal(g.node().parentNode, formatValue);
|
|
86
|
+
});
|
|
87
|
+
};
|
|
88
|
+
this.drawTicks = (left, offsetX, top, offsetY, startAngle, endAngle, arc) => {
|
|
89
|
+
const {
|
|
90
|
+
globalTheme
|
|
91
|
+
} = this.props;
|
|
92
|
+
const theme = _constants.CHART_THEME_COLOR[globalTheme];
|
|
93
|
+
const ticks = Array.from({
|
|
94
|
+
length: 51
|
|
95
|
+
}, (_, i) => i);
|
|
96
|
+
const lineInnerRadius = arc.innerRadius()();
|
|
97
|
+
const x = d3.scaleBand().domain(ticks).range([startAngle, endAngle]).paddingInner(1).paddingOuter(0);
|
|
98
|
+
this.chart.append('g').attr('class', 'ticks-line-wrapper').attr('transform', "translate(".concat(left + offsetX, ", ").concat(top + offsetY, ")")).selectAll().data(x.domain()).join('g').attr('transform', (d, index) => {
|
|
99
|
+
return "\n rotate(".concat(x(d) * 180 / Math.PI - 90, ")\n translate(").concat(lineInnerRadius, ",0)\n ");
|
|
100
|
+
}).attr('data-value', d => d).call(g => {
|
|
101
|
+
g.nodes().forEach(group => {
|
|
102
|
+
const value = Number(group.getAttribute('data-value'));
|
|
103
|
+
// line
|
|
104
|
+
d3.select(group).append('line').attr('x2', () => value % 5 === 0 ? -15 : -10).attr('stroke', () => value % 5 === 0 ? '#CBCBCB' : '#545454');
|
|
105
|
+
|
|
106
|
+
// text
|
|
107
|
+
if (value % 5 === 0) {
|
|
108
|
+
const text = value / 5;
|
|
109
|
+
const rotateVal = ((x(value) + x.bandwidth() / 2) * 180 / Math.PI - 90) * -1; // -1 is Rotate the text
|
|
110
|
+
d3.select(group).append('text').attr('transform', () => {
|
|
111
|
+
if (x(value) <= -(Math.PI / 4)) {
|
|
112
|
+
return "translate(-25,-5) rotate(".concat(rotateVal, ")");
|
|
113
|
+
}
|
|
114
|
+
if (x(value) <= 0) {
|
|
115
|
+
return "translate(-30,-5) rotate(".concat(rotateVal, ")");
|
|
116
|
+
}
|
|
117
|
+
if (x(value) <= Math.PI / 4) {
|
|
118
|
+
return "translate(-30,-2) rotate(".concat(rotateVal, ")");
|
|
119
|
+
}
|
|
120
|
+
if (x(value) <= Math.PI) {
|
|
121
|
+
return "translate(-30,3) rotate(".concat(rotateVal, ")");
|
|
122
|
+
}
|
|
123
|
+
}).text(text).attr('fill', theme.textColor);
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
};
|
|
128
|
+
this.drawPointer = (wrapper, xScale, formatValue) => {
|
|
129
|
+
const rotate = xScale(formatValue) * 180 / Math.PI;
|
|
130
|
+
|
|
131
|
+
// Circle
|
|
132
|
+
d3.select(wrapper).append('g').attr('class', 'pointer-circle-wrapper').append('circle').attr('cx', 0).attr('cy', 0).attr('r', 10).attr('fill', 'white').attr('stroke', '#1890FF').attr('stroke-width', 5);
|
|
133
|
+
|
|
134
|
+
// Pointer
|
|
135
|
+
d3.select(wrapper).append('g').attr('class', 'pointer-wrapper').append('rect').attr('x', -2).attr('y', -78).attr('width', 6).attr('height', 70).attr('fill', '#1890FF').attr('rx', 3).attr('transform', () => {
|
|
136
|
+
return "rotate(".concat(rotate, ")");
|
|
137
|
+
});
|
|
138
|
+
};
|
|
139
|
+
this.drawUncompletedPath = (wrapper, innerRadius, outerRadius, startAngle, endAngle) => {
|
|
140
|
+
const uncompletedArc = d3.arc().innerRadius(innerRadius).outerRadius(outerRadius).startAngle(startAngle).endAngle(endAngle);
|
|
141
|
+
d3.select(wrapper).append('path').attr('class', 'uncompleted-path').attr('opacity', 1).attr('d', () => uncompletedArc()).attr('fill', '#CBCBCB');
|
|
142
|
+
};
|
|
143
|
+
this.drawTotal = (wrapper, formatValue) => {
|
|
144
|
+
const {
|
|
145
|
+
chart,
|
|
146
|
+
globalTheme
|
|
147
|
+
} = this.props;
|
|
148
|
+
const {
|
|
149
|
+
name
|
|
150
|
+
} = chart.config;
|
|
151
|
+
const theme = _constants.CHART_THEME_COLOR[globalTheme];
|
|
152
|
+
const {
|
|
153
|
+
height: chartHeight
|
|
154
|
+
} = this.chartBoundingClientRect;
|
|
155
|
+
const totalWrapper = d3.select(wrapper).append('g').attr('class', 'total-wrapper');
|
|
156
|
+
// title
|
|
157
|
+
totalWrapper.append('text').attr('fill', '#545454').attr('font-size', chartHeight > 240 ? 20 : 12).text(name).attr('dy', 50).call(g => {
|
|
158
|
+
const {
|
|
159
|
+
width
|
|
160
|
+
} = g.node().getBoundingClientRect();
|
|
161
|
+
g.attr('dx', "".concat(-(width / 2)));
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
// total
|
|
165
|
+
totalWrapper.append('text').attr('fill', theme.textColor).attr('font-size', chartHeight > 240 ? 36 : 16).text("".concat(formatValue, "%")).attr('dx', -10).attr('dy', 90).call(g => {
|
|
166
|
+
const {
|
|
167
|
+
width
|
|
168
|
+
} = g.node().getBoundingClientRect();
|
|
169
|
+
g.attr('dx', "".concat(-(width / 2)));
|
|
170
|
+
});
|
|
171
|
+
};
|
|
172
|
+
this.chart = null;
|
|
173
|
+
this.state = {
|
|
174
|
+
tooltipData: null,
|
|
175
|
+
toolTipPosition: null
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
componentDidMount() {
|
|
179
|
+
this.createChart();
|
|
180
|
+
this.drawChart();
|
|
181
|
+
this.debouncedHandleResize = (0, _lodashEs.debounce)(this.handleResize, 300);
|
|
182
|
+
window.addEventListener('resize', this.debouncedHandleResize);
|
|
183
|
+
}
|
|
184
|
+
componentDidUpdate(prevProps) {
|
|
185
|
+
super.componentDidUpdate(prevProps);
|
|
186
|
+
if (_utils.BaseUtils.shouldChartComponentUpdate(prevProps, this.props)) {
|
|
187
|
+
this.destroyChart();
|
|
188
|
+
this.createChart();
|
|
189
|
+
this.drawChart();
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
componentWillUnmount() {
|
|
193
|
+
this.destroyChart();
|
|
194
|
+
window.removeEventListener('resize', this.debouncedHandleResize);
|
|
195
|
+
}
|
|
196
|
+
render() {
|
|
197
|
+
const {
|
|
198
|
+
tooltipData,
|
|
199
|
+
toolTipPosition
|
|
200
|
+
} = this.state;
|
|
201
|
+
return /*#__PURE__*/_react.default.createElement("div", {
|
|
202
|
+
ref: ref => this.container = ref,
|
|
203
|
+
className: "sea-chart-container"
|
|
204
|
+
}, /*#__PURE__*/_react.default.createElement(_tooltip.default, {
|
|
205
|
+
tooltipData: tooltipData,
|
|
206
|
+
toolTipPosition: toolTipPosition,
|
|
207
|
+
chart: this.chart
|
|
208
|
+
}));
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
Dashboard.propTypes = {
|
|
212
|
+
canvasStyle: _propTypes.default.object,
|
|
213
|
+
chart: _propTypes.default.object,
|
|
214
|
+
groupbyColumn: _propTypes.default.object,
|
|
215
|
+
summaryColumn: _propTypes.default.object,
|
|
216
|
+
result: _propTypes.default.number,
|
|
217
|
+
tables: _propTypes.default.array,
|
|
218
|
+
globalTheme: _propTypes.default.string,
|
|
219
|
+
chartColorTheme: _propTypes.default.string,
|
|
220
|
+
toggleRecords: _propTypes.default.func,
|
|
221
|
+
customRender: _propTypes.default.func
|
|
222
|
+
};
|
|
223
|
+
var _default = exports.default = Dashboard;
|
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard").default;
|
|
4
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
|
|
5
|
+
Object.defineProperty(exports, "__esModule", {
|
|
6
|
+
value: true
|
|
7
|
+
});
|
|
8
|
+
exports.default = void 0;
|
|
9
|
+
var _react = _interopRequireDefault(require("react"));
|
|
10
|
+
var _propTypes = _interopRequireDefault(require("prop-types"));
|
|
11
|
+
var _lodashEs = require("lodash-es");
|
|
12
|
+
var d3 = _interopRequireWildcard(require("d3"));
|
|
13
|
+
var _classnames = _interopRequireDefault(require("classnames"));
|
|
14
|
+
var _dayjs = _interopRequireDefault(require("dayjs"));
|
|
15
|
+
var _dtableUtils = require("dtable-utils");
|
|
16
|
+
var _dayOfYear = _interopRequireDefault(require("dayjs/plugin/dayOfYear"));
|
|
17
|
+
var _style = require("../../constants/style");
|
|
18
|
+
var _constants = require("../../constants");
|
|
19
|
+
var _utils = require("../../utils");
|
|
20
|
+
var _intl = _interopRequireDefault(require("../../intl"));
|
|
21
|
+
var _tooltip = _interopRequireDefault(require("../../components/tooltip"));
|
|
22
|
+
var _chartComponent = _interopRequireDefault(require("./chart-component"));
|
|
23
|
+
_dayjs.default.extend(_dayOfYear.default);
|
|
24
|
+
class HeatMap extends _chartComponent.default {
|
|
25
|
+
constructor(props) {
|
|
26
|
+
super(props);
|
|
27
|
+
this.handleResize = () => {
|
|
28
|
+
this.destroyChart();
|
|
29
|
+
this.createChart();
|
|
30
|
+
this.drawChart();
|
|
31
|
+
};
|
|
32
|
+
this.createChart = () => {
|
|
33
|
+
const {
|
|
34
|
+
chart,
|
|
35
|
+
result
|
|
36
|
+
} = this.props;
|
|
37
|
+
const initConfig = {
|
|
38
|
+
insertPadding: 30,
|
|
39
|
+
borderRadius: 0.06,
|
|
40
|
+
monthAxisHeight: 30
|
|
41
|
+
};
|
|
42
|
+
const {
|
|
43
|
+
width,
|
|
44
|
+
height
|
|
45
|
+
} = this.getCustomWidthAndHeight(result, chart.config, initConfig);
|
|
46
|
+
initConfig['customWidth'] = width;
|
|
47
|
+
initConfig['customHeight'] = height;
|
|
48
|
+
this.initChart(this.container, chart === null || chart === void 0 ? void 0 : chart.id, initConfig);
|
|
49
|
+
};
|
|
50
|
+
this.drawChart = () => {
|
|
51
|
+
const {
|
|
52
|
+
result = {}
|
|
53
|
+
} = this.props;
|
|
54
|
+
if (Object.keys(result).length === 0) return;
|
|
55
|
+
this.draw(result);
|
|
56
|
+
this.renderAxisLabel(this.props.chart, this.props.tables, this.container);
|
|
57
|
+
};
|
|
58
|
+
this.getCustomWidthAndHeight = (result, chartConfig, initConfig) => {
|
|
59
|
+
const {
|
|
60
|
+
insertPadding,
|
|
61
|
+
monthAxisHeight
|
|
62
|
+
} = initConfig;
|
|
63
|
+
const count = result.years.length;
|
|
64
|
+
let {
|
|
65
|
+
grid_size,
|
|
66
|
+
grid_distance
|
|
67
|
+
} = chartConfig;
|
|
68
|
+
grid_size = grid_size || _constants.DEFAULT_GRID_SIZE;
|
|
69
|
+
grid_distance = grid_distance || _constants.DEFAULT_GRID_DISTANCE;
|
|
70
|
+
const yearHeight = grid_size * 7 + grid_distance * 6; // height for 1 year
|
|
71
|
+
const height = (yearHeight + monthAxisHeight) * count + (insertPadding + insertPadding); // monthAxisHeight is axis height, insertPadding is top and bottm height
|
|
72
|
+
const width = grid_size * 53 + grid_distance * 52 + (insertPadding + insertPadding); // insertPadding is left and right width
|
|
73
|
+
return {
|
|
74
|
+
width,
|
|
75
|
+
height
|
|
76
|
+
};
|
|
77
|
+
};
|
|
78
|
+
this.showTooltip = (event, data, columnData) => {
|
|
79
|
+
const {
|
|
80
|
+
offsetX,
|
|
81
|
+
offsetY
|
|
82
|
+
} = event;
|
|
83
|
+
const newTooltipData = {
|
|
84
|
+
title: data.name,
|
|
85
|
+
items: [{
|
|
86
|
+
color: '',
|
|
87
|
+
name: _intl.default.get(_constants.TITLE_AMOUNT),
|
|
88
|
+
value: (0, _dtableUtils.getNumberDisplayString)(data.value, columnData)
|
|
89
|
+
}]
|
|
90
|
+
};
|
|
91
|
+
this.setState({
|
|
92
|
+
tooltipData: newTooltipData
|
|
93
|
+
});
|
|
94
|
+
this.setState({
|
|
95
|
+
toolTipPosition: {
|
|
96
|
+
offsetX,
|
|
97
|
+
offsetY
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
};
|
|
101
|
+
this.moveTooltip = event => {
|
|
102
|
+
const {
|
|
103
|
+
offsetX,
|
|
104
|
+
offsetY
|
|
105
|
+
} = event;
|
|
106
|
+
this.setState({
|
|
107
|
+
toolTipPosition: {
|
|
108
|
+
offsetX,
|
|
109
|
+
offsetY
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
};
|
|
113
|
+
this.hiddenTooltip = event => {
|
|
114
|
+
this.setState({
|
|
115
|
+
toolTipPosition: null
|
|
116
|
+
});
|
|
117
|
+
};
|
|
118
|
+
this.draw = resultData => {
|
|
119
|
+
const {
|
|
120
|
+
data,
|
|
121
|
+
years
|
|
122
|
+
} = resultData;
|
|
123
|
+
const {
|
|
124
|
+
chart,
|
|
125
|
+
tables
|
|
126
|
+
} = this.props;
|
|
127
|
+
const {
|
|
128
|
+
width: chartWidth,
|
|
129
|
+
height: chartHeight,
|
|
130
|
+
insertPadding,
|
|
131
|
+
borderRadius,
|
|
132
|
+
monthAxisHeight
|
|
133
|
+
} = this.chartBoundingClientRect;
|
|
134
|
+
let {
|
|
135
|
+
data_color,
|
|
136
|
+
grid_size,
|
|
137
|
+
table_id,
|
|
138
|
+
summary_type,
|
|
139
|
+
summary_column
|
|
140
|
+
} = chart.config;
|
|
141
|
+
grid_size = grid_size ? grid_size : _constants.DEFAULT_GRID_SIZE;
|
|
142
|
+
const currentColorOption = _style.COLOR_OPTIONS.filter(item => item.name === data_color)[0] || _style.COLOR_OPTIONS[0];
|
|
143
|
+
const {
|
|
144
|
+
exampleColors
|
|
145
|
+
} = currentColorOption;
|
|
146
|
+
const themeColors = this.getThemeColors();
|
|
147
|
+
let columnData = _constants.DEFAULT_NUMBER_FORMAT_OBJECT;
|
|
148
|
+
if (summary_type === _constants.CHART_SUMMARY_TYPE.ADVANCED) {
|
|
149
|
+
const table = (0, _dtableUtils.getTableById)(tables, table_id);
|
|
150
|
+
const summaryColumn = (0, _dtableUtils.getTableColumnByKey)(table, summary_column) || {};
|
|
151
|
+
columnData = summaryColumn.data || _constants.DEFAULT_NUMBER_FORMAT_OBJECT;
|
|
152
|
+
}
|
|
153
|
+
const yAxisWrapper = this.chart.append('g').attr('class', 'y-axis-wrapper');
|
|
154
|
+
const xAxisWrapper = this.chart.append('g').attr('class', 'x-axis-wrapper');
|
|
155
|
+
const contentWrapper = this.chart.append('g').attr('class', 'content-wrapper');
|
|
156
|
+
const titleWrapper = this.chart.append('g').attr('class', 'title-wrapper');
|
|
157
|
+
|
|
158
|
+
// Fy scale
|
|
159
|
+
const fyDomain = new Set(years.map(d => d));
|
|
160
|
+
const fy = d3.scaleBand().domain(fyDomain).range([insertPadding, chartHeight - insertPadding]).paddingInner(0).paddingOuter(0);
|
|
161
|
+
Array.from(fyDomain).forEach((year, index) => {
|
|
162
|
+
// Y axis
|
|
163
|
+
const y = d3.scaleBand().domain(this.weeks).range([fy(year), fy(year) + (fy.bandwidth() - monthAxisHeight)]).paddingInner(0).paddingOuter(0);
|
|
164
|
+
yAxisWrapper.append('g').attr('class', "y-axis-".concat(year)).attr('transform', "translate(".concat(insertPadding, ", 0)")).call(d3.axisLeft(y).tickSizeInner(0).tickSizeOuter(0).tickFormat(d => _intl.default.get(d))).call(g => {
|
|
165
|
+
g.select('.domain').remove();
|
|
166
|
+
g.selectAll('text').attr('font-size', 12);
|
|
167
|
+
g.selectAll('text').attr('fill', themeColors.textColor);
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
// Content
|
|
171
|
+
const [dates, weekCount] = this.generateYearDates(year);
|
|
172
|
+
const monthTranslateX = [];
|
|
173
|
+
const weekDomain = Array.from({
|
|
174
|
+
length: weekCount
|
|
175
|
+
}, (_, i) => i + 1);
|
|
176
|
+
const weekScale = d3.scaleBand().domain(weekDomain).range([insertPadding, chartWidth - insertPadding]).paddingInner(0).paddingOuter(0);
|
|
177
|
+
|
|
178
|
+
// year
|
|
179
|
+
const yearWrapper = contentWrapper.append('g').attr('class', "year-wrapper-".concat(year));
|
|
180
|
+
dates.forEach(_ref => {
|
|
181
|
+
let [monthIndex, days] = _ref;
|
|
182
|
+
// month
|
|
183
|
+
const monthWrapper = yearWrapper.append('g').attr('class', "month-".concat(this.months[monthIndex]));
|
|
184
|
+
// day
|
|
185
|
+
days.forEach((d, index) => {
|
|
186
|
+
monthWrapper.append('rect').attr('class', () => "day-".concat((0, _dayjs.default)(d).dayOfYear())).attr('x', () => {
|
|
187
|
+
let curWeek = (0, _dayjs.default)(d).week();
|
|
188
|
+
// The last few days are the first week of the next year
|
|
189
|
+
if (monthIndex === 11 && curWeek === 1) {
|
|
190
|
+
curWeek = weekCount;
|
|
191
|
+
}
|
|
192
|
+
if (index === 0) {
|
|
193
|
+
monthTranslateX.push(weekScale(curWeek));
|
|
194
|
+
} // Record the x position of the first day of each month
|
|
195
|
+
return weekScale(curWeek);
|
|
196
|
+
}).attr('y', () => {
|
|
197
|
+
const curWeek = this.weeks[(0, _dayjs.default)(d).day()];
|
|
198
|
+
return y(curWeek);
|
|
199
|
+
}).attr('width', grid_size).attr('height', grid_size).attr('rx', grid_size * borderRadius).attr('fill', () => this.getRectColor(d, data, 'fill', exampleColors)).attr('stroke', () => this.getRectColor(d, data, 'stroke', exampleColors)).attr('stroke-width', 1).on('click', () => {
|
|
200
|
+
const curDate = data.find(item => item.name === (0, _dayjs.default)(d).format('YYYY-MM-DD'));
|
|
201
|
+
if (curDate) {
|
|
202
|
+
this.props.toggleRecords(curDate);
|
|
203
|
+
}
|
|
204
|
+
}).on('mouseover', event => {
|
|
205
|
+
const curDate = data.find(item => item.name === (0, _dayjs.default)(d).format('YYYY-MM-DD'));
|
|
206
|
+
if (curDate) {
|
|
207
|
+
this.showTooltip(event, curDate, columnData);
|
|
208
|
+
}
|
|
209
|
+
}).on('mousemove', event => {
|
|
210
|
+
const curDate = data.find(item => item.name === (0, _dayjs.default)(d).format('YYYY-MM-DD'));
|
|
211
|
+
if (curDate) {
|
|
212
|
+
this.moveTooltip(event);
|
|
213
|
+
}
|
|
214
|
+
}).on('mouseleave', () => {
|
|
215
|
+
this.hiddenTooltip();
|
|
216
|
+
});
|
|
217
|
+
});
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
// X axis
|
|
221
|
+
const x = d3.scalePoint().domain(this.months).range([insertPadding, chartWidth - insertPadding]);
|
|
222
|
+
xAxisWrapper.append('g').attr('class', "x-axis-".concat(year)).attr('transform', "translate(0, ".concat(fy(year) + fy.bandwidth() - monthAxisHeight, ")")).call(d3.axisBottom(x).tickSizeInner(0).tickSizeOuter(0).tickFormat(d => _intl.default.get(d))).call(g => {
|
|
223
|
+
g.select('.domain').remove();
|
|
224
|
+
g.selectAll('.tick').nodes().forEach((item, index) => {
|
|
225
|
+
const curTranslateX = monthTranslateX[index] + weekScale.bandwidth() / 2;
|
|
226
|
+
d3.select(item).attr('transform', "translate(".concat(curTranslateX, ", 0)"));
|
|
227
|
+
});
|
|
228
|
+
g.selectAll('text').attr('font-size', 12);
|
|
229
|
+
g.selectAll('text').attr('fill', themeColors.textColor);
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
// Title
|
|
233
|
+
titleWrapper.append('text').attr('class', "text-".concat(year)).attr('x', 0).attr('y', fy(year) + fy.bandwidth()).attr('fill', '#000').attr('font-size', 12).attr('font-weight', 500).text(year);
|
|
234
|
+
});
|
|
235
|
+
this.setLegendForHeatMap({
|
|
236
|
+
exampleColors: ['#EBEDF0', ...exampleColors],
|
|
237
|
+
themeColors
|
|
238
|
+
});
|
|
239
|
+
};
|
|
240
|
+
this.generateYearDates = year => {
|
|
241
|
+
const dates = [];
|
|
242
|
+
let current = (0, _dayjs.default)("".concat(year, "-01-01"));
|
|
243
|
+
while (current.year() === year) {
|
|
244
|
+
dates.push(current);
|
|
245
|
+
current = current.add(1, 'day');
|
|
246
|
+
}
|
|
247
|
+
const weekCount = Math.ceil(dates.length / 7);
|
|
248
|
+
return [d3.groups(dates, d => (0, _dayjs.default)(d).month()), weekCount];
|
|
249
|
+
};
|
|
250
|
+
this.getRectColor = (d, data, type, exampleColors) => {
|
|
251
|
+
const maxVal = d3.max(data, d => d.value);
|
|
252
|
+
const defaultColor = type === 'stroke' ? '#E1E3E6' : '#EBEDF0';
|
|
253
|
+
const curDate = data.find(item => item.name === (0, _dayjs.default)(d).format('YYYY-MM-DD'));
|
|
254
|
+
if (curDate) {
|
|
255
|
+
if (curDate.value <= 0) return defaultColor;
|
|
256
|
+
if (curDate.value === maxVal) return type === 'stroke' ? _style.FILL_BORDER_COLOR_MAP[exampleColors[8]] : exampleColors[8];
|
|
257
|
+
const curColor = Math.floor(curDate.value / (maxVal / 9));
|
|
258
|
+
return type === 'stroke' ? _style.FILL_BORDER_COLOR_MAP[exampleColors[curColor]] : exampleColors[curColor];
|
|
259
|
+
}
|
|
260
|
+
return defaultColor;
|
|
261
|
+
};
|
|
262
|
+
_dayjs.default.locale('en');
|
|
263
|
+
this.weeks = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
|
|
264
|
+
this.months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
|
|
265
|
+
this.chart = null;
|
|
266
|
+
this.state = {
|
|
267
|
+
tooltipData: null,
|
|
268
|
+
toolTipPosition: null
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
componentDidMount() {
|
|
272
|
+
this.createChart();
|
|
273
|
+
this.drawChart();
|
|
274
|
+
this.debouncedHandleResize = (0, _lodashEs.debounce)(this.handleResize, 300);
|
|
275
|
+
window.addEventListener('resize', this.debouncedHandleResize);
|
|
276
|
+
}
|
|
277
|
+
componentDidUpdate(prevProps) {
|
|
278
|
+
super.componentDidUpdate(prevProps);
|
|
279
|
+
if (_utils.BaseUtils.shouldChartComponentUpdate(prevProps, this.props)) {
|
|
280
|
+
this.destroyChart();
|
|
281
|
+
this.createChart();
|
|
282
|
+
this.drawChart();
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
componentWillUnmount() {
|
|
286
|
+
this.destroyChart();
|
|
287
|
+
window.removeEventListener('resize', this.debouncedHandleResize);
|
|
288
|
+
}
|
|
289
|
+
render() {
|
|
290
|
+
const {
|
|
291
|
+
chart
|
|
292
|
+
} = this.props;
|
|
293
|
+
const {
|
|
294
|
+
tooltipData,
|
|
295
|
+
toolTipPosition
|
|
296
|
+
} = this.state;
|
|
297
|
+
return /*#__PURE__*/_react.default.createElement("div", {
|
|
298
|
+
ref: ref => this.container = ref,
|
|
299
|
+
className: (0, _classnames.default)('sea-chart-container', {
|
|
300
|
+
'show-x-axis-label': this.isShowXAxisLabel(chart),
|
|
301
|
+
'show-y-axis-label': this.isShowYAxisLabel(chart)
|
|
302
|
+
})
|
|
303
|
+
}, /*#__PURE__*/_react.default.createElement(_tooltip.default, {
|
|
304
|
+
tooltipData: tooltipData,
|
|
305
|
+
toolTipPosition: toolTipPosition,
|
|
306
|
+
chart: this.chart
|
|
307
|
+
}));
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
HeatMap.propTypes = {
|
|
311
|
+
canvasStyle: _propTypes.default.object,
|
|
312
|
+
chart: _propTypes.default.object,
|
|
313
|
+
groupbyColumn: _propTypes.default.object,
|
|
314
|
+
columnGroupbyColumn: _propTypes.default.object,
|
|
315
|
+
summaryColumn: _propTypes.default.object,
|
|
316
|
+
result: _propTypes.default.object,
|
|
317
|
+
tables: _propTypes.default.array,
|
|
318
|
+
globalTheme: _propTypes.default.string,
|
|
319
|
+
chartColorTheme: _propTypes.default.string,
|
|
320
|
+
toggleRecords: _propTypes.default.func,
|
|
321
|
+
customRender: _propTypes.default.func
|
|
322
|
+
};
|
|
323
|
+
var _default = exports.default = HeatMap;
|
|
@@ -34,6 +34,9 @@ var _map = _interopRequireDefault(require("./map"));
|
|
|
34
34
|
var _mapBubble = _interopRequireDefault(require("./map-bubble"));
|
|
35
35
|
var _mapWorld = _interopRequireDefault(require("./map-world"));
|
|
36
36
|
var _mapWorldBubble = _interopRequireDefault(require("./map-world-bubble"));
|
|
37
|
+
var _heatMap = _interopRequireDefault(require("./heat-map"));
|
|
38
|
+
var _mirror = _interopRequireDefault(require("./mirror"));
|
|
39
|
+
var _dashboard = _interopRequireDefault(require("./dashboard"));
|
|
37
40
|
var _trend = _interopRequireDefault(require("./trend"));
|
|
38
41
|
var _tableElement = _interopRequireDefault(require("./table-element"));
|
|
39
42
|
const Wrapper = _ref => {
|
|
@@ -281,6 +284,24 @@ const Wrapper = _ref => {
|
|
|
281
284
|
canvasStyle: canvasStyle
|
|
282
285
|
}));
|
|
283
286
|
}
|
|
287
|
+
case _constants.CHART_TYPE.HEAT_MAP:
|
|
288
|
+
{
|
|
289
|
+
return /*#__PURE__*/_react.default.createElement(_heatMap.default, Object.assign({}, baseProps, {
|
|
290
|
+
canvasStyle: canvasStyle
|
|
291
|
+
}));
|
|
292
|
+
}
|
|
293
|
+
case _constants.CHART_TYPE.MIRROR:
|
|
294
|
+
{
|
|
295
|
+
return /*#__PURE__*/_react.default.createElement(_mirror.default, Object.assign({}, baseProps, {
|
|
296
|
+
canvasStyle: canvasStyle
|
|
297
|
+
}));
|
|
298
|
+
}
|
|
299
|
+
case _constants.CHART_TYPE.DASHBOARD:
|
|
300
|
+
{
|
|
301
|
+
return /*#__PURE__*/_react.default.createElement(_dashboard.default, Object.assign({}, baseProps, {
|
|
302
|
+
canvasStyle: canvasStyle
|
|
303
|
+
}));
|
|
304
|
+
}
|
|
284
305
|
case _constants.CHART_TYPE.BASIC_NUMBER_CARD:
|
|
285
306
|
{
|
|
286
307
|
return /*#__PURE__*/_react.default.createElement(_basicNumberCard.default, Object.assign({}, baseProps, {
|
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard").default;
|
|
4
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
|
|
5
|
+
Object.defineProperty(exports, "__esModule", {
|
|
6
|
+
value: true
|
|
7
|
+
});
|
|
8
|
+
exports.default = void 0;
|
|
9
|
+
var _react = _interopRequireDefault(require("react"));
|
|
10
|
+
var _propTypes = _interopRequireDefault(require("prop-types"));
|
|
11
|
+
var _lodashEs = require("lodash-es");
|
|
12
|
+
var d3 = _interopRequireWildcard(require("d3"));
|
|
13
|
+
var _classnames = _interopRequireDefault(require("classnames"));
|
|
14
|
+
var _dtableUtils = require("dtable-utils");
|
|
15
|
+
var _constants = require("../../constants");
|
|
16
|
+
var _utils = require("../../utils");
|
|
17
|
+
var _intl = _interopRequireDefault(require("../../intl"));
|
|
18
|
+
var _tooltip = _interopRequireDefault(require("../../components/tooltip"));
|
|
19
|
+
var _chartComponent = _interopRequireDefault(require("./chart-component"));
|
|
20
|
+
class Mirror extends _chartComponent.default {
|
|
21
|
+
constructor(props) {
|
|
22
|
+
super(props);
|
|
23
|
+
this.handleResize = () => {
|
|
24
|
+
this.destroyChart();
|
|
25
|
+
this.createChart();
|
|
26
|
+
this.drawChart();
|
|
27
|
+
};
|
|
28
|
+
this.createChart = () => {
|
|
29
|
+
const {
|
|
30
|
+
chart
|
|
31
|
+
} = this.props;
|
|
32
|
+
const initConfig = {
|
|
33
|
+
insertPadding: 30,
|
|
34
|
+
bottomLegendSpace: 20
|
|
35
|
+
};
|
|
36
|
+
this.initChart(this.container, chart === null || chart === void 0 ? void 0 : chart.id, initConfig);
|
|
37
|
+
};
|
|
38
|
+
this.drawChart = () => {
|
|
39
|
+
let {
|
|
40
|
+
result
|
|
41
|
+
} = this.props;
|
|
42
|
+
const data = _utils.BaseUtils.formatEmptyName(result.data, '', _intl.default.get('Empty'));
|
|
43
|
+
if (!Array.isArray(data)) return;
|
|
44
|
+
this.draw({
|
|
45
|
+
data,
|
|
46
|
+
colorSet: result.colorSet
|
|
47
|
+
});
|
|
48
|
+
this.renderAxisLabel(this.props.chart, this.props.tables, this.container);
|
|
49
|
+
};
|
|
50
|
+
this.showTooltip = (event, data) => {
|
|
51
|
+
const {
|
|
52
|
+
chart
|
|
53
|
+
} = this.props;
|
|
54
|
+
const {
|
|
55
|
+
summary_type,
|
|
56
|
+
summary_method
|
|
57
|
+
} = chart.config;
|
|
58
|
+
const {
|
|
59
|
+
offsetX,
|
|
60
|
+
offsetY
|
|
61
|
+
} = event;
|
|
62
|
+
const newTooltipData = {
|
|
63
|
+
title: summary_type === 'count' ? _intl.default.get(_constants.TITLE_AMOUNT) : _intl.default.get(_constants.CHART_SUMMARY_SHOW[summary_method]),
|
|
64
|
+
items: [{
|
|
65
|
+
color: '',
|
|
66
|
+
name: data.name,
|
|
67
|
+
value: data.value
|
|
68
|
+
}]
|
|
69
|
+
};
|
|
70
|
+
this.setState({
|
|
71
|
+
tooltipData: newTooltipData
|
|
72
|
+
});
|
|
73
|
+
this.setState({
|
|
74
|
+
toolTipPosition: {
|
|
75
|
+
offsetX,
|
|
76
|
+
offsetY
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
};
|
|
80
|
+
this.moveTooltip = event => {
|
|
81
|
+
const {
|
|
82
|
+
offsetX,
|
|
83
|
+
offsetY
|
|
84
|
+
} = event;
|
|
85
|
+
this.setState({
|
|
86
|
+
toolTipPosition: {
|
|
87
|
+
offsetX,
|
|
88
|
+
offsetY
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
};
|
|
92
|
+
this.hiddenTooltip = event => {
|
|
93
|
+
this.setState({
|
|
94
|
+
toolTipPosition: null
|
|
95
|
+
});
|
|
96
|
+
};
|
|
97
|
+
this.draw = _ref => {
|
|
98
|
+
let {
|
|
99
|
+
data,
|
|
100
|
+
colorSet
|
|
101
|
+
} = _ref;
|
|
102
|
+
const {
|
|
103
|
+
chart,
|
|
104
|
+
tables
|
|
105
|
+
} = this.props;
|
|
106
|
+
const {
|
|
107
|
+
table_id,
|
|
108
|
+
summary_type,
|
|
109
|
+
summary_column,
|
|
110
|
+
is_transpose
|
|
111
|
+
} = chart.config;
|
|
112
|
+
const {
|
|
113
|
+
width: chartWidth,
|
|
114
|
+
height: chartHeight,
|
|
115
|
+
insertPadding,
|
|
116
|
+
bottomLegendSpace
|
|
117
|
+
} = this.chartBoundingClientRect;
|
|
118
|
+
const themeColors = this.getThemeColors();
|
|
119
|
+
let columnData = _constants.DEFAULT_NUMBER_FORMAT_OBJECT;
|
|
120
|
+
if (summary_type === _constants.CHART_SUMMARY_TYPE.ADVANCED) {
|
|
121
|
+
const table = (0, _dtableUtils.getTableById)(tables, table_id);
|
|
122
|
+
const summaryColumn = (0, _dtableUtils.getTableColumnByKey)(table, summary_column) || {};
|
|
123
|
+
columnData = summaryColumn.data || _constants.DEFAULT_NUMBER_FORMAT_OBJECT;
|
|
124
|
+
}
|
|
125
|
+
const scaleBandDomain = Array.from(new Set(data.map(d => d.group_name)));
|
|
126
|
+
const scaleBand = d3.scaleBand().domain(scaleBandDomain).range(is_transpose ? [insertPadding, chartWidth - insertPadding] : [insertPadding, chartHeight - insertPadding - bottomLegendSpace]).paddingInner(0.1).paddingOuter(0);
|
|
127
|
+
|
|
128
|
+
// ScaleLinear axis
|
|
129
|
+
const maxDomain = d3.max(data, d => d.value);
|
|
130
|
+
const scaleLinear1 = d3.scaleLinear().domain([maxDomain, 0]).range([scaleBand(scaleBandDomain[0]), scaleBand.bandwidth()]);
|
|
131
|
+
const scaleLinear2 = d3.scaleLinear().domain([0, maxDomain]).range([scaleBand(scaleBandDomain[1]), scaleBand(scaleBandDomain[1]) + scaleBand.bandwidth()]);
|
|
132
|
+
const scaleLinearWrapper = this.chart.append('g').attr('class', 'scale-linear-axis-wrapper');
|
|
133
|
+
scaleLinearWrapper.append('g').attr('class', 'scale-linear-1').attr('transform', is_transpose ? "translate(0, ".concat(chartHeight - insertPadding - bottomLegendSpace, ")") : "translate(".concat(insertPadding, ", 0)")).call(is_transpose ? d3.axisBottom(scaleLinear1).tickSizeInner(0).tickSizeOuter(0).ticks(5) : d3.axisLeft(scaleLinear1).tickSizeInner(0).tickSizeOuter(0).ticks(5)).call(g => {
|
|
134
|
+
g.select('.domain').remove();
|
|
135
|
+
g.selectAll('text').attr('font-size', themeColors.fontSize).attr('fill', themeColors.textColor);
|
|
136
|
+
g.selectAll('.tick line').attr('stroke', themeColors.gridColor);
|
|
137
|
+
is_transpose ? g.selectAll('.tick line').attr('y2', -(chartHeight - insertPadding - insertPadding - bottomLegendSpace)) : g.selectAll('.tick line').attr('x2', chartWidth - insertPadding - insertPadding);
|
|
138
|
+
});
|
|
139
|
+
scaleLinearWrapper.append('g').attr('class', 'scale-linear-2').attr('transform', is_transpose ? "translate(0, ".concat(chartHeight - insertPadding - bottomLegendSpace, ")") : "translate(".concat(insertPadding, ", 0)")).call(is_transpose ? d3.axisBottom(scaleLinear2).tickSizeInner(0).tickSizeOuter(0).ticks(5).tickFormat(t => (0, _dtableUtils.getNumberDisplayString)(t, columnData)) : d3.axisLeft(scaleLinear2).tickSizeInner(0).tickSizeOuter(0).ticks(5).tickFormat(t => (0, _dtableUtils.getNumberDisplayString)(t, columnData))).call(g => {
|
|
140
|
+
g.select('.domain').remove();
|
|
141
|
+
g.selectAll('text').attr('font-size', themeColors.fontSize).attr('fill', themeColors.textColor);
|
|
142
|
+
g.selectAll('.tick line').attr('stroke', themeColors.gridColor);
|
|
143
|
+
is_transpose ? g.selectAll('.tick line').attr('y2', -(chartHeight - insertPadding - insertPadding - bottomLegendSpace)) : g.selectAll('.tick line').attr('x2', chartWidth - insertPadding - insertPadding);
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
// ScaleBand Center axis
|
|
147
|
+
const scaleBandCenter = d3.scaleBand().domain(new Set(data.map(d => d.name))).range(is_transpose ? [insertPadding, chartHeight - insertPadding - bottomLegendSpace] : [insertPadding, chartWidth - insertPadding]).paddingInner(0.5).paddingOuter(0.1);
|
|
148
|
+
this.chart.append('g').attr('class', 'scale-band-center-axis-wrapper').attr('transform', is_transpose ? "translate(".concat(scaleLinear1(0), ", 0)") : "translate(0, ".concat(scaleLinear1(0), ")")).call(is_transpose ? d3.axisRight(scaleBandCenter).tickSizeInner(4).tickSizeOuter(0).tickFormat(t => {
|
|
149
|
+
const name = String(t);
|
|
150
|
+
return name.length > 5 ? "".concat(name.slice(0, 5), "...") : name;
|
|
151
|
+
}) : d3.axisBottom(scaleBandCenter).tickSizeInner(4).tickSizeOuter(0).tickFormat(t => {
|
|
152
|
+
const name = String(t);
|
|
153
|
+
return name.length > 5 ? "".concat(name.slice(0, 5), "...") : name;
|
|
154
|
+
})).call(g => {
|
|
155
|
+
g.select('.domain').remove();
|
|
156
|
+
g.selectAll('.tick line').attr('stroke', themeColors.XAxisColor);
|
|
157
|
+
g.selectAll('text').attr('font-size', 12).attr('fill', themeColors.textColor);
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
// Content
|
|
161
|
+
const contentWrapper = this.chart.append('g').attr('class', 'content-wrapper');
|
|
162
|
+
contentWrapper.selectAll().data(d3.group(data, d => d.group_name)).join('g').call(g => {
|
|
163
|
+
// Add title
|
|
164
|
+
const titleWrapper = this.chart.append('g').attr('class', 'title-wrapper');
|
|
165
|
+
g.nodes().forEach((item, index) => {
|
|
166
|
+
const title = item === null || item === void 0 ? void 0 : item.__data__[0];
|
|
167
|
+
titleWrapper.append('text').text(title || '').attr('dominant-baseline', 'hanging').attr('fill', themeColors.textColor).attr('font-size', 14).attr('font-weight', 500).call(text => {
|
|
168
|
+
if (text.node()) {
|
|
169
|
+
var _text$node;
|
|
170
|
+
const {
|
|
171
|
+
width
|
|
172
|
+
} = (_text$node = text.node()) === null || _text$node === void 0 ? void 0 : _text$node.getBoundingClientRect();
|
|
173
|
+
const endPosition = index === 0 ? scaleLinear1(0) : scaleLinear2(maxDomain);
|
|
174
|
+
if (is_transpose) {
|
|
175
|
+
text.attr('x', endPosition - scaleBand.bandwidth() / 2 + width / 2);
|
|
176
|
+
text.attr('y', 0);
|
|
177
|
+
} else {
|
|
178
|
+
text.attr('x', chartWidth - width);
|
|
179
|
+
text.attr('y', endPosition - scaleBand.bandwidth() / 2);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
});
|
|
184
|
+
}).selectAll().data(_ref2 => {
|
|
185
|
+
let [groupName, d] = _ref2;
|
|
186
|
+
const newData = d.filter(item => item.value !== 0);
|
|
187
|
+
newData.groupName = groupName;
|
|
188
|
+
return newData;
|
|
189
|
+
}).join('rect').attr('opacity', 1).attr('x', d => {
|
|
190
|
+
const {
|
|
191
|
+
group_name,
|
|
192
|
+
value,
|
|
193
|
+
name
|
|
194
|
+
} = d;
|
|
195
|
+
if (group_name === scaleBandDomain[0]) {
|
|
196
|
+
return is_transpose ? scaleLinear1(value) : scaleBandCenter(name);
|
|
197
|
+
}
|
|
198
|
+
if (group_name === scaleBandDomain[1]) {
|
|
199
|
+
return is_transpose ? scaleLinear2(0) : scaleBandCenter(name);
|
|
200
|
+
}
|
|
201
|
+
}).attr('y', d => {
|
|
202
|
+
const {
|
|
203
|
+
group_name,
|
|
204
|
+
name,
|
|
205
|
+
value
|
|
206
|
+
} = d;
|
|
207
|
+
if (group_name === scaleBandDomain[0]) {
|
|
208
|
+
return is_transpose ? scaleBandCenter(name) : scaleLinear1(value);
|
|
209
|
+
}
|
|
210
|
+
if (group_name === scaleBandDomain[1]) {
|
|
211
|
+
return is_transpose ? scaleBandCenter(name) : scaleLinear2(0);
|
|
212
|
+
}
|
|
213
|
+
}).attr('width', d => {
|
|
214
|
+
const {
|
|
215
|
+
group_name,
|
|
216
|
+
value
|
|
217
|
+
} = d;
|
|
218
|
+
if (group_name === scaleBandDomain[0]) {
|
|
219
|
+
return is_transpose ? scaleLinear1(0) - scaleLinear1(value) : scaleBandCenter.bandwidth();
|
|
220
|
+
}
|
|
221
|
+
if (group_name === scaleBandDomain[1]) {
|
|
222
|
+
return is_transpose ? scaleLinear2(value) - scaleLinear2(0) : scaleBandCenter.bandwidth();
|
|
223
|
+
}
|
|
224
|
+
}).attr('height', d => {
|
|
225
|
+
const {
|
|
226
|
+
group_name,
|
|
227
|
+
value
|
|
228
|
+
} = d;
|
|
229
|
+
if (group_name === scaleBandDomain[0]) {
|
|
230
|
+
return is_transpose ? scaleBandCenter.bandwidth() : scaleLinear1(0) - scaleLinear1(value);
|
|
231
|
+
}
|
|
232
|
+
if (group_name === scaleBandDomain[1]) {
|
|
233
|
+
return is_transpose ? scaleBandCenter.bandwidth() : scaleLinear2(value) - scaleLinear2(0);
|
|
234
|
+
}
|
|
235
|
+
}).attr('fill', d => {
|
|
236
|
+
const {
|
|
237
|
+
color
|
|
238
|
+
} = d;
|
|
239
|
+
return color;
|
|
240
|
+
}).on('click', (event, data) => {
|
|
241
|
+
this.props.toggleRecords(data);
|
|
242
|
+
}).on('mouseover', (event, data) => {
|
|
243
|
+
this.showTooltip(event, data);
|
|
244
|
+
}).on('mousemove', event => {
|
|
245
|
+
this.moveTooltip(event);
|
|
246
|
+
}).on('mouseleave', event => {
|
|
247
|
+
this.hiddenTooltip(event);
|
|
248
|
+
});
|
|
249
|
+
this.setLegend({
|
|
250
|
+
legendName: 'group_name',
|
|
251
|
+
theme: themeColors,
|
|
252
|
+
legendPosition: 'top-left',
|
|
253
|
+
data,
|
|
254
|
+
groupColumn: this.props.columnGroupbyColumn,
|
|
255
|
+
chart,
|
|
256
|
+
colorScale: key => {
|
|
257
|
+
const curD = data.find(item => item.group_name === key);
|
|
258
|
+
return curD.color || '';
|
|
259
|
+
}
|
|
260
|
+
});
|
|
261
|
+
};
|
|
262
|
+
this.chart = null;
|
|
263
|
+
this.state = {
|
|
264
|
+
tooltipData: null,
|
|
265
|
+
toolTipPosition: null
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
componentDidMount() {
|
|
269
|
+
this.createChart();
|
|
270
|
+
this.drawChart();
|
|
271
|
+
this.debouncedHandleResize = (0, _lodashEs.debounce)(this.handleResize, 300);
|
|
272
|
+
window.addEventListener('resize', this.debouncedHandleResize);
|
|
273
|
+
}
|
|
274
|
+
componentDidUpdate(prevProps) {
|
|
275
|
+
super.componentDidUpdate(prevProps);
|
|
276
|
+
if (_utils.BaseUtils.shouldChartComponentUpdate(prevProps, this.props)) {
|
|
277
|
+
this.destroyChart();
|
|
278
|
+
this.createChart();
|
|
279
|
+
this.drawChart();
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
componentWillUnmount() {
|
|
283
|
+
this.destroyChart();
|
|
284
|
+
window.removeEventListener('resize', this.debouncedHandleResize);
|
|
285
|
+
}
|
|
286
|
+
render() {
|
|
287
|
+
const {
|
|
288
|
+
chart
|
|
289
|
+
} = this.props;
|
|
290
|
+
const {
|
|
291
|
+
tooltipData,
|
|
292
|
+
toolTipPosition
|
|
293
|
+
} = this.state;
|
|
294
|
+
return /*#__PURE__*/_react.default.createElement("div", {
|
|
295
|
+
ref: ref => this.container = ref,
|
|
296
|
+
className: (0, _classnames.default)('sea-chart-container', {
|
|
297
|
+
'show-x-axis-label': this.isShowXAxisLabel(chart),
|
|
298
|
+
'show-y-axis-label': this.isShowYAxisLabel(chart)
|
|
299
|
+
})
|
|
300
|
+
}, /*#__PURE__*/_react.default.createElement(_tooltip.default, {
|
|
301
|
+
tooltipData: tooltipData,
|
|
302
|
+
toolTipPosition: toolTipPosition,
|
|
303
|
+
chart: this.chart
|
|
304
|
+
}));
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
Mirror.propTypes = {
|
|
308
|
+
canvasStyle: _propTypes.default.object,
|
|
309
|
+
chart: _propTypes.default.object,
|
|
310
|
+
groupbyColumn: _propTypes.default.object,
|
|
311
|
+
columnGroupbyColumn: _propTypes.default.object,
|
|
312
|
+
summaryColumn: _propTypes.default.object,
|
|
313
|
+
result: _propTypes.default.object,
|
|
314
|
+
tables: _propTypes.default.array,
|
|
315
|
+
globalTheme: _propTypes.default.string,
|
|
316
|
+
chartColorTheme: _propTypes.default.string,
|
|
317
|
+
toggleRecords: _propTypes.default.func,
|
|
318
|
+
customRender: _propTypes.default.func
|
|
319
|
+
};
|
|
320
|
+
var _default = exports.default = Mirror;
|