@antv/gpt-vis 1.0.0-beta.2 → 1.0.0

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.
package/README.zh-CN.md CHANGED
@@ -1,42 +1,42 @@
1
1
  <img src="https://gw.alipayobjects.com/zos/antfincdn/R8sN%24GNdh6/language.svg" width="18"> [English](./README.md) | 简体中文
2
2
 
3
- <h1 align="center">GPT-Vis,为 AI 而生的可视化方案</h1>
3
+ <div align="center">
4
+ <img src="https://github.com/eosphoros-ai/GPT-Vis/assets/17919400/c8804ffb-d3d6-45d3-846f-cf217681ab05" height="70" />
5
+ </div>
6
+
7
+ <h1 align="center">GPT-Vis</h1>
4
8
 
5
9
  <div align="center">
6
- <img src="https://github.com/eosphoros-ai/GPT-Vis/assets/17919400/c8804ffb-d3d6-45d3-846f-cf217681ab05" height="70">
7
10
 
8
- 面向 LLM 时代的 AI 原生可视化组件,为 AI 驱动应用设计的框架无关可视化库。
11
+ 面向 LLM 时代的 AI 原生可视化库,框架无关,开箱即用。
9
12
 
10
13
  [![npm version](https://img.shields.io/npm/v/@antv/gpt-vis.svg)](https://www.npmjs.com/package/@antv/gpt-vis)
11
14
  [![npm downloads](https://img.shields.io/npm/dm/@antv/gpt-vis.svg)](https://www.npmjs.com/package/@antv/gpt-vis)
12
15
  [![License](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE)
13
16
 
14
17
  <p align="center">
15
- <a href="https://gpt-vis.antv.vision" target="_blank">📖 文档</a>
16
- <a href="/skills/chart-visualization" target="_blank">🤖 图表技能</a>
17
- <a href="/knowledges" target="_blank">🧠 知识库</a>
18
- <a href="https://www.tbox.cn/share/202504APmv6c00373739?platform=WebService" target="_blank">🎮 在线体验</a>
19
- <a href="https://github.com/antvis/mcp-server-chart" target="_blank">🔌 MCP 服务器</a>
18
+ <a href="https://gpt-vis.antv.vision" target="_blank">📖 文档</a> ·
19
+ <a href="https://gpt-vis.antv.vision/examples" target="_blank">🎨 图表示例</a> ·
20
+ <a href="https://github.com/antvis/mcp-server-chart" target="_blank">🔌 MCP 服务</a> ·
21
+ <a href="/skills/chart-visualization" target="_blank">🧩 图表技能</a>
20
22
  </p>
21
23
 
22
24
  </div>
23
25
 
24
26
  <div align="center">
25
- <video src="https://github.com/user-attachments/assets/b8eb4a89-b0ed-4a39-8fab-316161949446" />
27
+ <img src="https://mdn.alipayobjects.com/huamei_qa8qxu/afts/img/A*k21VQY6NgAwAAAAAWAAAAAgAemJ7AQ/fmt.avif" width="100%" />
26
28
  </div>
27
29
 
28
30
  <br/>
29
31
 
30
- > **📢 Version 1.0 预览版**: 为 AI 优化的全新架构。正式版预计 **2026 年 3 月 21 日**发布。
32
+ ## 特性
31
33
 
32
- ## 核心特性
33
-
34
- - **🚀 框架无关**: 支持原生 JavaScript、React、Vue、Angular 或任何框架
35
- - **✍️ 自然语法**: 简单的类 Markdown 语法,LLM 可以轻松生成
36
- - **🌊 流式支持**: 内置支持 AI 模型的流式输出
37
- - **🛡️ 容错性**: 优雅处理不完整或格式错误数据
38
- - **📊 20+ 图表类型**: 统计图表、关系图表和高级可视化图表
39
- - **🧠 智能默认值**: 自动数据检测、智能配色方案、自适应布局
34
+ - 🚀 **框架无关** — 原生 JavaScript、React、Vue、Angular,任何框架均可使用
35
+ - ✍️ **类 Markdown 语法** — LLM 可以直接生成的简洁语法,易学易用
36
+ - 🌊 **流式渲染** 原生支持 AI 模型流式输出,边生成边渲染
37
+ - 🛡️ **高容错** 优雅处理不完整、格式异常的数据,适配 AI 生成内容的不确定性
38
+ - 📊 **26 种图表** 统计图表、关系图表、文本可视化,覆盖主流场景
39
+ - 🎨 **主题系统** — 内置亮色、暗色、学术三套主题,支持自定义配色
40
40
 
41
41
  ## 🚀 快速开始
42
42
 
@@ -57,7 +57,7 @@ const gptVis = new GPTVis({
57
57
  height: 400,
58
58
  });
59
59
 
60
- // 使用类 Markdown 语法渲染
60
+ // Markdown 的可视化语法
61
61
  const visSyntax = `
62
62
  vis line
63
63
  data
@@ -72,7 +72,11 @@ data
72
72
  gptVis.render(visSyntax);
73
73
  ```
74
74
 
75
- ### 流式支持
75
+ ### 流式渲染
76
+
77
+ AI 模型边生成、图表边渲染,无需等待完整响应:
78
+
79
+ <img src="https://mdn.alipayobjects.com/huamei_qa8qxu/afts/img/A*_xY7Q6QyuZ4AAAAAWeAAAAgAemJ7AQ/original" width="100%" />
76
80
 
77
81
  ```javascript
78
82
  import { GPTVis, isVisSyntax } from '@antv/gpt-vis';
@@ -90,18 +94,20 @@ function onToken(token) {
90
94
 
91
95
  ## 📚 语法指南
92
96
 
93
- ### 基本结构
97
+ `render()` 支持两种输入格式:vis 语法(适合 LLM 流式生成)和 JSON 对象(适合程序化调用)。
98
+
99
+ ### Vis 语法
100
+
101
+ 类 Markdown 的声明式语法,LLM 无需学习复杂 API 即可生成:
94
102
 
95
103
  ```
96
104
  vis [图表类型]
97
105
  [属性] [值]
98
106
  data
99
- - [] [值]
107
+ - [字段] [值]
100
108
  ```
101
109
 
102
- ### 示例
103
-
104
- **简单图表:**
110
+ **饼图:**
105
111
 
106
112
  ```
107
113
  vis pie
@@ -113,7 +119,29 @@ data
113
119
  innerRadius 0.6
114
120
  ```
115
121
 
116
- **带样式:**
122
+ **主题:**
123
+
124
+ 内置三套主题,通过 `theme` 属性切换:
125
+
126
+ | 主题 | 标识 | 背景色 | 色板 |
127
+ | ------------ | --------- | ------ | ----------------------------------------------------- |
128
+ | 默认(亮色) | `default` | `#FFF` | `#1783FF` `#F08F56` `#D580FF` `#00C9C9` `#7863FF` ... |
129
+ | 暗色 | `dark` | `#000` | `#1783FF` `#F08F56` `#D580FF` `#00C9C9` `#7863FF` ... |
130
+ | 学术 | `academy` | `#FFF` | `#4e79a7` `#f28e2c` `#e15759` `#76b7b2` `#59a14f` ... |
131
+
132
+ ```
133
+ vis line
134
+ data
135
+ - time 2020
136
+ value 100
137
+ - time 2021
138
+ value 120
139
+ theme dark
140
+ ```
141
+
142
+ **自定义样式:**
143
+
144
+ 通过 `style` 设置线宽、自定义配色等:
117
145
 
118
146
  ```
119
147
  vis line
@@ -129,17 +157,89 @@ style
129
157
  - #5AD8A6
130
158
  ```
131
159
 
132
- **层次数据:**
160
+ **包含空格的值用引号包裹:**
133
161
 
134
162
  ```
135
- vis mind-map
163
+ vis pie
136
164
  data
137
- - name 项目
165
+ - category "Q1 销售额"
166
+ value 30
167
+ - category "Q2 销售额"
168
+ value 25
169
+ ```
170
+
171
+ **层级数据:**
172
+
173
+ ```
174
+ vis mindmap
175
+ data
176
+ - name 项目规划
138
177
  children
139
- - name 阶段一
140
- - name 阶段二
178
+ - name 第一阶段
179
+ - name 第二阶段
180
+ ```
181
+
182
+ ### JSON 对象
183
+
184
+ 也支持直接传入 JSON 对象,适合程序化调用:
185
+
186
+ ```javascript
187
+ gptVis.render({
188
+ type: 'pie',
189
+ data: [
190
+ { category: 'Android', value: 72 },
191
+ { category: 'iOS', value: 28 },
192
+ ],
193
+ });
141
194
  ```
142
195
 
196
+ ## 📊 图表类型
197
+
198
+ 支持 26 种图表,覆盖统计分析、关系网络、文本可视化三大类。
199
+
200
+ ### 统计图表(18 种)
201
+
202
+ | 图表 | 类型标识 |
203
+ | -------- | ------------ |
204
+ | 折线图 | `line` |
205
+ | 面积图 | `area` |
206
+ | 柱状图 | `column` |
207
+ | 条形图 | `bar` |
208
+ | 饼图 | `pie` |
209
+ | 散点图 | `scatter` |
210
+ | 雷达图 | `radar` |
211
+ | 漏斗图 | `funnel` |
212
+ | 瀑布图 | `waterfall` |
213
+ | 双轴图 | `dual-axes` |
214
+ | 直方图 | `histogram` |
215
+ | 箱线图 | `boxplot` |
216
+ | 小提琴图 | `violin` |
217
+ | 韦恩图 | `venn` |
218
+ | 桑基图 | `sankey` |
219
+ | 树图 | `treemap` |
220
+ | 词云 | `word-cloud` |
221
+ | 水波图 | `liquid` |
222
+
223
+ ### 关系图表(6 种)
224
+
225
+ | 图表 | 类型标识 |
226
+ | ---------- | -------------------- |
227
+ | 流程图 | `flow-diagram` |
228
+ | 网络图 | `network-graph` |
229
+ | 思维导图 | `mindmap` |
230
+ | 缩进树 | `indented-tree` |
231
+ | 组织架构图 | `organization-chart` |
232
+ | 鱼骨图 | `fishbone-diagram` |
233
+
234
+ ### 文本可视化(2 种)
235
+
236
+ | 图表 | 类型标识 |
237
+ | -------- | --------- |
238
+ | 表格 | `table` |
239
+ | 文本摘要 | `summary` |
240
+
241
+ 查看全部示例 → [图表示例](https://gpt-vis.antv.vision/examples)
242
+
143
243
  ## 🔧 框架集成
144
244
 
145
245
  <details>
@@ -191,25 +291,22 @@ function ChartComponent({ visSyntax }) {
191
291
  </template>
192
292
 
193
293
  <script setup>
194
- import { ref, onMounted, onUnmounted, watch } from 'vue';
294
+ import { ref, watch, onUnmounted } from 'vue';
195
295
  import { GPTVis } from '@antv/gpt-vis';
196
296
 
197
297
  const props = defineProps(['visSyntax']);
198
298
  const chartRef = ref(null);
199
299
  let gptVis = null;
200
300
 
201
- onMounted(() => {
202
- gptVis = new GPTVis({ container: chartRef.value, width: 600, height: 400 });
203
- gptVis.render(props.visSyntax);
204
- });
205
-
206
301
  watch(
207
302
  () => props.visSyntax,
208
- (newSyntax) => {
209
- if (gptVis) {
210
- gptVis.render(newSyntax);
303
+ (syntax) => {
304
+ if (!gptVis) {
305
+ gptVis = new GPTVis({ container: chartRef.value, width: 600, height: 400 });
211
306
  }
307
+ gptVis.render(syntax);
212
308
  },
309
+ { immediate: true },
213
310
  );
214
311
 
215
312
  onUnmounted(() => gptVis?.destroy());
@@ -218,18 +315,95 @@ onUnmounted(() => gptVis?.destroy());
218
315
 
219
316
  </details>
220
317
 
221
- ## 🧠 知识库
318
+ <details>
319
+ <summary><strong>Markdown 渲染器(marked)</strong></summary>
222
320
 
223
- GPT-Vis 包含全面的[知识库](https://github.com/antvis/GPT-Vis/tree/main/knowledges),帮助 LLM 理解何时使用每种图表类型以及如何构建数据结构。在 200+ 场景中评估,准确率超过 90%。
321
+ GPT-Vis vis 语法天然兼容 Markdown code fence,可以与任何 Markdown 渲染器集成。以下示例使用 `marked` + `marked-highlight`,普通代码块走语法高亮,`vis` 代码块自动渲染为交互式图表。
224
322
 
225
- ## 🤝 贡献
323
+ **安装依赖:**
324
+
325
+ ```bash
326
+ npm install @antv/gpt-vis marked marked-highlight highlight.js
327
+ ```
328
+
329
+ **完整示例:**
330
+
331
+ ```javascript
332
+ import { Marked } from 'marked';
333
+ import { markedHighlight } from 'marked-highlight';
334
+ import hljs from 'highlight.js';
335
+ import { GPTVis } from '@antv/gpt-vis';
336
+
337
+ class GPTVisElement extends HTMLElement {
338
+ connectedCallback() {
339
+ const syntax = decodeURIComponent(this.dataset.syntax);
340
+ this._instance = new GPTVis({ container: this });
341
+ this._instance.render(syntax);
342
+ }
343
+ disconnectedCallback() {
344
+ this._instance?.destroy();
345
+ }
346
+ }
347
+ if (!customElements.get('gpt-vis')) {
348
+ customElements.define('gpt-vis', GPTVisElement);
349
+ }
350
+
351
+ const marked = new Marked(
352
+ markedHighlight({
353
+ langPrefix: 'hljs language-',
354
+ highlight(code, lang) {
355
+ if (lang?.startsWith('vis')) return code;
356
+ const language = hljs.getLanguage(lang) ? lang : 'plaintext';
357
+ return hljs.highlight(code, { language }).value;
358
+ },
359
+ }),
360
+ {
361
+ renderer: {
362
+ code({ text, lang }) {
363
+ if (lang?.startsWith('vis')) {
364
+ const syntax = encodeURIComponent(lang + '\n' + text);
365
+ return `<gpt-vis data-syntax="${syntax}" style="min-height:300px"></gpt-vis>`;
366
+ }
367
+ return false;
368
+ },
369
+ },
370
+ },
371
+ );
372
+
373
+ const markdown = `# My Report
374
+
375
+ \`\`\`vis bar
376
+ data
377
+ - category Python
378
+ value 28.1
379
+ - category JavaScript
380
+ value 18.5
381
+ - category Java
382
+ value 15.6
383
+ - category "C/C++"
384
+ value 12.3
385
+ title 2024 Programming Language Popularity
386
+ \`\`\`
387
+ `;
226
388
 
227
- > **⚠️ AI 生成代码策略**: 本项目仅合并 AI 生成的代码。
389
+ document.getElementById('content').innerHTML = marked.parse(markdown);
390
+ ```
391
+
392
+ </details>
393
+
394
+ ## 🤖 AI 生态
395
+
396
+ GPT-Vis 提供完整的 AI 集成方案:
397
+
398
+ - **[MCP 服务](https://github.com/antvis/mcp-server-chart)** — 通过 Model Context Protocol 让 AI 模型直接调用可视化能力
399
+ - **[图表技能](https://github.com/antvis/GPT-Vis/tree/main/skills/chart-visualization)** — 为 AI 助手提供图表推荐与生成能力,支持语法模式和代码模式两种输出
400
+
401
+ ## 🤝 贡献
228
402
 
229
- 贡献方式:
403
+ > **AI 生成代码策略**:本项目仅合并 AI 生成的代码。
230
404
 
231
- 1. 提交 Issue 描述问题或功能
232
- 2. 标记 @copilot 生成实现
405
+ 1. 提交 Issue 描述问题或需求
406
+ 2. 标记 @copilot 生成实现方案
233
407
  3. 提交包含 AI 生成代码的 PR
234
408
 
235
409
  ## 📄 开源协议
@@ -118,7 +118,7 @@ var _GPTVis = class {
118
118
  this.wrapperInstance = (0, import_vis_wrapper.createVisWrapper)(this.options.container, {
119
119
  chartType: type,
120
120
  syntax: config,
121
- locale: this.options.locale || "zh-CN"
121
+ locale: this.options.locale || "en-US"
122
122
  });
123
123
  } else {
124
124
  this.wrapperInstance.update(config);
@@ -76,8 +76,7 @@ var DualAxes = (options) => {
76
76
  },
77
77
  style: {
78
78
  columnWidthRatio: 0.8,
79
- radiusTopLeft: 4,
80
- radiusTopRight: 4
79
+ ...theme !== "academy" ? { radiusTopLeft: 4, radiusTopRight: 4 } : {}
81
80
  }
82
81
  };
83
82
  } else {
@@ -100,9 +100,17 @@ var FishboneDiagram = (options) => {
100
100
  height,
101
101
  autoFit: "view",
102
102
  autoResize: true,
103
- padding: 20,
104
- theme: chartTheme,
105
- plugins: title ? [{ key: "title", type: "title", title, titleFill: isDark ? "#e0e6ed" : "#1a1a2e" }] : [],
103
+ padding: title ? [46, 20, 20, 20] : 20,
104
+ theme: (0, import_theme.getTheme)(theme),
105
+ plugins: title ? [
106
+ {
107
+ key: "title",
108
+ type: "title",
109
+ title,
110
+ titleFill: isDark ? "#e0e6ed" : "#000",
111
+ titleFontFamily: "sans-serif"
112
+ }
113
+ ] : [],
106
114
  data: graphData,
107
115
  node: {
108
116
  type: "rect",
@@ -110,7 +118,7 @@ var FishboneDiagram = (options) => {
110
118
  var _a;
111
119
  const depth = d.depth ?? 0;
112
120
  const nodeStyle = {
113
- radius: 8,
121
+ radius: theme === "academy" ? 0 : 8,
114
122
  size: getNodeSize(String(d.id), depth),
115
123
  labelText: String(d.id),
116
124
  labelPlacement: "left",
@@ -53,12 +53,13 @@ function ensureBehaviorRegistered() {
53
53
  function escapeHtml(str = "") {
54
54
  return str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
55
55
  }
56
- function createNodeHTML(d, color, selectedBorderColor = "#000") {
56
+ function createNodeHTML(d, color, selectedBorderColor = "#000", theme = "default") {
57
57
  var _a, _b, _c;
58
58
  const text = escapeHtml(((_a = d.data) == null ? void 0 : _a.text) || "");
59
59
  const isHovered = (_b = d.states) == null ? void 0 : _b.includes("active");
60
60
  const isSelected = (_c = d.states) == null ? void 0 : _c.includes("selected");
61
61
  const nodeColor = isHovered ? ACTIVE_COLOR : color;
62
+ const borderRadius = theme === "academy" ? "0px" : "8px";
62
63
  return `
63
64
  <div
64
65
  data-node-key="${escapeHtml(String(d.id))}"
@@ -69,7 +70,7 @@ function createNodeHTML(d, color, selectedBorderColor = "#000") {
69
70
  padding: 16px;
70
71
  background: ${nodeColor};
71
72
  border: 3px solid ${isSelected ? selectedBorderColor : nodeColor};
72
- border-radius: 16px;
73
+ border-radius: ${borderRadius};
73
74
  color: #fff;
74
75
  font-size: 16px;
75
76
  font-weight: 600;
@@ -90,7 +91,7 @@ function createNodeHTML(d, color, selectedBorderColor = "#000") {
90
91
  </div>
91
92
  `;
92
93
  }
93
- function measureAndUpdateNodeSizes(graph, container, nodeColorMap, selectedBorderColor) {
94
+ function measureAndUpdateNodeSizes(graph, container, nodeColorMap, selectedBorderColor, theme = "default") {
94
95
  const nodes = graph.getNodeData();
95
96
  const updatedNodes = nodes.map((node) => {
96
97
  const dom = container.querySelector(`[data-node-key="${CSS.escape(String(node.id))}"]`);
@@ -107,7 +108,8 @@ function measureAndUpdateNodeSizes(graph, container, nodeColorMap, selectedBorde
107
108
  innerHTML: createNodeHTML(
108
109
  node,
109
110
  nodeColorMap.get(String(node.id)) || "#1783FF",
110
- selectedBorderColor
111
+ selectedBorderColor,
112
+ theme
111
113
  )
112
114
  }
113
115
  };
@@ -187,21 +189,35 @@ var FlowDiagram = (options) => {
187
189
  container: containerEl,
188
190
  width,
189
191
  height,
190
- theme,
192
+ theme: (0, import_theme.getTheme)(theme),
191
193
  data: { nodes: g6Nodes, edges: g6Edges },
192
194
  autoFit: "view",
193
195
  autoResize: true,
194
- padding: 20,
195
- plugins: title ? [{ key: "title", type: "title", title, titleFill: isDark ? "#e0e6ed" : "#1a1a2e" }] : [],
196
+ padding: title ? [46, 20, 20, 20] : 20,
197
+ plugins: title ? [
198
+ {
199
+ key: "title",
200
+ type: "title",
201
+ title,
202
+ titleFill: isDark ? "#e0e6ed" : "#000",
203
+ titleFontFamily: "sans-serif"
204
+ }
205
+ ] : [],
196
206
  node: {
197
207
  type: "html",
198
208
  style: (d) => {
209
+ var _a;
199
210
  const color = nodeColorMap.get(String(d.id)) || colors[0];
211
+ const size = ((_a = d.style) == null ? void 0 : _a.size) || [
212
+ DEFAULT_NODE_WIDTH,
213
+ DEFAULT_NODE_HEIGHT
214
+ ];
215
+ const height2 = size[1];
200
216
  return {
201
- size: [DEFAULT_NODE_WIDTH, DEFAULT_NODE_HEIGHT],
217
+ size,
202
218
  dx: -DEFAULT_NODE_WIDTH / 2,
203
- dy: -DEFAULT_NODE_HEIGHT / 2,
204
- innerHTML: createNodeHTML(d, color, selectedBorder),
219
+ dy: -height2 / 2,
220
+ innerHTML: createNodeHTML(d, color, selectedBorder, theme),
205
221
  ports: [{ placement: "top" }, { placement: "bottom" }]
206
222
  };
207
223
  },
@@ -248,7 +264,7 @@ var FlowDiagram = (options) => {
248
264
  graph.render();
249
265
  graph.once("afterrender", () => {
250
266
  if (graph) {
251
- measureAndUpdateNodeSizes(graph, containerEl, nodeColorMap, selectedBorder);
267
+ measureAndUpdateNodeSizes(graph, containerEl, nodeColorMap, selectedBorder, theme);
252
268
  }
253
269
  });
254
270
  };
@@ -281,15 +281,17 @@ var IndentedTree = (options) => {
281
281
  height,
282
282
  autoFit: "view",
283
283
  autoResize: true,
284
- padding: 20,
284
+ theme: (0, import_theme.getTheme)(theme),
285
+ padding: title ? [46, 20, 20, 20] : 20,
285
286
  data: graphData,
286
287
  node: {
287
288
  type: GPT_VIS_INDENTED_NODE,
288
289
  style: {
289
290
  size: (d) => [measureTextWidth(String(d.id ?? ""), 12) + 6, NODE_HEIGHT],
290
291
  labelBackground: (datum) => datum.id === rootId,
291
- labelBackgroundRadius: 0,
292
+ labelBackgroundRadius: theme === "academy" ? 0 : 4,
292
293
  labelBackgroundFill: palette[0] ?? "#1783FF",
294
+ labelPadding: (datum) => datum.id === rootId ? [2, 8] : 0,
293
295
  labelFill: (datum) => datum.id === rootId ? "#fff" : isDark ? "#d0d0d0" : "#666",
294
296
  labelText: (d) => {
295
297
  var _a;
@@ -352,7 +354,15 @@ var IndentedTree = (options) => {
352
354
  enable: (event) => event.targetType === "node" && event.target.id !== rootId
353
355
  }
354
356
  ],
355
- plugins: title ? [{ key: "title", type: "title", title, titleFill: isDark ? "#e0e6ed" : "#1a1a2e" }] : []
357
+ plugins: title ? [
358
+ {
359
+ key: "title",
360
+ type: "title",
361
+ title,
362
+ titleFill: isDark ? "#e0e6ed" : "#000",
363
+ titleFontFamily: "sans-serif"
364
+ }
365
+ ] : []
356
366
  });
357
367
  graph.render();
358
368
  };
@@ -111,12 +111,20 @@ var Mindmap = (options) => {
111
111
  height,
112
112
  autoFit: "view",
113
113
  autoResize: true,
114
- padding: 20,
114
+ padding: title ? [46, 20, 20, 20] : 20,
115
115
  zoomRange: [0.1, 5],
116
116
  zoom: 1,
117
- theme: chartTheme,
117
+ theme: (0, import_theme.getTheme)(theme),
118
118
  data: graphData,
119
- plugins: title ? [{ key: "title", type: "title", title, titleFill: isDark ? "#e0e6ed" : "#1a1a2e" }] : [],
119
+ plugins: title ? [
120
+ {
121
+ key: "title",
122
+ type: "title",
123
+ title,
124
+ titleFill: isDark ? "#e0e6ed" : "#000",
125
+ titleFontFamily: "sans-serif"
126
+ }
127
+ ] : [],
120
128
  node: {
121
129
  type: "rect",
122
130
  animation: { translate: false, update: false },
@@ -134,7 +142,7 @@ var Mindmap = (options) => {
134
142
  const base = {
135
143
  size: [nodeWidth, nodeHeight],
136
144
  dx,
137
- radius: 8,
145
+ radius: theme === "academy" ? 0 : 8,
138
146
  labelText: label,
139
147
  labelPlacement: "center",
140
148
  labelFontSize: fontSize,
@@ -119,7 +119,8 @@ var NetworkGraph = (options) => {
119
119
  height,
120
120
  autoFit: "view",
121
121
  autoResize: true,
122
- padding: 24,
122
+ theme: (0, import_theme.getTheme)(theme),
123
+ padding: title ? [46, 20, 20, 20] : 20,
123
124
  data: {
124
125
  nodes: nodeData,
125
126
  edges: edgeData
@@ -132,7 +133,15 @@ var NetworkGraph = (options) => {
132
133
  }
133
134
  },
134
135
  behaviors: ["drag-canvas", "drag-element", "click-select"],
135
- plugins: title ? [{ key: "title", type: "title", title, titleFill: isDark ? "#e0e6ed" : "#1a1a2e" }] : []
136
+ plugins: title ? [
137
+ {
138
+ key: "title",
139
+ type: "title",
140
+ title,
141
+ titleFill: isDark ? "#e0e6ed" : "#000",
142
+ titleFontFamily: "sans-serif"
143
+ }
144
+ ] : []
136
145
  });
137
146
  graph.render();
138
147
  };
@@ -83,7 +83,8 @@ var OrganizationChart = (options) => {
83
83
  height,
84
84
  autoFit: "view",
85
85
  autoResize: true,
86
- padding: 24,
86
+ theme: (0, import_theme.getTheme)(theme),
87
+ padding: title ? [46, 20, 20, 20] : 20,
87
88
  data: { nodes: nodeData, edges: edgeData },
88
89
  plugins: [
89
90
  {
@@ -119,7 +120,15 @@ var OrganizationChart = (options) => {
119
120
  }
120
121
  }
121
122
  },
122
- ...title ? [{ key: "title", type: "title", title, titleFill: isDark ? "#e0e6ed" : "#1a1a2e" }] : []
123
+ ...title ? [
124
+ {
125
+ key: "title",
126
+ type: "title",
127
+ title,
128
+ titleFill: isDark ? "#e0e6ed" : "#000",
129
+ titleFontFamily: "sans-serif"
130
+ }
131
+ ] : []
123
132
  ],
124
133
  node: {
125
134
  type: "rect",
@@ -132,7 +141,7 @@ var OrganizationChart = (options) => {
132
141
  fill: (d) => colors[d.data.depth % colors.length],
133
142
  stroke: isDark ? "#555" : "#e8ebf0",
134
143
  lineWidth: 1,
135
- radius: 8,
144
+ radius: theme === "academy" ? 0 : 8,
136
145
  // Use official label wrapping/ellipsis for BOTH name & description.
137
146
  // 1 line name + up to 2 lines description => total maxLines = 3.
138
147
  labelText: (d) => d.data.description ? `${d.data.name}
@@ -14,6 +14,8 @@ export interface ScatterConfig {
14
14
  type?: 'scatter';
15
15
  data: ScatterDataItem[];
16
16
  title?: string;
17
+ axisXTitle?: string;
18
+ axisYTitle?: string;
17
19
  theme?: 'default' | 'academy' | 'dark';
18
20
  style?: {
19
21
  backgroundColor?: string;