UNPKG

chart-mcp-service

Version:

MCP服务,实现根据输入自动生成对应图表的功能

427 lines (403 loc) 13 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ChartGenerator = void 0; class ChartGenerator { constructor() { this.charts = new Map(); this.chartTemplates = { line: { import: `import { Line, LineProps } from '@alife/bi-material-center-chart';`, template: `const LineChart: React.FC = () => { const data = [ { month: '1月', value: 3, category: '系列1' }, { month: '2月', value: 4, category: '系列1' }, { month: '3月', value: 3.5, category: '系列1' }, { month: '4月', value: 5, category: '系列1' }, { month: '1月', value: 2, category: '系列2' }, { month: '2月', value: 3, category: '系列2' }, { month: '3月', value: 4, category: '系列2' }, { month: '4月', value: 4.5, category: '系列2' }, ]; const config: LineProps = { data, xField: 'month', yField: 'value', seriesField: 'category', height: 500, point: { size: 5 }, line: { style: { lineWidth: 2 } }, legend: { position: 'top' }, tooltip: { shared: true }, color: ['#1890ff', '#2fc25b'] }; return <Line {...config} />; };`, }, bar: { import: `import { Bar, BarProps } from '@alife/bi-material-center-chart';`, template: `const BarChart: React.FC = () => { const data = [ { category: 'A类', value: 100, group: '分组1' }, { category: 'B类', value: 200, group: '分组1' }, { category: 'C类', value: 150, group: '分组1' }, { category: 'A类', value: 120, group: '分组2' }, { category: 'B类', value: 180, group: '分组2' }, { category: 'C类', value: 190, group: '分组2' }, ]; const config: BarProps = { data, xField: 'category', yField: 'value', seriesField: 'group', height: 500, columnWidthRatio: 0.6, legend: { position: 'top' }, tooltip: { shared: true }, color: ['#1890ff', '#2fc25b'] }; return <Bar {...config} />; };`, }, pie: { import: `import { Pie, PieProps } from '@alife/bi-material-center-chart';`, template: `const PieChart: React.FC = () => { const data = [ { type: 'A类', value: 27 }, { type: 'B类', value: 25 }, { type: 'C类', value: 18 }, { type: 'D类', value: 15 }, { type: 'E类', value: 10 }, { type: '其他', value: 5 }, ]; const config: PieProps = { data, angleField: 'value', colorField: 'type', height: 500, radius: 0.8, label: { type: 'outer' }, legend: { position: 'top' }, tooltip: { shared: true }, color: ['#1890ff', '#2fc25b', '#facc14', '#f759ab', '#13c2c2', '#52c41a'] }; return <Pie {...config} />; };`, }, area: { import: `import { Area, AreaProps } from '@alife/bi-material-center-chart';`, template: `const AreaChart: React.FC = () => { const data = [ { month: '1月', value: 3, category: '产品A' }, { month: '2月', value: 4, category: '产品A' }, { month: '3月', value: 3.5, category: '产品A' }, { month: '4月', value: 5, category: '产品A' }, { month: '1月', value: 2, category: '产品B' }, { month: '2月', value: 3, category: '产品B' }, { month: '3月', value: 4, category: '产品B' }, { month: '4月', value: 4.5, category: '产品B' }, ]; const config: AreaProps = { data, xField: 'month', yField: 'value', seriesField: 'category', height: 500, point: { size: 4 }, area: { style: { fillOpacity: 0.3 } }, legend: { position: 'top' }, tooltip: { shared: true }, color: ['#1890ff', '#2fc25b'] }; return <Area {...config} />; };`, }, scatter: { import: `import { Scatter, ScatterProps } from '@alife/bi-material-center-chart';`, template: `const ScatterChart: React.FC = () => { const data = [ { x: 10, y: 20, category: '类别A', value: 15 }, { x: 15, y: 25, category: '类别A', value: 20 }, { x: 20, y: 30, category: '类别B', value: 25 }, { x: 25, y: 35, category: '类别B', value: 30 }, { x: 30, y: 40, category: '类别C', value: 35 }, ]; const config: ScatterProps = { data, xField: 'x', yField: 'y', seriesField: 'category', height: 500, point: { size: 4 }, legend: { position: 'top' }, tooltip: { shared: true }, color: ['#1890ff', '#2fc25b', '#facc14'] }; return <Scatter {...config} />; };`, }, radar: { import: `import { Radar, RadarProps } from '@alife/bi-material-center-chart';`, template: `const RadarChart: React.FC = () => { const data = [ { item: '设计', score: 70, product: '产品A' }, { item: '开发', score: 60, product: '产品A' }, { item: '营销', score: 50, product: '产品A' }, { item: '技术', score: 40, product: '产品A' }, { item: '设计', score: 60, product: '产品B' }, { item: '开发', score: 70, product: '产品B' }, { item: '营销', score: 40, product: '产品B' }, { item: '技术', score: 60, product: '产品B' }, ]; const config: RadarProps = { data, xField: 'item', yField: 'score', seriesField: 'product', height: 500, point: { size: 4 }, area: { style: { fillOpacity: 0.3 } }, legend: { position: 'top' }, tooltip: { shared: true }, color: ['#1890ff', '#2fc25b'] }; return <Radar {...config} />; };`, }, wordcloud: { import: `import { WordCloud, WordCloudProps } from '@alife/bi-material-center-chart';`, template: `const WordCloudChart: React.FC = () => { const data = [ { word: 'React', weight: 100 }, { word: 'JavaScript', weight: 80 }, { word: 'TypeScript', weight: 70 }, { word: 'Vue', weight: 60 }, { word: 'Angular', weight: 50 }, { word: 'Node.js', weight: 40 }, { word: 'Express', weight: 30 }, ]; const config: WordCloudProps = { data, wordField: 'word', weightField: 'weight', height: 500, wordStyle: { fontSize: [12, 48], rotation: [0, 0] }, legend: { position: 'top' }, tooltip: { shared: true } }; return <WordCloud {...config} />; };`, }, strip: { import: `import { Strip, StripProps } from '@alife/bi-material-center-chart';`, template: `const StripChart: React.FC = () => { const data = [ { x: '类别A', y: 10 }, { x: '类别A', y: 12 }, { x: '类别A', y: 14 }, { x: '类别B', y: 8 }, { x: '类别B', y: 15 }, { x: '类别B', y: 20 }, { x: '类别C', y: 5 }, { x: '类别C', y: 18 }, ]; const config: StripProps = { data, xField: 'x', yField: 'y', height: 500, legend: { position: 'top' }, tooltip: { shared: true }, yAxis: { title: { text: '数值' } }, xAxis: { title: { text: '类别' } } }; return <Strip {...config} />; };`, }, heatmap: { import: `import { Heatmap, HeatmapProps } from '@alife/bi-material-center-chart';`, template: `const HeatmapChart: React.FC = () => { const data = [ { xField: '星期一', yField: '上午', value: 10 }, { xField: '星期一', yField: '下午', value: 20 }, { xField: '星期二', yField: '上午', value: 15 }, { xField: '星期二', yField: '下午', value: 25 }, { xField: '星期三', yField: '上午', value: 12 }, { xField: '星期三', yField: '下午', value: 18 }, ]; const config: HeatmapProps = { data, xField: 'xField', yField: 'yField', colorField: 'value', height: 500, legend: { position: 'top' }, tooltip: { shared: true }, color: ['#BAE7FF', '#1890FF', '#0050B3'] }; return <Heatmap {...config} />; };`, }, sankey: { import: `import { Sankey, SankeyProps } from '@alife/bi-material-center-chart';`, template: `const SankeyChart: React.FC = () => { const data = [ { source: '访问', target: '首页', value: 100 }, { source: '首页', target: '产品页', value: 60 }, { source: '首页', target: '关于页', value: 40 }, { source: '产品页', target: '购买', value: 30 }, { source: '产品页', target: '离开', value: 30 }, { source: '关于页', target: '联系', value: 20 }, { source: '关于页', target: '离开', value: 20 }, ]; const config: SankeyProps = { data, sourceField: 'source', targetField: 'target', weightField: 'value', height: 500, legend: { position: 'top' }, tooltip: { shared: true } }; return <Sankey {...config} />; };`, }, treemap: { import: `import { Treemap, TreemapProps } from '@alife/bi-material-center-chart';`, template: `const TreemapChart: React.FC = () => { const data = [ { year: '2020', value: 100 }, { year: '2021', value: 200 }, { year: '2022', value: 150 }, { year: '2023', value: 300 }, { year: '2024', value: 250 }, ]; const config: TreemapProps = { data, valueField: 'value', colorField: 'year', height: 500, legend: { position: 'top' }, tooltip: { shared: true } }; return <Treemap {...config} />; };`, }, }; } async generateChartCode(type) { const template = this.chartTemplates[type]; if (!template) { throw new Error(`不支持的图表类型: ${type}`); } return `${template.import} import React from 'react'; ${template.template} export default ${this.getComponentName(type)}Chart;`; } async createChart(id, type, title, config) { if (this.charts.has(id)) { throw new Error(`图表 ${id} 已存在`); } const code = await this.generateChartCode(type); const chart = { id, type, title, config: config || this.getDefaultConfig(type), code, createdAt: new Date().toISOString(), updatedAt: new Date().toISOString(), }; this.charts.set(id, chart); return chart; } async getChart(id) { return this.charts.get(id) || null; } async listCharts() { return Array.from(this.charts.values()); } async updateChart(id, updates) { const chart = this.charts.get(id); if (!chart) { throw new Error(`图表 ${id} 不存在`); } const updatedChart = { ...chart, ...updates, updatedAt: new Date().toISOString(), }; // 如果更新了类型,需要重新生成代码 if (updates.type && updates.type !== chart.type) { updatedChart.code = await this.generateChartCode(updates.type); } this.charts.set(id, updatedChart); return updatedChart; } async deleteChart(id) { return this.charts.delete(id); } getComponentName(type) { const components = { line: "Line", bar: "Bar", pie: "Pie", area: "Area", scatter: "Scatter", radar: "Radar", heatmap: "Heatmap", wordcloud: "WordCloud", strip: "Strip", sankey: "Sankey", treemap: "Treemap", }; return components[type] || "Bar"; } getDefaultConfig(type) { const defaults = { line: { xField: "month", yField: "value", seriesField: "category", height: 500, point: { size: 5 }, legend: { position: "top" }, tooltip: { shared: true }, }, bar: { xField: "category", yField: "value", seriesField: "group", height: 500, columnWidthRatio: 0.6, legend: { position: "top" }, tooltip: { shared: true }, }, pie: { angleField: "value", colorField: "type", height: 500, radius: 0.8, label: { type: "outer" }, legend: { position: "top" }, tooltip: { shared: true }, }, area: { xField: "month", yField: "value", seriesField: "category", height: 500, point: { size: 4 }, area: { style: { fillOpacity: 0.3 } }, legend: { position: "top" }, tooltip: { shared: true }, }, }; return defaults[type] || defaults.bar; } } exports.ChartGenerator = ChartGenerator; //# sourceMappingURL=chart-generator.js.map