sea-chart 2.0.59 → 2.0.60

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.
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", {
6
6
  value: true
7
7
  });
8
8
  exports.default = void 0;
9
+ var _DTableSwitch2 = _interopRequireDefault(require("dtable-ui-component/lib/DTableSwitch"));
9
10
  var _DTableEmptyTip2 = _interopRequireDefault(require("dtable-ui-component/lib/DTableEmptyTip"));
10
11
  var _toaster2 = _interopRequireDefault(require("dtable-ui-component/lib/toaster"));
11
12
  var _react = _interopRequireWildcard(require("react"));
@@ -19,6 +20,8 @@ var _loading = _interopRequireDefault(require("../loading"));
19
20
  var _search = require("../../utils/search");
20
21
  var _chartDataSql = _interopRequireDefault(require("../../utils/sql/chart-data-sql"));
21
22
  var _rowRecordUtils = require("../../utils/row-record-utils");
23
+ var _icon = _interopRequireDefault(require("../icon"));
24
+ var _hideColumnPopover = _interopRequireDefault(require("../popover/hide-column-popover/hide-column-popover"));
22
25
  var _rowCard = _interopRequireDefault(require("../row-card/row-card"));
23
26
  var _commonConstants = require("../../constants/common-constants");
24
27
  var _utils = require("../../utils");
@@ -26,7 +29,83 @@ var _constants = require("../../constants");
26
29
  require("./index.css");
27
30
  class StatisticRecordDialog extends _react.default.Component {
28
31
  constructor(_props) {
32
+ var _this;
29
33
  super(_props);
34
+ _this = this;
35
+ this.initSearchSettings = (chart, table) => {
36
+ const allColumnKeys = ((table === null || table === void 0 ? void 0 : table.columns) || []).map(column => column.key);
37
+ const searchSettingKey = `${chart === null || chart === void 0 ? void 0 : chart.id}-${table === null || table === void 0 ? void 0 : table._id}`;
38
+ const searchConfig = JSON.parse(window.localStorage.getItem('sea-chart-search-config') || '{}');
39
+ const searchSetting = searchConfig[searchSettingKey] || {};
40
+ const nameColumnKey = allColumnKeys[0];
41
+ const savedColumns = searchSetting.search_participate_columns || allColumnKeys;
42
+ const searchParticipateColumns = savedColumns.includes(nameColumnKey) ? savedColumns : [nameColumnKey, ...savedColumns];
43
+ return {
44
+ isExactSearch: !!searchSetting.is_exact,
45
+ searchParticipateColumns
46
+ };
47
+ };
48
+ this.onSaveSearchConfig = function () {
49
+ let updatedConfig = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
50
+ const {
51
+ chart
52
+ } = _this.props.chartRecordsParams || {};
53
+ if (!chart || !_this.table) return;
54
+ const searchSettingKey = `${chart.id}-${_this.table._id}`;
55
+ const searchConfig = JSON.parse(window.localStorage.getItem('sea-chart-search-config') || '{}');
56
+ window.localStorage.setItem('sea-chart-search-config', JSON.stringify({
57
+ ...searchConfig,
58
+ [searchSettingKey]: updatedConfig
59
+ }));
60
+ };
61
+ this.onChangeExactSearch = () => {
62
+ const isExactSearch = !this.state.isExactSearch;
63
+ const {
64
+ rows,
65
+ searchVal
66
+ } = this.state;
67
+ const searchedRowsIds = this.getSearchedRows(rows, searchVal, {
68
+ isExactSearch
69
+ });
70
+ this.setState({
71
+ isExactSearch,
72
+ searchedRowsIds
73
+ });
74
+ this.onSaveSearchConfig({
75
+ is_exact: isExactSearch,
76
+ search_participate_columns: this.state.searchParticipateColumns
77
+ });
78
+ };
79
+ this.modifySearchParticipateColumns = shownColumnKeys => {
80
+ var _this$table$columns$;
81
+ const nameColumnKey = (_this$table$columns$ = this.table.columns[0]) === null || _this$table$columns$ === void 0 ? void 0 : _this$table$columns$.key;
82
+ const searchParticipateColumns = shownColumnKeys.includes(nameColumnKey) ? shownColumnKeys : [nameColumnKey, ...shownColumnKeys];
83
+ const {
84
+ rows,
85
+ searchVal
86
+ } = this.state;
87
+ const searchedRowsIds = this.getSearchedRows(rows, searchVal, {
88
+ searchParticipateColumns
89
+ });
90
+ this.setState({
91
+ searchParticipateColumns,
92
+ searchedRowsIds
93
+ });
94
+ this.onSaveSearchConfig({
95
+ is_exact: this.state.isExactSearch,
96
+ search_participate_columns: searchParticipateColumns
97
+ });
98
+ };
99
+ this.toggleSearchHidePopover = () => {
100
+ this.setState({
101
+ isShowSearchHidePopover: !this.state.isShowSearchHidePopover
102
+ });
103
+ };
104
+ this.onToggleShowExactMatch = () => {
105
+ this.setState({
106
+ isShowExactMatch: !this.state.isShowExactMatch
107
+ });
108
+ };
30
109
  this.init = () => {
31
110
  const {
32
111
  chartRecordsParams,
@@ -186,10 +265,22 @@ class StatisticRecordDialog extends _react.default.Component {
186
265
  searchVal: ''
187
266
  });
188
267
  };
189
- this.getSearchedRows = (rows, searchVal) => {
268
+ this.getSearchedRows = function (rows, searchVal) {
269
+ let settings = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
190
270
  if (!Array.isArray(rows) || rows.length === 0) return [];
191
271
  if (searchVal) {
192
- return (0, _search.searchRows)(rows, (0, _dtableUtils.getViewShownColumns)(this.view, this.table.columns), searchVal, row => {
272
+ var _settings$isExactSear, _settings$searchParti, _this$table$columns$2;
273
+ const isExactSearch = (_settings$isExactSear = settings.isExactSearch) !== null && _settings$isExactSear !== void 0 ? _settings$isExactSear : _this.state.isExactSearch;
274
+ const participateKeys = (_settings$searchParti = settings.searchParticipateColumns) !== null && _settings$searchParti !== void 0 ? _settings$searchParti : _this.state.searchParticipateColumns;
275
+ const nameColumnKey = (_this$table$columns$2 = _this.table.columns[0]) === null || _this$table$columns$2 === void 0 ? void 0 : _this$table$columns$2.key;
276
+ const searchParticipateColumns = participateKeys.includes(nameColumnKey) ? participateKeys : [nameColumnKey, ...participateKeys];
277
+ const searchColumns = (0, _dtableUtils.getViewShownColumns)(_this.view, _this.table.columns).filter(col => searchParticipateColumns.includes(col.key));
278
+ if (isExactSearch) {
279
+ return (0, _search.searchRowsByExactVal)(searchVal.trim().toLowerCase(), rows, searchColumns, {
280
+ formulaRows: _this.formulaRows
281
+ }).map(row => row._id);
282
+ }
283
+ return (0, _search.searchRows)(rows, searchColumns, searchVal, row => {
193
284
  return row;
194
285
  }).map(row => row._id);
195
286
  }
@@ -294,14 +385,25 @@ class StatisticRecordDialog extends _react.default.Component {
294
385
  formulaRows: view.formula_rows
295
386
  };
296
387
  };
388
+ this.getCachedSearchedRows = (searchedRowsIds, rows) => {
389
+ if (this.searchedRowsCache.searchedRowsIds !== searchedRowsIds || this.searchedRowsCache.rows !== rows) {
390
+ this.searchedRowsCache = {
391
+ searchedRowsIds,
392
+ rows,
393
+ result: this.getRowsByIds(searchedRowsIds)
394
+ };
395
+ }
396
+ return this.searchedRowsCache.result;
397
+ };
297
398
  this.renderRowsCards = () => {
298
399
  const {
299
400
  isCalculateByView
300
401
  } = this.props;
301
402
  const {
302
- searchedRowsIds
403
+ searchedRowsIds,
404
+ rows
303
405
  } = this.state;
304
- const searchedRows = this.getRowsByIds(searchedRowsIds);
406
+ const searchedRows = this.getCachedSearchedRows(searchedRowsIds, rows);
305
407
  if (searchedRows.length === 0) return /*#__PURE__*/_react.default.createElement("div", {
306
408
  className: "w-100 h-100"
307
409
  }, /*#__PURE__*/_react.default.createElement(_DTableEmptyTip2.default, {
@@ -317,22 +419,45 @@ class StatisticRecordDialog extends _react.default.Component {
317
419
  columns: this.renderedColumns,
318
420
  rows: searchedRows,
319
421
  isExpandRowDetail: isCalculateByView,
422
+ isVirtualized: true,
423
+ showScrollBtn: !window.isMobile,
320
424
  rowCardType: 'statistic'
321
425
  };
322
426
  return /*#__PURE__*/_react.default.createElement(_rowCard.default, props);
323
427
  };
428
+ const {
429
+ chartRecordsParams: _chartRecordsParams,
430
+ tables: _tables
431
+ } = _props;
432
+ const {
433
+ chart: _chart
434
+ } = _chartRecordsParams || {};
435
+ const _table = _chart ? (0, _dtableUtils.getTableById)(_tables, _chart.config.table_id) : null;
436
+ const {
437
+ isExactSearch: _isExactSearch,
438
+ searchParticipateColumns: _searchParticipateColumns
439
+ } = this.initSearchSettings(_chart, _table);
324
440
  this.state = {
325
441
  loading: true,
326
442
  title: '',
327
443
  rows: [],
328
444
  idRowMap: {},
329
445
  searchVal: '',
330
- searchedRowsIds: []
446
+ searchedRowsIds: [],
447
+ isExactSearch: _isExactSearch,
448
+ searchParticipateColumns: _searchParticipateColumns,
449
+ isShowExactMatch: _isExactSearch,
450
+ isShowSearchHidePopover: false
331
451
  };
332
452
  this.table = null;
333
453
  this.valueChanged = false;
334
454
  this.renderedColumns = [];
335
455
  this.formulaRows = null;
456
+ this.searchedRowsCache = {
457
+ searchedRowsIds: null,
458
+ rows: null,
459
+ result: []
460
+ };
336
461
  }
337
462
  componentDidMount() {
338
463
  const {
@@ -348,10 +473,17 @@ class StatisticRecordDialog extends _react.default.Component {
348
473
  this.unsubscribeExpandRowDeleted && this.unsubscribeExpandRowDeleted();
349
474
  }
350
475
  render() {
476
+ var _this$table, _this$table2, _this$table2$columns, _this$table2$columns$;
351
477
  const {
352
478
  loading,
353
- title
479
+ title,
480
+ isExactSearch,
481
+ searchParticipateColumns,
482
+ isShowExactMatch,
483
+ isShowSearchHidePopover
354
484
  } = this.state;
485
+ const searchableColumns = (((_this$table = this.table) === null || _this$table === void 0 ? void 0 : _this$table.columns) || []).filter(col => _search.SUPPORT_SEARCH_COLUMN_TYPES.includes(col.type));
486
+ const nameColumnKey = (_this$table2 = this.table) === null || _this$table2 === void 0 ? void 0 : (_this$table2$columns = _this$table2.columns) === null || _this$table2$columns === void 0 ? void 0 : (_this$table2$columns$ = _this$table2$columns[0]) === null || _this$table2$columns$ === void 0 ? void 0 : _this$table2$columns$.key;
355
487
  return /*#__PURE__*/_react.default.createElement(_reactstrap.Modal, {
356
488
  isOpen: true,
357
489
  autoFocus: false,
@@ -384,9 +516,40 @@ class StatisticRecordDialog extends _react.default.Component {
384
516
  }, /*#__PURE__*/_react.default.createElement("i", {
385
517
  className: "dtable-font dtable-icon-x-"
386
518
  }));
519
+ },
520
+ ExactMatchIndicator: () => {
521
+ return /*#__PURE__*/_react.default.createElement("span", {
522
+ className: "clear-search-text exact-match-search-text"
523
+ }, /*#__PURE__*/_react.default.createElement("div", {
524
+ className: "right-exact-button",
525
+ onClick: this.onToggleShowExactMatch
526
+ }, /*#__PURE__*/_react.default.createElement(_icon.default, {
527
+ symbol: "exact-match"
528
+ })));
387
529
  }
388
530
  }
389
- })), /*#__PURE__*/_react.default.createElement(_reactstrap.ModalBody, {
531
+ })), isShowExactMatch && /*#__PURE__*/_react.default.createElement("div", {
532
+ className: "search-settings-container d-flex align-items-center"
533
+ }, /*#__PURE__*/_react.default.createElement(_DTableSwitch2.default, {
534
+ size: "sm",
535
+ switchPosition: "left",
536
+ checked: isExactSearch,
537
+ placeholder: _intl.default.get('Exact_match'),
538
+ onChange: this.onChangeExactSearch
539
+ }), /*#__PURE__*/_react.default.createElement("span", {
540
+ className: "toolbar-btn exact-search-columns",
541
+ id: "statistic-search-hide-column",
542
+ onClick: this.toggleSearchHidePopover
543
+ }, /*#__PURE__*/_react.default.createElement(_icon.default, {
544
+ symbol: "field-set"
545
+ }), /*#__PURE__*/_react.default.createElement("span", null, _intl.default.get('Searchable_columns')))), isShowSearchHidePopover && /*#__PURE__*/_react.default.createElement(_hideColumnPopover.default, {
546
+ columns: searchableColumns,
547
+ ignoreColumnsKeys: nameColumnKey ? [nameColumnKey] : [],
548
+ target: "statistic-search-hide-column",
549
+ shownColumnKeys: searchParticipateColumns,
550
+ modifyHiddenColumns: this.modifySearchParticipateColumns,
551
+ onPopoverToggle: this.toggleSearchHidePopover
552
+ }), /*#__PURE__*/_react.default.createElement(_reactstrap.ModalBody, {
390
553
  className: "sea-chart-statistic-records-container"
391
554
  }, loading ? /*#__PURE__*/_react.default.createElement("div", {
392
555
  className: "d-flex py-8"
@@ -259,6 +259,10 @@ const de = {
259
259
  "Use_default_color": "Standardfarbe verwenden",
260
260
  "Use_colors_in_single_select_solumn": "Verwenden Sie Farben in einer einzelnen Auswahlspalte",
261
261
  "Search_records": "Einträge suchen",
262
+ "Exact_match": "Exakte Übereinstimmung",
263
+ "Searchable_columns": "Durchsuchbare Spalten",
264
+ "Clear_search_text": "Suchtext leeren",
265
+ "No_columns_available_to_be_hidden": "Es können keine Spalten ausgeblendet werden.",
262
266
  "Please_select_a_grouping_column": "Bitte Gruppierungsspalte auswählen",
263
267
  "View": "Sicht",
264
268
  "Funnel": "Trichterdiagramm",
@@ -259,6 +259,10 @@ const en = {
259
259
  "Use_default_color": "Use default color",
260
260
  "Use_colors_in_single_select_solumn": "Use colors in single select column",
261
261
  "Search_records": "Search records",
262
+ "Exact_match": "Exact match",
263
+ "Searchable_columns": "Searchable columns",
264
+ "Clear_search_text": "Clear search text",
265
+ "No_columns_available_to_be_hidden": "No columns available to be hidden.",
262
266
  "Please_select_a_grouping_column": "Please select grouping column",
263
267
  "View": "View",
264
268
  "Funnel": "Funnel",
@@ -259,6 +259,10 @@ const es = {
259
259
  "Use_default_color": "Use default color",
260
260
  "Use_colors_in_single_select_solumn": "Use colors in single select column",
261
261
  "Search_records": "Search records",
262
+ "Exact_match": "Coincidencia exacta",
263
+ "Searchable_columns": "Columnas de búsqueda",
264
+ "Clear_search_text": "Limpiar texto de búsqueda",
265
+ "No_columns_available_to_be_hidden": "No hay columnas disponibles para ocultar.",
262
266
  "Please_select_a_grouping_column": "Please select grouping column",
263
267
  "View": "View",
264
268
  "Funnel": "Funnel",
@@ -259,6 +259,10 @@ const fr = {
259
259
  "Use_default_color": "Utiliser la couleur par défaut",
260
260
  "Use_colors_in_single_select_solumn": "Utiliser les couleurs dans une colonne de sélection unique",
261
261
  "Search_records": "Rechercher des enregistrements",
262
+ "Exact_match": "Correspondence exacte",
263
+ "Searchable_columns": "Colonnes de recherche",
264
+ "Clear_search_text": "Effacer le texte de recherche",
265
+ "No_columns_available_to_be_hidden": "Aucune colonne ne peut être masquée.",
262
266
  "Please_select_a_grouping_column": "Veuillez sélectionner la colonne de regroupement",
263
267
  "View": "Voir",
264
268
  "Funnel": "Entonnoir",
@@ -259,6 +259,10 @@ const pt = {
259
259
  "Use_default_color": "Use default color",
260
260
  "Use_colors_in_single_select_solumn": "Use colors in single select column",
261
261
  "Search_records": "Search records",
262
+ "Exact_match": "Correspondência exacta",
263
+ "Searchable_columns": "Colunas pesquisáveis",
264
+ "Clear_search_text": "Limpar texto de pesquisa",
265
+ "No_columns_available_to_be_hidden": "Nenhuma coluna disponível para ser ocultada.",
262
266
  "Please_select_a_grouping_column": "Please select grouping column",
263
267
  "View": "View",
264
268
  "Funnel": "Funnel",
@@ -259,6 +259,10 @@ const ru = {
259
259
  "Use_default_color": "Use default color",
260
260
  "Use_colors_in_single_select_solumn": "Use colors in single select column",
261
261
  "Search_records": "Search records",
262
+ "Exact_match": "Точное соответствие",
263
+ "Searchable_columns": "Поиск столбцов",
264
+ "Clear_search_text": "Очистить текст поиска",
265
+ "No_columns_available_to_be_hidden": "Нет доступных столбцов для скрытия",
262
266
  "Please_select_a_grouping_column": "Please select grouping column",
263
267
  "View": "View",
264
268
  "Funnel": "Funnel",
@@ -259,6 +259,10 @@ const zh_CN = {
259
259
  "Use_default_color": "使用默认颜色",
260
260
  "Use_colors_in_single_select_solumn": "使用列中的选项颜色",
261
261
  "Search_records": "搜索记录",
262
+ "Exact_match": "精确匹配",
263
+ "Searchable_columns": "可搜索的列",
264
+ "Clear_search_text": "清除搜索文本",
265
+ "No_columns_available_to_be_hidden": "没有列可以被隐藏。",
262
266
  "Please_select_a_grouping_column": "请选择一个分组列",
263
267
  "View": "视图",
264
268
  "Funnel": "漏斗图",
@@ -4,12 +4,13 @@ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefau
4
4
  Object.defineProperty(exports, "__esModule", {
5
5
  value: true
6
6
  });
7
- exports.searchRows = void 0;
7
+ exports.searchRowsByExactVal = exports.searchRows = exports.SUPPORT_SEARCH_COLUMN_TYPES = void 0;
8
8
  var _dayjs = _interopRequireDefault(require("dayjs"));
9
- var _context = _interopRequireDefault(require("../context"));
10
9
  var _dtableUtils = require("dtable-utils");
10
+ var _context = _interopRequireDefault(require("../context"));
11
11
  var _columnUtils = require("./column-utils");
12
- const SUPPORT_SEARCH_COLUMN_TYPES = [_dtableUtils.CellType.DATE, _dtableUtils.CellType.TEXT, _dtableUtils.CellType.LONG_TEXT, _dtableUtils.CellType.NUMBER, _dtableUtils.CellType.URL, _dtableUtils.CellType.EMAIL, _dtableUtils.CellType.SINGLE_SELECT, _dtableUtils.CellType.CTIME, _dtableUtils.CellType.MTIME, _dtableUtils.CellType.MULTIPLE_SELECT, _dtableUtils.CellType.LAST_MODIFIER, _dtableUtils.CellType.CREATOR, _dtableUtils.CellType.COLLABORATOR, _dtableUtils.CellType.LINK, _dtableUtils.CellType.FORMULA, _dtableUtils.CellType.LINK_FORMULA, _dtableUtils.CellType.AUTO_NUMBER, _dtableUtils.CellType.GEOLOCATION, _dtableUtils.CellType.DURATION];
12
+ var _cellFormatUtils = require("./cell-format-utils");
13
+ const SUPPORT_SEARCH_COLUMN_TYPES = exports.SUPPORT_SEARCH_COLUMN_TYPES = [_dtableUtils.CellType.DATE, _dtableUtils.CellType.TEXT, _dtableUtils.CellType.LONG_TEXT, _dtableUtils.CellType.NUMBER, _dtableUtils.CellType.URL, _dtableUtils.CellType.EMAIL, _dtableUtils.CellType.SINGLE_SELECT, _dtableUtils.CellType.CTIME, _dtableUtils.CellType.MTIME, _dtableUtils.CellType.MULTIPLE_SELECT, _dtableUtils.CellType.LAST_MODIFIER, _dtableUtils.CellType.CREATOR, _dtableUtils.CellType.COLLABORATOR, _dtableUtils.CellType.LINK, _dtableUtils.CellType.FORMULA, _dtableUtils.CellType.LINK_FORMULA, _dtableUtils.CellType.AUTO_NUMBER, _dtableUtils.CellType.GEOLOCATION, _dtableUtils.CellType.DURATION];
13
14
  const searchRows = (rows, columns, val, processRow) => {
14
15
  let dtableCollaborators = _context.default.getCollaboratorFromCache() || [];
15
16
  let collaborators = _context.default.collaborators || [];
@@ -71,4 +72,35 @@ const searchRows = (rows, columns, val, processRow) => {
71
72
  });
72
73
  return searchResult;
73
74
  };
74
- exports.searchRows = searchRows;
75
+ exports.searchRows = searchRows;
76
+ const searchRowsByExactVal = function (searchValue) {
77
+ let rows = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
78
+ let columns = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : [];
79
+ let {
80
+ formulaRows = {}
81
+ } = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
82
+ // search matched rows from support columns
83
+ const validColumns = columns.filter(column => SUPPORT_SEARCH_COLUMN_TYPES.includes(column.type));
84
+ if (!Array.isArray(rows) || rows.length === 0) return [];
85
+ if (!searchValue) return rows;
86
+ const collaborators = [...(_context.default.getCollaboratorsFromCache() || []), ...(_context.default.collaborators || [])];
87
+ return rows.filter(row => {
88
+ for (const column of validColumns) {
89
+ const {
90
+ key,
91
+ type,
92
+ data
93
+ } = column;
94
+ const formattedCellValue = (0, _cellFormatUtils.getClientCellValueDisplayString)(row, type, key, {
95
+ formulaRows,
96
+ data,
97
+ collaborators
98
+ });
99
+ if (formattedCellValue && formattedCellValue.trim() && formattedCellValue.toLowerCase() === searchValue) {
100
+ return true;
101
+ }
102
+ }
103
+ return false;
104
+ });
105
+ };
106
+ exports.searchRowsByExactVal = searchRowsByExactVal;
@@ -565,27 +565,63 @@ class ChartComponent extends _react.Component {
565
565
  return _intl.default.get(name) || name;
566
566
  }
567
567
  };
568
+ this.getSvgTextWidth = textNode => {
569
+ if (!textNode) return 0;
570
+ if (typeof textNode.getComputedTextLength === 'function') {
571
+ return textNode.getComputedTextLength();
572
+ }
573
+ return textNode.getBoundingClientRect().width;
574
+ };
575
+ this.getRightLegendLayout = _ref => {
576
+ let {
577
+ data,
578
+ legendName,
579
+ theme
580
+ } = _ref;
581
+ const {
582
+ width: chartWidth,
583
+ insertPadding
584
+ } = this.chartBoundingClientRect;
585
+ const legendRectWidth = 20;
586
+ const legendRecTextGap = 8;
587
+ const minChartWidth = 160;
588
+ const chartLegendGap = 30;
589
+ const measureText = text => {
590
+ const textNode = this.chart.append('text').attr('font-size', theme.legendFontSize).text(text).node();
591
+ const textWidth = this.getSvgTextWidth(textNode);
592
+ textNode.remove();
593
+ return textWidth;
594
+ };
595
+ const maxTextWidth = Array.from(new Set(data.map(item => item[legendName]))).reduce((maxWidth, name) => Math.max(maxWidth, measureText(this.formatterLegendName(name))), 0);
596
+ const desiredLegendSpace = legendRectWidth + legendRecTextGap + maxTextWidth;
597
+ const minLegendSpace = legendRectWidth + legendRecTextGap + measureText('...');
598
+ const maxLegendSpace = chartWidth - insertPadding * 2 - minChartWidth - chartLegendGap;
599
+ const rightLegendSpace = Math.min(desiredLegendSpace, Math.max(minLegendSpace, maxLegendSpace));
600
+ return {
601
+ rightLegendSpace,
602
+ chartLegendGap
603
+ };
604
+ };
568
605
  this.truncateLegendText = (textNode, maxWidth) => {
569
- if (!textNode || !Number.isFinite(maxWidth) || maxWidth <= 0) return false;
606
+ if (!textNode || !Number.isFinite(maxWidth)) return false;
570
607
  const fullText = textNode.textContent || '';
571
- const getTextWidth = () => {
572
- if (typeof textNode.getComputedTextLength === 'function') {
573
- return textNode.getComputedTextLength();
574
- }
575
- return textNode.getBoundingClientRect().width;
576
- };
577
- if (!fullText || getTextWidth() <= maxWidth) return false;
608
+ if (!fullText) return false;
609
+ if (maxWidth <= 0) {
610
+ textNode.textContent = '...';
611
+ return true;
612
+ }
613
+ if (this.getSvgTextWidth(textNode) <= maxWidth) return false;
578
614
  const ellipsis = '...';
579
615
  let textLength = fullText.length;
580
616
  while (textLength > 0) {
581
617
  textNode.textContent = `${fullText.slice(0, textLength)}${ellipsis}`;
582
- if (getTextWidth() <= maxWidth) return true;
618
+ if (this.getSvgTextWidth(textNode) <= maxWidth) return true;
583
619
  textLength--;
584
620
  }
585
621
  textNode.textContent = ellipsis;
586
622
  return true;
587
623
  };
588
- this.setLegend = _ref => {
624
+ this.setLegend = _ref2 => {
589
625
  var _chart$config, _chart$config2;
590
626
  let {
591
627
  legendName,
@@ -595,7 +631,7 @@ class ChartComponent extends _react.Component {
595
631
  colorScale,
596
632
  groupColumn,
597
633
  chart
598
- } = _ref;
634
+ } = _ref2;
599
635
  if (!this.chart) return;
600
636
  this.legendConfig = {
601
637
  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,
@@ -732,14 +768,14 @@ class ChartComponent extends _react.Component {
732
768
  });
733
769
  }
734
770
  };
735
- this.renderLegend = _ref2 => {
771
+ this.renderLegend = _ref3 => {
736
772
  let {
737
773
  legendWrapper,
738
774
  groupData,
739
775
  colorScale,
740
776
  theme,
741
777
  text
742
- } = _ref2;
778
+ } = _ref3;
743
779
  const {
744
780
  legendItemPaddingTop,
745
781
  legendItemTextPaddingTop,
@@ -765,15 +801,15 @@ class ChartComponent extends _react.Component {
765
801
  d3.select(item).remove();
766
802
  });
767
803
  }
768
- legendWrapper.selectAll().data(groupData).join('g').attr('data-groupName', _ref3 => {
769
- let [groupName] = _ref3;
770
- return groupName;
771
- }).append('rect').attr('width', legendRectWidth).attr('height', legendRectHeight).attr('y', legendItemPaddingTop).attr('rx', r).attr('fill', _ref4 => {
804
+ legendWrapper.selectAll().data(groupData).join('g').attr('data-groupName', _ref4 => {
772
805
  let [groupName] = _ref4;
806
+ return groupName;
807
+ }).append('rect').attr('width', legendRectWidth).attr('height', legendRectHeight).attr('y', legendItemPaddingTop).attr('rx', r).attr('fill', _ref5 => {
808
+ let [groupName] = _ref5;
773
809
  if (colorScale) return colorScale(groupName);
774
810
  return this.colorMap[groupName] || _constants.CHART_STYLE_COLORS[0];
775
- }).attr('data-text', _ref5 => {
776
- let [groupName] = _ref5;
811
+ }).attr('data-text', _ref6 => {
812
+ let [groupName] = _ref6;
777
813
  return groupName;
778
814
  }).call(g => {
779
815
  const legendItems = Array.from(legendWrapper.node().children).filter(item => item.getAttribute('class') !== 'legend-flip-page');
@@ -783,8 +819,7 @@ class ChartComponent extends _react.Component {
783
819
  top,
784
820
  bottom
785
821
  } = this.getLegendBoundary(legendPosition);
786
- const legendTranslateX = legendPosition === 'center-right' ? start - 50 : start;
787
- const maxLegendTextWidth = legendPosition === 'center-right' ? end - legendTranslateX - legendRectWidth - legendRecTextGap : null;
822
+ const maxLegendTextWidth = legendPosition === 'center-right' ? end - start - legendRectWidth - legendRecTextGap : null;
788
823
 
789
824
  // Add text
790
825
  g.nodes().forEach(rect => {
@@ -807,8 +842,7 @@ class ChartComponent extends _react.Component {
807
842
  const prevTranslateY = Number(prevItem.getAttribute('data-translateY'));
808
843
  translateY = prevTranslateY + height + legendItemMargin;
809
844
  }
810
- const translateX = legendPosition === 'center-right' ? start - 50 : start;
811
- d3.select(item).attr('transform', `translate(${translateX},${translateY})`).attr('data-translateY', translateY);
845
+ d3.select(item).attr('transform', `translate(${start},${translateY})`).attr('data-translateY', translateY);
812
846
  this.bindLegendItemInteraction(item);
813
847
  });
814
848
  } else {
@@ -1153,7 +1187,7 @@ class ChartComponent extends _react.Component {
1153
1187
  annotationWrapper.append('text').attr('x', chartWidth - insertPadding - 30).attr('y', yScale(goal_value) - 10).attr('fill', '#666').text(goal_label);
1154
1188
  });
1155
1189
  };
1156
- this.addLabelToRectTop = _ref6 => {
1190
+ this.addLabelToRectTop = _ref7 => {
1157
1191
  let {
1158
1192
  container,
1159
1193
  x,
@@ -1162,7 +1196,7 @@ class ChartComponent extends _react.Component {
1162
1196
  theme,
1163
1197
  label_font_size,
1164
1198
  text
1165
- } = _ref6;
1199
+ } = _ref7;
1166
1200
  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 => {
1167
1201
  if (!g.node()) return;
1168
1202
  const {
@@ -1171,7 +1205,7 @@ class ChartComponent extends _react.Component {
1171
1205
  g.attr('x', Number(x) + Number(xWidth) / 2 - width / 2);
1172
1206
  });
1173
1207
  };
1174
- this.addLabelToRectRight = _ref7 => {
1208
+ this.addLabelToRectRight = _ref8 => {
1175
1209
  let {
1176
1210
  container,
1177
1211
  x,
@@ -1181,7 +1215,7 @@ class ChartComponent extends _react.Component {
1181
1215
  theme,
1182
1216
  label_font_size,
1183
1217
  text
1184
- } = _ref7;
1218
+ } = _ref8;
1185
1219
  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 => {
1186
1220
  if (g.node()) {
1187
1221
  var _g$node;
@@ -1192,7 +1226,7 @@ class ChartComponent extends _react.Component {
1192
1226
  }
1193
1227
  });
1194
1228
  };
1195
- this.addLabelToRectCenter = _ref8 => {
1229
+ this.addLabelToRectCenter = _ref9 => {
1196
1230
  let {
1197
1231
  chartType,
1198
1232
  container,
@@ -1203,7 +1237,7 @@ class ChartComponent extends _react.Component {
1203
1237
  theme,
1204
1238
  label_font_size,
1205
1239
  text
1206
- } = _ref8;
1240
+ } = _ref9;
1207
1241
  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 => {
1208
1242
  if (!g.node()) return;
1209
1243
  const {
@@ -1245,12 +1279,12 @@ class ChartComponent extends _react.Component {
1245
1279
  });
1246
1280
  }
1247
1281
  };
1248
- this.addClipPath = _ref9 => {
1282
+ this.addClipPath = _ref0 => {
1249
1283
  let {
1250
1284
  rect,
1251
1285
  attr,
1252
1286
  borderRadiusVal
1253
- } = _ref9;
1287
+ } = _ref0;
1254
1288
  return this.addRoundedClip(rect, attr === 'x' ? 'x' : 'y', null, borderRadiusVal);
1255
1289
  };
1256
1290
  this.addRoundedClip = function (rect, orient) {
@@ -1503,13 +1537,13 @@ class ChartComponent extends _react.Component {
1503
1537
  }).filter(Boolean).sort((a, b) => a.top - b.top);
1504
1538
  const keptTicks = [];
1505
1539
  let prevBottom = -Infinity;
1506
- visibleTicks.forEach(_ref0 => {
1540
+ visibleTicks.forEach(_ref1 => {
1507
1541
  let {
1508
1542
  tick,
1509
1543
  index,
1510
1544
  top,
1511
1545
  bottom
1512
- } = _ref0;
1546
+ } = _ref1;
1513
1547
  const shouldKeepFirstTick = index === 0;
1514
1548
  const shouldKeepLastTick = index === ticks.length - 1;
1515
1549
  const hasEnoughSpace = top > prevBottom + this.yAxisTickLabelGap;
@@ -1711,11 +1745,11 @@ class ChartComponent extends _react.Component {
1711
1745
  const annotationWrapper = contentWrapper.insert('g', ':first-child').attr('class', 'vertical-annotation-wrapper');
1712
1746
  annotationWrapper.append('line').attr('x1', x).attr('y1', insertPadding + marginTop).attr('x2', x).attr('y2', chartHeight - insertPadding).attr('stroke', theme.XAxisColor);
1713
1747
  };
1714
- this.setLegendForHeatMap = _ref1 => {
1748
+ this.setLegendForHeatMap = _ref10 => {
1715
1749
  let {
1716
1750
  exampleColors,
1717
1751
  themeColors
1718
- } = _ref1;
1752
+ } = _ref10;
1719
1753
  const legendOffsetY = 3;
1720
1754
  const legendItemTextWidth = 32;
1721
1755
  const legendItemWidth = 12;
@@ -1729,7 +1763,7 @@ class ChartComponent extends _react.Component {
1729
1763
  });
1730
1764
  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'));
1731
1765
  };
1732
- this.setContinuousLegend = _ref10 => {
1766
+ this.setContinuousLegend = _ref11 => {
1733
1767
  var _this$chart$node2;
1734
1768
  let {
1735
1769
  previewType,
@@ -1740,7 +1774,7 @@ class ChartComponent extends _react.Component {
1740
1774
  legendTextRange,
1741
1775
  bubbleColor,
1742
1776
  type
1743
- } = _ref10;
1777
+ } = _ref11;
1744
1778
  const {
1745
1779
  width: chartWidth,
1746
1780
  height: chartHeight,