@antv/gpt-vis 1.0.0 → 1.0.2

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.
Files changed (98) hide show
  1. package/README.md +153 -34
  2. package/README.zh-CN.md +153 -34
  3. package/dist/cjs/types/index.d.ts +2 -1
  4. package/dist/cjs/util/animation.d.ts +2 -0
  5. package/dist/cjs/util/animation.js +38 -0
  6. package/dist/cjs/util/components.d.ts +15 -0
  7. package/dist/cjs/util/components.js +94 -0
  8. package/dist/cjs/util/crosshair-axis-labels.d.ts +15 -0
  9. package/dist/cjs/util/crosshair-axis-labels.js +401 -0
  10. package/dist/cjs/util/html.d.ts +1 -0
  11. package/dist/cjs/util/html.js +29 -0
  12. package/dist/cjs/util/index.d.ts +6 -0
  13. package/dist/cjs/util/index.js +33 -0
  14. package/dist/cjs/util/interaction.d.ts +14 -0
  15. package/dist/cjs/util/interaction.js +89 -0
  16. package/dist/cjs/util/theme.d.ts +18 -24
  17. package/dist/cjs/util/theme.js +303 -120
  18. package/dist/cjs/util/tokens.d.ts +31 -0
  19. package/dist/cjs/util/tokens.js +98 -0
  20. package/dist/cjs/vis/area/index.d.ts +2 -2
  21. package/dist/cjs/vis/area/index.js +76 -31
  22. package/dist/cjs/vis/bar/index.d.ts +2 -2
  23. package/dist/cjs/vis/bar/index.js +22 -19
  24. package/dist/cjs/vis/boxplot/index.js +1 -4
  25. package/dist/cjs/vis/column/index.d.ts +2 -2
  26. package/dist/cjs/vis/column/index.js +28 -18
  27. package/dist/cjs/vis/dual-axes/index.d.ts +2 -2
  28. package/dist/cjs/vis/dual-axes/index.js +107 -34
  29. package/dist/cjs/vis/funnel/index.d.ts +3 -2
  30. package/dist/cjs/vis/funnel/index.js +171 -94
  31. package/dist/cjs/vis/histogram/index.js +1 -4
  32. package/dist/cjs/vis/line/index.d.ts +2 -2
  33. package/dist/cjs/vis/line/index.js +71 -31
  34. package/dist/cjs/vis/liquid/index.d.ts +2 -2
  35. package/dist/cjs/vis/liquid/index.js +41 -16
  36. package/dist/cjs/vis/pie/index.d.ts +2 -2
  37. package/dist/cjs/vis/pie/index.js +26 -16
  38. package/dist/cjs/vis/radar/index.d.ts +2 -2
  39. package/dist/cjs/vis/radar/index.js +21 -29
  40. package/dist/cjs/vis/sankey/index.js +1 -4
  41. package/dist/cjs/vis/scatter/index.d.ts +2 -2
  42. package/dist/cjs/vis/scatter/index.js +40 -17
  43. package/dist/cjs/vis/table/index.js +13 -5
  44. package/dist/cjs/vis/treemap/index.js +1 -4
  45. package/dist/cjs/vis/venn/index.js +1 -4
  46. package/dist/cjs/vis/violin/index.js +1 -1
  47. package/dist/cjs/vis/waterfall/index.js +1 -1
  48. package/dist/cjs/vis/word-cloud/index.d.ts +3 -2
  49. package/dist/cjs/vis/word-cloud/index.js +125 -10
  50. package/dist/esm/types/index.d.ts +2 -1
  51. package/dist/esm/util/animation.d.ts +2 -0
  52. package/dist/esm/util/animation.js +17 -0
  53. package/dist/esm/util/components.d.ts +15 -0
  54. package/dist/esm/util/components.js +67 -0
  55. package/dist/esm/util/crosshair-axis-labels.d.ts +15 -0
  56. package/dist/esm/util/crosshair-axis-labels.js +431 -0
  57. package/dist/esm/util/html.d.ts +1 -0
  58. package/dist/esm/util/html.js +3 -0
  59. package/dist/esm/util/index.d.ts +6 -0
  60. package/dist/esm/util/index.js +6 -0
  61. package/dist/esm/util/interaction.d.ts +14 -0
  62. package/dist/esm/util/interaction.js +73 -0
  63. package/dist/esm/util/theme.d.ts +18 -24
  64. package/dist/esm/util/theme.js +302 -126
  65. package/dist/esm/util/tokens.d.ts +31 -0
  66. package/dist/esm/util/tokens.js +64 -0
  67. package/dist/esm/vis/area/index.d.ts +2 -2
  68. package/dist/esm/vis/area/index.js +91 -41
  69. package/dist/esm/vis/bar/index.d.ts +2 -2
  70. package/dist/esm/vis/bar/index.js +28 -29
  71. package/dist/esm/vis/boxplot/index.js +4 -5
  72. package/dist/esm/vis/column/index.d.ts +2 -2
  73. package/dist/esm/vis/column/index.js +36 -29
  74. package/dist/esm/vis/dual-axes/index.d.ts +2 -2
  75. package/dist/esm/vis/dual-axes/index.js +145 -42
  76. package/dist/esm/vis/funnel/index.d.ts +3 -2
  77. package/dist/esm/vis/funnel/index.js +159 -85
  78. package/dist/esm/vis/histogram/index.js +4 -5
  79. package/dist/esm/vis/line/index.d.ts +2 -2
  80. package/dist/esm/vis/line/index.js +80 -37
  81. package/dist/esm/vis/liquid/index.d.ts +2 -2
  82. package/dist/esm/vis/liquid/index.js +41 -14
  83. package/dist/esm/vis/pie/index.d.ts +2 -2
  84. package/dist/esm/vis/pie/index.js +36 -16
  85. package/dist/esm/vis/radar/index.d.ts +2 -2
  86. package/dist/esm/vis/radar/index.js +21 -34
  87. package/dist/esm/vis/sankey/index.js +4 -5
  88. package/dist/esm/vis/scatter/index.d.ts +2 -2
  89. package/dist/esm/vis/scatter/index.js +41 -25
  90. package/dist/esm/vis/table/index.js +9 -9
  91. package/dist/esm/vis/treemap/index.js +4 -5
  92. package/dist/esm/vis/venn/index.js +4 -5
  93. package/dist/esm/vis/violin/index.js +5 -13
  94. package/dist/esm/vis/waterfall/index.js +5 -7
  95. package/dist/esm/vis/word-cloud/index.d.ts +3 -2
  96. package/dist/esm/vis/word-cloud/index.js +158 -10
  97. package/dist/umd/index.min.js +1 -1
  98. package/package.json +18 -15
@@ -23,18 +23,19 @@ __export(pie_exports, {
23
23
  });
24
24
  module.exports = __toCommonJS(pie_exports);
25
25
  var import_g2 = require("@antv/g2");
26
- var import_theme = require("../../util/theme");
26
+ var import_util = require("../../util");
27
27
  var Pie = (options) => {
28
28
  const { container, width, height, theme: chartTheme = "default" } = options;
29
29
  let chart = null;
30
+ let hasRendered = false;
30
31
  const PERCENTAGE_PRECISION_MULTIPLIER = 1e4;
31
32
  const render = (config) => {
32
33
  const { data = [], innerRadius = 0, theme = chartTheme, title, style = {} } = config;
33
34
  if (chart) {
34
35
  chart.destroy();
35
36
  }
36
- const colors = (0, import_theme.normalizePalette)(style.palette, theme);
37
- const backgroundColor = style.backgroundColor || (0, import_theme.getBackgroundColor)(theme);
37
+ const colors = (0, import_util.normalizePalette)(style.palette, theme);
38
+ const tokens = (0, import_util.getChartVisualTokens)(theme);
38
39
  const sumValue = data.reduce((sum, item) => sum + item.value, 0);
39
40
  chart = new import_g2.Chart({
40
41
  container,
@@ -43,10 +44,10 @@ var Pie = (options) => {
43
44
  autoFit: true
44
45
  });
45
46
  const chartOptions = {
46
- animate: false,
47
+ animate: (0, import_util.getChartAnimation)(hasRendered, "waveIn"),
47
48
  type: "interval",
48
49
  data,
49
- title: title ?? "",
50
+ title: title || "",
50
51
  encode: {
51
52
  y: "value",
52
53
  color: "category"
@@ -56,14 +57,13 @@ var Pie = (options) => {
56
57
  scale: {
57
58
  color: { range: colors }
58
59
  },
59
- legend: {
60
- color: { position: "top" }
61
- },
62
- labels: [
60
+ legend: (0, import_util.getColorLegend)(true),
61
+ labels: data.length > 8 ? [] : [
63
62
  {
64
63
  text: (d) => {
65
- const percentage = Math.round(d.value / sumValue * 100 * PERCENTAGE_PRECISION_MULTIPLIER) / PERCENTAGE_PRECISION_MULTIPLIER;
66
- return `${d.category}: ${percentage}%`;
64
+ const percentage = sumValue ? Math.round(d.value / sumValue * 100 * PERCENTAGE_PRECISION_MULTIPLIER) / PERCENTAGE_PRECISION_MULTIPLIER : 0;
65
+ const formattedPercentage = Number(percentage.toFixed(1)).toString();
66
+ return `${d.category}: ${formattedPercentage}%`;
67
67
  },
68
68
  position: "outside",
69
69
  transform: [{ type: "overlapHide" }]
@@ -78,24 +78,34 @@ var Pie = (options) => {
78
78
  ]
79
79
  },
80
80
  interaction: {
81
+ tooltip: true,
82
+ elementHighlight: true,
83
+ elementHoverScale: { shadow: false },
81
84
  elementSelect: { single: true }
82
85
  },
83
- style: {
84
- fillOpacity: 0.8
86
+ state: {
87
+ active: { fillOpacity: 1, lineWidth: 3 },
88
+ inactive: { fillOpacity: 0.3 },
89
+ selected: { fillOpacity: 1, lineWidth: 3 }
85
90
  },
86
- viewStyle: {
87
- viewFill: backgroundColor
91
+ style: {
92
+ fillOpacity: 1,
93
+ stroke: tokens.separator,
94
+ lineWidth: 2
88
95
  },
89
- theme: (0, import_theme.getThemeObject)(theme)
96
+ viewStyle: style.backgroundColor ? { viewFill: style.backgroundColor } : void 0,
97
+ theme: (0, import_util.getThemeObject)(theme)
90
98
  };
91
99
  chart.options(chartOptions);
92
100
  chart.render();
101
+ hasRendered = true;
93
102
  };
94
103
  const destroy = () => {
95
104
  if (chart) {
96
105
  chart.destroy();
97
106
  chart = null;
98
107
  }
108
+ hasRendered = false;
99
109
  };
100
110
  return {
101
111
  render,
@@ -1,4 +1,4 @@
1
- import type { VisualizationOptions } from '../../types';
1
+ import type { VisualizationOptions, VisualizationTheme } from '../../types';
2
2
  /**
3
3
  * RadarDataItem is the type for each data item in the radar chart.
4
4
  */
@@ -15,7 +15,7 @@ export interface RadarConfig {
15
15
  data: RadarDataItem[];
16
16
  title?: string;
17
17
  align?: boolean;
18
- theme?: 'default' | 'academy' | 'dark';
18
+ theme?: VisualizationTheme;
19
19
  style?: {
20
20
  backgroundColor?: string;
21
21
  palette?: string[];
@@ -23,7 +23,7 @@ __export(radar_exports, {
23
23
  });
24
24
  module.exports = __toCommonJS(radar_exports);
25
25
  var import_g2 = require("@antv/g2");
26
- var import_theme = require("../../util/theme");
26
+ var import_util = require("../../util");
27
27
  function transformRadarToParallel(data) {
28
28
  if (!data || data.length === 0) {
29
29
  return [];
@@ -55,11 +55,12 @@ var Radar = (options) => {
55
55
  if (chart) {
56
56
  chart.destroy();
57
57
  }
58
- const { lineWidth = 2 } = style;
59
- const colors = (0, import_theme.normalizePalette)(style.palette, theme);
60
- const backgroundColor = style.backgroundColor || (0, import_theme.getBackgroundColor)(theme);
58
+ const { lineWidth = import_util.CHART_STYLE_DEFAULTS.lineWidth } = style;
59
+ const colors = (0, import_util.normalizePalette)(style.palette, theme);
61
60
  const parallelData = transformRadarToParallel(data);
62
61
  const position = Object.keys(parallelData[0] || {}).filter((key) => key !== "group");
62
+ const hasMultipleSeries = parallelData.length > 1;
63
+ const legend = (0, import_util.getColorLegend)(hasMultipleSeries);
63
64
  chart = new import_g2.Chart({
64
65
  container,
65
66
  width,
@@ -70,9 +71,9 @@ var Radar = (options) => {
70
71
  animate: false,
71
72
  type: "line",
72
73
  data: parallelData,
73
- title: title ?? "",
74
+ title: title || "",
74
75
  coordinate: { type: "radar" },
75
- inset: 18,
76
+ inset: 24,
76
77
  encode: {
77
78
  position,
78
79
  color: "group"
@@ -96,42 +97,33 @@ var Radar = (options) => {
96
97
  Array.from({ length: position.length }, (_, i) => [
97
98
  `position${i === 0 ? "" : i}`,
98
99
  {
99
- zIndex: 1,
100
- titleFontSize: 10,
101
- titleSpacing: 8,
102
- label: true,
103
- labelFill: theme === "dark" ? "#fff" : "#000",
104
- labelOpacity: 0.45,
105
- labelFontSize: 10,
106
- line: true,
107
- lineFill: "#000",
108
- lineStrokeOpacity: 0.25,
100
+ label: align ? i === 0 : true,
109
101
  tickFilter: (_2, idx) => {
110
102
  return !(i !== 0 && idx === 0);
111
103
  },
112
- tickCount: 4,
113
- gridStrokeOpacity: 0.45,
114
- gridStroke: theme === "dark" ? "#fff" : "#000",
115
- gridLineWidth: 1,
116
- gridLineDash: [4, 4]
104
+ grid: i === 0
117
105
  }
118
106
  ])
119
107
  ),
120
108
  style: {
121
109
  lineWidth,
122
110
  lineCap: "round",
123
- lineJoin: "round"
111
+ lineJoin: "round",
112
+ strokeOpacity: import_util.CHART_STYLE_DEFAULTS.lineOpacity
124
113
  },
125
- legend: parallelData.length > 1 ? { color: { position: "top", itemMarker: "point" } } : false,
126
- interaction: {
127
- tooltip: {
128
- series: false
114
+ state: hasMultipleSeries ? (0, import_util.getLineHighlightState)(lineWidth) : void 0,
115
+ legend: legend === false ? false : {
116
+ color: {
117
+ ...legend.color,
118
+ itemMarker: "smooth"
129
119
  }
130
120
  },
131
- viewStyle: {
132
- viewFill: backgroundColor
121
+ interaction: {
122
+ tooltip: true,
123
+ ...hasMultipleSeries ? (0, import_util.getSeriesHighlightByColorInteraction)() : {}
133
124
  },
134
- theme: (0, import_theme.getThemeObject)(theme)
125
+ viewStyle: style.backgroundColor ? { viewFill: style.backgroundColor } : void 0,
126
+ theme: (0, import_util.getThemeObject)(theme)
135
127
  };
136
128
  chart.options(chartOptions);
137
129
  chart.render();
@@ -33,7 +33,6 @@ var Sankey = (options) => {
33
33
  chart.destroy();
34
34
  }
35
35
  const colors = (0, import_theme.normalizePalette)(style.palette, theme);
36
- const backgroundColor = style.backgroundColor || (0, import_theme.getBackgroundColor)(theme);
37
36
  chart = new import_g2.Chart({
38
37
  container,
39
38
  width,
@@ -67,9 +66,7 @@ var Sankey = (options) => {
67
66
  nodeLineWidth: 1,
68
67
  linkFillOpacity: 0.3
69
68
  },
70
- viewStyle: {
71
- viewFill: backgroundColor
72
- },
69
+ viewStyle: style.backgroundColor ? { viewFill: style.backgroundColor } : void 0,
73
70
  theme: (0, import_theme.getThemeObject)(theme),
74
71
  legend: false,
75
72
  tooltip: false
@@ -1,4 +1,4 @@
1
- import type { VisualizationOptions } from '../../types';
1
+ import type { VisualizationOptions, VisualizationTheme } from '../../types';
2
2
  /**
3
3
  * ScatterDataItem is the type for each data item in the scatter chart.
4
4
  */
@@ -16,7 +16,7 @@ export interface ScatterConfig {
16
16
  title?: string;
17
17
  axisXTitle?: string;
18
18
  axisYTitle?: string;
19
- theme?: 'default' | 'academy' | 'dark';
19
+ theme?: VisualizationTheme;
20
20
  style?: {
21
21
  backgroundColor?: string;
22
22
  palette?: string[];
@@ -23,18 +23,19 @@ __export(scatter_exports, {
23
23
  });
24
24
  module.exports = __toCommonJS(scatter_exports);
25
25
  var import_g2 = require("@antv/g2");
26
- var import_theme = require("../../util/theme");
26
+ var import_util = require("../../util");
27
27
  var Scatter = (options) => {
28
28
  const { container, width, height, theme: chartTheme = "default" } = options;
29
29
  let chart = null;
30
+ let hasRendered = false;
30
31
  const render = (config) => {
31
32
  var _a;
32
33
  const { data = [], theme = chartTheme, title, axisXTitle, axisYTitle, style = {} } = config;
33
34
  if (chart) {
34
35
  chart.destroy();
35
36
  }
36
- const colors = (0, import_theme.normalizePalette)(style.palette, theme);
37
- const backgroundColor = style.backgroundColor || (0, import_theme.getBackgroundColor)(theme);
37
+ const colors = (0, import_util.normalizePalette)(style.palette, theme);
38
+ const backgroundColor = style.backgroundColor || (0, import_util.getBackgroundColor)(theme);
38
39
  const hasGroupField = data.length > 0 && ((_a = data[0]) == null ? void 0 : _a.group) !== void 0;
39
40
  chart = new import_g2.Chart({
40
41
  container,
@@ -44,29 +45,47 @@ var Scatter = (options) => {
44
45
  });
45
46
  let encode = {};
46
47
  const scaleConfig = {
47
- y: { nice: true }
48
+ y: { nice: true },
49
+ x: { nice: true }
48
50
  };
49
51
  if (hasGroupField) {
50
- encode = { x: "x", y: "y", color: "group" };
52
+ encode = {
53
+ x: "x",
54
+ y: "y",
55
+ color: "group",
56
+ shape: "point",
57
+ size: import_util.CHART_STYLE_DEFAULTS.scatterPointSize
58
+ };
51
59
  scaleConfig.color = { range: colors };
52
60
  } else {
53
- encode = { x: "x", y: "y", color: () => "all" };
61
+ encode = {
62
+ x: "x",
63
+ y: "y",
64
+ shape: "point",
65
+ size: import_util.CHART_STYLE_DEFAULTS.scatterPointSize
66
+ };
54
67
  }
55
68
  const chartOptions = {
56
- animate: false,
69
+ animate: (0, import_util.getChartAnimation)(hasRendered, "fadeIn"),
57
70
  type: "point",
58
71
  data,
59
- title: title ?? "",
72
+ title: title || "",
60
73
  encode,
61
- legend: hasGroupField ? { color: { position: "top" } } : false,
74
+ legend: (0, import_util.getColorLegend)(hasGroupField),
62
75
  scale: scaleConfig,
63
- axis: {
64
- x: { title: axisXTitle ?? "x" },
65
- y: { title: axisYTitle ?? "y" }
66
- },
76
+ axis: (0, import_util.getCartesianAxis)({
77
+ axisXTitle,
78
+ axisYTitle
79
+ }),
67
80
  style: {
68
- lineWidth: 1
81
+ lineWidth: import_util.CHART_STYLE_DEFAULTS.pointLineWidth,
82
+ fillOpacity: 0.88,
83
+ stroke: backgroundColor,
84
+ ...!hasGroupField ? { fill: colors[0] } : {}
69
85
  },
86
+ // A same-color stroke enlarges the rendered path without changing its transform or
87
+ // hit area, so repeated pointer events cannot accumulate scale.
88
+ state: (0, import_util.getPointHighlightState)(),
70
89
  tooltip: {
71
90
  title: (d) => (d == null ? void 0 : d.group) ? d.group : false,
72
91
  items: [
@@ -74,19 +93,23 @@ var Scatter = (options) => {
74
93
  { channel: "y", name: axisYTitle ?? "y" }
75
94
  ]
76
95
  },
77
- viewStyle: {
78
- viewFill: backgroundColor
96
+ interaction: {
97
+ tooltip: true,
98
+ elementHighlight: true
79
99
  },
80
- theme: (0, import_theme.getThemeObject)(theme)
100
+ viewStyle: style.backgroundColor ? { viewFill: backgroundColor } : void 0,
101
+ theme: (0, import_util.getThemeObject)(theme)
81
102
  };
82
103
  chart.options(chartOptions);
83
104
  chart.render();
105
+ hasRendered = true;
84
106
  };
85
107
  const destroy = () => {
86
108
  if (chart) {
87
109
  chart.destroy();
88
110
  chart = null;
89
111
  }
112
+ hasRendered = false;
90
113
  };
91
114
  return {
92
115
  render,
@@ -24,6 +24,7 @@ __export(table_exports, {
24
24
  });
25
25
  module.exports = __toCommonJS(table_exports);
26
26
  var import_measury = require("measury");
27
+ var import_html = require("../../util/html");
27
28
  var SCOPE_ID = "__gpt-vis-table__";
28
29
  var FONT_FAMILY = '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif';
29
30
  var CELL_PADDING = 16;
@@ -43,6 +44,12 @@ var TABLE_STYLES = `
43
44
  color: #1d2129;
44
45
  }
45
46
 
47
+ .${SCOPE_ID} .table-empty {
48
+ padding: 20px;
49
+ text-align: center;
50
+ color: #999;
51
+ }
52
+
46
53
  .${SCOPE_ID} table {
47
54
  border-collapse: separate;
48
55
  border-spacing: 0;
@@ -167,10 +174,11 @@ var Table = (options) => {
167
174
  if (theme === "dark") {
168
175
  tableWrapper.setAttribute("data-theme", "dark");
169
176
  }
177
+ const titleHTML = title ? `<div class="table-title">${(0, import_html.escapeHtml)(title)}</div>` : "";
170
178
  if (data.length === 0) {
171
179
  tableWrapper.innerHTML = `
172
- ${title ? `<div class="table-title">${title}</div>` : ""}
173
- <div style="padding: 20px; text-align: center; color: #999;">No data available</div>
180
+ ${titleHTML}
181
+ <div class="table-empty">No data available</div>
174
182
  `;
175
183
  container.appendChild(tableWrapper);
176
184
  return;
@@ -178,12 +186,12 @@ var Table = (options) => {
178
186
  const columns = Object.keys(data[0]);
179
187
  let minWidth = calculateTableMinWidth(data, columns);
180
188
  minWidth = Math.max(minWidth, columns.length * 100);
181
- const headerHTML = columns.map((col) => `<th>${col}</th>`).join("");
189
+ const headerHTML = columns.map((column) => `<th>${(0, import_html.escapeHtml)(column)}</th>`).join("");
182
190
  const bodyHTML = data.map(
183
- (row) => `<tr>${columns.map((col) => `<td>${row[col] != null ? row[col] : ""}</td>`).join("")}</tr>`
191
+ (row) => `<tr>${columns.map((column) => `<td>${(0, import_html.escapeHtml)(row[column])}</td>`).join("")}</tr>`
184
192
  ).join("");
185
193
  tableWrapper.innerHTML = `
186
- ${title ? `<div class="table-title">${title}</div>` : ""}
194
+ ${titleHTML}
187
195
  <table style="min-width: ${minWidth}px;">
188
196
  <thead><tr>${headerHTML}</tr></thead>
189
197
  <tbody>${bodyHTML}</tbody>
@@ -33,7 +33,6 @@ var Treemap = (options) => {
33
33
  chart.destroy();
34
34
  }
35
35
  const colors = (0, import_theme.normalizePalette)(style.palette, theme);
36
- const backgroundColor = style.backgroundColor || (0, import_theme.getBackgroundColor)(theme);
37
36
  chart = new import_g2.Chart({
38
37
  container,
39
38
  width,
@@ -74,9 +73,7 @@ var Treemap = (options) => {
74
73
  }
75
74
  ]
76
75
  },
77
- viewStyle: {
78
- viewFill: backgroundColor
79
- },
76
+ viewStyle: style.backgroundColor ? { viewFill: style.backgroundColor } : void 0,
80
77
  theme: (0, import_theme.getThemeObject)(theme),
81
78
  scale: {
82
79
  ...colors.length > 0 ? {
@@ -43,7 +43,6 @@ var Venn = (options) => {
43
43
  chart.destroy();
44
44
  }
45
45
  const colors = (0, import_theme.normalizePalette)(style.palette, theme);
46
- const backgroundColor = style.backgroundColor || (0, import_theme.getBackgroundColor)(theme);
47
46
  const normalizedData = data.map((d) => ({
48
47
  ...d,
49
48
  sets: normalizeVennSets(d.sets)
@@ -87,9 +86,7 @@ var Venn = (options) => {
87
86
  fontSize: 10
88
87
  }
89
88
  ],
90
- viewStyle: {
91
- viewFill: backgroundColor
92
- },
89
+ viewStyle: style.backgroundColor ? { viewFill: style.backgroundColor } : void 0,
93
90
  theme: (0, import_theme.getThemeObject)(theme),
94
91
  legend: false,
95
92
  axis: false,
@@ -133,7 +133,7 @@ var Violin = (options) => {
133
133
  legend: {
134
134
  color: hasGroupField ? { position: "top" } : false
135
135
  },
136
- ...backgroundColor ? { viewStyle: { viewFill: backgroundColor } } : {},
136
+ viewStyle: style.backgroundColor ? { viewFill: backgroundColor } : void 0,
137
137
  theme: (0, import_theme.getThemeObject)(theme)
138
138
  };
139
139
  chart.options(chartOptions);
@@ -172,7 +172,7 @@ var Waterfall = (options) => {
172
172
  }
173
173
  ],
174
174
  legend: false,
175
- ...backgroundColor ? { viewStyle: { viewFill: backgroundColor } } : {},
175
+ viewStyle: style.backgroundColor ? { viewFill: backgroundColor } : void 0,
176
176
  theme: (0, import_theme.getThemeObject)(theme)
177
177
  };
178
178
  chart.options(chartOptions);
@@ -1,4 +1,4 @@
1
- import type { VisualizationOptions } from '../../types';
1
+ import type { VisualizationOptions, VisualizationTheme } from '../../types';
2
2
  /**
3
3
  * WordCloudDataItem is the type for each data item in the word cloud chart.
4
4
  */
@@ -12,8 +12,9 @@ export type WordCloudDataItem = {
12
12
  export interface WordCloudConfig {
13
13
  type?: 'word-cloud';
14
14
  data: WordCloudDataItem[];
15
- theme?: 'default' | 'academy' | 'dark';
15
+ theme?: VisualizationTheme;
16
16
  title?: string;
17
+ locale?: string;
17
18
  style?: {
18
19
  backgroundColor?: string;
19
20
  palette?: string[];
@@ -23,17 +23,99 @@ __export(word_cloud_exports, {
23
23
  });
24
24
  module.exports = __toCommonJS(word_cloud_exports);
25
25
  var import_g2 = require("@antv/g2");
26
+ var import_components = require("../../util/components");
26
27
  var import_theme = require("../../util/theme");
28
+ var WORD_CLOUD_MAX_WORDS = 50;
29
+ var WORD_CLOUD_FONT_FAMILY = "Impact";
30
+ var WORD_CLOUD_ROTATIONS = [-90, -60, -30, 0, 30, 60];
31
+ var WORD_CLOUD_LABELS = {
32
+ "en-US": {
33
+ rank: "Rank",
34
+ share: "Share of total weight",
35
+ weight: "Weight / frequency"
36
+ },
37
+ "zh-CN": {
38
+ rank: "排名",
39
+ share: "占总权重",
40
+ weight: "权重 / 词频"
41
+ }
42
+ };
43
+ var hashWordCloudData = (data) => {
44
+ let hash = 2166136261;
45
+ data.forEach(({ text, value }) => {
46
+ const input = `${text}\0${value}`;
47
+ for (let index = 0; index < input.length; index += 1) {
48
+ hash ^= input.charCodeAt(index);
49
+ hash = Math.imul(hash, 16777619);
50
+ }
51
+ });
52
+ return hash >>> 0;
53
+ };
54
+ var createSeededRandom = (seed) => {
55
+ let state = seed || 1;
56
+ return () => {
57
+ state += 1831565813;
58
+ let value = state;
59
+ value = Math.imul(value ^ value >>> 15, value | 1);
60
+ value ^= value + Math.imul(value ^ value >>> 7, value | 61);
61
+ return ((value ^ value >>> 14) >>> 0) / 4294967296;
62
+ };
63
+ };
64
+ var getWordCloudPalette = (palette, theme) => (0, import_theme.normalizePalette)(palette, theme);
65
+ var prepareWordCloudData = (data, colors) => {
66
+ const rankedData = data.map((item, index) => ({ item, index })).filter(
67
+ ({ item }) => item.text.trim().length > 0 && Number.isFinite(item.value) && item.value > 0
68
+ ).sort((a, b) => b.item.value - a.item.value || a.index - b.index);
69
+ const totalWeight = rankedData.reduce((sum, { item }) => sum + item.value, 0);
70
+ const visibleData = rankedData.slice(0, WORD_CLOUD_MAX_WORDS);
71
+ const lastVisibleIndex = Math.max(1, visibleData.length - 1);
72
+ const colorByText = /* @__PURE__ */ new Map();
73
+ let nextColorIndex = 0;
74
+ return visibleData.map(({ item }, index) => {
75
+ const percentile = index / lastVisibleIndex;
76
+ const fontWeight = percentile <= 0.1 ? 700 : percentile <= 0.32 ? 600 : percentile <= 0.68 ? 500 : 400;
77
+ let wordColor = colorByText.get(item.text);
78
+ if (!wordColor) {
79
+ wordColor = colors[nextColorIndex % colors.length];
80
+ colorByText.set(item.text, wordColor);
81
+ nextColorIndex += 1;
82
+ }
83
+ return {
84
+ ...item,
85
+ rank: index + 1,
86
+ share: totalWeight > 0 ? item.value / totalWeight : 0,
87
+ fontWeight,
88
+ wordColor
89
+ };
90
+ });
91
+ };
27
92
  var WordCloud = (options) => {
28
- const { container, width, height, theme: chartTheme = "default" } = options;
93
+ const { container, width, height, locale, theme: chartTheme = "default" } = options;
29
94
  let chart = null;
30
95
  const render = (config) => {
31
- const { data = [], theme = chartTheme, title, style = {} } = config;
96
+ const {
97
+ data = [],
98
+ theme = chartTheme,
99
+ title,
100
+ locale: renderLocale = locale,
101
+ style = {}
102
+ } = config;
103
+ const chartLocale = (0, import_components.resolveChartLocale)(renderLocale);
104
+ const labels = WORD_CLOUD_LABELS[chartLocale];
105
+ const valueFormatter = new Intl.NumberFormat(chartLocale, {
106
+ maximumFractionDigits: 2
107
+ });
108
+ const percentageFormatter = new Intl.NumberFormat(chartLocale, {
109
+ style: "percent",
110
+ maximumFractionDigits: 2
111
+ });
32
112
  if (chart) {
33
113
  chart.destroy();
34
114
  }
35
- const colors = (0, import_theme.normalizePalette)(style.palette, theme);
36
- const backgroundColor = style.backgroundColor || (0, import_theme.getBackgroundColor)(theme);
115
+ const colors = getWordCloudPalette(style.palette, theme);
116
+ const preparedData = prepareWordCloudData(data, colors);
117
+ const layoutSeed = hashWordCloudData(preparedData);
118
+ const rotationRandom = createSeededRandom(layoutSeed ^ 2654435769);
37
119
  chart = new import_g2.Chart({
38
120
  container,
39
121
  width,
@@ -43,31 +125,64 @@ var WordCloud = (options) => {
43
125
  const chartOptions = {
44
126
  animate: false,
45
127
  type: "wordCloud",
46
- data,
128
+ data: preparedData,
47
129
  title: title ?? "",
48
130
  layout: {
49
- fontSize: [8, 42]
131
+ font: WORD_CLOUD_FONT_FAMILY,
132
+ fontSize: [11, 44],
133
+ fontWeight: (d) => d.fontWeight,
134
+ padding: 2,
135
+ random: createSeededRandom(layoutSeed),
136
+ rotate: () => WORD_CLOUD_ROTATIONS[Math.floor(rotationRandom() * WORD_CLOUD_ROTATIONS.length)]
50
137
  },
51
138
  encode: {
52
139
  text: "text",
53
140
  color: "text",
54
141
  value: "value"
55
142
  },
143
+ style: {
144
+ fill: (d) => d.wordColor,
145
+ fontFamily: WORD_CLOUD_FONT_FAMILY,
146
+ fontWeight: (d) => d.weight ?? d.fontWeight,
147
+ stroke: (d) => d.wordColor
148
+ },
56
149
  scale: {
57
150
  color: { range: colors }
58
151
  },
59
152
  legend: false,
153
+ state: {
154
+ active: {
155
+ fillOpacity: 1,
156
+ strokeOpacity: 1
157
+ },
158
+ inactive: {
159
+ fillOpacity: 0.3,
160
+ strokeOpacity: 0.3
161
+ }
162
+ },
60
163
  tooltip: {
164
+ title: "text",
61
165
  items: [
62
166
  (d) => ({
63
- name: d.text,
64
- value: d.value
167
+ name: labels.weight,
168
+ value: valueFormatter.format(d.value)
169
+ }),
170
+ (d) => ({
171
+ name: labels.rank,
172
+ value: `#${d.rank}`
173
+ }),
174
+ (d) => ({
175
+ name: labels.share,
176
+ value: percentageFormatter.format(d.share)
65
177
  })
66
178
  ]
67
179
  },
68
- viewStyle: {
69
- viewFill: backgroundColor
180
+ interaction: {
181
+ tooltip: true,
182
+ elementHighlight: true,
183
+ elementHoverScale: true
70
184
  },
185
+ viewStyle: style.backgroundColor ? { viewFill: style.backgroundColor } : void 0,
71
186
  theme: (0, import_theme.getThemeObject)(theme)
72
187
  };
73
188
  chart.options(chartOptions);
@@ -2,11 +2,12 @@
2
2
  * Common visualization options for all chart components.
3
3
  * Defines the container and dimensions for rendering visualizations.
4
4
  */
5
+ export type VisualizationTheme = 'default' | 'light' | 'dark' | 'academy';
5
6
  export interface VisualizationOptions {
6
7
  container: string | HTMLElement;
7
8
  width?: number;
8
9
  height?: number;
9
- theme?: 'default' | 'light' | 'dark' | 'academy';
10
+ theme?: VisualizationTheme;
10
11
  wrapper?: boolean;
11
12
  locale?: string;
12
13
  }
@@ -0,0 +1,2 @@
1
+ export type ChartEnterAnimation = 'fadeIn' | 'pathIn' | 'growInX' | 'growInY' | 'waveIn';
2
+ export declare const getChartAnimation: (hasRendered: boolean, enterType?: ChartEnterAnimation) => false | Record<string, unknown>;