ziwei-mcp
Version:
紫微斗数 MCP (Ziwei Doushu Model Context Protocol) - 基于 MCP 协议的紫微斗数命理分析工具
886 lines (790 loc) • 23.1 kB
JavaScript
/**
* 增强版SVG生成器
* 支持模板化生成、多种图表类型和自定义主题
*/
class EnhancedSVGGenerator {
constructor() {
this.templates = new Map();
this.themes = new Map();
this.chartTypes = new Map();
// 初始化默认模板和主题
this.initializeDefaultTemplates();
this.initializeDefaultThemes();
this.initializeChartTypes();
}
/**
* 初始化默认SVG模板
*/
initializeDefaultTemplates() {
// 传统命盘模板
this.templates.set("traditional", {
width: 600,
height: 600,
viewBox: "0 0 600 600",
structure: {
outerCircle: { cx: 300, cy: 300, r: 280 },
innerCircle: { cx: 300, cy: 300, r: 120 },
palaces: this.generatePalacePositions("traditional"),
centerArea: { x: 200, y: 200, width: 200, height: 200 },
},
template: `
<svg width="{{width}}" height="{{height}}" viewBox="{{viewBox}}" xmlns="http://www.w3.org/2000/svg">
<defs>
{{gradients}}
{{patterns}}
{{filters}}
</defs>
<!-- 背景 -->
<rect width="100%" height="100%" fill="{{theme.background}}"/>
<!-- 外圈 -->
<circle cx="{{structure.outerCircle.cx}}" cy="{{structure.outerCircle.cy}}"
r="{{structure.outerCircle.r}}" fill="none"
stroke="{{theme.borderColor}}" stroke-width="{{theme.borderWidth}}"/>
<!-- 内圈 -->
<circle cx="{{structure.innerCircle.cx}}" cy="{{structure.innerCircle.cy}}"
r="{{structure.innerCircle.r}}" fill="none"
stroke="{{theme.borderColor}}" stroke-width="{{theme.borderWidth}}"/>
<!-- 宫位分割线 -->
{{palaceDividers}}
<!-- 宫位内容 -->
{{palaceContents}}
<!-- 中心区域 -->
{{centerContent}}
<!-- 装饰元素 -->
{{decorations}}
</svg>
`,
});
// 现代轮盘模板
this.templates.set("modern", {
width: 800,
height: 800,
viewBox: "0 0 800 800",
structure: {
outerRadius: 380,
innerRadius: 150,
palaces: this.generatePalacePositions("modern"),
centerArea: { x: 250, y: 250, width: 300, height: 300 },
},
template: `
<svg width="{{width}}" height="{{height}}" viewBox="{{viewBox}}" xmlns="http://www.w3.org/2000/svg">
<defs>
{{gradients}}
{{patterns}}
{{filters}}
</defs>
<!-- 背景渐变 -->
<rect width="100%" height="100%" fill="url(#backgroundGradient)"/>
<!-- 宫位扇形 -->
{{palaceSectors}}
<!-- 宫位内容 -->
{{palaceContents}}
<!-- 中心圆形 -->
<circle cx="400" cy="400" r="{{structure.innerRadius}}"
fill="{{theme.centerFill}}" stroke="{{theme.borderColor}}"
stroke-width="{{theme.borderWidth}}"/>
<!-- 中心内容 -->
{{centerContent}}
<!-- 装饰和标签 -->
{{decorations}}
</svg>
`,
});
// 网格布局模板
this.templates.set("grid", {
width: 900,
height: 600,
viewBox: "0 0 900 600",
structure: {
rows: 3,
cols: 4,
cellWidth: 200,
cellHeight: 180,
margin: 25,
palaces: this.generateGridPositions(),
},
template: `
<svg width="{{width}}" height="{{height}}" viewBox="{{viewBox}}" xmlns="http://www.w3.org/2000/svg">
<defs>
{{gradients}}
{{patterns}}
{{filters}}
</defs>
<!-- 背景 -->
<rect width="100%" height="100%" fill="{{theme.background}}"/>
<!-- 网格单元格 -->
{{gridCells}}
<!-- 宫位内容 -->
{{palaceContents}}
<!-- 连接线 -->
{{connections}}
<!-- 标题和说明 -->
{{annotations}}
</svg>
`,
});
// 星曜关系图模板
this.templates.set("relationship", {
width: 1000,
height: 800,
viewBox: "0 0 1000 800",
structure: {
centerNode: { x: 500, y: 400, r: 60 },
nodeRadius: 30,
linkDistance: 200,
},
template: `
<svg width="{{width}}" height="{{height}}" viewBox="{{viewBox}}" xmlns="http://www.w3.org/2000/svg">
<defs>
{{gradients}}
{{patterns}}
{{filters}}
{{markers}}
</defs>
<!-- 背景 -->
<rect width="100%" height="100%" fill="{{theme.background}}"/>
<!-- 连接线 -->
{{relationships}}
<!-- 星曜节点 -->
{{starNodes}}
<!-- 标签和说明 -->
{{labels}}
<!-- 图例 -->
{{legend}}
</svg>
`,
});
}
/**
* 初始化默认主题
*/
initializeDefaultThemes() {
// 经典主题
this.themes.set("classic", {
name: "经典",
background: "#f8f9fa",
borderColor: "#2c3e50",
borderWidth: 2,
textColor: "#2c3e50",
primaryColor: "#3498db",
secondaryColor: "#e74c3c",
accentColor: "#f39c12",
centerFill: "#ecf0f1",
palaceColors: {
destiny: "#3498db",
siblings: "#2ecc71",
spouse: "#e74c3c",
children: "#f39c12",
wealth: "#9b59b6",
health: "#1abc9c",
travel: "#34495e",
friends: "#e67e22",
career: "#c0392b",
property: "#27ae60",
fortune: "#8e44ad",
parents: "#16a085",
},
starColors: {
main: "#2c3e50",
auxiliary: "#7f8c8d",
malefic: "#e74c3c",
benefic: "#27ae60",
neutral: "#95a5a6",
},
gradients: {
background: "linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%)",
palace:
"linear-gradient(45deg, rgba(255,255,255,0.8) 0%, rgba(240,240,240,0.8) 100%)",
},
});
// 暗色主题
this.themes.set("dark", {
name: "暗色",
background: "#1a1a1a",
borderColor: "#4a90e2",
borderWidth: 2,
textColor: "#ffffff",
primaryColor: "#4a90e2",
secondaryColor: "#ff6b6b",
accentColor: "#ffd93d",
centerFill: "#2d2d2d",
palaceColors: {
destiny: "#4a90e2",
siblings: "#6bcf7f",
spouse: "#ff6b6b",
children: "#ffd93d",
wealth: "#bd93f9",
health: "#8be9fd",
travel: "#6272a4",
friends: "#ffb86c",
career: "#ff5555",
property: "#50fa7b",
fortune: "#bd93f9",
parents: "#8be9fd",
},
starColors: {
main: "#f8f8f2",
auxiliary: "#6272a4",
malefic: "#ff5555",
benefic: "#50fa7b",
neutral: "#6272a4",
},
gradients: {
background: "linear-gradient(135deg, #1a1a1a 0%, #2d2d2d 100%)",
palace:
"linear-gradient(45deg, rgba(68,68,68,0.8) 0%, rgba(45,45,45,0.8) 100%)",
},
});
// 中国风主题
this.themes.set("chinese", {
name: "中国风",
background: "#faf8f3",
borderColor: "#8b4513",
borderWidth: 3,
textColor: "#2f1b14",
primaryColor: "#dc143c",
secondaryColor: "#ffd700",
accentColor: "#228b22",
centerFill: "#fff8dc",
palaceColors: {
destiny: "#dc143c",
siblings: "#228b22",
spouse: "#ff69b4",
children: "#ffd700",
wealth: "#9370db",
health: "#20b2aa",
travel: "#4682b4",
friends: "#ff8c00",
career: "#b22222",
property: "#32cd32",
fortune: "#8a2be2",
parents: "#008b8b",
},
starColors: {
main: "#8b0000",
auxiliary: "#8b4513",
malefic: "#dc143c",
benefic: "#228b22",
neutral: "#696969",
},
gradients: {
background: "linear-gradient(135deg, #faf8f3 0%, #f0e68c 100%)",
palace:
"linear-gradient(45deg, rgba(255,248,220,0.9) 0%, rgba(240,230,140,0.7) 100%)",
},
patterns: {
traditional: "url(#chinesePattern)",
},
});
// 简约主题
this.themes.set("minimal", {
name: "简约",
background: "#ffffff",
borderColor: "#333333",
borderWidth: 1,
textColor: "#333333",
primaryColor: "#007acc",
secondaryColor: "#ff6b35",
accentColor: "#4caf50",
centerFill: "#f9f9f9",
palaceColors: {
destiny: "#007acc",
siblings: "#4caf50",
spouse: "#ff6b35",
children: "#ffc107",
wealth: "#9c27b0",
health: "#00bcd4",
travel: "#607d8b",
friends: "#ff9800",
career: "#f44336",
property: "#8bc34a",
fortune: "#673ab7",
parents: "#009688",
},
starColors: {
main: "#333333",
auxiliary: "#666666",
malefic: "#f44336",
benefic: "#4caf50",
neutral: "#999999",
},
gradients: {
background: "#ffffff",
palace: "rgba(249,249,249,0.8)",
},
});
}
/**
* 初始化图表类型
*/
initializeChartTypes() {
this.chartTypes.set("traditional_chart", {
name: "传统命盘",
template: "traditional",
defaultTheme: "chinese",
generator: this.generateTraditionalChart.bind(this),
});
this.chartTypes.set("modern_wheel", {
name: "现代轮盘",
template: "modern",
defaultTheme: "classic",
generator: this.generateModernWheel.bind(this),
});
this.chartTypes.set("grid_layout", {
name: "网格布局",
template: "grid",
defaultTheme: "minimal",
generator: this.generateGridLayout.bind(this),
});
this.chartTypes.set("star_relationship", {
name: "星曜关系图",
template: "relationship",
defaultTheme: "dark",
generator: this.generateStarRelationship.bind(this),
});
this.chartTypes.set("fortune_timeline", {
name: "运势时间线",
template: "timeline",
defaultTheme: "classic",
generator: this.generateFortuneTimeline.bind(this),
});
this.chartTypes.set("compatibility_radar", {
name: "合婚雷达图",
template: "radar",
defaultTheme: "minimal",
generator: this.generateCompatibilityRadar.bind(this),
});
}
/**
* 生成SVG图表
*/
async generateChart(chartData, options = {}) {
const {
type = "traditional_chart",
theme = null,
customTemplate = null,
width = null,
height = null,
animations = false,
interactive = false,
} = options;
try {
// 获取图表类型配置
const chartType = this.chartTypes.get(type);
if (!chartType) {
throw new Error(`不支持的图表类型: ${type}`);
}
// 获取模板
const template = customTemplate || this.templates.get(chartType.template);
if (!template) {
throw new Error(`找不到模板: ${chartType.template}`);
}
// 获取主题
const selectedTheme = theme
? this.themes.get(theme)
: this.themes.get(chartType.defaultTheme);
if (!selectedTheme) {
throw new Error(`找不到主题: ${theme || chartType.defaultTheme}`);
}
// 调整尺寸
const finalTemplate = this.adjustTemplateDimensions(
template,
width,
height,
);
// 生成图表内容
const chartContent = await chartType.generator(
chartData,
finalTemplate,
selectedTheme,
options,
);
// 渲染SVG
const svg = this.renderTemplate(
finalTemplate,
selectedTheme,
chartContent,
);
// 添加动画和交互
const enhancedSvg = this.addEnhancements(svg, {
animations,
interactive,
});
return {
success: true,
svg: enhancedSvg,
metadata: {
type: type,
theme: selectedTheme.name,
template: chartType.template,
dimensions: {
width: finalTemplate.width,
height: finalTemplate.height,
},
features: {
animations: animations,
interactive: interactive,
},
},
};
} catch (error) {
return {
success: false,
error: error.message,
timestamp: new Date().toISOString(),
};
}
}
/**
* 渲染模板
*/
renderTemplate(template, theme, content) {
let svg = template.template;
// 替换基础变量
svg = svg.replace(/{{width}}/g, template.width);
svg = svg.replace(/{{height}}/g, template.height);
svg = svg.replace(/{{viewBox}}/g, template.viewBox);
// 替换主题变量
svg = this.replaceThemeVariables(svg, theme);
// 替换内容变量
svg = this.replaceContentVariables(svg, content);
// 生成定义元素
const defs = this.generateDefs(theme);
svg = svg.replace(/{{gradients}}/g, defs.gradients);
svg = svg.replace(/{{patterns}}/g, defs.patterns);
svg = svg.replace(/{{filters}}/g, defs.filters);
svg = svg.replace(/{{markers}}/g, defs.markers || "");
return svg;
}
/**
* 替换主题变量
*/
replaceThemeVariables(svg, theme) {
// 替换主题颜色
Object.keys(theme).forEach((key) => {
if (typeof theme[key] === "string") {
const regex = new RegExp(`{{theme\.${key}}}`, "g");
svg = svg.replace(regex, theme[key]);
}
});
return svg;
}
/**
* 替换内容变量
*/
replaceContentVariables(svg, content) {
Object.keys(content).forEach((key) => {
const regex = new RegExp(`{{${key}}}`, "g");
svg = svg.replace(regex, content[key] || "");
});
return svg;
}
/**
* 生成定义元素
*/
generateDefs(theme) {
const gradients = this.generateGradients(theme);
const patterns = this.generatePatterns(theme);
const filters = this.generateFilters();
const markers = this.generateMarkers(theme);
return { gradients, patterns, filters, markers };
}
/**
* 生成渐变定义
*/
generateGradients(theme) {
return `
<linearGradient id="backgroundGradient" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" style="stop-color:${theme.background};stop-opacity:1" />
<stop offset="100%" style="stop-color:${this.adjustColor(theme.background, -10)};stop-opacity:1" />
</linearGradient>
<radialGradient id="palaceGradient" cx="50%" cy="50%" r="50%">
<stop offset="0%" style="stop-color:rgba(255,255,255,0.8);stop-opacity:1" />
<stop offset="100%" style="stop-color:rgba(240,240,240,0.6);stop-opacity:1" />
</radialGradient>
<linearGradient id="starGradient" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" style="stop-color:${theme.primaryColor};stop-opacity:1" />
<stop offset="100%" style="stop-color:${this.adjustColor(theme.primaryColor, -20)};stop-opacity:1" />
</linearGradient>
`;
}
/**
* 生成图案定义
*/
generatePatterns(theme) {
if (theme.name === "中国风") {
return `
<pattern id="chinesePattern" x="0" y="0" width="20" height="20" patternUnits="userSpaceOnUse">
<rect width="20" height="20" fill="${theme.background}"/>
<circle cx="10" cy="10" r="1" fill="${theme.accentColor}" opacity="0.3"/>
</pattern>
`;
}
return "";
}
/**
* 生成滤镜定义
*/
generateFilters() {
return `
<filter id="shadow" x="-20%" y="-20%" width="140%" height="140%">
<feDropShadow dx="2" dy="2" stdDeviation="3" flood-opacity="0.3"/>
</filter>
<filter id="glow" x="-20%" y="-20%" width="140%" height="140%">
<feGaussianBlur stdDeviation="3" result="coloredBlur"/>
<feMerge>
<feMergeNode in="coloredBlur"/>
<feMergeNode in="SourceGraphic"/>
</feMerge>
</filter>
`;
}
/**
* 生成箭头标记
*/
generateMarkers(theme) {
return `
<marker id="arrowhead" markerWidth="10" markerHeight="7"
refX="9" refY="3.5" orient="auto">
<polygon points="0 0, 10 3.5, 0 7" fill="${theme.borderColor}" />
</marker>
`;
}
/**
* 生成传统命盘
*/
generateTraditionalChart(chartData, template, theme, options) {
const content = {
palaceDividers: this.generatePalaceDividers(template, theme),
palaceContents: this.generatePalaceContents(
chartData.palaces,
template,
theme,
"traditional",
),
centerContent: this.generateCenterContent(
chartData.info,
template,
theme,
),
decorations: this.generateTraditionalDecorations(template, theme),
};
return content;
}
/**
* 生成现代轮盘
*/
generateModernWheel(chartData, template, theme, options) {
const content = {
palaceSectors: this.generatePalaceSectors(template, theme),
palaceContents: this.generatePalaceContents(
chartData.palaces,
template,
theme,
"modern",
),
centerContent: this.generateCenterContent(
chartData.info,
template,
theme,
),
decorations: this.generateModernDecorations(template, theme),
};
return content;
}
/**
* 生成网格布局
*/
generateGridLayout(chartData, template, theme, options) {
const content = {
gridCells: this.generateGridCells(template, theme),
palaceContents: this.generatePalaceContents(
chartData.palaces,
template,
theme,
"grid",
),
connections: this.generateConnections(template, theme),
annotations: this.generateAnnotations(chartData, template, theme),
};
return content;
}
/**
* 生成星曜关系图
*/
generateStarRelationship(chartData, template, theme, options) {
const content = {
relationships: this.generateRelationshipLines(chartData, template, theme),
starNodes: this.generateStarNodes(chartData, template, theme),
labels: this.generateNodeLabels(chartData, template, theme),
legend: this.generateLegend(template, theme),
};
return content;
}
/**
* 调整模板尺寸
*/
adjustTemplateDimensions(template, width, height) {
if (!width && !height) return template;
const adjusted = { ...template };
if (width) {
const scale = width / template.width;
adjusted.width = width;
adjusted.height = Math.round(template.height * scale);
} else if (height) {
const scale = height / template.height;
adjusted.height = height;
adjusted.width = Math.round(template.width * scale);
}
adjusted.viewBox = `0 0 ${adjusted.width} ${adjusted.height}`;
return adjusted;
}
/**
* 添加动画和交互增强
*/
addEnhancements(svg, options) {
let enhanced = svg;
if (options.animations) {
enhanced = this.addAnimations(enhanced);
}
if (options.interactive) {
enhanced = this.addInteractivity(enhanced);
}
return enhanced;
}
/**
* 添加动画效果
*/
addAnimations(svg) {
// 添加淡入动画
const fadeInAnimation = `
<style>
.fade-in {
animation: fadeIn 1s ease-in-out;
}
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
.rotate {
animation: rotate 20s linear infinite;
transform-origin: center;
}
@keyframes rotate {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
</style>
`;
return svg.replace("<svg", fadeInAnimation + '<svg class="fade-in"');
}
/**
* 添加交互功能
*/
addInteractivity(svg) {
const interactiveScript = `
<script><![CDATA[
function showTooltip(evt, text) {
const tooltip = document.getElementById('tooltip');
tooltip.textContent = text;
tooltip.style.display = 'block';
tooltip.setAttribute('x', evt.clientX + 10);
tooltip.setAttribute('y', evt.clientY - 10);
}
function hideTooltip() {
document.getElementById('tooltip').style.display = 'none';
}
]]></script>
<text id="tooltip" x="0" y="0" fill="black"
style="display:none; background:white; padding:5px; border:1px solid black;"/>
`;
return svg.replace("</svg>", interactiveScript + "</svg>");
}
// 辅助方法
adjustColor(color, percent) {
const num = parseInt(color.replace("#", ""), 16);
const amt = Math.round(2.55 * percent);
const R = (num >> 16) + amt;
const G = ((num >> 8) & 0x00ff) + amt;
const B = (num & 0x0000ff) + amt;
return (
"#" +
(
0x1000000 +
(R < 255 ? (R < 1 ? 0 : R) : 255) * 0x10000 +
(G < 255 ? (G < 1 ? 0 : G) : 255) * 0x100 +
(B < 255 ? (B < 1 ? 0 : B) : 255)
)
.toString(16)
.slice(1)
);
}
generatePalacePositions(type) {
// 根据类型生成宫位位置
if (type === "traditional") {
return [
{ id: "destiny", angle: 0, radius: 200 },
{ id: "siblings", angle: 30, radius: 200 },
// ... 其他宫位
];
}
return [];
}
generateGridPositions() {
const positions = [];
for (let row = 0; row < 3; row++) {
for (let col = 0; col < 4; col++) {
positions.push({
x: 25 + col * 225,
y: 25 + row * 200,
width: 200,
height: 180,
});
}
}
return positions;
}
// 其他生成方法的占位符
generatePalaceDividers(template, theme) {
return "";
}
generatePalaceContents(palaces, template, theme, type) {
return "";
}
generateCenterContent(info, template, theme) {
return "";
}
generateTraditionalDecorations(template, theme) {
return "";
}
generatePalaceSectors(template, theme) {
return "";
}
generateModernDecorations(template, theme) {
return "";
}
generateGridCells(template, theme) {
return "";
}
generateConnections(template, theme) {
return "";
}
generateAnnotations(chartData, template, theme) {
return "";
}
generateRelationshipLines(chartData, template, theme) {
return "";
}
generateStarNodes(chartData, template, theme) {
return "";
}
generateNodeLabels(chartData, template, theme) {
return "";
}
generateLegend(template, theme) {
return "";
}
}
module.exports = {
EnhancedSVGGenerator,
};