sea-chart 2.0.12 → 2.0.13

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.
@@ -70,7 +70,7 @@ const TypesDialog = _ref => {
70
70
  const handleFilterTypes = (0, _react.useCallback)(() => {
71
71
  if (hideTypeToggle) {
72
72
  const newChartTypes = _constants.CHART_TYPES.filter(item => ['Histogram', 'Bar_chart'].includes(item.name));
73
- newChartTypes[1].children = newChartTypes[1].children.slice(0, 2);
73
+ newChartTypes[1].children = newChartTypes[1].children.slice(0, 4);
74
74
  return newChartTypes;
75
75
  }
76
76
  return _constants.CHART_TYPES;
@@ -560,6 +560,9 @@ BaseUtils.formatEmptyName = (dataList, column_groupby_column_key, emptyName) =>
560
560
  if (!item.slugId) {
561
561
  item.slugId = _slugid.default.nice();
562
562
  }
563
+ if (!item.value) {
564
+ item.value = 0;
565
+ }
563
566
  updatedStatistics.push(item);
564
567
  }
565
568
  return updatedStatistics;
@@ -1081,6 +1081,7 @@ class ChartComponent extends _react.Component {
1081
1081
  this.addLabelToRectRight = _ref7 => {
1082
1082
  let {
1083
1083
  container,
1084
+ x,
1084
1085
  y,
1085
1086
  xWidth,
1086
1087
  yHeight,
@@ -1088,11 +1089,14 @@ class ChartComponent extends _react.Component {
1088
1089
  label_font_size,
1089
1090
  text
1090
1091
  } = _ref7;
1091
- d3.select(container).append('text').attr('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 => {
1092
- const {
1093
- height
1094
- } = g.node().getBoundingClientRect();
1095
- g.attr('y', Number(y) + Number(yHeight) / 2 - height / 2);
1092
+ d3.select(container).append('text').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 => {
1093
+ if (g.node()) {
1094
+ var _g$node;
1095
+ const {
1096
+ height
1097
+ } = (_g$node = g.node()) === null || _g$node === void 0 ? void 0 : _g$node.getBoundingClientRect();
1098
+ g.attr('y', Number(y) + Number(yHeight) / 2 - height / 2);
1099
+ }
1096
1100
  });
1097
1101
  };
1098
1102
  this.addLabelToRectCenter = _ref8 => {
@@ -1203,64 +1207,112 @@ class ChartComponent extends _react.Component {
1203
1207
  this.horizontalOverflowOffset = offset;
1204
1208
  }
1205
1209
  };
1206
- this.checkTickOverlap = g => {
1210
+ this.checkTickOverlap = (g, axis) => {
1207
1211
  const allTicks = g.selectAll('.tick').nodes();
1212
+ if (axis === 'yAxis') {
1213
+ allTicks.reverse();
1214
+ }
1215
+
1208
1216
  // Hide overlapping ticks
1209
1217
  for (let i = 0; i < allTicks.length; i++) {
1210
1218
  const curText = d3.select(allTicks[i]).select('text').node();
1211
1219
  const {
1212
- right: curRight
1220
+ right: curRight,
1221
+ bottom: curBottom
1213
1222
  } = curText.getBoundingClientRect();
1214
1223
  for (let j = i + 1; j < allTicks.length; j++) {
1215
1224
  const nextText = d3.select(allTicks[j]).select('text').node();
1216
1225
  if (curText && nextText) {
1217
1226
  const {
1218
- left: nextLeft
1227
+ left: nextLeft,
1228
+ top: nextTop
1219
1229
  } = nextText.getBoundingClientRect();
1220
- if (curRight >= nextLeft) {
1221
- i = j;
1222
- d3.select(nextText.parentNode).attr('opacity', 0);
1230
+ if (axis === 'yAxis') {
1231
+ if (curBottom >= nextTop) {
1232
+ i = j;
1233
+ d3.select(nextText.parentNode).attr('opacity', 0);
1234
+ }
1235
+ } else {
1236
+ if (curRight >= nextLeft) {
1237
+ i = j;
1238
+ d3.select(nextText.parentNode).attr('opacity', 0);
1239
+ }
1223
1240
  }
1224
1241
  }
1225
1242
  }
1226
1243
  }
1227
1244
  const {
1228
- width: maxWidth
1245
+ width: maxWidth,
1246
+ height: maxHeight
1229
1247
  } = g.node().getBoundingClientRect();
1230
- let allWidth = 0;
1231
- // Can't fit tilted text
1232
- for (let tick of allTicks) {
1248
+ const {
1249
+ insertPadding
1250
+ } = this.chartBoundingClientRect;
1251
+ const viewBox = this.chart.node().getAttribute('viewBox').split(',');
1252
+ if (axis === 'yAxis') {
1253
+ let allHeight = 0;
1254
+ // Can't fit tilted text, Italic text
1255
+ for (let tick of allTicks) {
1256
+ const {
1257
+ height
1258
+ } = tick.getBoundingClientRect();
1259
+ allHeight = allHeight + height;
1260
+ if (allHeight > maxHeight) {
1261
+ allTicks.forEach(tick => {
1262
+ const opacityVal = tick.getAttribute('opacity');
1263
+ if (Number(opacityVal) !== 0) {
1264
+ // roate
1265
+ d3.select(tick).select('text').attr('transform', 'rotate(30)').style('text-anchor', 'end').attr('dy', '1em').attr('dx', '-0.5em');
1266
+ }
1267
+ });
1268
+ break;
1269
+ }
1270
+ }
1271
+
1272
+ // Text overflow scale view box
1233
1273
  const {
1234
1274
  width
1235
- } = tick.getBoundingClientRect();
1236
- allWidth = allWidth + width;
1237
- if (allWidth > maxWidth) break;
1238
- }
1239
- if (allWidth > maxWidth) {
1240
- allTicks.forEach(tick => {
1241
- const opacityVal = tick.getAttribute('opacity');
1242
- if (Number(opacityVal) !== 0) {
1243
- // roate
1244
- d3.select(tick).select('text').attr('transform', 'rotate(45)').style('text-anchor', 'start').attr('dy', '0.4em').attr('dx', '0.4em');
1275
+ } = g.node().getBoundingClientRect();
1276
+ if (width > insertPadding) {
1277
+ const viewWidth = viewBox[viewBox.length - 2];
1278
+ viewBox[0] = "-".concat(width - insertPadding);
1279
+ viewBox[viewBox.length - 2] = "".concat(Number(viewWidth) + (width - insertPadding));
1280
+ queueMicrotask(() => {
1281
+ this.chart.attr('viewBox', viewBox.join(','));
1282
+ });
1283
+ }
1284
+ } else {
1285
+ let allWidth = 0;
1286
+ // Can't fit tilted text, Italic text
1287
+ for (let tick of allTicks) {
1288
+ const {
1289
+ width
1290
+ } = tick.getBoundingClientRect();
1291
+ allWidth = allWidth + width;
1292
+ if (allWidth > maxWidth) {
1293
+ allTicks.forEach(tick => {
1294
+ const opacityVal = tick.getAttribute('opacity');
1295
+ if (Number(opacityVal) !== 0) {
1296
+ // roate
1297
+ d3.select(tick).select('text').attr('transform', 'rotate(45)').style('text-anchor', 'start').attr('dy', '0.4em').attr('dx', '0.4em');
1298
+ }
1299
+ });
1300
+ break;
1245
1301
  }
1246
- });
1247
- }
1302
+ ;
1303
+ }
1248
1304
 
1249
- // Text overflow
1250
- const {
1251
- height
1252
- } = g.node().getBoundingClientRect();
1253
- const {
1254
- insertPadding
1255
- } = this.chartBoundingClientRect;
1256
- if (height > insertPadding) {
1257
- const viewBox = this.chart.node().getAttribute('viewBox').split(',');
1258
- const viewHeight = viewBox[viewBox.length - 1];
1259
- const newViewHeight = Number(viewHeight) + (height - insertPadding);
1260
- viewBox[viewBox.length - 1] = "".concat(newViewHeight);
1261
- queueMicrotask(() => {
1262
- this.chart.attr('viewBox', viewBox.join(','));
1263
- });
1305
+ // Text overflow scale view box
1306
+ const {
1307
+ height
1308
+ } = g.node().getBoundingClientRect();
1309
+ if (height > insertPadding) {
1310
+ const viewHeight = viewBox[viewBox.length - 1];
1311
+ viewBox[viewBox.length - 1] = "".concat(Number(viewHeight) + (height - insertPadding));
1312
+ queueMicrotask(() => {
1313
+ this.chart.attr('viewBox', viewBox.join(','));
1314
+ });
1315
+ }
1264
1316
  }
1265
1317
  };
1266
1318
  this.initLabelStroke(props === null || props === void 0 ? void 0 : props.globalTheme);
@@ -0,0 +1,344 @@
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 _constants = require("../../constants");
15
+ var _utils = require("../../utils");
16
+ var _intl = _interopRequireDefault(require("../../intl"));
17
+ var _tooltip = _interopRequireDefault(require("../../components/tooltip"));
18
+ var _chartComponent = _interopRequireDefault(require("./chart-component"));
19
+ class Completeness extends _chartComponent.default {
20
+ constructor(props) {
21
+ super(props);
22
+ this.handleResize = () => {
23
+ this.chart.node() && this.chart.node().remove();
24
+ this.createChart();
25
+ this.drawChart();
26
+ };
27
+ this.createChart = () => {
28
+ const {
29
+ chart
30
+ } = this.props;
31
+ const {
32
+ show_percentage
33
+ } = chart.config;
34
+ const initConfig = {
35
+ insertPadding: 30,
36
+ borderRadius: 0.2,
37
+ marginRight: show_percentage ? 35 : 0
38
+ };
39
+ this.initChart(this.container, chart === null || chart === void 0 ? void 0 : chart.id, initConfig);
40
+ };
41
+ this.drawChart = () => {
42
+ let {
43
+ result: data
44
+ } = this.props;
45
+ data = _utils.BaseUtils.formatEmptyName(data, '', _intl.default.get('Empty'));
46
+ if (!Array.isArray(data)) return;
47
+ this.draw(data);
48
+ };
49
+ this.draw = data => {
50
+ const {
51
+ chart,
52
+ globalTheme,
53
+ chartColorTheme
54
+ } = this.props;
55
+ const theme = _constants.CHART_THEME_COLOR[globalTheme];
56
+ const {
57
+ y_axis_auto_range,
58
+ y_axis_min,
59
+ y_axis_max,
60
+ show_percentage,
61
+ label_font_size
62
+ } = chart.config;
63
+ const {
64
+ width: chartWidth,
65
+ height: chartHeight,
66
+ insertPadding,
67
+ marginRight
68
+ } = this.chartBoundingClientRect;
69
+ const colors = _utils.BaseUtils.getCurrentTheme(chartColorTheme).colors;
70
+ this.markFirstOrLast(data, 'last');
71
+ const series = d3.stack().keys(d3.union(data.map(d => d.group_name))).value((_ref, key) => {
72
+ var _group$get;
73
+ let [_, group] = _ref;
74
+ return ((_group$get = group.get(String(key))) === null || _group$get === void 0 ? void 0 : _group$get.value) || 0;
75
+ })(d3.index(data, d => d.name, d => d.group_name));
76
+ const newSeries = this.handleSeries(series, data);
77
+
78
+ // Y axis
79
+ const y = d3.scaleBand().domain(new Set(data.map(d => d.name))).range([chartHeight - insertPadding, insertPadding]).paddingInner(0.1).paddingOuter(0.1);
80
+ const yAxis = this.chart.append('g').call(d3.axisLeft(y).tickSizeOuter(0).tickPadding(0).tickSizeInner(5)).call(g => {
81
+ g.selectAll('.domain').attr('stroke', theme.XAxisColor);
82
+ g.selectAll('.tick line').attr('stroke', theme.XAxisColor);
83
+ g.selectAll('text').attr('font-size', theme.fontSize);
84
+ g.selectAll('text').attr('fill', theme.textColor);
85
+ // Update axis transform
86
+ const {
87
+ width: axisWidth
88
+ } = g.node().getBoundingClientRect();
89
+ g.attr('transform', "translate(".concat(axisWidth, ", 0)")).attr('data-axisWidth', axisWidth);
90
+ this.checkTickOverlap(g, 'yAxis');
91
+ });
92
+
93
+ // X axis
94
+ const niceEnd = d3.nice(0, d3.max(newSeries, d => d[1].sumValue), 5)[1];
95
+ const x = d3.scaleLinear().domain(y_axis_auto_range ? [0, niceEnd] : [y_axis_min || 0, y_axis_max || niceEnd]).range([Number(yAxis.node().getAttribute('data-axisWidth')), chartWidth - insertPadding - marginRight]);
96
+ this.chart.append('g').attr('transform', "translate(0, ".concat(chartHeight - insertPadding, ")")).call(d3.axisBottom(x).tickSizeInner(0).ticks(5)).call(g => {
97
+ g.selectAll('.domain').remove();
98
+ g.selectAll('.tick line').node() && g.selectAll('.tick line').node().remove(); // delete the first line
99
+ g.selectAll('.tick line').attr('y2', -(chartHeight - insertPadding * 2)).attr('stroke', theme.gridColor).attr('stroke-dasharray', '8,3');
100
+ g.selectAll('text').attr('font-size', theme.fontSize);
101
+ g.selectAll('text').attr('fill', theme.textColor);
102
+ });
103
+
104
+ // Rect group
105
+ const rectsWrapper = this.chart.append('g').attr('class', "rects-wrapper-".concat(chart === null || chart === void 0 ? void 0 : chart.id)).attr('transform', "translate(".concat(Number(yAxis.node().getAttribute('data-axisWidth')), ", 0)"));
106
+ rectsWrapper.selectAll().data(newSeries).join('g').attr('data-completedRate', d => {
107
+ const restData = d[1].find(item => item.key === 'rest');
108
+ const completedRate = restData.data.completedRate;
109
+ if (completedRate === 'empty') return '';
110
+ return completedRate + '%';
111
+ }).selectAll().data(_ref2 => {
112
+ let [groupKey, d] = _ref2;
113
+ d.forEach(item => item['groupKey'] = groupKey);
114
+ return d;
115
+ }).join('rect').attr('x', (d, index) => {
116
+ return x(d[0]) - Number(yAxis.node().getAttribute('data-axisWidth'));
117
+ }).attr('y', (d, index) => y(d.groupKey)).attr('width', d => x(d[1]) - x(d[0])).attr('height', y.bandwidth()).attr('fill', d => {
118
+ return d.key === 'rest' ? '#bdbdbd' : colors[0];
119
+ }).attr('data-value', d => d.data.value).attr('data-groupName', d => d.data.slugId).attr('data-tooltipTitle', d => d.groupKey).attr('data-tooltipName', d => d.key).call(g => {
120
+ // add rect borderRadius
121
+ const allGroup = this.getAllGroup(rectsWrapper);
122
+ allGroup.forEach(group => {
123
+ const firstEl = group[0];
124
+ firstEl && this.addMaskRect(firstEl === null || firstEl === void 0 ? void 0 : firstEl.parentNode, firstEl, yAxis);
125
+ });
126
+
127
+ // Add label
128
+ if (show_percentage) {
129
+ const newAllGroup = this.getAllGroup(rectsWrapper);
130
+ newAllGroup.forEach(group => {
131
+ const firstEl = group[0];
132
+ firstEl && this.addLabelToRectRight({
133
+ container: firstEl === null || firstEl === void 0 ? void 0 : firstEl.parentNode,
134
+ xWidth: Number(firstEl.getAttribute('width')),
135
+ yHeight: Number(firstEl.getAttribute('height')),
136
+ x: Number(firstEl.getAttribute('x')),
137
+ y: Number(firstEl.getAttribute('y')),
138
+ theme,
139
+ label_font_size,
140
+ text: firstEl === null || firstEl === void 0 ? void 0 : firstEl.parentNode.getAttribute('data-completedRate')
141
+ });
142
+ });
143
+ }
144
+ }).on('click', (event, data) => {
145
+ this.props.toggleRecords(data);
146
+ }).on('mouseover', event => {
147
+ this.showTooltip(event);
148
+ this.handleAcitveAndInActiveState('inActive', event);
149
+ }).on('mousemove', event => {
150
+ this.moveTooltip(event);
151
+ }).on('mouseleave', (event, data) => {
152
+ this.hiddenTooltip();
153
+ this.handleAcitveAndInActiveState('active', event);
154
+ });
155
+ this.setLegend({
156
+ legendName: 'group_name',
157
+ theme,
158
+ legendPosition: 'top-right',
159
+ data,
160
+ colorScale: group_name => group_name === 'rest' ? '#bdbdbd' : colors[0]
161
+ });
162
+ };
163
+ this.handleAcitveAndInActiveState = (state, event) => {
164
+ const allGroup = Array.from(event.currentTarget.parentNode.parentNode.children);
165
+ const curGroupName = event.currentTarget.getAttribute('data-groupName');
166
+ this.setActiveAndInActiveState(state, allGroup, curGroupName);
167
+ };
168
+ this.showTooltip = (event, isDiv) => {
169
+ let {
170
+ offsetX,
171
+ offsetY
172
+ } = event;
173
+ if (isDiv) {
174
+ const initX = Number(event.currentTarget.getAttribute('data-x'));
175
+ const initY = Number(event.currentTarget.getAttribute('y'));
176
+ offsetX = offsetX + initX;
177
+ offsetY = offsetY + initY;
178
+ }
179
+ const {
180
+ chartColorTheme
181
+ } = this.props;
182
+ const colors = _utils.BaseUtils.getCurrentTheme(chartColorTheme).colors;
183
+ const newTooltipData = {
184
+ title: event.currentTarget.getAttribute('data-tooltipTitle'),
185
+ items: [{
186
+ color: event.currentTarget.getAttribute('data-tooltipTitle') === 'rest' ? '#bdbdbd' : colors[0],
187
+ name: _intl.default.get(event.currentTarget.getAttribute('data-tooltipName')),
188
+ value: event.currentTarget.getAttribute('data-value')
189
+ }]
190
+ };
191
+ this.setState({
192
+ tooltipData: newTooltipData
193
+ });
194
+ this.setState({
195
+ toolTipPosition: {
196
+ offsetX,
197
+ offsetY
198
+ }
199
+ });
200
+ };
201
+ this.moveTooltip = (event, isDiv) => {
202
+ let {
203
+ offsetX,
204
+ offsetY
205
+ } = event;
206
+ if (isDiv) {
207
+ const initX = Number(event.currentTarget.getAttribute('data-x'));
208
+ const initY = Number(event.currentTarget.getAttribute('y'));
209
+ offsetX = offsetX + initX;
210
+ offsetY = offsetY + initY;
211
+ }
212
+ this.setState({
213
+ toolTipPosition: {
214
+ offsetX,
215
+ offsetY
216
+ }
217
+ });
218
+ };
219
+ this.hiddenTooltip = event => {
220
+ this.setState({
221
+ toolTipPosition: null
222
+ });
223
+ };
224
+ this.handleSeries = (series, data) => {
225
+ const newSeries = d3.groups(data, d => d.name);
226
+ newSeries.forEach(item => item[1] = []);
227
+ newSeries.forEach(_ref3 => {
228
+ let [key, dataArr] = _ref3;
229
+ series.forEach(itemSeries => {
230
+ itemSeries.forEach(jtem => {
231
+ const curName = jtem.data[0];
232
+ if (curName === key) {
233
+ jtem['key'] = itemSeries.key;
234
+ jtem['data'] = jtem.data[1].get(jtem['key']) || {
235
+ value: 0
236
+ };
237
+ dataArr.push(jtem);
238
+ }
239
+ });
240
+ });
241
+ let sumValue = 0;
242
+ dataArr.forEach(item => {
243
+ sumValue = sumValue + Number(item.data.value);
244
+ });
245
+ dataArr['sumValue'] = sumValue;
246
+ });
247
+ return newSeries;
248
+ };
249
+ this.getAllGroup = rectsWrapper => {
250
+ const allGroup = [];
251
+ Array.from(rectsWrapper.node().children).forEach(item => {
252
+ const group = [];
253
+ Array.from(item.children).forEach(child => {
254
+ if (Number(child.getAttribute('width')) !== 0) {
255
+ group.push(child);
256
+ }
257
+ });
258
+ group.reverse();
259
+ allGroup.push(group);
260
+ });
261
+ return allGroup;
262
+ };
263
+ this.addMaskRect = (topG, rect, yAxis) => {
264
+ const xWidth = Number(rect.getAttribute('height'));
265
+ const {
266
+ borderRadius
267
+ } = this.chartBoundingClientRect;
268
+ // Add mask rect
269
+ d3.select(topG).append('foreignObject').attr('x', rect.getAttribute('x')).attr('y', rect.getAttribute('y')).attr('width', rect.getAttribute('width')).attr('height', rect.getAttribute('height')).attr('data-groupName', rect.getAttribute('data-groupName')).attr('data-value', rect.getAttribute('data-value')).attr('data-tooltipTitle', rect.getAttribute('data-tooltipTitle')).attr('data-tooltipName', rect.getAttribute('data-tooltipName')).attr('data-x', () => {
270
+ const x = Number(rect.getAttribute('x'));
271
+ return x + Number(yAxis.node().getAttribute('data-axisWidth'));
272
+ }).on('click', (event, data) => {
273
+ this.props.toggleRecords(data);
274
+ }).on('mouseover', event => {
275
+ this.showTooltip(event, true);
276
+ this.handleAcitveAndInActiveState('inActive', event);
277
+ }).on('mousemove', event => {
278
+ this.moveTooltip(event, true);
279
+ }).on('mouseleave', event => {
280
+ this.hiddenTooltip();
281
+ this.handleAcitveAndInActiveState('active', event);
282
+ }).append('xhtml:div').attr('style', "width: 100%; height: 100%; background-color: ".concat(rect.getAttribute('fill'), "; border-radius: 0px ").concat(xWidth * borderRadius, "px ").concat(xWidth * borderRadius, "px 0px"));
283
+
284
+ // Remove old rect
285
+ d3.select(rect).remove();
286
+ };
287
+ this.chart = null;
288
+ this.state = {
289
+ tooltipData: null,
290
+ toolTipPosition: null
291
+ };
292
+ }
293
+ componentDidMount() {
294
+ super.componentDidMount();
295
+ this.createChart();
296
+ this.drawChart();
297
+ this.debouncedHandleResize = (0, _lodashEs.debounce)(this.handleResize, 300);
298
+ window.addEventListener('resize', this.debouncedHandleResize);
299
+ }
300
+ componentDidUpdate(prevProps) {
301
+ super.componentDidUpdate(prevProps);
302
+ if (_utils.BaseUtils.shouldChartComponentUpdate(prevProps, this.props)) {
303
+ this.drawChart();
304
+ }
305
+ }
306
+ componentWillUnmount() {
307
+ super.componentWillUnmount();
308
+ this.chart.node() && this.chart.node().remove();
309
+ window.removeEventListener('resize', this.debouncedHandleResize);
310
+ }
311
+ render() {
312
+ const {
313
+ chart
314
+ } = this.props;
315
+ const {
316
+ tooltipData,
317
+ toolTipPosition
318
+ } = this.state;
319
+ return /*#__PURE__*/_react.default.createElement("div", {
320
+ ref: ref => this.container = ref,
321
+ className: (0, _classnames.default)('sea-chart-container', {
322
+ 'show-x-axis-label': this.isShowHorizontalAxisLabel(chart),
323
+ 'show-y-axis-label': this.isShowVerticalAxisLabel(chart)
324
+ })
325
+ }, /*#__PURE__*/_react.default.createElement(_tooltip.default, {
326
+ tooltipData: tooltipData,
327
+ toolTipPosition: toolTipPosition,
328
+ chart: this.chart
329
+ }));
330
+ }
331
+ }
332
+ Completeness.propTypes = {
333
+ canvasStyle: _propTypes.default.object,
334
+ chart: _propTypes.default.object,
335
+ groupbyColumn: _propTypes.default.object,
336
+ columnGroupbyColumn: _propTypes.default.object,
337
+ summaryColumn: _propTypes.default.object,
338
+ result: _propTypes.default.array,
339
+ tables: _propTypes.default.array,
340
+ globalTheme: _propTypes.default.string,
341
+ chartColorTheme: _propTypes.default.string,
342
+ toggleRecords: _propTypes.default.func
343
+ };
344
+ var _default = exports.default = Completeness;
@@ -103,6 +103,7 @@ class HorizontalBarGroup extends _chartComponent.default {
103
103
  width: axisWidth
104
104
  } = g.node().getBoundingClientRect();
105
105
  g.attr('transform', "translate(".concat(axisWidth, ", 0)")).attr('data-axisWidth', axisWidth);
106
+ this.checkTickOverlap(g, 'yAxis');
106
107
  });
107
108
  const niceEnd = d3.nice(0, d3.max(data, d => d.value), 5)[1];
108
109
  const x = d3.scaleLinear().domain(horizontal_axis_auto_range ? [0, niceEnd] : [horizontal_axis_min || 0, horizontal_axis_max || niceEnd]).range([Number(yAxis.node().getAttribute('data-axisWidth')), chartWidth - insertPadding - marginRight]);
@@ -145,6 +146,7 @@ class HorizontalBarGroup extends _chartComponent.default {
145
146
  container: rect.parentNode,
146
147
  xWidth: Number(rect.getAttribute('width')),
147
148
  yHeight: Number(rect.getAttribute('height')),
149
+ x: Number(rect.getAttribute('x')),
148
150
  y: Number(rect.getAttribute('y')),
149
151
  theme,
150
152
  label_font_size,
@@ -0,0 +1,361 @@
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 _classnames = _interopRequireDefault(require("classnames"));
13
+ var d3 = _interopRequireWildcard(require("d3"));
14
+ var _dtableUtils = require("dtable-utils");
15
+ var _constants = require("../../constants");
16
+ var _utils = require("../../utils");
17
+ var _intl = _interopRequireDefault(require("../../intl"));
18
+ var _colorRules = require("../../constants/color-rules");
19
+ var _columnUtils = require("../../utils/column-utils");
20
+ var _tooltip = _interopRequireDefault(require("../../components/tooltip"));
21
+ var _chartComponent = _interopRequireDefault(require("./chart-component"));
22
+ class HorizontalBarStack extends _chartComponent.default {
23
+ constructor(props) {
24
+ super(props);
25
+ this.handleResize = (0, _lodashEs.debounce)(() => {
26
+ this.chart.node() && this.chart.node().remove();
27
+ this.createChart();
28
+ this.drawChart();
29
+ }, 300);
30
+ this.createChart = () => {
31
+ const {
32
+ chart
33
+ } = this.props;
34
+ const {
35
+ show_horizontal_axis_label,
36
+ show_vertical_axis_label
37
+ } = chart.config;
38
+ const initConfig = {
39
+ insertPadding: 30,
40
+ borderRadius: 0.2,
41
+ marginLeft: show_vertical_axis_label ? 20 : 0,
42
+ marginBottom: show_horizontal_axis_label ? 20 : 0
43
+ };
44
+ this.initChart(this.container, chart === null || chart === void 0 ? void 0 : chart.id, initConfig);
45
+ };
46
+ this.drawChart = () => {
47
+ let {
48
+ result: data,
49
+ customRender,
50
+ chart
51
+ } = this.props;
52
+ data = _utils.BaseUtils.formatEmptyName(data, '', _intl.default.get('Empty'));
53
+ if (!Array.isArray(data)) return;
54
+ const {
55
+ sort_type,
56
+ type
57
+ } = chart.config;
58
+ if (type === _constants.CHART_TYPE.STACKED_HORIZONTAL_BAR && sort_type) {
59
+ data = (0, _columnUtils.sortDataByGroupSum)(data, sort_type);
60
+ }
61
+ this.draw(data);
62
+ (0, _utils.isFunction)(customRender) && customRender(this.chart);
63
+ this.renderHorizontalLabel(this.props.chart, this.props.tables, this.container);
64
+ };
65
+ this.draw = data => {
66
+ const {
67
+ chart,
68
+ globalTheme,
69
+ chartColorTheme,
70
+ tables
71
+ } = this.props;
72
+ const theme = _constants.CHART_THEME_COLOR[globalTheme];
73
+ const {
74
+ display_data,
75
+ label_font_size,
76
+ column_groupby_column_key,
77
+ table_id,
78
+ color_theme,
79
+ horizontal_axis_auto_range,
80
+ horizontal_axis_min,
81
+ horizontal_axis_max
82
+ } = chart.config;
83
+ const {
84
+ width: chartWidth,
85
+ height: chartHeight,
86
+ insertPadding
87
+ } = this.chartBoundingClientRect;
88
+ const groupByColumn = this.getColumn(tables, table_id, column_groupby_column_key);
89
+ const useSingleSelectColumnColor = (groupByColumn === null || groupByColumn === void 0 ? void 0 : groupByColumn.type) === _dtableUtils.CellType.SINGLE_SELECT && color_theme === _colorRules.SUPPORT_SINGLE_SELECT_THEMES_OPTIONS.SINGLE_SELECT_COLUMN_COLORS;
90
+ useSingleSelectColumnColor ? this.setSingleSelectColorMap(data) : this.setColorMap(data, chartColorTheme);
91
+ const series = d3.stack().keys(d3.union(data.map(d => d.group_name))).value((_ref, key) => {
92
+ var _group$get;
93
+ let [_, group] = _ref;
94
+ return ((_group$get = group.get(String(key))) === null || _group$get === void 0 ? void 0 : _group$get.value) || 0;
95
+ })(d3.index(data, d => d.name, d => d.group_name));
96
+ const newSeries = this.handleSeries(series, data);
97
+ const y = d3.scaleBand().domain(new Set(data.map(d => d.name))).range([chartHeight - insertPadding, insertPadding]).paddingInner(0.1).paddingOuter(0.1);
98
+
99
+ // Y axis
100
+ const yAxis = this.chart.append('g').call(d3.axisLeft(y).tickSizeOuter(0).tickPadding(0).tickSizeInner(5)).call(g => {
101
+ g.selectAll('.domain').attr('stroke', theme.XAxisColor);
102
+ g.selectAll('.tick line').attr('stroke', theme.XAxisColor);
103
+ g.selectAll('text').attr('font-size', theme.fontSize);
104
+ g.selectAll('text').attr('fill', theme.textColor);
105
+ // Update axis transform
106
+ const {
107
+ width: axisWidth
108
+ } = g.node().getBoundingClientRect();
109
+ g.attr('transform', "translate(".concat(axisWidth, ", 0)")).attr('data-axisWidth', axisWidth);
110
+ this.checkTickOverlap(g, 'yAxis');
111
+ });
112
+
113
+ // X axis
114
+ const niceEnd = d3.nice(0, d3.max(newSeries, d => d[1].sumValue), 5)[1];
115
+ const x = d3.scaleLinear().domain(horizontal_axis_auto_range ? [0, niceEnd] : [horizontal_axis_min || 0, horizontal_axis_max || niceEnd]).range([Number(yAxis.node().getAttribute('data-axisWidth')), chartWidth - insertPadding]);
116
+ this.chart.append('g').attr('transform', "translate(0, ".concat(chartHeight - insertPadding, ")")).call(d3.axisBottom(x).tickSizeInner(0).ticks(5).tickFormat(d => d)).call(g => {
117
+ g.selectAll('.domain').remove();
118
+ g.selectAll('.tick line').node() && g.selectAll('.tick line').node().remove(); // delete the first line
119
+ g.selectAll('.tick line').attr('y2', -(chartHeight - insertPadding * 2)).attr('stroke', theme.gridColor).attr('stroke-dasharray', '8,3');
120
+ g.selectAll('text').attr('font-size', theme.fontSize);
121
+ g.selectAll('text').attr('fill', theme.textColor);
122
+ });
123
+
124
+ // Rect group
125
+ const rectsWrapper = this.chart.append('g').attr('class', "rects-wrapper-".concat(chart === null || chart === void 0 ? void 0 : chart.id)).attr('transform', "translate(".concat(Number(yAxis.node().getAttribute('data-axisWidth')), ", 0)"));
126
+ rectsWrapper.selectAll().data(newSeries).join('g')
127
+ // rect item
128
+ .selectAll().data(_ref2 => {
129
+ let [groupKey, d] = _ref2;
130
+ d.forEach(item => item['groupKey'] = groupKey);
131
+ return d;
132
+ }).join('rect').attr('x', (d, index) => {
133
+ return x(d[0]) - Number(yAxis.node().getAttribute('data-axisWidth'));
134
+ }).attr('y', (d, index) => y(d.groupKey)).attr('width', d => x(d[1]) - x(d[0])).attr('height', y.bandwidth()).attr('fill', d => {
135
+ return this.colorMap[d.data.group_name] || _constants.CHART_STYLE_COLORS[0];
136
+ }).attr('data-value', d => d.data.value).attr('data-slugid', d => d.data.slugId).attr('data-groupName', d => d.data.name).attr('data-stackKey', d => d.key).call(g => {
137
+ // add rect borderRadius
138
+ const allGroup = this.getAllGroup(rectsWrapper);
139
+ allGroup.forEach(group => {
140
+ const firstEl = group[0];
141
+ firstEl && this.addMaskRect(firstEl === null || firstEl === void 0 ? void 0 : firstEl.parentNode, firstEl, yAxis);
142
+ });
143
+
144
+ // Add label
145
+ if (display_data) {
146
+ const newAllGroup = this.getAllGroup(rectsWrapper);
147
+ newAllGroup.forEach(group => {
148
+ group.forEach(rect => {
149
+ this.addLabelToRectCenter({
150
+ container: rect.parentNode,
151
+ x: Number(rect.getAttribute('x')),
152
+ y: Number(rect.getAttribute('y')),
153
+ xWidth: Number(rect.getAttribute('width')),
154
+ yheight: Number(rect.getAttribute('height')),
155
+ theme,
156
+ label_font_size,
157
+ text: rect.getAttribute('data-value')
158
+ });
159
+ });
160
+ });
161
+ }
162
+ }).on('click', (event, data) => {
163
+ this.props.toggleRecords(data);
164
+ }).on('mouseover', event => {
165
+ this.showTooltip(event);
166
+ this.handleAcitveAndInActiveState('inActive', event);
167
+ }).on('mousemove', event => {
168
+ this.moveTooltip(event);
169
+ }).on('mouseleave', event => {
170
+ this.hiddenTooltip();
171
+ this.handleAcitveAndInActiveState('active', event);
172
+ });
173
+ this.setLegend({
174
+ legendName: 'group_name',
175
+ theme,
176
+ legendPosition: 'top-right',
177
+ data
178
+ });
179
+ };
180
+ this.handleAcitveAndInActiveState = (state, event) => {
181
+ const allGroup = Array.from(event.currentTarget.parentNode.parentNode.children);
182
+ const curGroupName = event.currentTarget.getAttribute('data-groupName');
183
+ this.setActiveAndInActiveState(state, allGroup, curGroupName);
184
+ };
185
+ this.showTooltip = (event, isDiv) => {
186
+ let {
187
+ offsetX,
188
+ offsetY
189
+ } = event;
190
+ if (isDiv) {
191
+ const initX = Number(event.currentTarget.getAttribute('data-x'));
192
+ const initY = Number(event.currentTarget.getAttribute('y'));
193
+ offsetX = offsetX + initX;
194
+ offsetY = offsetY + initY;
195
+ }
196
+ const title = event.currentTarget.getAttribute('data-groupName');
197
+ const stackName = event.currentTarget.getAttribute('data-stackKey');
198
+ const stackValue = event.currentTarget.getAttribute('data-value');
199
+ const newTooltipData = {
200
+ title: !title && typeof title !== 'number' ? _intl.default.get(_constants.EMPTY_NAME) : title,
201
+ items: [{
202
+ color: this.colorMap[stackName] || _constants.CHART_STYLE_COLORS[0],
203
+ name: stackName,
204
+ value: stackValue
205
+ }]
206
+ };
207
+ this.setState({
208
+ tooltipData: newTooltipData
209
+ });
210
+ this.setState({
211
+ toolTipPosition: {
212
+ offsetX,
213
+ offsetY
214
+ }
215
+ });
216
+ };
217
+ this.moveTooltip = (event, isDiv) => {
218
+ let {
219
+ offsetX,
220
+ offsetY
221
+ } = event;
222
+ if (isDiv) {
223
+ const initX = Number(event.currentTarget.getAttribute('data-x'));
224
+ const initY = Number(event.currentTarget.getAttribute('y'));
225
+ offsetX = offsetX + initX;
226
+ offsetY = offsetY + initY;
227
+ }
228
+ this.setState({
229
+ toolTipPosition: {
230
+ offsetX,
231
+ offsetY
232
+ }
233
+ });
234
+ };
235
+ this.hiddenTooltip = event => {
236
+ this.setState({
237
+ toolTipPosition: null
238
+ });
239
+ };
240
+ this.handleSeries = (series, data) => {
241
+ const newSeries = d3.groups(data, d => d.name);
242
+ newSeries.forEach(item => item[1] = []);
243
+ newSeries.forEach(_ref3 => {
244
+ let [key, dataArr] = _ref3;
245
+ series.forEach(itemSeries => {
246
+ itemSeries.forEach(jtem => {
247
+ const curName = jtem.data[0];
248
+ if (curName === key) {
249
+ jtem['key'] = itemSeries.key;
250
+ jtem['data'] = jtem.data[1].get(jtem['key']) || {
251
+ value: 0
252
+ };
253
+ dataArr.push(jtem);
254
+ }
255
+ });
256
+ });
257
+ let sumValue = 0;
258
+ dataArr.forEach(item => {
259
+ sumValue = sumValue + Number(item.data.value);
260
+ });
261
+ dataArr['sumValue'] = sumValue;
262
+ });
263
+ return newSeries;
264
+ };
265
+ this.getAllGroup = rectsWrapper => {
266
+ const allGroup = [];
267
+ Array.from(rectsWrapper.node().children).forEach(item => {
268
+ const group = [];
269
+ Array.from(item.children).forEach(child => {
270
+ if (Number(child.getAttribute('width')) !== 0) {
271
+ group.push(child);
272
+ }
273
+ });
274
+ group.reverse();
275
+ allGroup.push(group);
276
+ });
277
+ return allGroup;
278
+ };
279
+ this.addMaskRect = (topG, rect, yAxis) => {
280
+ const xWidth = Number(rect.getAttribute('height'));
281
+ const {
282
+ borderRadius
283
+ } = this.chartBoundingClientRect;
284
+ // Add mask rect
285
+ d3.select(topG).append('foreignObject').attr('x', rect.getAttribute('x')).attr('y', rect.getAttribute('y')).attr('width', rect.getAttribute('width')).attr('height', rect.getAttribute('height')).attr('data-groupName', rect.getAttribute('data-groupName')).attr('data-value', rect.getAttribute('data-value')).attr('data-stackKey', rect.getAttribute('data-stackKey')).attr('data-x', () => {
286
+ const x = Number(rect.getAttribute('x'));
287
+ return x + Number(yAxis.node().getAttribute('data-axisWidth'));
288
+ }).on('click', (event, data) => {
289
+ this.props.toggleRecords(data);
290
+ }).on('mouseover', event => {
291
+ this.showTooltip(event, true);
292
+ this.handleAcitveAndInActiveState('inActive', event);
293
+ }).on('mousemove', event => {
294
+ this.moveTooltip(event, true);
295
+ }).on('mouseleave', event => {
296
+ this.hiddenTooltip();
297
+ this.handleAcitveAndInActiveState('active', event);
298
+ }).append('xhtml:div').attr('style', "width: 100%; height: 100%; background-color: ".concat(rect.getAttribute('fill'), "; border-radius: 0px ").concat(xWidth * borderRadius, "px ").concat(xWidth * borderRadius, "px 0px"));
299
+
300
+ // Remove old rect
301
+ d3.select(rect).remove();
302
+ };
303
+ this.chart = null;
304
+ this.state = {
305
+ tooltipData: null,
306
+ toolTipPosition: null
307
+ };
308
+ }
309
+ componentDidMount() {
310
+ this.createChart();
311
+ this.drawChart();
312
+ window.addEventListener('resize', this.handleResize);
313
+ }
314
+ componentDidUpdate(prevProps) {
315
+ super.componentDidUpdate(prevProps);
316
+ if (_utils.BaseUtils.shouldChartComponentUpdate(prevProps, this.props)) {
317
+ this.chart.node() && this.chart.node().remove();
318
+ this.createChart();
319
+ this.drawChart();
320
+ }
321
+ }
322
+ componentWillUnmount() {
323
+ var _this$chart;
324
+ ((_this$chart = this.chart) === null || _this$chart === void 0 ? void 0 : _this$chart.autoPadding) && this.chart.destroy();
325
+ window.removeEventListener('resize', this.handleResize);
326
+ }
327
+ render() {
328
+ const {
329
+ chart
330
+ } = this.props;
331
+ const {
332
+ tooltipData,
333
+ toolTipPosition
334
+ } = this.state;
335
+ return /*#__PURE__*/_react.default.createElement("div", {
336
+ ref: ref => this.container = ref,
337
+ className: (0, _classnames.default)('sea-chart-container', {
338
+ 'show-x-axis-label': this.isShowHorizontalAxisLabel(chart),
339
+ 'show-y-axis-label': this.isShowVerticalAxisLabel(chart)
340
+ })
341
+ }, /*#__PURE__*/_react.default.createElement(_tooltip.default, {
342
+ tooltipData: tooltipData,
343
+ toolTipPosition: toolTipPosition,
344
+ chart: this.chart
345
+ }));
346
+ }
347
+ }
348
+ HorizontalBarStack.propTypes = {
349
+ canvasStyle: _propTypes.default.object,
350
+ chart: _propTypes.default.object,
351
+ groupbyColumn: _propTypes.default.object,
352
+ columnGroupbyColumn: _propTypes.default.object,
353
+ summaryColumn: _propTypes.default.object,
354
+ result: _propTypes.default.array,
355
+ tables: _propTypes.default.array,
356
+ globalTheme: _propTypes.default.string,
357
+ chartColorTheme: _propTypes.default.string,
358
+ toggleRecords: _propTypes.default.func,
359
+ customRender: _propTypes.default.func
360
+ };
361
+ var _default = exports.default = HorizontalBarStack;
@@ -99,6 +99,7 @@ class HorizontalBar extends _chartComponent.default {
99
99
  width: axisWidth
100
100
  } = g.node().getBoundingClientRect();
101
101
  g.attr('transform', "translate(".concat(axisWidth, ", 0)")).attr('data-axisWidth', axisWidth);
102
+ this.checkTickOverlap(g, 'yAxis');
102
103
  });
103
104
  const niceEnd = d3.nice(0, d3.max(data, d => d.value), 5)[1];
104
105
  const x = d3.scaleLinear().domain(horizontal_axis_auto_range ? [0, niceEnd] : [horizontal_axis_min || 0, horizontal_axis_max || niceEnd]).range([Number(yAxis.node().getAttribute('data-axisWidth')), chartWidth - insertPadding - marginRight]);
@@ -135,6 +136,7 @@ class HorizontalBar extends _chartComponent.default {
135
136
  container: g._parents[0],
136
137
  xWidth: Number(rect.getAttribute('width')),
137
138
  yHeight: Number(rect.getAttribute('height')),
139
+ x: Number(rect.getAttribute('x')),
138
140
  y: Number(rect.getAttribute('y')),
139
141
  theme,
140
142
  label_font_size,
@@ -18,6 +18,8 @@ var _barCompare = _interopRequireDefault(require("./bar-compare"));
18
18
  var _barCustomStack = _interopRequireDefault(require("./bar-custom-stack"));
19
19
  var _horizontalBar = _interopRequireDefault(require("./horizontal-bar"));
20
20
  var _horizontalBarGroup = _interopRequireDefault(require("./horizontal-bar-group"));
21
+ var _horizontalBarStack = _interopRequireDefault(require("./horizontal-bar-stack"));
22
+ var _completeness = _interopRequireDefault(require("./completeness"));
21
23
  var _basicNumberCard = _interopRequireDefault(require("./basic-number-card"));
22
24
  var _trend = _interopRequireDefault(require("./trend"));
23
25
  var _tableElement = _interopRequireDefault(require("./table-element"));
@@ -157,6 +159,35 @@ const Wrapper = _ref => {
157
159
  chart: newChart
158
160
  }));
159
161
  }
162
+ case _constants.CHART_TYPE.STACKED_HORIZONTAL_BAR:
163
+ {
164
+ const {
165
+ config,
166
+ id,
167
+ style_config
168
+ } = chart;
169
+ const newConfig = _utils.BaseUtils.convertConfig(config);
170
+ const newChart = {
171
+ id,
172
+ config: newConfig,
173
+ style_config
174
+ };
175
+ const {
176
+ column_groupby_column_key,
177
+ column_groupby_multiple_numeric_column
178
+ } = config;
179
+ const HorizontalComponent = column_groupby_column_key || column_groupby_multiple_numeric_column ? _horizontalBarStack.default : _horizontalBar.default;
180
+ return /*#__PURE__*/_react.default.createElement(HorizontalComponent, Object.assign({}, baseProps, {
181
+ canvasStyle: canvasStyle,
182
+ chart: newChart
183
+ }));
184
+ }
185
+ case _constants.CHART_TYPE.COMPLETENESS:
186
+ {
187
+ return /*#__PURE__*/_react.default.createElement(_completeness.default, Object.assign({}, baseProps, {
188
+ canvasStyle: canvasStyle
189
+ }));
190
+ }
160
191
  case _constants.CHART_TYPE.BASIC_NUMBER_CARD:
161
192
  {
162
193
  return /*#__PURE__*/_react.default.createElement(_basicNumberCard.default, Object.assign({}, baseProps, {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sea-chart",
3
- "version": "2.0.12",
3
+ "version": "2.0.13",
4
4
  "main": "./dist/index.js",
5
5
  "dependencies": {
6
6
  "@dnd-kit/core": "^6.1.0",