益智教育网

2025最新思维导图源码有哪些?可商用吗?

  1. 使用现有库/框架的源码:这是最常见和高效的方式,即使用成熟的 JavaScript 库(如 Mind-.js, JointJS, GoJS 等)来创建思维导图,我会提供几个主流库的源码示例。
  2. 从零开始编写的源码:这涉及到大量的 Canvas 或 SVG 操作,以及复杂的交互逻辑,我会提供一个极简的、从零开始的 SVG 思维导图示例,帮助你理解其核心原理。
  3. 相关资源链接:提供一些优秀的开源项目、教程和工具,供你深入学习。

使用现有库(推荐)

对于大多数项目来说,直接使用成熟的库是最佳选择,它们功能强大、稳定,并且有良好的社区支持。

示例 1:使用 Mind-Map 库 (简单易用)

这是一个非常轻量且易于集成的库。

安装

npm install mind-map
# 或者直接在 HTML 中引入 CDN

HTML 代码 (index.html)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">思维导图示例</title>
    <!-- 引入 Mind-Map 的 CSS 和 JS -->
    <link rel="stylesheet" href="https://unpkg.com/mind-map/dist/mind-map.css">
    <script src="https://unpkg.com/mind-map/dist/mind-map.js"></script>
    <style>
        body, html {
            margin: 0;
            padding: 0;
            width: 100%;
            height: 100%;
            overflow: hidden;
        }
        #mindMap {
            width: 100%;
            height: 100%;
        }
    </style>
</head>
<body>
    <div id="mindMap"></div>
    <script>
        // 定义思维导图数据
        const data = {
            "data": {
                "text": "中心主题"
            },
            "children": [
                {
                    "data": {
                        "text": "分支 1"
                    },
                    "children": [
                        { "data": { "text": "子分支 1.1" } },
                        { "data": { "text": "子分支 1.2" } }
                    ]
                },
                {
                    "data": {
                        "text": "分支 2"
                    },
                    "children": [
                        { "data": { "text": "子分支 2.1" } },
                        { "data": { "text": "子分支 2.2" } }
                    ]
                }
            ]
        };
        // 初始化思维导图
        const mindMap = new MindMap({
            el: document.getElementById('mindMap'), // 挂载的 DOM 元素
            data: data, // 数据
            theme: 'classic' // 主题
        });
    </script>
</body>
</html>

源码解析

  • 这个“源码”主要是 HTML 和 JavaScript 的组合。
  • mind-map.jsmind-map.css 是库的核心源码,你可以在其 GitHub 仓库中找到,我们通过 CDN 引入它们,然后调用 new MindMap() 来实例化一个导图实例。
  • data 对象是导图的数据结构,通常是嵌套的 JSON,每个节点包含 text (文本) 和 children (子节点)。

示例 2:使用 JointJS (功能强大,适合流程图和复杂图表)

JointJS 是一个更底层的图表库,可以用来构建非常复杂的图形应用,包括思维导图。

安装

npm install jointjs

HTML 代码 (index.html)

<!DOCTYPE html>
<html>
<head>JointJS 思维导图</title>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jointjs/3.7.0/joint.min.css" />
    <style>
        body {
            margin: 0;
            padding: 0;
            width: 100%;
            height: 100vh;
            display: flex;
            flex-direction: column;
        }
        #paper {
            flex: 1;
            background-color: #f5f5f5;
        }
    </style>
</head>
<body>
    <div id="paper"></div>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/backbone.js/1.4.1/backbone-min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jointjs/3.7.0/joint.min.js"></script>
    <script>
        // 创建画布 (Paper)
        const paper = new joint.dia.Paper({
            el: document.getElementById('paper'),
            width: '100%',
            height: '100%',
            model: new joint.dia.Graph(), // 关联一个图模型
            gridSize: 1,
            drawGrid: true,
            background: {
                color: '#ffffff'
            },
            interactive: true,
            snapLinks: { radius: 5 },
            linkPinning: false,
            highlighting: {
                'default': {
                    name: 'stroke',
                    options: {
                        padding: 2,
                        rx: 5,
                        ry: 5,
                        attrs: {
                            'stroke-width': 2,
                            stroke: 'rgba(255, 255, 255, 0.5)',
                            'fill-opacity': 0
                        }
                    }
                }
            }
        });
        // 定义节点和链接的默认样式
        const nodeDefaults = {
            attrs: {
                body: {
                    fill: '#ffffff',
                    stroke: '#333333',
                    strokeWidth: 2,
                    rx: 5,
                    ry: 5
                },
                label: {
                    textVerticalAnchor: 'middle',
                    textAnchor: 'middle',
                    fontSize: 14,
                    fill: '#333333'
                }
            }
        };
        // 创建中心节点
        const centerNode = new joint.shapes.standard.Rectangle({
            position: { x: 400, y: 250 },
            size: { width: 120, height: 60 },
            attrs: {
                body: { fill: '#4a90e2' },
                label: { text: '中心主题' }
            }
        });
        // 创建分支节点
        const branchNode1 = new joint.shapes.standard.Rectangle({
            position: { x: 200, y: 150 },
            size: { width: 100, height: 50 },
            attrs: {
                body: { fill: '#7ed321' },
                label: { text: '分支 1' }
            }
        });
        const branchNode2 = new joint.shapes.standard.Rectangle({
            position: { x: 200, y: 350 },
            size: { width: 100, height: 50 },
            attrs: {
                body: { fill: '#f5a623' },
                label: { text: '分支 2' }
            }
        });
        // 创建连接线
        const link1 = new joint.shapes.standard.Link({
            source: { id: centerNode.id },
            target: { id: branchNode1.id },
            attrs: {
                line: {
                    stroke: '#333333',
                    strokeWidth: 2
                }
            }
        });
        const link2 = new joint.shapes.standard.Link({
            source: { id: centerNode.id },
            target: { id: branchNode2.id },
            attrs: {
                line: {
                    stroke: '#333333',
                    strokeWidth: 2
                }
            }
        });
        // 将所有元素添加到图中
        paper.model.addCell([centerNode, branchNode1, branchNode2, link1, link2]);
    </script>
</body>
</html>

源码解析

  • JointJS 的核心是 Graph (图)Paper (画布),Graph 存储所有节点和链接的数据,Paper 负责渲染和交互。
  • joint.shapes.standard.Rectangle 是一个预定义的矩形节点。
  • joint.shapes.standard.Link 是一个预定义的链接。
  • 通过 sourcetarget 属性将链接与节点连接起来。
  • 你可以在 JointJS GitHub 找到其完整的源码和文档。

从零开始编写一个极简版 SVG 思维导图

这个示例不依赖任何库,直接使用原生 JavaScript 和 SVG 来实现,它能帮助你理解思维导图渲染和交互的本质。

HTML 代码 (index.html)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">原生 SVG 思维导图</title>
    <style>
        body {
            margin: 0;
            padding: 20px;
            font-family: sans-serif;
            background-color: #f0f0f0;
        }
        #map-container {
            background-color: white;
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0,0,0,0.1);
            overflow: auto;
        }
        .node {
            cursor: pointer;
        }
        .node text {
            user-select: none; /* 防止文本被选中 */
            pointer-events: none; /* 让鼠标事件穿透文本,作用在 rect 上 */
        }
        .link {
            fill: none;
            stroke: #999;
            stroke-width: 2px;
        }
    </style>
</head>
<body>
    <h1>原生 SVG 思维导图</h1>
    <div id="map-container"></div>
    <script>
        // 1. 定义数据
        const mindMapData = {
            id: 'root',
            name: '中心主题',
            children: [
                {
                    id: 'c1',
                    name: '分支 1',
                    children: [
                        { id: 'c1-1', name: '子分支 1.1' },
                        { id: 'c1-2', name: '子分支 1.2' }
                    ]
                },
                {
                    id: 'c2',
                    name: '分支 2',
                    children: [
                        { id: 'c2-1', name: '子分支 2.1' },
                        { id: 'c2-2', name: '子分支 2.2' }
                    ]
                }
            ]
        };
        // 2. 渲染函数
        function renderMindMap(data, container, x = 400, y = 50, level = 0) {
            const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
            svg.setAttribute('width', '100%');
            svg.setAttribute('height', '600'); // 固定高度,可动态计算
            container.appendChild(svg);
            // 递归渲染节点和连接线
            function renderNode(node, parentX, parentY, currentX, currentY) {
                // 创建连接线
                if (parentX !== null && parentY !== null) {
                    const link = document.createElementNS('http://www.w3.org/2000/svg', 'path');
                    const d = `M ${parentX} ${parentY} C ${parentX} ${parentY + 50}, ${currentX} ${currentY - 50}, ${currentX} ${currentY}`;
                    link.setAttribute('d', d);
                    link.setAttribute('class', 'link');
                    svg.appendChild(link);
                }
                // 创建节点组
                const nodeGroup = document.createElementNS('http://www.w3.org/2000/svg', 'g');
                nodeGroup.setAttribute('class', 'node');
                nodeGroup.setAttribute('transform', `translate(${currentX - 50}, ${currentY - 20})`);
                // 创建节点矩形
                const rect = document.createElementNS('http://www.w3.org/2000/svg', 'rect');
                rect.setAttribute('width', '100');
                rect.setAttribute('height', '40');
                rect.setAttribute('rx', '5');
                rect.setAttribute('ry', '5');
                rect.setAttribute('fill', level === 0 ? '#4a90e2' : (level === 1 ? '#7ed321' : '#f5a623'));
                // 创建节点文本
                const text = document.createElementNS('http://www.w3.org/2000/svg', 'text');
                text.setAttribute('x', '50');
                text.setAttribute('y', '25');
                text.setAttribute('text-anchor', 'middle');
                text.setAttribute('dominant-baseline', 'middle');
                text.setAttribute('fill', 'white');
                text.textContent = node.name;
                nodeGroup.appendChild(rect);
                nodeGroup.appendChild(text);
                svg.appendChild(nodeGroup);
                // 递归渲染子节点
                if (node.children && node.children.length > 0) {
                    const childCount = node.children.length;
                    const spacing = 150; // 子节点之间的水平间距
                    const startX = currentX - (spacing * (childCount - 1)) / 2;
                    node.children.forEach((child, index) => {
                        const childX = startX + index * spacing;
                        const childY = currentY + 120; // 子节点的垂直偏移
                        renderNode(child, currentX, currentY, childX, childY, level + 1);
                    });
                }
            }
            // 从根节点开始渲染
            renderNode(data, null, null, x, y, 0);
        }
        // 3. 执行渲染
        const container = document.getElementById('map-container');
        renderMindMap(mindMapData, container);
    </script>
</body>
</html>

源码解析

  • 数据结构:依然是一个嵌套的 JSON 对象。
  • SVG:所有图形元素(<rect>, <text>, <path>)都在 SVG 画布上创建。
  • 递归渲染renderNode 函数是核心,它负责创建当前节点的图形,然后递归地为每个子节点调用自身,并计算子节点的位置。
  • 布局算法:这是一个非常简单的层级式布局,父节点在上方,子节点在下方水平排列,更复杂的布局(如树形、径向形)需要更复杂的算法。
  • 交互:这个版本没有添加拖拽、编辑等交互,但通过 cursor: pointeraddEventListener 可以轻松添加。

相关资源与工具

如果你想深入研究或寻找更多灵感,可以看看以下资源:

  1. GitHub 开源项目:

    • Mind-Map: 一个功能丰富、高度可定制的中文思维导图库。
    • JointJS: 强大的图表库,可以画思维导图、流程图、UML 图等。
    • GoJS: 商业级的图形库,功能极其强大,有免费版和付费版。
    • D3.js: 数据驱动文档的库,它不是一个“思维导图库”,而是构建任何数据可视化的底层工具,使用 D3 可以实现任何你想要的思维导图效果,但学习曲线较陡。
  2. 在线工具:

    • XMind: 付费/免费,桌面端和在线版都非常流行。
    • MindNode: Mac/iOS 平台上的优秀工具。
    • Miro: 在线白板工具,内置强大的思维导图功能。
方案 优点 缺点 适用场景
使用现有库 开发快、功能稳定、有文档支持 定制化受限,需要学习库的API 绝大多数项目,尤其是商业项目
从零编写 完全可控、无依赖、能深入理解原理 开发周期长、bug多、需自己实现所有功能 学习研究、高度定制化的特殊需求项目

对于初学者和大多数应用场景,强烈推荐从方案一开始,选择一个合适的库进行开发,当你对思维导图的原理有了深入了解后,再考虑从零编写或对现有库进行深度定制。

分享:
扫描分享到社交APP
上一篇
下一篇