sea-chart 2.0.9 → 2.0.10

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.
@@ -13,6 +13,7 @@ var _dtableUtils = require("dtable-utils");
13
13
  var _utils = require("../../utils");
14
14
  var _constants = require("../../constants");
15
15
  var _intl = _interopRequireDefault(require("../../intl"));
16
+ var _columnUtils = require("../../utils/column-utils");
16
17
  require("../../assets/css/sea-chart-d3-tooltip.css");
17
18
  class ChartComponent extends _react.Component {
18
19
  constructor(props) {
@@ -51,14 +52,22 @@ class ChartComponent extends _react.Component {
51
52
  this.initChart = function (container, id) {
52
53
  let initConfig = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
53
54
  const {
54
- width,
55
- height
55
+ width: containerWidth,
56
+ height: containerHeight
56
57
  } = container.getBoundingClientRect();
58
+ const {
59
+ marginLeft = 0,
60
+ marginBottom = 0
61
+ } = initConfig;
62
+ const width = containerWidth - marginLeft;
63
+ const height = containerHeight - marginBottom;
57
64
  _this.chart = d3.create('svg').attr('id', id).attr('class', "svg-wrapper-".concat(id)).attr('width', width).attr('height', height).attr('viewBox', [0, 0, width, height]);
58
65
  _this.container.appendChild(_this.chart.node());
59
66
  _this.chartBoundingClientRect = {
60
67
  ...JSON.parse(JSON.stringify(_this.chart.node().getBoundingClientRect())),
61
- ...initConfig
68
+ ...initConfig,
69
+ width,
70
+ height
62
71
  };
63
72
  };
64
73
  this.initDefs = () => {
@@ -70,7 +79,7 @@ class ChartComponent extends _react.Component {
70
79
  const {
71
80
  width,
72
81
  height
73
- } = this.container.getBoundingClientRect();
82
+ } = this.chartBoundingClientRect;
74
83
  this.chart.append('defs').append('mask').attr('id', "mask-wrapper-".concat(previewType, "-").concat(this.chart.node().id)).append('rect').attr('x', 0).attr('y', 0).attr('width', width).attr('height', height - 30).attr('fill', 'white');
75
84
  }
76
85
  };
@@ -216,7 +225,6 @@ class ChartComponent extends _react.Component {
216
225
  }
217
226
  };
218
227
  this.renderAxisLabel = (chart, tables, chartContainer) => {
219
- var _this$chart2;
220
228
  if (!this.chart || !chart) return;
221
229
  let {
222
230
  table_id,
@@ -237,30 +245,31 @@ class ChartComponent extends _react.Component {
237
245
  y_axis_column_key = y_axis_summary_column_key;
238
246
  }
239
247
  const table = (0, _dtableUtils.getTableById)(tables, table_id);
240
- const autoPadding = ((_this$chart2 = this.chart) === null || _this$chart2 === void 0 ? void 0 : _this$chart2.autoPadding) || {
241
- bottom: 0
242
- };
243
248
  let textColor;
244
249
  this.globalTheme === _constants.THEME_NAME_MAP.DARK ? textColor = '#fff' : textColor = '#999';
245
250
  const xAxisID = "chart-x-axis-label_".concat(chart.id);
246
251
  const xLabel = chartContainer === null || chartContainer === void 0 ? void 0 : chartContainer.querySelector("#".concat(xAxisID));
252
+ const {
253
+ width: containerWidth
254
+ } = this.chartBoundingClientRect;
247
255
  if (!xLabel && x_axis_show_label) {
248
256
  const div = document.createElement('div');
249
257
  div.id = xAxisID;
250
258
  div.className = 'chart-axis-label';
251
259
  const column = (0, _dtableUtils.getTableColumnByKey)(table, x_axis_column_key);
252
260
  div.innerHTML = "".concat(column ? column.name : '');
253
- div.setAttribute('style', "color:".concat(textColor, "; width: 100%; text-align: ").concat(x_axis_label_position, "; bottom: -20px; position: absolute"));
261
+ div.setAttribute('style', "color:".concat(textColor, "; width: ").concat(containerWidth, "px; text-align: ").concat(x_axis_label_position, "; position: absolute"));
254
262
  chartContainer.appendChild(div);
255
263
  }
256
264
  if (xLabel && x_axis_show_label) {
257
- xLabel.setAttribute('style', "color:".concat(textColor, "; width: 100%; text-align: ").concat(x_axis_label_position, "; bottom: -20px; position: absolute"));
265
+ xLabel.setAttribute('style', "color:".concat(textColor, "; width: ").concat(containerWidth, "px; text-align: ").concat(x_axis_label_position, "; position: absolute"));
258
266
  }
259
267
  if (xLabel && !x_axis_show_label) {
260
268
  xLabel.parentNode.removeChild(xLabel);
261
269
  }
262
270
  const yAxisID = "chart-y-axis-label_".concat(chart.id);
263
271
  const yLabel = chartContainer.querySelector("#".concat(yAxisID));
272
+ const divHeight = 20;
264
273
  if (!yLabel && y_axis_show_label) {
265
274
  const div = document.createElement('div');
266
275
  div.id = yAxisID;
@@ -274,24 +283,103 @@ class ChartComponent extends _react.Component {
274
283
  div.innerHTML = title_name || '';
275
284
  }
276
285
  }
277
- const containerHeight = chartContainer.offsetHeight;
286
+ const {
287
+ height: containerHeight
288
+ } = this.chartBoundingClientRect;
278
289
  let textAlign = 'center';
279
290
  if (y_axis_label_position === _constants.LABEL_POSITION_TYPE.BOTTOM) textAlign = 'left';
280
291
  if (y_axis_label_position === _constants.LABEL_POSITION_TYPE.TOP) textAlign = 'right';
281
- div.setAttribute('style', "color:".concat(textColor, "; position: absolute; width: ").concat(containerHeight, "px; text-align: ").concat(textAlign, "; top: 0; left: 0; transform: translate(-").concat(containerHeight / 2 + 12, "px, ").concat((containerHeight - autoPadding.bottom) / 2 + autoPadding.bottom / 4, "px) rotate(-90deg)"));
292
+ div.setAttribute('style', "color:".concat(textColor, "; position: absolute; width: ").concat(containerHeight, "px; height: ").concat(divHeight, "px; text-align: ").concat(textAlign, "; top: 0; left: 0; transform: translate(-").concat(containerHeight / 2 - divHeight / 2, "px, ").concat(containerHeight / 2 - divHeight / 2, "px) rotate(-90deg)"));
282
293
  chartContainer.appendChild(div);
283
294
  }
284
295
  if (yLabel && y_axis_show_label) {
285
- const containerHeight = chartContainer.offsetHeight;
296
+ const {
297
+ height: containerHeight
298
+ } = this.chartBoundingClientRect;
286
299
  let textAlign = 'center';
287
300
  if (y_axis_label_position === _constants.LABEL_POSITION_TYPE.BOTTOM) textAlign = 'left';
288
301
  if (y_axis_label_position === _constants.LABEL_POSITION_TYPE.TOP) textAlign = 'right';
289
- yLabel.setAttribute('style', "color:".concat(textColor, "; position: absolute; width: ").concat(containerHeight, "px; text-align: ").concat(textAlign, "; top: 0; left: 0; transform: translate(-").concat(containerHeight / 2 + 12, "px, ").concat((containerHeight - autoPadding.bottom) / 2 + autoPadding.bottom / 4, "px) rotate(-90deg)"));
302
+ yLabel.setAttribute('style', "color:".concat(textColor, "; position: absolute; width: ").concat(containerHeight, "px; height: ").concat(divHeight, "px; text-align: ").concat(textAlign, "; top: 0; left: 0; transform: translate(-").concat(containerHeight / 2 - divHeight / 2, "px, ").concat(containerHeight / 2 - divHeight / 2, "px) rotate(-90deg)"));
290
303
  }
291
304
  if (yLabel && !y_axis_show_label) {
292
305
  yLabel.parentNode.removeChild(yLabel);
293
306
  }
294
307
  };
308
+ this.renderHorizontalLabel = (chart, tables, chartContainer) => {
309
+ if (!this.chart || !chart) return;
310
+ const {
311
+ table_id,
312
+ vertical_axis_column_key,
313
+ horizontal_axis_column_key,
314
+ horizontal_axis_summary_type,
315
+ horizontal_axis_label_position,
316
+ vertical_axis_label_position,
317
+ show_vertical_axis_label,
318
+ show_horizontal_axis_label
319
+ } = chart.config;
320
+ const table = (0, _dtableUtils.getTableById)(tables, table_id);
321
+ const textColor = '#999999';
322
+ const xAxisID = "chart-x-axis-label_".concat(chart.id);
323
+ const xLabel = chartContainer.querySelector("#".concat(xAxisID));
324
+ const {
325
+ width: containerWidth
326
+ } = this.chartBoundingClientRect;
327
+ if (!xLabel && show_horizontal_axis_label) {
328
+ const div = document.createElement('div');
329
+ div.id = xAxisID;
330
+ div.className = 'chart-axis-label';
331
+ if (horizontal_axis_summary_type === _constants.CHART_SUMMARY_TYPE.COUNT) {
332
+ div.innerHTML = _intl.default.get('Amount');
333
+ } else {
334
+ const column = (0, _dtableUtils.getTableColumnByKey)(table, horizontal_axis_column_key);
335
+ div.innerHTML = "".concat(column ? column.name : '');
336
+ }
337
+ div.setAttribute('style', "color:".concat(textColor, "; width: ").concat(containerWidth, "px; text-align: ").concat(horizontal_axis_label_position, "; position: absolute"));
338
+ chartContainer.appendChild(div);
339
+ }
340
+ if (xLabel && show_horizontal_axis_label) {
341
+ xLabel.setAttribute('style', "color:".concat(textColor, "; width: ").concat(containerWidth, "px; text-align: ").concat(horizontal_axis_label_position, "; position: absolute"));
342
+ }
343
+ if (xLabel && !show_horizontal_axis_label) {
344
+ xLabel.parentNode.removeChild(xLabel);
345
+ }
346
+ const yAxisID = "chart-y-axis-label_".concat(chart.id);
347
+ const yLabel = chartContainer.querySelector("#".concat(yAxisID));
348
+ const divHeight = 20;
349
+ if (!yLabel && show_vertical_axis_label) {
350
+ const div = document.createElement('div');
351
+ div.id = yAxisID;
352
+ div.className = 'chart-axis-label';
353
+ const column = (0, _dtableUtils.getTableColumnByKey)(table, vertical_axis_column_key) || {};
354
+ div.innerHTML = column.name || '';
355
+ const {
356
+ height: containerHeight
357
+ } = this.chartBoundingClientRect;
358
+ let textAlign = 'center';
359
+ if (vertical_axis_label_position === _constants.LABEL_POSITION_TYPE.BOTTOM) textAlign = 'left';
360
+ if (vertical_axis_label_position === _constants.LABEL_POSITION_TYPE.TOP) textAlign = 'right';
361
+ div.setAttribute('style', "color:".concat(textColor, "; position: absolute; width: ").concat(containerHeight, "px; height: ").concat(divHeight, "px; text-align: ").concat(textAlign, "; top: 0; left: 0; transform: translate(-").concat(containerHeight / 2 - divHeight / 2, "px, ").concat(containerHeight / 2 - divHeight / 2, "px) rotate(-90deg)"));
362
+ chartContainer.appendChild(div);
363
+ }
364
+ if (yLabel && show_horizontal_axis_label) {
365
+ const {
366
+ height: containerHeight
367
+ } = this.chartBoundingClientRect;
368
+ let textAlign = 'center';
369
+ if (vertical_axis_label_position === _constants.LABEL_POSITION_TYPE.BOTTOM) textAlign = 'left';
370
+ if (vertical_axis_label_position === _constants.LABEL_POSITION_TYPE.TOP) textAlign = 'right';
371
+ yLabel.setAttribute('style', "color:".concat(textColor, "; position: absolute; width: ").concat(containerHeight, "px; height: ").concat(divHeight, "px; text-align: ").concat(textAlign, "; top: 0; left: 0; transform: translate(-").concat(containerHeight / 2 - divHeight / 2, "px, ").concat(containerHeight / 2 - divHeight / 2, "px) rotate(-90deg)"));
372
+ }
373
+ if (yLabel && !show_horizontal_axis_label) {
374
+ yLabel.parentNode.removeChild(yLabel);
375
+ }
376
+ };
377
+ this.isShowVerticalAxisLabel = chart => {
378
+ return !!(chart && chart.config && chart.config.show_vertical_axis_label);
379
+ };
380
+ this.isShowHorizontalAxisLabel = chart => {
381
+ return !!(chart && chart.config && chart.config.show_horizontal_axis_label);
382
+ };
295
383
  // Automatic adjustment of maximum and minimum values
296
384
  this.autoAdjustDataOptions = function (chart) {
297
385
  let data = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
@@ -481,93 +569,290 @@ class ChartComponent extends _react.Component {
481
569
  return _intl.default.get(name) || name;
482
570
  }
483
571
  };
484
- this.getOthersLegendItemWidth = (curIndex, allLegendItems, direction) => {
485
- let width = 0;
486
- let otherItems = [];
487
- if (direction === 1) {
488
- otherItems = allLegendItems.slice(0, curIndex);
489
- }
490
- if (direction === -1) {
491
- otherItems = allLegendItems.slice(curIndex);
492
- }
493
- otherItems.forEach(item => {
494
- const {
495
- width: legendItemWidth
496
- } = item.getBoundingClientRect();
497
- width = width + legendItemWidth;
572
+ this.sortLegend = (result, groupColumn, legendName) => {
573
+ result.forEach(item => {
574
+ const option = groupColumn.data.options.find(option => option.name === item[legendName]);
575
+ if (option !== null && option !== void 0 && option.id) {
576
+ item['group_name_id'] = option.id;
577
+ item['oldName'] = item.name;
578
+ item.name = item['group_name_id'];
579
+ }
580
+ });
581
+ _utils.BaseUtils.sortCharts(result, groupColumn, 'name');
582
+ result.forEach(item => {
583
+ item.name = item['oldName'];
498
584
  });
499
- return width;
500
585
  };
501
586
  // set legend
502
- this.setLegend = function (legendName) {
587
+ this.setLegend = _ref => {
503
588
  var _this$chart$node;
504
- let theme = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : _constants.CHART_THEME_COLOR['light'];
505
- let legendPosition = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'top-left';
506
- let data = arguments.length > 3 ? arguments[3] : undefined;
507
- let colorScale = arguments.length > 4 ? arguments[4] : undefined;
508
- if (!_this.chart) return;
589
+ let {
590
+ legendName,
591
+ theme = _constants.CHART_THEME_COLOR['light'],
592
+ legendPosition = 'top-left',
593
+ data,
594
+ colorScale,
595
+ groupColumn
596
+ } = _ref;
597
+ if (!this.chart) return;
598
+ const legendData = (0, _lodashEs.cloneDeep)(data);
599
+ this.legendConfig = {
600
+ legendRectWidth: 20,
601
+ legendRectHeight: 6,
602
+ r: 3,
603
+ legendItemPaddingTop: 3,
604
+ legendItemMargin: 20,
605
+ legendRecTextGap: 8,
606
+ legendPageNavWrapperWidth: 100,
607
+ legendPosition,
608
+ legendName,
609
+ theme
610
+ };
611
+
612
+ // sort legend data
613
+ if (groupColumn && [_dtableUtils.CellType.SINGLE_SELECT].includes(groupColumn.type)) {
614
+ this.sortLegend(legendData, groupColumn, legendName);
615
+ }
509
616
  const {
510
617
  width: chartWidth,
511
618
  insertPadding
512
- } = _this.chartBoundingClientRect;
513
- const legendItemPaddingTop = 8;
514
- const legendItemSpacing = 30;
515
- const legendRectWidth = 18;
516
- const legendRectHeight = 6;
517
- const r = 3;
518
- let translateX = 0;
519
- let legendData = [];
520
- let direction = 0; // 1 means left, -1 means right
521
- if (legendPosition === 'top-left') {
522
- translateX = insertPadding;
523
- legendData = d3.group(data, d => d[legendName]);
524
- direction = 1;
619
+ } = this.chartBoundingClientRect;
620
+ const groupsData = this.getLegendDataGroups(legendData);
621
+ const legendWrapper = this.chart.append('g').attr('class', "legend-wrapper-".concat((_this$chart$node = this.chart.node()) === null || _this$chart$node === void 0 ? void 0 : _this$chart$node.id));
622
+
623
+ // Render first group legend
624
+ this.renderLegend({
625
+ legendWrapper,
626
+ groupData: groupsData[0],
627
+ colorScale,
628
+ theme
629
+ });
630
+
631
+ // Render Page navigator
632
+ if (groupsData.length > 1) {
633
+ const {
634
+ legendPageNavWrapperWidth
635
+ } = this.legendConfig;
636
+ let curCount = 0;
637
+ const pageNavigator = legendWrapper.append('g').attr('class', 'legend-flip-page');
638
+
639
+ // count
640
+ pageNavigator.append('text').attr('class', 'legend-count').attr('dominant-baseline', 'hanging').attr('x', 15).attr('fill', theme.legendTextColor).attr('font-size', theme.legendFontSize).text("".concat(curCount + 1, "/").concat(groupsData.length));
641
+
642
+ // prev page
643
+ pageNavigator.append('polygon').attr('class', 'legend-prev-page').attr('points', this.calcEquilateralTriangle(5, 5, 12)).attr('fill', theme.legendPageNavigatorMarkerColor).attr('opacity', curCount === 0 ? 0.45 : 1).attr('style', 'cursor: pointer;').on('click', event => {
644
+ if (curCount > 0) {
645
+ curCount--;
646
+ this.renderLegend({
647
+ legendWrapper,
648
+ groupData: groupsData[curCount],
649
+ colorScale,
650
+ theme,
651
+ text: "".concat(curCount + 1, "/").concat(groupsData.length)
652
+ });
653
+ }
654
+ });
655
+
656
+ // next page
657
+ pageNavigator.append('polygon').attr('class', 'legend-next-page').attr('points', this.calcEquilateralTriangle(45, 5, 12, 'bottom')).attr('fill', theme.legendPageNavigatorMarkerColor).attr('opacity', curCount === groupsData.length - 1 ? 0.45 : 1).attr('style', 'cursor: pointer;').on('click', event => {
658
+ if (curCount < groupsData.length - 1) {
659
+ curCount++;
660
+ this.renderLegend({
661
+ legendWrapper,
662
+ groupData: groupsData[curCount],
663
+ colorScale,
664
+ theme,
665
+ text: "".concat(curCount + 1, "/").concat(groupsData.length)
666
+ });
667
+ }
668
+ });
669
+
670
+ // update pageNavigator transform
671
+ pageNavigator.call(g => {
672
+ let groupTranslateX = 0;
673
+ if (legendPosition === 'top-right') {
674
+ groupTranslateX = insertPadding;
675
+ } else if (legendPosition === 'top-left') {
676
+ groupTranslateX = chartWidth - insertPadding - legendPageNavWrapperWidth;
677
+ const {
678
+ width
679
+ } = g.node().getBoundingClientRect();
680
+ const offset = legendPageNavWrapperWidth - width;
681
+ groupTranslateX = groupTranslateX + offset;
682
+ }
683
+ g.attr('transform', "translate(".concat(groupTranslateX, ", 0)"));
684
+ });
525
685
  }
526
- if (legendPosition === 'top-right') {
527
- translateX = chartWidth;
528
- legendData = d3.group(data, d => d[legendName]);
529
- direction = -1;
686
+ };
687
+ this.renderLegend = _ref2 => {
688
+ let {
689
+ legendWrapper,
690
+ groupData,
691
+ colorScale,
692
+ theme,
693
+ text
694
+ } = _ref2;
695
+ const {
696
+ legendItemPaddingTop,
697
+ legendRectWidth,
698
+ legendRectHeight,
699
+ r,
700
+ legendRecTextGap,
701
+ legendItemMargin,
702
+ legendPosition
703
+ } = this.legendConfig;
704
+
705
+ // clear old legends
706
+ const oldChildren = Array.from(legendWrapper.node().children);
707
+ if (oldChildren.length !== 0) {
708
+ oldChildren.forEach(item => {
709
+ // update navigator button opacity and text
710
+ if (item.getAttribute('class') == 'legend-flip-page') {
711
+ this.handleNavigatorOpacity(item, text);
712
+ d3.select(item).selectAll('text').text(text);
713
+ return;
714
+ }
715
+ // remove old legend item
716
+ d3.select(item).remove();
717
+ });
530
718
  }
531
- const legendWrapper = _this.chart.append('g').attr('class', "legend-wrapper-".concat((_this$chart$node = _this.chart.node()) === null || _this$chart$node === void 0 ? void 0 : _this$chart$node.id)).attr('transform', "translate(".concat(translateX, ", 0)"));
532
- legendWrapper.selectAll().data(legendData).join('g').append('rect').attr('width', legendRectWidth).attr('height', legendRectHeight).attr('rx', r).attr('fill', _ref => {
533
- let [groupName] = _ref;
719
+ legendWrapper.selectAll().data(groupData).join('g').attr('data-groupName', _ref3 => {
720
+ let [groupName] = _ref3;
721
+ return groupName;
722
+ }).append('rect').attr('width', legendRectWidth).attr('height', legendRectHeight).attr('y', legendItemPaddingTop).attr('rx', r).attr('fill', _ref4 => {
723
+ let [groupName] = _ref4;
534
724
  if (colorScale) return colorScale(groupName);
535
- return _this.colorMap[groupName] || _constants.CHART_STYLE_COLORS[0];
536
- }).attr('data-text', _ref2 => {
537
- let [groupName] = _ref2;
725
+ return this.colorMap[groupName] || _constants.CHART_STYLE_COLORS[0];
726
+ }).attr('data-text', _ref5 => {
727
+ let [groupName] = _ref5;
538
728
  return groupName;
539
729
  }).call(g => {
540
- const legendItems = Array.from(legendWrapper.node().children);
541
- const legendItemCount = legendItems.length;
542
-
543
730
  // Add text
544
731
  g.nodes().forEach(rect => {
545
732
  const parentNode = rect.parentNode;
546
- let textHeight = 0;
547
- let textWidth = 0;
548
- d3.select(parentNode).append('text').attr('x', legendRectWidth).attr('width', 30).attr('fill', theme.legendTextColor).attr('font-size', theme.legendFontSize).text(_this.formatterLegendName(rect.dataset.text)).attr('data-text', rect.dataset.text).call(g => {
549
- // set text y position
733
+ d3.select(parentNode).append('text').attr('x', legendRectWidth + legendRecTextGap).attr('fill', theme.legendTextColor).attr('font-size', theme.legendFontSize).text(this.formatterLegendName(rect.dataset.text)).attr('data-text', rect.dataset.text).attr('dominant-baseline', 'hanging');
734
+ });
735
+ // update g translateX
736
+ const legendItems = Array.from(legendWrapper.node().children).filter(item => item.getAttribute('class') !== 'legend-flip-page');
737
+ const {
738
+ start,
739
+ end
740
+ } = this.getLegendBoundary(legendPosition);
741
+ legendItems.forEach((item, index) => {
742
+ let translateX = start;
743
+ const lastItem = legendItems[index - 1];
744
+ if (index > 0) {
550
745
  const {
551
- height,
552
746
  width
553
- } = g.node().getBoundingClientRect();
554
- textHeight = height;
555
- textWidth = width;
556
- g.attr('y', textHeight / 2);
557
- });
558
- });
747
+ } = lastItem.getBoundingClientRect();
748
+ const prevTranslateX = Number(lastItem.getAttribute('data-translateX'));
749
+ translateX = prevTranslateX + width + legendItemMargin;
750
+ }
559
751
 
560
- // set g position
561
- legendItems.forEach((item, index) => {
562
- const otherslegendItemWidth = _this.getOthersLegendItemWidth(index, legendItems, direction);
563
- d3.select(item).attr('transform', () => {
564
- const gaps = direction === 1 ? index : legendItemCount - index;
565
- const translateX = direction * (otherslegendItemWidth + gaps * legendItemSpacing);
566
- return "translate(".concat(translateX, ", ").concat(legendItemPaddingTop, ")");
567
- });
752
+ // legend items add offset
753
+ if (legendPosition === 'top-right') {
754
+ d3.select(item).attr('opacity', 0);
755
+ if (index === legendItems.length - 1) {
756
+ queueMicrotask(() => {
757
+ this.setLegendItemOffset(legendItems, end);
758
+ });
759
+ }
760
+ }
761
+ d3.select(item).attr('transform', "translate(".concat(translateX, ",0)")).attr('data-translateX', translateX);
568
762
  });
569
763
  });
570
764
  };
765
+ this.getLegendDataGroups = legendData => {
766
+ const {
767
+ legendName,
768
+ theme,
769
+ legendPosition
770
+ } = this.legendConfig;
771
+ legendData = d3.groups(legendData, d => d[legendName]);
772
+ const {
773
+ legendItemMargin,
774
+ legendRectWidth,
775
+ legendRectHeight,
776
+ r,
777
+ legendRecTextGap
778
+ } = this.legendConfig;
779
+ const {
780
+ start,
781
+ end
782
+ } = this.getLegendBoundary(legendPosition);
783
+ let allWidth = start;
784
+ const groupsData = [];
785
+ const newLegendData = (0, _lodashEs.cloneDeep)(legendData);
786
+ legendData.forEach((item, index) => {
787
+ const virtualLegend = this.chart.append('g').attr('opacity', 0);
788
+ virtualLegend.append('rect').attr('width', legendRectWidth).attr('height', legendRectHeight).attr('rx', r);
789
+ virtualLegend.append('text').attr('x', legendRectWidth + legendRecTextGap).attr('font-size', theme.legendFontSize).text(this.formatterLegendName(item[0]));
790
+ const {
791
+ width
792
+ } = virtualLegend.node().getBoundingClientRect();
793
+ const itemWidth = index === legendData.length - 1 ? width : width + legendItemMargin; // last item no used margin
794
+ allWidth = allWidth + itemWidth;
795
+ if (allWidth >= end) {
796
+ groupsData.push(newLegendData.slice(0, index));
797
+ newLegendData.splice(0, index);
798
+ allWidth = 0;
799
+ }
800
+ virtualLegend.remove();
801
+ });
802
+ const restLegendItems = newLegendData.slice(0);
803
+ groupsData.push(restLegendItems);
804
+ return groupsData;
805
+ };
806
+ this.getLegendBoundary = legendPosition => {
807
+ const {
808
+ legendPageNavWrapperWidth
809
+ } = this.legendConfig;
810
+ const {
811
+ width: chartWidth,
812
+ insertPadding
813
+ } = this.chartBoundingClientRect;
814
+ let start = 0;
815
+ let end = 0;
816
+ if (legendPosition === 'top-left') {
817
+ start = insertPadding;
818
+ end = chartWidth - insertPadding - legendPageNavWrapperWidth;
819
+ }
820
+ if (legendPosition === 'top-right') {
821
+ start = insertPadding + legendPageNavWrapperWidth;
822
+ end = chartWidth - insertPadding;
823
+ }
824
+ return {
825
+ start,
826
+ end
827
+ };
828
+ };
829
+ this.handleNavigatorOpacity = (navigator, text) => {
830
+ const curCount = text.split('/')[0];
831
+ const allCount = text.split('/')[1];
832
+ if (Number(curCount) === 0) {
833
+ d3.select(navigator).selectAll('.legend-prev-page').attr('opacity', 0.45);
834
+ d3.select(navigator).selectAll('.legend-next-page').attr('opacity', 1);
835
+ } else if (Number(curCount) === Number(allCount)) {
836
+ d3.select(navigator).selectAll('.legend-prev-page').attr('opacity', 1);
837
+ d3.select(navigator).selectAll('.legend-next-page').attr('opacity', 0.45);
838
+ } else {
839
+ d3.select(navigator).selectAll('.legend-prev-page').attr('opacity', 1);
840
+ d3.select(navigator).selectAll('.legend-next-page').attr('opacity', 1);
841
+ }
842
+ };
843
+ this.setLegendItemOffset = (legendItems, end) => {
844
+ const endItem = legendItems[legendItems.length - 1];
845
+ const endTranslateX = Number(endItem.getAttribute('data-translateX'));
846
+ const {
847
+ width: endWidth
848
+ } = endItem.getBoundingClientRect();
849
+ const offset = end - (endTranslateX + endWidth);
850
+ legendItems.forEach(legendItem => {
851
+ const curTranslateX = Number(legendItem.getAttribute('data-translateX')) + offset;
852
+ d3.select(legendItem).attr('transform', "translate(".concat(curTranslateX, ",0)")).attr('data-translateX', curTranslateX);
853
+ d3.select(legendItem).attr('opacity', 1);
854
+ });
855
+ };
571
856
  // theta is pie or ring chart
572
857
  this.setLegendForTheta = function (legendName) {
573
858
  let theme = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : _constants.CHART_THEME_COLOR['light'];
@@ -581,6 +866,13 @@ class ChartComponent extends _react.Component {
581
866
  basicLegendConfig.itemName.style.fontSize = theme.fontSize;
582
867
  _this.chart.legend(legendName, basicLegendConfig);
583
868
  };
869
+ this.calcEquilateralTriangle = (cx, cy, size, direction) => {
870
+ const height = size * Math.sqrt(3) / 2;
871
+ if (direction === 'bottom') {
872
+ return [[cx, cy + height / 2], [cx - size / 2, cy - height / 2], [cx + size / 2, cy - height / 2]];
873
+ }
874
+ return [[cx, cy - height / 2], [cx - size / 2, cy + height / 2], [cx + size / 2, cy + height / 2]];
875
+ };
584
876
  this.setColorMap = (data, chartColorTheme) => {
585
877
  let currentIdx = 0;
586
878
  const defaultColors = _constants.CHART_STYLE_COLORS;
@@ -762,11 +1054,11 @@ class ChartComponent extends _react.Component {
762
1054
  width: chartWidth
763
1055
  } = this.chartBoundingClientRect;
764
1056
  const annotationWrapper = this.chart.append('g').attr('class', "annotation-wrapper-".concat((_this$chart$node2 = this.chart.node()) === null || _this$chart$node2 === void 0 ? void 0 : _this$chart$node2.id));
765
- annotationWrapper.append('line').attr('stroke', '#aaa').attr('x1', insertPadding).attr('y1', yScale(goal_value)).attr('x2', chartWidth - insertPadding).attr('y2', yScale(goal_value)).call(g => {
1057
+ annotationWrapper.append('line').attr('stroke', '#aaa').attr('x1', insertPadding).attr('y1', yScale(goal_value)).attr('x2', chartWidth - insertPadding).attr('y2', yScale(goal_value)).attr('stroke-dasharray', '8,3').call(g => {
766
1058
  annotationWrapper.append('text').attr('x', chartWidth - insertPadding - 30).attr('y', yScale(goal_value) - 10).attr('fill', '#666').text(goal_label);
767
1059
  });
768
1060
  };
769
- this.addLabelToRectTop = _ref3 => {
1061
+ this.addLabelToRectTop = _ref6 => {
770
1062
  let {
771
1063
  container,
772
1064
  x,
@@ -775,7 +1067,7 @@ class ChartComponent extends _react.Component {
775
1067
  theme,
776
1068
  label_font_size,
777
1069
  text
778
- } = _ref3;
1070
+ } = _ref6;
779
1071
  d3.select(container).append('text').attr('y', Number(y) - 10).attr('fill', theme.labelColor).attr('font-size', _utils.BaseUtils.getLabelFontSize(label_font_size)).text(text).call(g => {
780
1072
  const {
781
1073
  width
@@ -783,7 +1075,24 @@ class ChartComponent extends _react.Component {
783
1075
  g.attr('x', Number(x) + Number(xWidth) / 2 - width / 2);
784
1076
  });
785
1077
  };
786
- this.addLabelToRectCenter = _ref4 => {
1078
+ this.addLabelToRectRight = _ref7 => {
1079
+ let {
1080
+ container,
1081
+ y,
1082
+ xWidth,
1083
+ yHeight,
1084
+ theme,
1085
+ label_font_size,
1086
+ text
1087
+ } = _ref7;
1088
+ 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 => {
1089
+ const {
1090
+ height
1091
+ } = g.node().getBoundingClientRect();
1092
+ g.attr('y', Number(y) + Number(yHeight) / 2 - height / 2);
1093
+ });
1094
+ };
1095
+ this.addLabelToRectCenter = _ref8 => {
787
1096
  let {
788
1097
  chartType,
789
1098
  container,
@@ -791,11 +1100,10 @@ class ChartComponent extends _react.Component {
791
1100
  y,
792
1101
  xWidth,
793
1102
  yheight,
794
- overflowHeight,
795
1103
  theme,
796
1104
  label_font_size,
797
1105
  text
798
- } = _ref4;
1106
+ } = _ref8;
799
1107
  d3.select(container).append('text').attr('fill', theme.labelColor).attr('font-size', _utils.BaseUtils.getLabelFontSize(label_font_size)).text(text).call(g => {
800
1108
  const {
801
1109
  width,
@@ -804,7 +1112,7 @@ class ChartComponent extends _react.Component {
804
1112
  const translateX = Number(x) + xWidth / 2 - width / 2;
805
1113
  let translateY = Number(y) + Number(yheight / 2) + height / 2;
806
1114
  if (chartType === _constants.CHART_TYPE.BAR_STACK) {
807
- translateY = translateY - overflowHeight / 2;
1115
+ translateY = translateY;
808
1116
  }
809
1117
  g.attr('transform', "translate(".concat(translateX, ", ").concat(translateY, ")"));
810
1118
  });
@@ -829,6 +1137,31 @@ class ChartComponent extends _react.Component {
829
1137
  });
830
1138
  }
831
1139
  };
1140
+ // Use clipPath to make rectangle rounded corners
1141
+ this.addClipPath = _ref9 => {
1142
+ let {
1143
+ rect,
1144
+ parentNode,
1145
+ attr,
1146
+ rectId
1147
+ } = _ref9;
1148
+ const {
1149
+ borderRadius
1150
+ } = this.chartBoundingClientRect;
1151
+ const clipRect = d3.select(rect.cloneNode());
1152
+ if (attr === 'x') {
1153
+ const borderRadiusVal = Number(rect.getAttribute('height')) * borderRadius;
1154
+ clipRect.attr('rx', borderRadiusVal);
1155
+ clipRect.attr('x', Number(rect.getAttribute('x')) - borderRadiusVal).attr('width', Number(rect.getAttribute('width')) + borderRadiusVal);
1156
+ } else {
1157
+ const borderRadiusVal = Number(rect.getAttribute('width')) * borderRadius;
1158
+ clipRect.attr('rx', borderRadiusVal);
1159
+ clipRect.attr('height', Number(rect.getAttribute('height')) + borderRadiusVal);
1160
+ }
1161
+ const clipPath = d3.select(parentNode).append('clipPath').attr('id', rectId);
1162
+ clipPath.node().appendChild(clipRect.node());
1163
+ d3.select(rect).attr('clip-path', "url(#".concat(rectId, ")"));
1164
+ };
832
1165
  this.initLabelStroke(props === null || props === void 0 ? void 0 : props.globalTheme);
833
1166
  this.chartBoundingClientRect = {};
834
1167
  }