Vue中使用mind-map實現(xiàn)在線思維導(dǎo)圖

概述

在前面的文章Vue中實現(xiàn)在線畫流程圖實現(xiàn)中介紹了流程圖的在線繪制,在本文,給大家分享一下基于mind-map實現(xiàn)在線的思維導(dǎo)圖沉唠,并實現(xiàn):1. 導(dǎo)圖導(dǎo)出為圖片步鉴;2. 打開xmind文件状囱。

實現(xiàn)效果

圖標(biāo)選擇
主題選擇
結(jié)構(gòu)選擇

實現(xiàn)

1. mind-map簡介

simple-mind-map(思緒思維導(dǎo)圖)是一個簡單&強(qiáng)大的Web思維導(dǎo)圖庫涉馅,不依賴任何特定框架授账】菖埽可以幫助你快速開發(fā)思維導(dǎo)圖產(chǎn)品。

2. 實現(xiàn)

1)添加依賴

{
    "simple-mind-map": "^0.10.2-fix.1",
}

2)引入插件

import MindMap from 'simple-mind-map'

3)插件導(dǎo)入

import MiniMap from 'simple-mind-map/src/plugins/MiniMap.js'
import Watermark from 'simple-mind-map/src/plugins/Watermark.js'
import KeyboardNavigation from 'simple-mind-map/src/plugins/KeyboardNavigation.js'
import ExportPDF from 'simple-mind-map/src/plugins/ExportPDF.js'
import ExportXMind from 'simple-mind-map/src/plugins/ExportXMind.js'
import Export from 'simple-mind-map/src/plugins/Export.js'
import Drag from 'simple-mind-map/src/plugins/Drag.js'
import Select from 'simple-mind-map/src/plugins/Select.js'
import AssociativeLine from 'simple-mind-map/src/plugins/AssociativeLine.js'
import TouchEvent from 'simple-mind-map/src/plugins/TouchEvent.js'
import NodeImgAdjust from 'simple-mind-map/src/plugins/NodeImgAdjust.js'
import SearchPlugin from 'simple-mind-map/src/plugins/Search.js'
import Painter from 'simple-mind-map/src/plugins/Painter.js'
import Formula from 'simple-mind-map/src/plugins/Formula.js'
import RainbowLines from 'simple-mind-map/src/plugins/RainbowLines.js'
import Demonstrate from 'simple-mind-map/src/plugins/Demonstrate.js'
import OuterFrame from 'simple-mind-map/src/plugins/OuterFrame.js'

// 注冊插件
MindMap.usePlugin(MiniMap)
  .usePlugin(Watermark)
  .usePlugin(Drag)
  .usePlugin(KeyboardNavigation)
  .usePlugin(ExportPDF)
  .usePlugin(ExportXMind)
  .usePlugin(Export)
  .usePlugin(Select)
  .usePlugin(AssociativeLine)
  .usePlugin(NodeImgAdjust)
  .usePlugin(TouchEvent)
  .usePlugin(SearchPlugin)
  .usePlugin(Painter)
  .usePlugin(Formula)
  .usePlugin(RainbowLines)
  .usePlugin(Demonstrate)
  .usePlugin(OuterFrame)

4)自定義主題

import cactus from './themes/cactus'
import classic5 from './themes/classic5'
import classic6 from './themes/classic6'
import classic7 from './themes/classic7'
import dark3 from './themes/dark3'
import dark4 from './themes/dark4'
import darkNightLceBlade from './themes/darkNightLceBlade'
import index from './themes/index'
import lemonBubbles from './themes/lemonBubbles'
import morandi from './themes/morandi'
import neonLamp from './themes/neonLamp'
import oreo from './themes/oreo'
import rose from './themes/rose'
import seaBlueLine from './themes/seaBlueLine'
import shallowSea from './themes/shallowSea'

MindMap.defineTheme('cactus', cactus)
MindMap.defineTheme('classic5', classic5)
MindMap.defineTheme('classic6', classic6)
MindMap.defineTheme('classic7', classic7)
MindMap.defineTheme('dark3', dark3)
MindMap.defineTheme('dark4', dark4)
MindMap.defineTheme('darkNightLceBlade', darkNightLceBlade)
MindMap.defineTheme('index', index)
MindMap.defineTheme('lemonBubbles', lemonBubbles)
MindMap.defineTheme('morandi', morandi)
MindMap.defineTheme('neonLamp', neonLamp)
MindMap.defineTheme('oreo', oreo)
MindMap.defineTheme('rose', rose)
MindMap.defineTheme('seaBlueLine', seaBlueLine)
MindMap.defineTheme('shallowSea', shallowSea)

5)引入圖標(biāo)

import { nodeIconList } from 'simple-mind-map/src/svg/icons'

6)導(dǎo)出圖片

mindMapInstance.export('png', true, this.name)

7)打開xmind文件

import xmind from 'simple-mind-map/src/parse/xmind.js'

{
  methods:{
      ElMessageBox.confirm('是否直接替換當(dāng)前思維導(dǎo)圖?', '警告', {
        confirmButtonText: '確認(rèn)',
        cancelButtonText: '取消',
        type: 'warning',
      })
     .then(() => {
          const { raw } = file
          xmind.parseXmindFile(raw).then(data => {
            that.setData(data)
          })
        })
        .catch(() => {})
     }
}

完整代碼如下:

<template>
  <div class="mind-map-container">
    <div class="mindmap-tools" v-show="!readonly">
      <el-upload
        ref="upload"
        style="margin-right: 0.8rem"
        :limit="1"
        :on-change="handleChange"
        :show-file-list="false"
        :accept="'.xmind'"
        :auto-upload="false"
      >
        <template #trigger>
          <el-button class="my-button" size="small">
            <div class="my-button">
              <svg
                t="1720518684993"
                class="icon"
                viewBox="0 0 1024 1024"
                version="1.1"
                xmlns="http://www.w3.org/2000/svg"
                p-id="29039"
                width="32"
                height="32"
              >
                <path
                  d="M910.19 175.16L776.1 41.07A136.94 136.94 0 0 0 679.27 1H235A161.29 161.29 0 0 0 73.69 162.25v699.5A161.29 161.29 0 0 0 235 1023h554a161.29 161.29 0 0 0 161.31-161.25V272a136.89 136.89 0 0 0-40.12-96.84z m-148.8 459.72c-1.53 8-14.94 8.24-36.72 11.59s-95.51 17.6-103 17.6-12.56-11.31-13.4-14.66-9.35-33.24-20.53-46.92-49.74-54.17-112.86-51.66-68.14 49.57-69.82 64.65 2.52 30.16-10.89 32.67-103 19.27-109.33 19.69-11.31-4.19-10.89-20.11 6.28-45.24 31.84-65.35 93.83-48.17 100.95-52.38 10.47-7.54 8-13.82-46.54-21.76-65.39-30.18-54.45-26-71.21-54.87-17.59-42.73-15.08-46.92S274 378 274 378s125.67-23 131.53-21.78 16.76 39.37 20.94 47.33 30.16 61.58 93.42 58.64 52.78-41 49.42-53-8.16-22.44-1.46-25.8 108.28-20.52 115.4-19.68 19.27 4.47 18.71 31.83-6.56 46.92-27.93 60.32-65.48 19.55-68.13 26.39 5.58 12.43 25.41 21.36 72.88 36 88.8 51.67 46.59 56.43 41.28 79.6z"
                  p-id="29040"
                  fill="currentColor"
                ></path>
              </svg>
              <div>打開xmind文件</div>
            </div>
          </el-button>
        </template>
      </el-upload>
      <el-button
        :disabled="activeNodes.length === 0"
        class="my-button"
        size="small"
        @click="addNode"
      >
        <div class="my-button">
          <svg
            t="1719284042715"
            class="icon"
            viewBox="0 0 1024 1024"
            version="1.1"
            xmlns="http://www.w3.org/2000/svg"
            p-id="32998"
            width="32"
            height="32"
          >
            <path
              d="M510.833431 62.695924c-247.644193 0-448.406636 200.762443-448.406636 448.406636 0 247.65545 200.762443 448.416869 448.406636 448.416869 247.65545 0 448.416869-200.76142 448.416869-448.416869C959.2503 263.458367 758.488881 62.695924 510.833431 62.695924zM779.544429 562.112328 560.358381 562.112328l0 219.186048-102.008278 0L458.350103 562.112328 239.164055 562.112328l0-102.008278 219.186048 0L458.350103 240.918002l102.008278 0 0 219.186048 219.186048 0L779.544429 562.112328z"
              fill="currentColor"
              p-id="32999"
            ></path>
          </svg>
          <div>添加同級節(jié)點</div>
        </div>
      </el-button>
      <el-button
        :disabled="activeNodes.length === 0"
        class="my-button"
        size="small"
        @click="addChildNode"
      >
        <div class="my-button">
          <svg
            t="1719283662028"
            class="icon"
            viewBox="0 0 1024 1024"
            version="1.1"
            xmlns="http://www.w3.org/2000/svg"
            p-id="23087"
            width="32"
            height="32"
          >
            <path
              d="M739.555556 0a56.888889 56.888889 0 0 1 56.888888 56.888889v227.555555a56.888889 56.888889 0 0 1-56.888888 56.888889H227.555556v455.111111h170.666666v-56.888888a56.888889 56.888889 0 0 1 56.888889-56.888889h512a56.888889 56.888889 0 0 1 56.888889 56.888889v227.555555a56.888889 56.888889 0 0 1-56.888889 56.888889H455.111111a56.888889 56.888889 0 0 1-56.888889-56.888889v-56.888889H170.666667a56.888889 56.888889 0 0 1-56.888889-56.888889V341.333333H56.888889a56.888889 56.888889 0 0 1-56.888889-56.888889V56.888889a56.888889 56.888889 0 0 1 56.888889-56.888889h682.666667z"
              fill="currentColor"
              p-id="23088"
            ></path>
          </svg>
          <div>添加子節(jié)點</div>
        </div>
      </el-button>
      <el-button
        :disabled="activeNodes.length === 0"
        class="my-button"
        size="small"
        @click="dropNode"
      >
        <div class="my-button">
          <svg
            t="1719283698787"
            class="icon"
            viewBox="0 0 1024 1024"
            version="1.1"
            xmlns="http://www.w3.org/2000/svg"
            p-id="24126"
            width="32"
            height="32"
          >
            <path
              d="M316.652201 74.043048L339.889115 28.356912A53.16921 53.16921 0 0 1 386.756789 0h250.486058a53.16921 53.16921 0 0 1 46.867674 28.356912l23.236914 45.686136a53.16921 53.16921 0 0 0 47.261521 28.356913h177.624547A51.987672 51.987672 0 0 1 984.615021 153.599941a51.987672 51.987672 0 0 1-52.381518 51.19998H91.766134A51.987672 51.987672 0 0 1 39.384615 153.599941a51.987672 51.987672 0 0 1 52.381519-51.19998h177.624547a53.16921 53.16921 0 0 0 47.26152-28.356913z m-118.153801 181.956854h630.153604a51.593826 51.593826 0 0 1 52.381518 51.19998v614.399764a101.218423 101.218423 0 0 1-30.719988 72.467664 105.944575 105.944575 0 0 1-74.043048 29.932296H250.879919a105.944575 105.944575 0 0 1-74.043049-29.932296 101.218423 101.218423 0 0 1-30.719988-72.467664V307.199882A51.593826 51.593826 0 0 1 196.923016 255.999902z m52.381519 153.59994v460.799823a51.987672 51.987672 0 0 0 52.775364 51.199981h419.839838a51.987672 51.987672 0 0 0 52.775365-51.199981V409.599842a51.987672 51.987672 0 0 0-52.775365-51.19998H303.655283a51.987672 51.987672 0 0 0-54.350748 51.19998z m157.538401 51.199981a51.987672 51.987672 0 0 1 52.775364 51.19998v255.999902a51.987672 51.987672 0 0 1-52.775364 51.19998 51.987672 51.987672 0 0 1-52.381519-51.19998V511.999803a51.987672 51.987672 0 0 1 50.806135-51.19998z m210.313765 0a51.987672 51.987672 0 0 1 52.381518 51.19998v255.999902a51.987672 51.987672 0 0 1-52.381518 51.19998 51.987672 51.987672 0 0 1-52.775364-51.19998V511.999803a51.987672 51.987672 0 0 1 51.19998-51.19998z"
              p-id="24127"
              fill="currentColor"
            ></path>
          </svg>
          <div>刪除節(jié)點</div>
        </div>
      </el-button>
      <el-button
        :disabled="activeNodes.length === 0"
        class="my-button"
        size="small"
        @click="addGeneralization"
      >
        <div class="my-button">
          <svg
            t="1719283740026"
            class="icon"
            viewBox="0 0 1024 1024"
            version="1.1"
            xmlns="http://www.w3.org/2000/svg"
            p-id="26481"
            width="32"
            height="32"
          >
            <path
              d="M128 576h416a64 64 0 0 1 64 64v192a64 64 0 0 1-64 64H128a64 64 0 0 1-64-64v-192a64 64 0 0 1 64-64z m32 64h352a32 32 0 0 1 32 32v128a32 32 0 0 1-32 32H160a32 32 0 0 1-32-32v-128a32 32 0 0 1 32-32zM128 128h416a64 64 0 0 1 64 64v192a64 64 0 0 1-64 64H128a64 64 0 0 1-64-64V192a64 64 0 0 1 64-64z m766.56 415.968A352.16 352.16 0 0 1 704 825.632c-23.68 3.52-35.52-7.2-35.52-32.224 0-15.584 11.84-29.568 35.52-41.92A287.712 287.712 0 0 0 832 512c0-99.84-50.816-187.84-128-239.488-23.68-14.848-35.52-29.536-35.52-44.064 0-25.568 11.84-35.584 35.52-30.08a352.16 352.16 0 0 1 190.56 281.664L896 480h32a32 32 0 0 1 0 64h-32l-1.44-0.032zM160 192h352a32 32 0 0 1 32 32v128a32 32 0 0 1-32 32H160a32 32 0 0 1-32-32V224a32 32 0 0 1 32-32z"
              fill="currentColor"
              p-id="26482"
            ></path>
          </svg>
          <div>添加概要</div>
        </div>
      </el-button>
      <el-button class="my-button" size="small" @click="exportPng">
        <div class="my-button">
          <svg
            t="1719283812353"
            class="icon"
            viewBox="0 0 1024 1024"
            version="1.1"
            xmlns="http://www.w3.org/2000/svg"
            p-id="28576"
            width="32"
            height="32"
          >
            <path
              d="M896.341333 128c23.381333 0 42.325333 18.986667 42.325334 42.368v398.890667A255.573333 255.573333 0 0 0 853.333333 554.666667V213.333333H170.666667l0.042666 597.333334 396.458667-396.501334a42.624 42.624 0 0 1 56.32-3.584l3.968 3.626667 151.296 151.466667a256.128 256.128 0 0 0-166.826667 330.368L127.658667 896A42.368 42.368 0 0 1 85.333333 853.632V170.368A42.666667 42.666667 0 0 1 127.658667 128h768.682666zM341.333333 298.666667a85.333333 85.333333 0 1 1 0 170.666666 85.333333 85.333333 0 0 1 0-170.666666z m512 469.333333v-128l170.666667 170.666667-170.666667 170.666666v-128h-170.666666v-85.333333h170.666666z"
              fill="currentColor"
              p-id="28577"
            ></path>
          </svg>
          <div>導(dǎo)出圖片</div>
        </div>
      </el-button>
      <el-button
        :disabled="activeNodes.length === 0"
        :type="activedPanel === 'icon' ? 'primary' : 'default'"
        class="my-button"
        size="small"
        @click="activePanel('icon')"
      >
        <div class="my-button">
          <svg
            t="1719283775623"
            class="icon"
            viewBox="0 0 1026 1024"
            version="1.1"
            xmlns="http://www.w3.org/2000/svg"
            p-id="27549"
            width="32"
            height="32"
          >
            <path
              d="M495.465 830.665c-187.138 0-264.948-168.222-268.193-175.401l62.966-28.307c2.486 5.49 62.207 134.667 205.194 134.667 153.067-1.795 211.302-129.213 213.685-134.633l63.103 27.996c-3.141 7.077-79.054 173.364-273.13 175.643l-3.625 0.034zM500.16 991.221c-256.974 0-466.034-209.060-466.034-466.034s209.060-466.034 466.034-466.034 466.034 209.060 466.034 466.034-209.060 466.034-466.034 466.034zM500.16 128.196c-218.897 0-396.991 178.094-396.991 396.991s178.094 396.991 396.991 396.991 396.991-178.094 396.991-396.991-178.059-396.991-396.991-396.991zM311.088 444.27c0 29.689 24.062 53.818 53.818 53.818s53.818-24.096 53.818-53.818-24.062-53.818-53.818-53.818-53.818 24.096-53.818 53.818zM580.765 444.27c0 29.689 24.062 53.818 53.818 53.818s53.818-24.096 53.818-53.818-24.062-53.818-53.818-53.818-53.818 24.096-53.818 53.818z"
              fill="currentColor"
              p-id="27550"
            ></path>
          </svg>
          <div>設(shè)置圖標(biāo)</div>
        </div>
      </el-button>
      <el-button
        :type="activedPanel === 'theme' ? 'primary' : 'default'"
        class="my-button"
        size="small"
        @click="activePanel('theme')"
      >
        <div class="my-button">
          <svg
            t="1719283846317"
            class="icon"
            viewBox="0 0 1024 1024"
            version="1.1"
            xmlns="http://www.w3.org/2000/svg"
            p-id="29654"
            width="32"
            height="32"
          >
            <path
              d="M772.8 96v64L936 321.6l-91.2 91.2c-12.8-11.2-27.2-16-43.2-16-36.8 0-65.6 28.8-65.6 65.6V800c0 35.2-28.8 64-64 64H352c-35.2 0-64-28.8-64-64V462.4c0-36.8-28.8-65.6-65.6-65.6-16 0-32 6.4-43.2 16L88 321.6 249.6 160h40l1.6 1.6C336 228.8 420.8 272 512 272c91.2 0 176-41.6 220.8-110.4 0-1.6 1.6-1.6 1.6-1.6h38.4V96m-481.6 0H256c-22.4 0-38.4 6.4-49.6 19.2L43.2 276.8c-25.6 25.6-25.6 65.6 0 89.6l94.4 94.4c11.2 11.2 27.2 17.6 41.6 17.6s30.4-6.4 41.6-17.6h1.6c1.6 0 1.6 0 1.6 1.6V800c0 70.4 57.6 128 128 128h320c70.4 0 128-57.6 128-128V462.4c0-1.6 0-1.6 1.6-1.6h1.6c11.2 11.2 27.2 17.6 41.6 17.6 16 0 30.4-6.4 41.6-17.6l94.4-94.4c25.6-25.6 25.6-65.6 0-89.6L819.2 115.2C806.4 102.4 790.4 96 772.8 96h-40c-22.4 0-41.6 11.2-54.4 30.4-33.6 49.6-96 81.6-168 81.6s-134.4-33.6-168-81.6C332.8 107.2 312 96 291.2 96z"
              fill="currentColor"
              p-id="29655"
            ></path>
          </svg>
          <div>選擇主題</div>
        </div>
      </el-button>
      <el-button
        :type="activedPanel === 'layout' ? 'primary' : 'default'"
        class="my-button"
        size="small"
        @click="activePanel('layout')"
      >
        <div class="my-button">
          <svg
            t="1719283873990"
            class="icon"
            viewBox="0 0 1024 1024"
            version="1.1"
            xmlns="http://www.w3.org/2000/svg"
            p-id="30805"
            width="32"
            height="32"
          >
            <path
              d="M938.666667 640h-64v-42.666667c0-72.533333-55.466667-128-128-128H554.666667V384h64c46.933333 0 85.333333-38.4 85.333333-85.333333V85.333333c0-46.933333-38.4-85.333333-85.333333-85.333333h-213.333334c-46.933333 0-85.333333 38.4-85.333333 85.333333v213.333334c0 46.933333 38.4 85.333333 85.333333 85.333333H469.333333v85.333333H277.333333c-72.533333 0-128 55.466667-128 128v29.866667c0 4.266667 0 8.533333 4.266667 12.8H85.333333c-46.933333 0-85.333333 38.4-85.333333 85.333333v213.333334c0 46.933333 38.4 85.333333 85.333333 85.333333h213.333334c46.933333 0 85.333333-38.4 85.333333-85.333333v-213.333334c0-46.933333-38.4-85.333333-85.333333-85.333333H230.4c0-4.266667 4.266667-8.533333 4.266667-12.8V597.333333c0-25.6 17.066667-42.666667 42.666666-42.666666h469.333334c25.6 0 42.666667 17.066667 42.666666 42.666666v42.666667H725.333333c-46.933333 0-85.333333 38.4-85.333333 85.333333v213.333334c0 46.933333 38.4 85.333333 85.333333 85.333333h213.333334c46.933333 0 85.333333-38.4 85.333333-85.333333v-213.333334c0-46.933333-38.4-85.333333-85.333333-85.333333zM298.666667 725.333333v213.333334H85.333333v-213.333334h213.333334zM405.333333 298.666667V85.333333h213.333334v213.333334h-213.333334zM938.666667 938.666667h-213.333334v-213.333334h213.333334v213.333334z"
              fill="currentColor"
              p-id="30806"
            ></path>
          </svg>
          <div>選擇結(jié)構(gòu)</div>
        </div>
      </el-button>
    </div>
    <div
      id="mindMapContainer"
      @dragenter.stop.prevent
      @dragleave.stop.prevent
      @dragover.stop.prevent
      @drop.stop.prevent
    ></div>
    <div class="active-panel" v-show="!readonly && activedPanel !== ''">
      <!-- 圖標(biāo) -->
      <div class="active-panel-box" v-if="activedPanel === 'icon'">
        <div class="title">
          選擇圖標(biāo)
          <span class="close" @click="activedPanel = ''">×</span>
        </div>
        <div class="content icon">
          <div class="icon-group" v-for="group of nodeIconList" :key="group.type">
            <div class="group-title">
              {{ group.name }}
            </div>
            <div class="group-content">
              <span
                class="icon-item"
                :class="activeNodes.length === 0 ? 'disabled' : ''"
                v-for="icon of group.list"
                :key="icon.name"
                @click="setIcon(group.type, icon.name)"
                v-html="icon.icon"
              ></span>
            </div>
          </div>
        </div>
      </div>
      <!-- 主題 -->
      <div class="active-panel-box" v-else-if="activedPanel === 'theme'">
        <div class="title">
          選擇主題
          <span class="close" @click="activedPanel = ''">×</span>
        </div>
        <div class="content">
          <li
            v-for="item of themes"
            :key="item.value"
            @click="changeTheme(item.value)"
            :class="theme === item.value ? 'active' : ''"
          >
            <img :src="`/pages/online-doc/icons/theme/${item.value}.jpg`" />
            <div>{{ item.label }}</div>
          </li>
        </div>
      </div>
      <!-- 結(jié)構(gòu) -->
      <div class="active-panel-box" v-else-if="activedPanel === 'layout'">
        <div class="title">
          選擇結(jié)構(gòu)
          <span class="close" @click="activedPanel = ''">×</span>
        </div>
        <div class="content">
          <li
            v-for="item of layouts"
            :key="item.value"
            @click="changeLayout(item.value)"
            :class="layout === item.value ? 'active' : ''"
          >
            <img :src="`/pages/online-doc/icons/layout/${item.value}.png`" />
            <div>{{ item.label }}</div>
          </li>
        </div>
      </div>
    </div>
  </div>

  <div class="mind-map-scale">
    <el-button text @click="zoomOut">
      <span style="font-size: 1.2rem; font-weight: bold">─</span>
    </el-button>
    <el-input
      style="display: inline-block; width: 50px; text-align: center"
      v-model="showScale"
      disabled
    />
    <el-button text @click="zoomIn"><span style="font-size: 1.2rem">+</span></el-button>
  </div>
</template>

<script>
import MindMap from 'simple-mind-map'
import MiniMap from 'simple-mind-map/src/plugins/MiniMap.js'
import Watermark from 'simple-mind-map/src/plugins/Watermark.js'
import KeyboardNavigation from 'simple-mind-map/src/plugins/KeyboardNavigation.js'
import ExportPDF from 'simple-mind-map/src/plugins/ExportPDF.js'
import ExportXMind from 'simple-mind-map/src/plugins/ExportXMind.js'
import Export from 'simple-mind-map/src/plugins/Export.js'
import Drag from 'simple-mind-map/src/plugins/Drag.js'
import Select from 'simple-mind-map/src/plugins/Select.js'
import AssociativeLine from 'simple-mind-map/src/plugins/AssociativeLine.js'
import TouchEvent from 'simple-mind-map/src/plugins/TouchEvent.js'
import NodeImgAdjust from 'simple-mind-map/src/plugins/NodeImgAdjust.js'
import SearchPlugin from 'simple-mind-map/src/plugins/Search.js'
import Painter from 'simple-mind-map/src/plugins/Painter.js'
import Formula from 'simple-mind-map/src/plugins/Formula.js'
import RainbowLines from 'simple-mind-map/src/plugins/RainbowLines.js'
import Demonstrate from 'simple-mind-map/src/plugins/Demonstrate.js'
import OuterFrame from 'simple-mind-map/src/plugins/OuterFrame.js'
import { nodeIconList } from 'simple-mind-map/src/svg/icons'
import { ElMessageBox } from 'element-plus'
import xmind from 'simple-mind-map/src/parse/xmind.js'

import cactus from './themes/cactus'
import classic5 from './themes/classic5'
import classic6 from './themes/classic6'
import classic7 from './themes/classic7'
import dark3 from './themes/dark3'
import dark4 from './themes/dark4'
import darkNightLceBlade from './themes/darkNightLceBlade'
import index from './themes/index'
import lemonBubbles from './themes/lemonBubbles'
import morandi from './themes/morandi'
import neonLamp from './themes/neonLamp'
import oreo from './themes/oreo'
import rose from './themes/rose'
import seaBlueLine from './themes/seaBlueLine'
import shallowSea from './themes/shallowSea'

// 注冊插件
MindMap.usePlugin(MiniMap)
  .usePlugin(Watermark)
  .usePlugin(Drag)
  .usePlugin(KeyboardNavigation)
  .usePlugin(ExportPDF)
  .usePlugin(ExportXMind)
  .usePlugin(Export)
  .usePlugin(Select)
  .usePlugin(AssociativeLine)
  .usePlugin(NodeImgAdjust)
  .usePlugin(TouchEvent)
  .usePlugin(SearchPlugin)
  .usePlugin(Painter)
  .usePlugin(Formula)
  .usePlugin(RainbowLines)
  .usePlugin(Demonstrate)
  .usePlugin(OuterFrame)

MindMap.defineTheme('cactus', cactus)
MindMap.defineTheme('classic5', classic5)
MindMap.defineTheme('classic6', classic6)
MindMap.defineTheme('classic7', classic7)
MindMap.defineTheme('dark3', dark3)
MindMap.defineTheme('dark4', dark4)
MindMap.defineTheme('darkNightLceBlade', darkNightLceBlade)
MindMap.defineTheme('index', index)
MindMap.defineTheme('lemonBubbles', lemonBubbles)
MindMap.defineTheme('morandi', morandi)
MindMap.defineTheme('neonLamp', neonLamp)
MindMap.defineTheme('oreo', oreo)
MindMap.defineTheme('rose', rose)
MindMap.defineTheme('seaBlueLine', seaBlueLine)
MindMap.defineTheme('shallowSea', shallowSea)

let mindMapInstance = null

window.mindMapInstance = mindMapInstance

export const defaultData = {
  data: {
    text: '根節(jié)點',
    expand: true,
    isActive: true,
  },
  children: [],
}

export default {
  props: {
    readonly: {
      type: Boolean,
      default: false,
    },
    name: {
      type: String,
      default: '思維導(dǎo)圖',
    },
    mindData: {
      type: Object,
      default() {
        return defaultData
      },
    },
  },
  data() {
    return {
      nodeIconList,
      scale: 1,
      theme: 'classic4',
      //  default(默認(rèn))白热、classic(腦圖經(jīng)典)敛助、minions(小黃人)、
      // pinkGrape(粉紅葡萄)屋确、mint(薄荷)辜腺、gold(金色vip)、vitalityOrange(活力橙)乍恐、
      // greenLeaf(綠葉)、dark2(暗色2)测砂、skyGreen(天清綠)茵烈、classic2(腦圖經(jīng)典2)、
      // classic3(腦圖經(jīng)典3)砌些、classic4(腦圖經(jīng)典4呜投,v0.2.0+)加匈、classicGreen(經(jīng)典綠)、
      // classicBlue(經(jīng)典藍(lán))仑荐、blueSky(天空藍(lán))雕拼、brainImpairedPink(腦殘粉)、
      // dark(暗色)粘招、earthYellow(泥土黃)啥寇、freshGreen(清新綠)、freshRed(清新紅)辑甜、
      // romanticPurple(浪漫紫)袍冷、simpleBlack(v0.5.4+簡約黑)、courseGreen(v0.5.4+課程綠)胡诗、
      // coffee(v0.5.4+咖啡)邓线、redSpirit(v0.5.4+紅色精神)煌恢、blackHumour(v0.5.4+黑色幽默)、
      // lateNightOffice(v0.5.4+深夜辦公室)症虑、blackGold(v0.5.4+黑金)缩歪、avocado(v.5.10-fix.2+牛油果)谍憔、
      // autumn(v.5.10-fix.2+秋天)、orangeJuice(v.5.10-fix.2+橙汁)
      themes: [
        { value: 'classic4', label: '腦圖經(jīng)典4' },
        { value: 'classic5', label: '腦圖經(jīng)典5' },
        { value: 'classic6', label: '腦圖經(jīng)典6' },
        { value: 'classic7', label: '腦圖經(jīng)典7' },
        { value: 'autumn', label: '秋天' },
        { value: 'cactus', label: '仙人掌' },
        { value: 'lemonBubbles', label: '檸檬氣泡' },
        { value: 'coffee', label: '咖啡' },
        { value: 'courseGreen', label: '課程綠' },
        { value: 'gold', label: '金色vip' },
        { value: 'greenLeaf', label: '綠葉' },
        { value: 'minions', label: '小黃人' },
        { value: 'morandi', label: '莫蘭迪' },
        { value: 'redSpirit', label: '紅色精神' },
        { value: 'simpleBlack', label: '簡約黑' },
        { value: 'vitalityOrange', label: '活力橙' },
        { value: 'oreo', label: '奧利奧' },
        { value: 'rose', label: '玫瑰' },
        { value: 'seaBlueLine', label: '海藍(lán)線' },
        { value: 'shallowSea', label: '淺海' },
      ],
      layout: 'mindMap',
      layouts: [
        { value: 'mindMap', label: '思維導(dǎo)圖' },
        { value: 'logicalStructure', label: '邏輯結(jié)構(gòu)圖' },
        { value: 'organizationStructure', label: '組織結(jié)構(gòu)圖' },
        { value: 'catalogOrganization', label: '目錄組織圖' },
        { value: 'timeline', label: '時間軸' },
        { value: 'timeline2', label: '時間軸2' },
        { value: 'fishbone', label: '魚骨圖' },
        { value: 'verticalTimeline', label: '垂直時間軸' },
      ],
      activeNodes: [],
      currentIconList: [],
      activedPanel: '',
    }
  },
  computed: {
    showScale() {
      return (this.scale * 100).toFixed(0)
    },
  },
  mounted() {
    this.init()
  },
  unmounted() {
    mindMapInstance.destroy()
  },
  watch: {
    mindData() {
      mindMapInstance.destroy()
      this.init()
    },
  },
  methods: {
    handleChange(file) {
      const that = this
      ElMessageBox.confirm('是否直接替換當(dāng)前思維導(dǎo)圖?', '警告', {
        confirmButtonText: '確認(rèn)',
        cancelButtonText: '取消',
        type: 'warning',
      })
        .then(() => {
          const { raw } = file
          xmind.parseXmindFile(raw).then(data => {
            that.setData(data)
          })
        })
        .catch(() => {})
    },
    activePanel(type) {
      this.activedPanel = type === this.activedPanel ? '' : type
    },
    setIcon(type, name) {
      if (this.activeNodes.length === 0) return
      let key = type + '_' + name
      // 檢查當(dāng)前節(jié)點是否存在該圖標(biāo)
      let index = this.currentIconList.findIndex(item => {
        return item === key
      })
      // 存在則刪除icon
      if (index !== -1) {
        this.currentIconList.splice(index, 1)
      } else {
        // 否則判斷當(dāng)前圖標(biāo)是否和要插入的圖標(biāo)是一個組的
        let typeIndex = this.currentIconList.findIndex(item => {
          return item.split('_')[0] === type
        })
        // 是一個組的則進(jìn)行替換
        if (typeIndex !== -1) {
          this.currentIconList.splice(typeIndex, 1, key)
        } else {
          // 否則添加icon
          this.currentIconList.push(key)
        }
      }
      this.activeNodes.forEach(node => {
        node.setIcon([...this.currentIconList])
      })
    },
    addRelationLine() {
      mindMapInstance.createLineFromActiveNode()
    },
    addGeneralization() {
      mindMapInstance.execCommand('ADD_GENERALIZATION')
    },
    dropNode() {
      mindMapInstance.execCommand('REMOVE_NODE')
    },
    addNode() {
      mindMapInstance.execCommand('INSERT_NODE')
    },
    addChildNode() {
      mindMapInstance.execCommand('INSERT_CHILD_NODE')
    },
    changeTheme(theme) {
      this.theme = theme
      mindMapInstance.setTheme(theme)
    },
    changeLayout(layout) {
      this.layout = layout
      mindMapInstance.setLayout(layout)
    },
    zoomMap(e) {
      mindMapInstance.view.setScale(e)
    },
    zoomIn() {
      let scale = mindMapInstance.view.scale
      scale += 0.2
      if (scale > 2) scale = 2
      mindMapInstance.view.setScale(scale)
    },
    zoomOut() {
      let scale = mindMapInstance.view.scale
      scale -= 0.2
      if (scale < 0.1) scale = 0.1
      mindMapInstance.view.setScale(scale)
    },
    getData() {
      return mindMapInstance.getData(true)
    },
    setData(data) {
      mindMapInstance.setData(data)
    },
    exportPng() {
      mindMapInstance.export('png', true, this.name)
    },
    init() {
      const data = this.mindData || defaultData
      let mindData = data
      if (data.root) {
        this.layout = data.layout
        this.theme = data.theme.template
        mindData = data.root
      }
      mindMapInstance = new MindMap({
        enableFreeDrag: false,
        readonly: this.readonly,
        layout: this.layout, // 'logicalStructure',
        theme: this.theme,
        el: document.getElementById('mindMapContainer'),
        mousewheelAction: 'zoom', // zoom(放大縮猩徊)、move(上下移動)
        data: mindData,
        fit: true,
        nodeTextEditZIndex: 1000,
        nodeNoteTooltipZIndex: 1000,
        initRootNodePosition: ['center', 'center'],
      })
      mindMapInstance.on('scale', e => {
        this.scale = Number(e.toFixed(2))
      })
      mindMapInstance.on('node_active', (...args) => {
        this.activeNodes = args[1]
        if (this.activeNodes.length > 0) {
          let firstNode = this.activeNodes[0]
          this.currentIconList = firstNode.getData('icon') || []
        } else {
          this.currentIconList = []
        }
      })
    },
  },
}
</script>

<style lang="scss" scoped>
.mind-map-container,
#mindMapContainer {
  width: 100%;
  height: 100%;
  overflow: hidden;
  position: relative;
}
.my-button {
  svg {
    width: 1.5rem;
    height: 1.5rem;
  }
  width: 6rem;
  height: 3.8rem;
  text-align: center;
  line-height: 1.5rem;
  margin-top: 0.8rem;
}
.mindmap-tools {
  position: absolute;
  top: 10px;
  right: 10px;
  z-index: 1000;
  display: flex;
  flex-direction: row;
  justify-content: center;
  width: 100%;
  align-items: center;
}

$iconSize: 1.4rem;

.active-panel {
  position: absolute;
  top: 10rem;
  right: 5px;
  bottom: 10rem;
  width: 16rem;
  background: white;
  user-select: none;
  .active-panel-box {
    height: 100%;
    .title {
      height: 3rem;
      line-height: 3rem;
      padding: 0 0.8rem;
      font-weight: bold;
      font-size: 1.1rem;
      border-bottom: 1px solid #ccc;
      .close {
        float: right;
        cursor: pointer;
        font-size: 1.3rem;
      }
    }
    .content {
      height: calc(100% - 3rem);
      overflow-y: auto;
      overflow-x: hidden;
      padding: 1rem;
      &.icon {
        padding-right: 0.5rem;
      }

      .icon-group {
        margin-top: 1rem;
        line-height: 2;
        &:first-child {
          margin-top: 0;
        }
      }
      .group-title {
        font-weight: bold;
      }
      .group-content {
        display: flex;
        flex-direction: row;
        flex-wrap: wrap;
        .icon-item {
          width: $iconSize;
          height: $iconSize;
          margin-right: 0.4rem;
          margin-top: 0.4rem;
          cursor: pointer;
          &.disabled {
            cursor: not-allowed;
            opacity: 0.5;
          }
          svg {
            width: $iconSize;
            height: $iconSize;
          }
        }
      }

      li {
        list-style: none;
        text-align: center;
        margin-top: 1rem;
        border: 1px solid #ccc;
        border-radius: 4px;
        &:first-child {
          margin-top: 0;
        }
        &:hover {
          cursor: pointer;
          box-shadow: 4px 4px 8px rgba(0, 0, 0, 0.2);
        }
        &.active {
          border: 1px solid #67c23a;
          box-shadow: 4px 4px 8px rgba(0, 0, 0, 0.2);
        }
        img {
          width: 100%;
          height: 8rem;
        }
      }
    }
  }
}
.mind-map-scale {
  position: absolute;
  bottom: -1rem;
  right: 1rem;
  z-index: 99;
  background: #efefef;
  border-radius: 5px;
  opacity: 0.8;
}
:deep .mind-map-scale {
  .el-input__wrapper .el-input__inner {
    text-align: center !important;
  }
}
</style>
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末袜硫,一起剝皮案震驚了整個濱河市婉陷,隨后出現(xiàn)的幾起案子官研,更是在濱河造成了極大的恐慌闯睹,老刑警劉巖楼吃,帶你破解...
    沈念sama閱讀 221,576評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件所刀,死亡現(xiàn)場離奇詭異,居然都是意外死亡忧吟,警方通過查閱死者的電腦和手機(jī)斩披,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,515評論 3 399
  • 文/潘曉璐 我一進(jìn)店門垦沉,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人寡壮,你說我怎么就攤上這事讹弯。” “怎么了棒仍?”我有些...
    開封第一講書人閱讀 168,017評論 0 360
  • 文/不壞的土叔 我叫張陵莫其,是天一觀的道長耸三。 經(jīng)常有香客問我仪壮,道長,這世上最難降的妖魔是什么烙心? 我笑而不...
    開封第一講書人閱讀 59,626評論 1 296
  • 正文 為了忘掉前任乏沸,我火速辦了婚禮蹬跃,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘丹喻。我一直安慰自己翁都,他們只是感情好柄慰,可當(dāng)我...
    茶點故事閱讀 68,625評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著藏研,像睡著了一般蠢挡。 火紅的嫁衣襯著肌膚如雪凳忙。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,255評論 1 308
  • 那天堡称,我揣著相機(jī)與錄音却紧,去河邊找鬼胎撤。 笑死,一個胖子當(dāng)著我的面吹牛巫俺,可吹牛的內(nèi)容都是我干的介汹。 我是一名探鬼主播,決...
    沈念sama閱讀 40,825評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼窗价,長吁一口氣:“原來是場噩夢啊……” “哼叹卷!你這毒婦竟也來了骤竹?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,729評論 0 276
  • 序言:老撾萬榮一對情侶失蹤靶溜,失蹤者是張志新(化名)和其女友劉穎墨技,沒想到半個月后挎狸,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體锨匆,經(jīng)...
    沈念sama閱讀 46,271評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,363評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了土榴。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片玷禽。...
    茶點故事閱讀 40,498評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡矢赁,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出给涕,到底是詐尸還是另有隱情,我是刑警寧澤恭应,帶...
    沈念sama閱讀 36,183評論 5 350
  • 正文 年R本政府宣布耘眨,位于F島的核電站毅桃,受9級特大地震影響准夷,放射性物質(zhì)發(fā)生泄漏衫嵌。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,867評論 3 333
  • 文/蒙蒙 一结闸、第九天 我趴在偏房一處隱蔽的房頂上張望酒朵。 院中可真熱鬧蔫耽,春花似錦、人聲如沸图甜。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,338評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至匪凡,卻和暖如春掘猿,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背衬衬。 一陣腳步聲響...
    開封第一講書人閱讀 33,458評論 1 272
  • 我被黑心中介騙來泰國打工滋尉, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留狮惜,地道東北人。 一個月前我還...
    沈念sama閱讀 48,906評論 3 376
  • 正文 我出身青樓虱而,卻偏偏與公主長得像开泽,于是被迫代替她去往敵國和親穆律。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,507評論 2 359

推薦閱讀更多精彩內(nèi)容