sea-chart 2.0.7 → 2.0.9

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.
@@ -0,0 +1,334 @@
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 _dtableUtils = require("dtable-utils");
12
+ var _lodashEs = require("lodash-es");
13
+ var d3 = _interopRequireWildcard(require("d3"));
14
+ var _intl = _interopRequireDefault(require("../../intl"));
15
+ var _columnUtils = require("../../utils/column-utils");
16
+ var _constants = require("../../constants");
17
+ var _utils = require("../../utils");
18
+ var _colorRules = require("../../constants/color-rules");
19
+ var _tooltip = _interopRequireDefault(require("../../components/tooltip"));
20
+ var _chartComponent = _interopRequireDefault(require("./chart-component"));
21
+ class BarStack extends _chartComponent.default {
22
+ constructor(props) {
23
+ super(props);
24
+ this.handleResize = () => {
25
+ this.chart.node() && this.chart.node().remove();
26
+ this.createChart();
27
+ this.drawChart();
28
+ };
29
+ this.createChart = () => {
30
+ const {
31
+ chart
32
+ } = this.props;
33
+ const initConfig = {
34
+ insertPadding: 30,
35
+ borderRadius: 10
36
+ };
37
+ this.initChart(this.container, chart === null || chart === void 0 ? void 0 : chart.id, initConfig);
38
+ };
39
+ this.drawChart = () => {
40
+ const {
41
+ customRender
42
+ } = this.props;
43
+ let {
44
+ result: data
45
+ } = this.props;
46
+ data = _utils.BaseUtils.formatEmptyName(data, '', _intl.default.get('Empty'));
47
+ if (!Array.isArray(data)) return;
48
+ const {
49
+ chart
50
+ } = this.props;
51
+ const {
52
+ sort_type,
53
+ type
54
+ } = chart.config;
55
+ if (type === _constants.CHART_TYPE.BAR_STACK && sort_type) {
56
+ data = (0, _columnUtils.sortDataByGroupSum)(data, sort_type);
57
+ }
58
+ this.draw(data);
59
+ this.renderAxisLabel(this.props.chart, this.props.tables, this.container);
60
+ (0, _utils.isFunction)(customRender) && customRender(this.chart);
61
+ };
62
+ this.draw = data => {
63
+ const {
64
+ chart,
65
+ globalTheme,
66
+ chartColorTheme,
67
+ tables
68
+ } = this.props;
69
+ const {
70
+ display_goal_line,
71
+ goal_value,
72
+ goal_label
73
+ } = chart.style_config || {};
74
+ const {
75
+ y_axis_show_value,
76
+ display_each_block_data,
77
+ table_id,
78
+ column_groupby_column_key,
79
+ color_theme,
80
+ y_axis_max,
81
+ y_axis_min,
82
+ y_axis_auto_range
83
+ } = chart.config;
84
+ const theme = _constants.CHART_THEME_COLOR[globalTheme];
85
+ const column_groupby_column = this.getColumn(tables, table_id, column_groupby_column_key);
86
+ const useSingleSelectColumnColor = (column_groupby_column === null || column_groupby_column === void 0 ? void 0 : column_groupby_column.type) === _dtableUtils.CellType.SINGLE_SELECT && color_theme === _colorRules.SUPPORT_SINGLE_SELECT_THEMES_OPTIONS.SINGLE_SELECT_COLUMN_COLORS;
87
+ // use single select column color
88
+ useSingleSelectColumnColor ? this.setSingleSelectColorMap(data) : this.setColorMap(data, chartColorTheme);
89
+ const {
90
+ width: chartWidth,
91
+ height: chartHeight,
92
+ insertPadding
93
+ } = this.chartBoundingClientRect;
94
+ const series = d3.stack().keys(d3.union(data.map(d => d.group_name))).value((_ref, key) => {
95
+ var _group$get;
96
+ let [_, group] = _ref;
97
+ return (_group$get = group.get(String(key))) === null || _group$get === void 0 ? void 0 : _group$get.value;
98
+ })(d3.index(data, d => d.name, d => d.group_name));
99
+ const x = d3.scaleBand().domain(d3.group(data, d => d.name).keys()).range([insertPadding, chartWidth - insertPadding]).paddingInner(0.1).paddingOuter(0.1);
100
+ const niceEnd = d3.nice(0, d3.max(series, d => d3.max(d, d => d[1])), 5)[1];
101
+ const y = d3.scaleLinear().domain(y_axis_auto_range ? [0, niceEnd] : [y_axis_min, y_axis_max]).range([chartHeight - insertPadding, insertPadding]);
102
+
103
+ // X axis
104
+ this.chart.append('g').attr('transform', "translate(0,".concat(chartHeight - insertPadding, ")")).call(d3.axisBottom(x).tickSizeOuter(0).tickSizeInner(5)).call(g => {
105
+ g.selectAll('.domain').attr('stroke', theme.XAxisColor);
106
+ g.selectAll('.tick line').attr('stroke', theme.XAxisColor);
107
+ g.selectAll('text').attr('font-size', theme.fontSize);
108
+ g.selectAll('text').attr('fill', theme.textColor);
109
+ });
110
+
111
+ // Y axis
112
+ this.chart.append('g').attr('transform', "translate(".concat(insertPadding, ",0)")).call(d3.axisLeft(y).tickSizeInner(0).ticks(5).tickFormat(d => d)).call(g => {
113
+ g.select('.domain').remove();
114
+ g.selectAll('line').node() && g.selectAll('line').node().remove(); // delete the first line
115
+ g.selectAll('.tick line').clone().attr('x2', chartWidth - insertPadding * 2).attr('stroke', theme.gridColor).attr('stroke-dasharray', '8,3');
116
+ g.selectAll('text').attr('font-size', theme.fontSize);
117
+ g.selectAll('text').attr('fill', theme.textColor);
118
+ });
119
+
120
+ // Rect group
121
+ this.rectsWrapper = this.chart.append('g').attr('class', "rects-wrapper-".concat(chart === null || chart === void 0 ? void 0 : chart.id));
122
+ this.rectsWrapper.selectAll().data(series).join('g').attr('data-key', d => d.key).selectAll('rect').data(D => {
123
+ const data = D.map(d => {
124
+ d.key = D.key;
125
+ return d;
126
+ });
127
+ return data;
128
+ }).join('rect').attr('x', d => x(d.data[0])).attr('y', d => y(d[1])).attr('height', d => {
129
+ const height = y(d[0]) - y(d[1]);
130
+ return (0, _lodashEs.isNaN)(height) ? 0 : height;
131
+ }).attr('width', x.bandwidth()).attr('fill', d => this.colorMap[d.key] || _constants.CHART_STYLE_COLORS[0]).attr('data-value', d => {
132
+ const {
133
+ data,
134
+ key
135
+ } = d;
136
+ const rowData = data[1].get(key);
137
+ return rowData ? rowData.value : 0;
138
+ }).attr('data-groupName', d => {
139
+ const {
140
+ data
141
+ } = d;
142
+ return data[0];
143
+ }).call(g => {
144
+ const [topG] = g._parents.slice(-1);
145
+ Array.from(topG.children).forEach(rect => {
146
+ // Add label (get the total value of each stack)
147
+ if (display_each_block_data) {
148
+ this.addLabelByEachStack(data, topG, rect, x);
149
+ }
150
+ // Add mask rect
151
+ this.addMaskRect(topG, rect, x.bandwidth());
152
+ });
153
+ // Add label
154
+ if (y_axis_show_value) {
155
+ this.handleLabelToRectCenter(g, x.bandwidth());
156
+ }
157
+ }).on('click', (event, data) => {
158
+ this.props.toggleRecords(data);
159
+ }).on('mouseover', event => {
160
+ this.showTooltip(event);
161
+ this.handleAcitveAndInActiveState('inActive', event);
162
+ }).on('mousemove', event => {
163
+ this.moveTooltip(event);
164
+ }).on('mouseleave', (event, data) => {
165
+ this.hiddenTooltip();
166
+ this.handleAcitveAndInActiveState('active', event);
167
+ });
168
+ if (display_goal_line && goal_label && goal_value) {
169
+ this.setDispalyGoalLine(goal_label, goal_value, insertPadding, y);
170
+ }
171
+ this.setLegend('group_name', theme, 'top-right', data);
172
+ };
173
+ this.showTooltip = event => {
174
+ const offsetX = d3.pointer(event)[0];
175
+ const offsetY = d3.pointer(event)[1];
176
+ const curRect = event.currentTarget;
177
+ const curGroup = curRect.parentNode;
178
+ const curGroupName = event.currentTarget.getAttribute('data-groupName');
179
+ const newTooltipData = {
180
+ title: !curGroupName && typeof curGroupName !== 'number' ? _intl.default.get(_constants.EMPTY_NAME) : curGroupName,
181
+ items: [{
182
+ color: this.colorMap[curGroup.getAttribute('data-key')],
183
+ name: curGroup.getAttribute('data-key'),
184
+ value: curRect.getAttribute('data-value')
185
+ }]
186
+ };
187
+ this.setState({
188
+ tooltipData: newTooltipData
189
+ });
190
+ this.setState({
191
+ toolTipPosition: {
192
+ offsetX,
193
+ offsetY
194
+ }
195
+ });
196
+ };
197
+ this.moveTooltip = event => {
198
+ const offsetX = d3.pointer(event)[0];
199
+ const offsetY = d3.pointer(event)[1];
200
+ this.setState({
201
+ toolTipPosition: {
202
+ offsetX,
203
+ offsetY
204
+ }
205
+ });
206
+ };
207
+ this.hiddenTooltip = event => {
208
+ this.setState({
209
+ toolTipPosition: null
210
+ });
211
+ };
212
+ this.handleAcitveAndInActiveState = (state, event) => {
213
+ const allGroup = Array.from(this.rectsWrapper.node().children);
214
+ const curGroupName = event.currentTarget.getAttribute('data-groupName');
215
+ this.setActiveAndInActiveState(state, allGroup, curGroupName);
216
+ };
217
+ this.addMaskRect = (topG, rect, xWidth) => {
218
+ const {
219
+ borderRadius
220
+ } = this.chartBoundingClientRect;
221
+ // Add mask rect
222
+ d3.select(topG).append('foreignObject').attr('x', rect.getAttribute('x')).attr('y', rect.getAttribute('y')).attr('width', xWidth).attr('height', rect.getAttribute('height')).attr('data-groupName', rect.getAttribute('data-groupName')).attr('data-value', rect.getAttribute('data-value')).on('click', (event, data) => {
223
+ this.props.toggleRecords(data);
224
+ }).on('mouseover', event => {
225
+ this.showTooltip(event);
226
+ this.handleAcitveAndInActiveState('inActive', event);
227
+ }).on('mousemove', event => {
228
+ this.moveTooltip(event);
229
+ }).on('mouseleave', (event, data) => {
230
+ this.hiddenTooltip();
231
+ this.handleAcitveAndInActiveState('active', event);
232
+ }).append('xhtml:div').attr('style', "width: 100%; height: 100%; background-color: ".concat(rect.getAttribute('fill'), "; border-radius: ").concat(borderRadius, "px ").concat(borderRadius, "px 0px 0px"));
233
+
234
+ // Remove old rect
235
+ d3.select(rect).remove();
236
+ };
237
+ this.addLabelByEachStack = (data, topG, rect, x) => {
238
+ const {
239
+ globalTheme,
240
+ chart
241
+ } = this.props;
242
+ const {
243
+ label_font_size
244
+ } = chart.config;
245
+ const theme = _constants.CHART_THEME_COLOR[globalTheme];
246
+ const groupData = d3.group(data, d => d.name);
247
+ const group_name = rect.getAttribute('data-groupName');
248
+ const stackSum = groupData.get(group_name).reduce((p, n) => p.value + n.value);
249
+ this.addLabelToRectTop({
250
+ container: topG,
251
+ xWidth: Number(x.bandwidth()),
252
+ x: Number(rect.getAttribute('x')),
253
+ y: Number(rect.getAttribute('y')),
254
+ theme,
255
+ label_font_size,
256
+ text: stackSum
257
+ });
258
+ };
259
+ this.handleLabelToRectCenter = (g, xWidth) => {
260
+ const {
261
+ globalTheme,
262
+ chart
263
+ } = this.props;
264
+ const {
265
+ label_font_size
266
+ } = chart.config;
267
+ const theme = _constants.CHART_THEME_COLOR[globalTheme];
268
+ g._parents.forEach(group => {
269
+ Array.from(group.children).forEach(rect => {
270
+ this.addLabelToRectCenter({
271
+ container: group,
272
+ x: Number(rect.getAttribute('x')),
273
+ y: Number(rect.getAttribute('y')),
274
+ xWidth,
275
+ yheight: Number(rect.getAttribute('height')),
276
+ theme,
277
+ label_font_size,
278
+ text: rect.getAttribute('data-value')
279
+ });
280
+ });
281
+ });
282
+ };
283
+ this.chart = null;
284
+ this.state = {
285
+ tooltipData: null,
286
+ toolTipPosition: null
287
+ };
288
+ }
289
+ componentDidMount() {
290
+ this.createChart();
291
+ this.drawChart();
292
+ this.debouncedHandleResize = (0, _lodashEs.debounce)(this.handleResize, 300);
293
+ window.addEventListener('resize', this.debouncedHandleResize);
294
+ }
295
+ componentDidUpdate(prevProps) {
296
+ super.componentDidUpdate(prevProps);
297
+ if (_utils.BaseUtils.shouldChartComponentUpdate(prevProps, this.props)) {
298
+ this.createChart();
299
+ this.drawChart();
300
+ }
301
+ }
302
+ componentWillUnmount() {
303
+ this.chart.node() && this.chart.node().remove();
304
+ window.removeEventListener('resize', this.debouncedHandleResize);
305
+ }
306
+ render() {
307
+ const {
308
+ tooltipData,
309
+ toolTipPosition
310
+ } = this.state;
311
+ return /*#__PURE__*/_react.default.createElement("div", {
312
+ className: "sea-chart-container",
313
+ ref: ref => this.container = ref
314
+ }, /*#__PURE__*/_react.default.createElement(_tooltip.default, {
315
+ tooltipData: tooltipData,
316
+ toolTipPosition: toolTipPosition,
317
+ chart: this.chart
318
+ }));
319
+ }
320
+ }
321
+ BarStack.propTypes = {
322
+ canvasStyle: _propTypes.default.object,
323
+ chart: _propTypes.default.object,
324
+ groupbyColumn: _propTypes.default.object,
325
+ columnGroupbyColumn: _propTypes.default.object,
326
+ summaryColumn: _propTypes.default.object,
327
+ result: _propTypes.default.array,
328
+ tables: _propTypes.default.array,
329
+ globalTheme: _propTypes.default.string,
330
+ chartColorTheme: _propTypes.default.string,
331
+ toggleRecords: _propTypes.default.func,
332
+ customRender: _propTypes.default.func
333
+ };
334
+ var _default = exports.default = BarStack;
@@ -14,6 +14,7 @@ var _constants = require("../../constants");
14
14
  var _utils = require("../../utils");
15
15
  var _colorUtils = require("../../utils/color-utils");
16
16
  var _intl = _interopRequireDefault(require("../../intl"));
17
+ var _tooltip = _interopRequireDefault(require("../../components/tooltip"));
17
18
  var _chartComponent = _interopRequireDefault(require("./chart-component"));
18
19
  class Bar extends _chartComponent.default {
19
20
  constructor(props) {
@@ -24,7 +25,14 @@ class Bar extends _chartComponent.default {
24
25
  this.drawChart();
25
26
  };
26
27
  this.createChart = () => {
27
- this.initChart(this.container);
28
+ const {
29
+ chart
30
+ } = this.props;
31
+ const initConfig = {
32
+ insertPadding: 30,
33
+ borderRadius: 10
34
+ };
35
+ this.initChart(this.container, chart === null || chart === void 0 ? void 0 : chart.id, initConfig);
28
36
  };
29
37
  this.drawChart = () => {
30
38
  const {
@@ -101,22 +109,10 @@ class Bar extends _chartComponent.default {
101
109
  toolTipPosition: null
102
110
  });
103
111
  };
104
- this.setActiveAndInActiveState = (state, data) => {
105
- const {
106
- chart
107
- } = this.props;
108
- const paths = d3.selectAll(".rects-wrapper-".concat(chart === null || chart === void 0 ? void 0 : chart.id, " path"));
109
- if (state === 'active') {
110
- paths.nodes().forEach(path => {
111
- d3.select(path).attr('opacity', 1);
112
- });
113
- return;
114
- }
115
- paths.nodes().forEach(path => {
116
- if (path.id !== data.slugId) {
117
- d3.select(path).attr('opacity', 0.3);
118
- }
119
- });
112
+ this.handleAcitveAndInActiveState = (state, event) => {
113
+ const allGroup = [event.currentTarget.parentNode];
114
+ const curGroupName = event.currentTarget.getAttribute('data-groupName');
115
+ this.setActiveAndInActiveState(state, allGroup, curGroupName);
120
116
  };
121
117
  this.draw = data => {
122
118
  const {
@@ -144,10 +140,10 @@ class Bar extends _chartComponent.default {
144
140
  const tooltipTitle = this.getTitle(tables, table_id, y_axis_summary_type, y_axis_column_key || y_axis_summary_column_key);
145
141
  const {
146
142
  width: chartWidth,
147
- height: chartHeight
143
+ height: chartHeight,
144
+ insertPadding,
145
+ borderRadius
148
146
  } = this.chartBoundingClientRect;
149
- const insertPadding = 30;
150
- const borderRadius = 10;
151
147
  const x = d3.scaleBand().domain(data.map(item => item.name)).range([insertPadding, chartWidth - insertPadding]).paddingInner(0.4).paddingOuter(0.1);
152
148
  const y = d3.scaleLinear().domain(y_axis_auto_range ? [0, d3.max(data, d => d.value)] : [y_axis_min, y_axis_max]).range([chartHeight - insertPadding, insertPadding]);
153
149
  this.chart.append('g').attr('transform', "translate(0, ".concat(chartHeight - insertPadding, ")")).call(d3.axisBottom(x).tickSizeOuter(0).tickSizeInner(5)).call(g => {
@@ -163,7 +159,8 @@ class Bar extends _chartComponent.default {
163
159
  g.selectAll('text').attr('font-size', theme.fontSize);
164
160
  g.selectAll('text').attr('fill', theme.textColor);
165
161
  });
166
- this.chart.append('g').attr('class', "rects-wrapper-".concat(chart === null || chart === void 0 ? void 0 : chart.id)).selectAll().data(data).join('path').attr('fill', d => d3.color(this.getFillColor(d))).attr('data-x', d => x(d.name)).attr('data-y', d => y(d.value)).attr('data-width', x.bandwidth()).attr('data-value', d => d.value).attr('id', (d, index) => d.slugId).attr('d', d => {
162
+ const rectsWrapper = this.chart.append('g').attr('class', "rects-wrapper-".concat(chart === null || chart === void 0 ? void 0 : chart.id));
163
+ rectsWrapper.selectAll().data(data).join('path').attr('fill', d => d3.color(this.getFillColor(d))).attr('data-x', d => x(d.name)).attr('data-y', d => y(d.value)).attr('data-width', x.bandwidth()).attr('data-value', d => d.value).attr('data-groupName', d => d.name).attr('id', (d, index) => d.slugId).attr('d', d => {
167
164
  // Do not draw if the range is smaller than the minimum
168
165
  if (!y_axis_auto_range && d.value <= y_axis_min) {
169
166
  return '';
@@ -180,15 +177,17 @@ class Bar extends _chartComponent.default {
180
177
  path.closePath();
181
178
  return path.toString();
182
179
  }).call(g => {
183
- const parentNode = d3.select('.rects-wrapper');
184
180
  g.nodes().forEach(path => {
185
181
  // Add label
186
182
  if (y_axis_show_value) {
187
- parentNode.append('text').attr('y', Number(path.dataset.y) - 10).attr('fill', theme.labelColor).attr('font-size', _utils.BaseUtils.getLabelFontSize(label_font_size)).text(path.dataset.value).call(g => {
188
- const {
189
- width
190
- } = g.node().getBoundingClientRect();
191
- g.attr('x', Number(path.dataset.x) + Number(path.dataset.width) / 2 - width);
183
+ this.addLabelToRectTop({
184
+ container: rectsWrapper.node(),
185
+ xWidth: Number(path.dataset.width),
186
+ x: Number(path.dataset.x),
187
+ y: Number(path.dataset.y),
188
+ theme,
189
+ label_font_size,
190
+ text: path.dataset.value
192
191
  });
193
192
  }
194
193
  });
@@ -196,18 +195,15 @@ class Bar extends _chartComponent.default {
196
195
  this.props.toggleRecords(data);
197
196
  }).on('mouseover', (event, data) => {
198
197
  this.showTooltip(event, data, tooltipTitle);
199
- this.setActiveAndInActiveState('inActive', data);
198
+ this.handleAcitveAndInActiveState('inActive', event);
200
199
  }).on('mousemove', event => {
201
200
  this.moveTooltip(event);
202
201
  }).on('mouseleave', (event, data) => {
203
202
  this.hiddenTooltip();
204
- this.setActiveAndInActiveState('active', data);
203
+ this.handleAcitveAndInActiveState('active', event);
205
204
  });
206
- if (display_goal_line) {
207
- this.chart.append('g').attr('class', 'annotation-wrapper').append('line').attr('stroke', '#aaa').attr('x1', insertPadding).attr('y1', y(goal_value)).attr('x2', chartWidth - insertPadding).attr('y2', y(goal_value)).call(g => {
208
- const parentNode = d3.select('.annotation-wrapper');
209
- parentNode.append('text').attr('x', chartWidth - insertPadding - 30).attr('y', y(goal_value) - 10).attr('fill', '#666').text(goal_label);
210
- });
205
+ if (display_goal_line && goal_label && goal_value) {
206
+ this.setDispalyGoalLine(goal_label, goal_value, insertPadding, y);
211
207
  }
212
208
  };
213
209
  this.chart = null;
@@ -225,8 +221,6 @@ class Bar extends _chartComponent.default {
225
221
  componentDidUpdate(prevProps) {
226
222
  super.componentDidUpdate(prevProps);
227
223
  if (_utils.BaseUtils.shouldChartComponentUpdate(prevProps, this.props)) {
228
- var _this$chart;
229
- ((_this$chart = this.chart) === null || _this$chart === void 0 ? void 0 : _this$chart.autoPadding) && this.chart.destroy();
230
224
  this.createChart();
231
225
  this.drawChart();
232
226
  }
@@ -243,7 +237,11 @@ class Bar extends _chartComponent.default {
243
237
  return /*#__PURE__*/_react.default.createElement("div", {
244
238
  className: "sea-chart-container",
245
239
  ref: ref => this.container = ref
246
- }, this.getToolTipContainer(tooltipData, toolTipPosition));
240
+ }, /*#__PURE__*/_react.default.createElement(_tooltip.default, {
241
+ tooltipData: tooltipData,
242
+ toolTipPosition: toolTipPosition,
243
+ chart: this.chart
244
+ }));
247
245
  }
248
246
  }
249
247
  Bar.propTypes = {