自动根据名称生成er图

<!DOCTYPE html>
<html>
<head>
    <title>ER图生成器(最终版)</title>
    <style>
        .container { margin: 20px; }
        input, button { margin: 5px; }
        svg { border: 1px solid #ccc; margin: 10px; }
        input { width: 300px; }
    </style>
</head>
<body>
    <div class="container">
        <div>
            <label>实体名称:</label>
            <input type="text" id="entityName" placeholder="例如:User" value="User">
        </div>
        <div>
            <label>属性列表(逗号分隔):</label>
            <input type="text" id="attributes" placeholder="例如:id*,name,age" value="id*,username,password,email,created_at,updated_at,profile,status,role,department,phone,address">
            <small>(带*表示主键)</small>
        </div>
        <button onclick="generateER()">生成ER图</button>
    </div>
    <svg id="erDiagram" width="1000" height="800"></svg>

    <script>
        // 几何计算函数
        function getRectIntersection(centerX, centerY, rectWidth, rectHeight, targetX, targetY) {
            const dx = targetX - centerX;
            const dy = targetY - centerY;
            
            if (dx === 0 && dy === 0) return { x: centerX, y: centerY };

            let tx = Infinity;
            let ty = Infinity;

            if (dx !== 0) {
                const edgeX = dx > 0 ? rectWidth / 2 : -rectWidth / 2;
                tx = edgeX / dx;
            }
            
            if (dy !== 0) {
                const edgeY = dy > 0 ? rectHeight / 2 : -rectHeight / 2;
                ty = edgeY / dy;
            }

            const t = Math.min(tx, ty);
            return {
                x: centerX + dx * t,
                y: centerY + dy * t
            };
        }

        function getEllipseIntersection(startX, startY, ellipseX, ellipseY, rx, ry) {
            const deltaX = startX - ellipseX;
            const deltaY = startY - ellipseY;
            
            const a = (deltaX * deltaX) / (rx * rx) + (deltaY * deltaY) / (ry * ry);
            if (a === 0) return { x: ellipseX, y: ellipseY };

            const t = 1 - 1 / Math.sqrt(a);
            return {
                x: startX + (ellipseX - startX) * t,
                y: startY + (ellipseY - startY) * t
            };
        }

        function generateER() {
            const svg = document.getElementById('erDiagram');
            svg.innerHTML = '';
            
            const entityName = document.getElementById('entityName').value.trim();
            const attributes = document.getElementById('attributes').value
                .split(',')
                .filter(attr => attr.trim())
                .map(attr => ({
                    name: attr.replace('*', '').trim(),
                    isPrimary: attr.includes('*')
                }));

            if (!entityName || attributes.length === 0) {
                alert("请填写实体名称和至少一个属性!");
                return;
            }

            // 核心配置参数
            const config = {
                centerX: 500,
                centerY: 400,
                rectWidth: 160,
                rectHeight: 80,
                innerRadius: 200,
                outerRadius: 320,
                minSplitCount: 8,
                ellipseRX: 60,
                ellipseRY: 35
            };

            // 智能分圈系统
            const shouldSplit = attributes.length > config.minSplitCount;
            const groups = shouldSplit ? [
                {
                    attributes: attributes.slice(0, Math.ceil(attributes.length * 0.6)),
                    radius: config.innerRadius,
                    angleOffset: 0
                },
                {
                    attributes: attributes.slice(Math.ceil(attributes.length * 0.6)),
                    radius: config.outerRadius,
                    angleOffset: Math.PI / (attributes.length / 2)
                }
            ] : [{
                attributes: attributes,
                radius: config.innerRadius,
                angleOffset: 0
            }];

            // 绘制实体
            const entityRect = document.createElementNS("http://www.w3.org/2000/svg", "rect");
            entityRect.setAttribute("x", config.centerX - config.rectWidth/2);
            entityRect.setAttribute("y", config.centerY - config.rectHeight/2);
            entityRect.setAttribute("width", config.rectWidth);
            entityRect.setAttribute("height", config.rectHeight);
            entityRect.setAttribute("fill", "#f8f9fa");
            entityRect.setAttribute("stroke", "#333");
            entityRect.setAttribute("stroke-width", 2);
            svg.appendChild(entityRect);

            // 实体名称
            const entityText = document.createElementNS("http://www.w3.org/2000/svg", "text");
            entityText.setAttribute("x", config.centerX);
            entityText.setAttribute("y", config.centerY);
            entityText.setAttribute("text-anchor", "middle");
            entityText.setAttribute("dominant-baseline", "middle");
            entityText.setAttribute("font-weight", "bold");
            entityText.setAttribute("font-size", "18");
            entityText.textContent = entityName;
            svg.appendChild(entityText);

            // 绘制属性和连线
            groups.forEach(group => {
                const angleStep = (2 * Math.PI) / group.attributes.length;
                
                group.attributes.forEach((attr, index) => {
                    const angle = angleStep * index + group.angleOffset;
                    const attrX = config.centerX + group.radius * Math.cos(angle);
                    const attrY = config.centerY + group.radius * Math.sin(angle);

                    // 计算连接点
                    const startPoint = getRectIntersection(
                        config.centerX, config.centerY,
                        config.rectWidth, config.rectHeight,
                        attrX, attrY
                    );
                    
                    const endPoint = getEllipseIntersection(
                        startPoint.x, startPoint.y,
                        attrX, attrY,
                        config.ellipseRX, config.ellipseRY
                    );

                    // 绘制连接线
                    const line = document.createElementNS("http://www.w3.org/2000/svg", "line");
                    line.setAttribute("x1", startPoint.x);
                    line.setAttribute("y1", startPoint.y);
                    line.setAttribute("x2", endPoint.x);
                    line.setAttribute("y2", endPoint.y);
                    line.setAttribute("stroke", "#666");
                    line.setAttribute("stroke-width", 1.5);
                    svg.appendChild(line);

                    // 绘制属性椭圆
                    const ellipse = document.createElementNS("http://www.w3.org/2000/svg", "ellipse");
                    ellipse.setAttribute("cx", attrX);
                    ellipse.setAttribute("cy", attrY);
                    ellipse.setAttribute("rx", config.ellipseRX);
                    ellipse.setAttribute("ry", config.ellipseRY);
                    ellipse.setAttribute("fill", "#fff");
                    ellipse.setAttribute("stroke", "#333");
                    ellipse.setAttribute("stroke-width", 1.2);
                    svg.appendChild(ellipse);

                    // 属性文字
                    const text = document.createElementNS("http://www.w3.org/2000/svg", "text");
                    text.setAttribute("x", attrX);
                    text.setAttribute("y", attrY);
                    text.setAttribute("text-anchor", "middle");
                    text.setAttribute("dominant-baseline", "middle");
                    text.setAttribute("font-size", "14");
                    if(attr.isPrimary) {
                        text.innerHTML = `<tspan style="text-decoration: underline">${attr.name}</tspan>`;
                    } else {
                        text.textContent = attr.name;
                    }
                    svg.appendChild(text);
                });
            });
        }
    </script>
</body>
</html>
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 一、表格元素 1、table元素的基础元素组成 一个可选的 元素 一个可选的 元素 下列任意一个: 零个或...
    小男孩儿长大了阅读 221评论 0 0
  • 第一部分 HTML&CSS整理答案 1. 什么是HTML5? 答:HTML5是最新的HTML标准。 注意:讲述HT...
    kismetajun阅读 27,958评论 1 45
  • 原文链接https://blog.csdn.net/weixin_38536027/article/details...
    衰王之王阅读 1,269评论 0 0
  • 1.1CSS 基础与选择器初识 | CSS 1. CSS 加载方式有几种? CSS样式加载一共有四种方式: 1、行...
    没糖_cristalle阅读 816评论 0 0
  • CSS 面试题汇总 1. 介绍下 BFC 及其应用 参考答案:参考答案:所谓 BFC,指的是一个独立的布局环境,...
    5cc9c8608284阅读 776评论 0 1