<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      vue2 手寫思維導圖編輯器,支持圖片和節點拖拽(2)

      彈框模塊

      DigitalXmindDialog.vue

      <template>
        <el-dialog
          :title="title"
          width="1200px"
          class="auth-dialog"
          top="5%"
          :append-to-body="true"
          :lock-scroll="false"
          :close-on-click-modal="false"
          :visible.sync="visible"
          :closed="hide"
        >
          <VueXmind
            v-if="visible"
            ref="vueXmindDialogRef"
            :nodeData="xmindData.tree"
            :styleData="xmindData.theme"
          ></VueXmind>
      
          <div slot="footer" class="center-dialog-footer">
            <el-button class="btn btn-gray" @click="visible = false">取消</el-button>
            <el-button class="btn btn-shadow-pay" @click="onConfirm">確認</el-button>
          </div>
        </el-dialog>
      </template>
      
      <script>
        import VueXmind from '@/components/VueXmind/index'
        export default {
          components: { VueXmind },
          props: {
            title: {
              type: String,
              default: '在線導圖編輯-創建',
            },
          },
          data() {
            return {
              visible: false,
              currenNode: null,
              currentId: '',
              xmindData: {},
              saveLoading: false,
            }
          },
          methods: {
            async onConfirm() {
              if (this.$refs.vueXmindDialogRef && !this.saveLoading) {
                try {
                  this.saveLoading = true
                  let data = await this.$refs.vueXmindDialogRef.saveXmindData()
                  // 1表格 2圖片 3思維導圖
                  let params = {
                    bookExamModuleId: this.currenNode.id,
      
                    analysisType: 3,
                    analysisDetail: encodeURIComponent(JSON.stringify(data.data)),
                    picture: data.imgUrl,
                  }
                  if (this.currentId) {
                    params.id = this.currentId
                  }
                  this.$emit('updateNodeContent', params)
                  this.saveLoading = false
                } catch (e) {}
                this.hide()
              } else {
                console.log('在處理中')
              }
            },
            hide() {
              this.visible = false
            },
            show(node, snode) {
              this.currenNode = node
              this.saveLoading = false
      
              // console.log(node, snode)
              if (snode) {
                this.currentId = snode.id
                try {
                  this.xmindData = JSON.parse(
                    decodeURIComponent(snode.analysisDetail),
                  )
                  this.visible = true
                } catch (e) {
                  console.log(e)
                  this.xmindData = {}
                  this.visible = true
                }
              } else {
                this.xmindData = {}
                this.currentId = ''
                this.visible = true
              }
            },
          },
        }
      </script>
      
      <style scoped lang="scss"></style>
      

        VueXmind/index.vue

      <template>
        <div>
          <div class="cp-xmind-controller">
            <div class="control-left">
              <span @click="onClickAddMainNode">添加同級節點</span>
              <span @click="onClickAddNode">添加子級節點</span>
              <span @click="deleteSelectNode" title="快捷鍵 Delete">刪除節點</span>
              <span @click="openLatexEdit">插入/編輯公式</span>
            </div>
            <div class="control-right">
              <span @click="onSetSceneTheme">主題設置 (配色選擇)</span>
              <span @click="reSizeBox">排版優化</span>
              <!-- <span @click="savePhoto">保存圖片</span> -->
            </div>
          </div>
          <div class="xmind-node-panel-segment">
            <div class="xmind-node-box">
              <div
                v-if="treeData"
                class="xmind-node-content"
                ref="xmindNodeBoxRef"
                :style="treeBoxStyle"
                @dragover="onGragMove"
                @dblclick="onSelectlayer"
              >
                <XmindSvgLine
                  :node="treeData"
                  :dwidth="currentTheme.dwidth"
                  :canvasSize="canvasSize"
                  :lineStyle="currentTheme.lineStyle"
                  :drogDate="drogDate"
                  :startDrag="startDrag"
                  :dragNodeId="dragNodeId"
                ></XmindSvgLine>
                <XmindNode
                  :node="treeData"
                  ref="xmindsvgRef"
                  :dwidth="currentTheme.dwidth"
                  :boxStyle="currentTheme.boxStyle"
                  :boxColorStyle="currentTheme.boxColorStyle"
                  :currentId="currentId"
                  :dragNodeId="dragNodeId"
                  @updateNodeEnd="updateNodeEnd"
                  @selectNodeId="changeSelectNode"
                ></XmindNode>
              </div>
            </div>
            <div class="xmind-node-attribute">
              <NodeAttributes
                :node="currentNode"
                :currentId="currentId"
                @selectTheme="onSelectTheme"
                @updateAttribute="onUpdateAttribute"
              ></NodeAttributes>
            </div>
          </div>
          <!-- <img v-if="imgUrl" :src="imgUrl" /> -->
      
          <latex-edit-dialog
            ref="latexEditDialogRef"
            @updateNodeContent="onUpdateNodeContent"
          ></latex-edit-dialog>
        </div>
      </template>
      
      <script>
        import { API } from '@/api/config'
        import XmindNode from './XmindNode'
        import XmindSvgLine from './XmindSvgLine'
        import NodeAttributes from './NodeAttributes/index'
        import LatexEditDialog from './components/latex-edit-dialog'
        import XmindStyleMixins from './mixins/XmindStyleMixins'
        import XmindDateSaveMixins from './mixins/XmindDateSaveMixins'
        import KeyboardShortcutMixins from './mixins/KeyboardShortcutMixins'
        import {
          executeXmindNodePosition,
          CalculateDragUtil,
          selectNodeByTreeNode,
        } from './util'
        import html2canvas from 'html2canvas'
        export default {
          components: { XmindNode, XmindSvgLine, NodeAttributes, LatexEditDialog },
          mixins: [XmindStyleMixins, XmindDateSaveMixins, KeyboardShortcutMixins],
          watch: {
            treeData() {
              if (this.treeData) {
                if (this.currentId) {
                  this.currentNode = selectNodeByTreeNode(
                    this.treeData,
                    this.currentId,
                  )
                }
              }
            },
          },
          props: {
            nodeData: {
              type: Object,
            },
            styleData: {
              type: Object,
            },
          },
          data() {
            return {
              imgUrl: '',
              DemoData: {
                data: '中心主題',
                w: 94,
                h: 42,
                children: [
                  { w: 70, h: 40, data: '分支主題', children: [] },
                  { w: 70, h: 40, data: '分支主題', children: [] },
                ],
              },
              // 防抖 更新
              updateThrottle: null,
            }
          },
      
          destroyed() {
            this.updateThrottle.cancel()
            document.ondragend = null
            document.ondragstart = null
          },
          mounted() {
            this.updateThrottle = _.throttle(this.calculateDragExecute, 200)
            // 監聽 鼠標松開的時候
            document.ondragend = (e) => {
              this.onEndDragNode()
            }
            document.ondragstart = (ev) => {
              if (ev.target.id) {
                this.onStartDragNode(ev.target.id)
              }
            }
      
            if (this.styleData) {
              this.initStyleData(this.styleData)
            }
            if (this.nodeData) {
              this.updateTreeList(this.nodeData)
            } else {
              this.updateTreeList(this.DemoData)
            }
      
            this.$nextTick(() => {
              this.reSizeBox()
            })
          },
          methods: {
            savePhoto() {
              html2canvas(this.$refs.xmindNodeBoxRef, { useCORS: true }).then(
                (canvas) => {
                  let dataURL = canvas.toDataURL('image/png')
                  this.imgUrl = dataURL
                  if (this.imgUrl !== '') {
                    this.dialogTableVisible = true
                  }
                },
              )
            },
            getXmindPicture() {
              return new Promise((resolve, reject) => {
                html2canvas(this.$refs.xmindNodeBoxRef, { useCORS: true }).then(
                  (canvas) => {
                    let dataURL = canvas.toDataURL('image/png')
                    resolve(dataURL)
                  },
                  () => {
                    resolve('')
                  },
                )
              })
            },
            // 保存數據
            async saveXmindData() {
              this.currentId = ''
              await this.cpsleep(10)
              let imgUrl = await this.getXmindPicture()
              let params = { base64File: imgUrl }
              imgUrl = await this.apiPost(API.CONFIG_UPLOAD_BASE64FILE, params).then(
                (res) => {
                  if (this.checkoutRes(res)) {
                    return res.data
                  } else {
                    return ''
                  }
                },
                () => {
                  return ''
                },
              )
              //  上傳圖片 獲取 url
              return {
                imgUrl: imgUrl,
                data: {
                  tree: this.treeData,
                  theme: this.currentTheme,
                },
              }
            },
            openLatexEdit(e) {
              if (this.currentId) {
                let cnode = selectNodeByTreeNode(this.treeData, this.currentId)
                if (cnode) {
                  this.$refs.latexEditDialogRef.show(cnode.data)
                }
              } else {
                this.showMessage('請選擇要修改的內容')
              }
            },
            onGragMove(ev) {
              // 獲取 應該加到那個 node 上面
              let pos = { x: ev.layerX, y: ev.layerY, id: this.dragNodeId }
              this.updateThrottle(pos)
              ev.preventDefault()
            },
            calculateDragExecute(pos) {
              let dropDate = CalculateDragUtil.calculateDragOverNode(
                this.treeData,
                pos,
              )
              if (dropDate) {
                this.drogDate = dropDate
              } else {
                this.currentId = ''
                this.drogDate = null
              }
            },
            changeSelectNode(node) {
              this.currentId = node.id
              this.currentNode = node
            },
            onSelectlayer() {
              this.currentId = ''
            },
            updateTreeList(data) {
              // 渲染除 node 的位置
              if (data) {
                executeXmindNodePosition(
                  data,
                  this.currentTheme.dwidth,
                  this.currentTheme.dheight,
                  this.currentTheme.scaneBox,
                )
                this.treeData = data
              }
            },
            updateNodeEnd() {
              this.$nextTick(() => {
                let datas = JSON.parse(JSON.stringify(this.treeData))
                this.updateTreeList(datas)
              })
            },
            reSizeBox() {
              if (this.$refs.xmindsvgRef) {
                this.$refs.xmindsvgRef.reSizeBox()
                this.$nextTick(() => {
                  let datas = JSON.parse(JSON.stringify(this.treeData))
                  this.updateTreeList(datas)
                })
              }
            },
          },
        }
      </script>
      
      <style scoped lang="scss">
        .xmind-node-box {
          height: 600px;
          overflow: auto;
          background-color: #e4e4e4;
        }
        .xmind-node-content {
          background-color: #fff;
          position: relative;
        }
      
        .cp-xmind-controller {
          padding: 10px;
          display: flex;
          .control-left {
            flex: 1;
          }
          .control-right {
            flex: 1;
            text-align: right;
          }
          span {
            display: inline-block;
            border: 1px solid $color-theme;
            padding: 10px;
            border-radius: 6px;
            margin-left: 20px;
            cursor: pointer;
            user-select: none;
          }
        }
        .xmind-node-panel-segment {
          display: flex;
          .xmind-node-box {
            flex: 1;
          }
          .xmind-node-attribute {
            width: 200px;
          }
        }
      </style>
      

        節點數據

      XmindNode.vue
      <template>
        <span :style="{ opacity: dragNodeId === node.id ? 0.5 : 1 }">
          <div
            class="vue-xmind-node"
            :class="{ topnode: currentId === node.id }"
            :style="nodeBoxStyle"
            :ref="'xmindbox' + node.id + 'ref'"
            @click.stop="onSelectCurrent(node)"
          >
            <div class="vue-xmind-content">
              <div
                :id="node.id"
                :draggable="node.level !== 1 && !contenteditable"
                class="vue-xmind-name"
                :class="{ 'vue-xmind-edit': contenteditable }"
                :style="nodeBoxNameStyle"
                :ref="'xmindboxname' + node.id + 'ref'"
                :contenteditable="contenteditable"
                @blur.stop="onBlurSaveDate"
                @keydown="inputChecked"
                v-html="node.data"
                @dblclick.stop="openEditContent"
              ></div>
      
              <div class="mouse-zoom-move" v-if="currentId === node.id">
                <mouse-direction-move
                  id="x"
                  height="100%"
                  @translation="onTranslation"
                  @translationEnd="onTranslationEnd"
                >
                  <div class="mouse-zoom-box"></div>
                </mouse-direction-move>
              </div>
            </div>
          </div>
          <span
            class="vue-xmind-children"
            v-if="node.children && node.children.length"
          >
            <XmindNode
              v-for="item in node.children"
              :key="item.id"
              :level="level + 1"
              :ref="'xmind' + node.id"
              :node="item"
              :dwidth="dwidth"
              :boxStyle="boxStyle"
              :boxColorStyle="boxColorStyle"
              :currentId="currentId"
              :dragNodeId="dragNodeId"
              @updateNodeEnd="updateNodeEnd"
              @selectNodeId="onSelectCurrent"
            ></XmindNode>
          </span>
        </span>
      </template>
      
      <script>
        import { getLevelNodeDwidth, getLevelListDate } from './util'
        import MouseDirectionMove from './components/mouse-direction-move'
        export default {
          components: { MouseDirectionMove },
          props: {
            node: {
              type: Object,
              default: () => {
                return {}
              },
            },
            level: {
              type: Number,
              default: 1,
            },
            dragNodeId: String,
            currentId: String,
            dwidth: Array,
            boxStyle: Object,
            boxColorStyle: Object,
          },
          name: 'XmindNode',
          watch: {
            node() {
              this.customWidth = this.node.ctw || 0
            },
          },
          computed: {
            lineWidth() {
              return getLevelNodeDwidth(this.level, this.dwidth)
            },
            nodeBoxNameStyle() {
              let padding = [this.boxStyle.ptb + 'px', this.boxStyle.plr + 'px'].join(
                ' ',
              )
              let level = this.node.level
              let cwidth = 'auto'
              let lineHeight = getLevelListDate(level, this.boxStyle.lineSize) + 'px'
              let fontSize = getLevelListDate(level, this.boxStyle.fontSize) + 'px'
              let fontColor = getLevelListDate(level, this.boxColorStyle.fontColor)
              let borderColor = getLevelListDate(
                level,
                this.boxColorStyle.borderColor,
              )
              let backgroundColor = getLevelListDate(
                level,
                this.boxColorStyle.backgroundColor,
              )
      
              if (this.customWidth) {
                cwidth = this.customWidth + 'px'
              }
      
              let borderRadius =
                getLevelListDate(level, this.boxColorStyle.borderRadius) + 'px'
      
              if (this.currentId === this.node.id) {
                return {
                  padding: padding,
                  lineHeight: lineHeight,
                  fontSize: fontSize,
                  color: fontColor,
                  backgroundColor: backgroundColor,
                  borderColor: '#ff0000',
                  borderRadius: borderRadius,
                  width: cwidth,
                }
              } else {
                return {
                  padding: padding,
                  lineHeight: lineHeight,
                  fontSize: fontSize,
                  color: fontColor,
                  backgroundColor: backgroundColor,
                  borderColor: borderColor || backgroundColor,
                  borderRadius: borderRadius,
                  width: cwidth,
                }
              }
            },
            nodeBoxStyle() {
              return {
                transform:
                  'translate3d(' + this.node.x + 'px,' + this.node.y + 'px,0)',
              }
            },
          },
      
          data() {
            return {
              contenteditable: false,
              customWidth: 0,
            }
          },
          created() {
            this.customWidth = this.node.ctw || 0
          },
          methods: {
            onTranslationEnd() {
              this.node.ctw = this.customWidth
              this.$nextTick(() => {
                this.updateNodeBox()
                this.updateNodeEnd()
              })
            },
            onTranslation(t) {
              if (!this.customWidth) {
                this.customWidth = this.node.w
              }
              if (t.x + this.customWidth >= 40) {
                this.customWidth += t.x
              }
            },
            onSelectCurrent(data) {
              this.$emit('selectNodeId', data)
            },
            inputChecked(e) {
              // Backspace鍵8 F5鍵116 37~40方向箭頭 Del鍵46
              // if (e.keyCode === 8) {
              //   return
              // }
              // if (e.keyCode === 13) {
              //   e.preventDefault()
              // }
            },
            openEditContent(node) {
              if (this.contenteditable) return
              let content = this.$refs['xmindboxname' + this.node.id + 'ref']
              this.contenteditable = true
              this.$nextTick(() => {
                if (content) {
                  if (content[0]) {
                    content[0].focus()
                    this.getInputSelection(content[0])
                  } else {
                    content.focus()
                    this.getInputSelection(content)
                  }
                }
              })
            },
            /**
             * 獲取輸入的光標到字符串最后一位
             * @param {obj} obj
             */
            getInputSelection(obj) {
              // 處理光標問題
              if (window.getSelection) {
                // ie11 10 9 ff safari
                // obj.focus(); //解決ff不獲取焦點無法定位問題
                let range = window.getSelection() // 創建range
                range.selectAllChildren(obj) // range 選擇obj下所有子內容
                range.collapseToEnd() // 光標移至最后
              } else if (document.selection) {
                // ie10 9 8 7 6 5
                let range = document.selection.createRange() // 創建選擇對象
                // var range = document.body.createTextRange();
                range.moveToElementText(obj) // range定位到obj
                range.collapse(false) // 光標移至最后
                range.select()
              }
            },
            onBlurSaveDate(e) {
              this.contenteditable = false
              this.node.data = e.target.innerHTML || '內容'
              this.$nextTick(() => {
                this.updateNodeBox()
                this.updateNodeEnd()
              })
            },
            updateNodeEnd() {
              this.$emit('updateNodeEnd')
            },
            updateNodeBox() {
              let nodeel = this.$refs['xmindbox' + this.node.id + 'ref']
              if (nodeel) {
                this.node.h = nodeel.offsetHeight
                this.node.w = nodeel.offsetWidth
              }
            },
            reSizeBox() {
              if (this.node.children && this.node.children.length) {
                let els = this.$refs['xmind' + this.node.id]
                if (els) {
                  els.forEach((item) => {
                    if (item.reSizeBox) {
                      item.reSizeBox()
                    }
                  })
                }
              }
              this.updateNodeBox()
            },
          },
        }
      </script>
      
      <style scoped lang="scss">
        .node-box-edit {
          display: inline-block;
          position: absolute;
          top: 0;
          left: 0;
          z-index: 99;
        }
        .vue-xmind-node {
          display: inline-block;
          position: absolute;
          top: 0;
          left: 0;
          &.topnode {
            z-index: 999;
          }
        }
      
        .vue-xmind-name {
          border-radius: 6px;
          user-select: none;
          box-sizing: border-box;
          word-break: break-word;
          border: 2px solid #ffffff;
          &.vue-xmind-edit {
            box-shadow: 0px 0px 10px 0px rgba(42, 77, 138, 0.6);
          }
          /deep/ img {
            -webkit-user-drag: none;
          }
        }
      
        .mouse-zoom-move {
          position: absolute;
          top: 0;
          bottom: 0;
          right: 0px;
          display: inline-block;
          cursor: w-resize;
          .mouse-zoom-box {
            display: inline-block;
            // background: #ff0000;
            width: 10px;
            height: 100%;
            border-radius: 5px;
          }
        }
      
        .vue-xmind-content {
          display: inline-block;
          position: relative;
        }
      </style>
      

        XmindSvgLine.vue

      svg 背景先邏輯

      <template>
        <svg :width="canvasSize.w + 'px'" :height="canvasSize.h + 'px'">
          <g>
            <path
              v-for="(item, index) in pathList"
              :key="index"
              :d="item.path"
              :stroke="item.stroke"
              :stroke-width="item.strokeWidth"
              fill="none"
            />
          </g>
          <g v-if="drogDate && startDrag">
            <path
              :d="drogLine.path"
              stroke="$color-theme"
              stroke-width="1"
              fill="none"
            />
            <rect
              width="30"
              height="15"
              rx="5"
              ry="5"
              :x="drogRect.x"
              :y="drogRect.y - 7"
              style="fill: $color-theme"
            />
          </g>
        </svg>
      </template>
      
      <script>
        import { executeXmindNodeLineDate, getSpaceNodePath } from './util'
        export default {
          props: {
            node: {
              type: Object,
              default: () => {
                return {}
              },
            },
            lineStyle: Object,
            dragNodeId: String,
            canvasSize: Object,
            drogDate: Object,
            dwidth: Array,
            startDrag: Boolean,
          },
          data() {
            return {
              pathList: [],
              drogRect: { x: 0, y: 0 },
              drogLine: {
                path: '',
              },
            }
          },
          watch: {
            node() {
              this.updateSvgLine()
            },
            lineStyle() {
              this.updateSvgLine()
            },
            drogDate(v) {
              if (v && v.dpos) {
                this.drogRect.x = v.dpos[0]
                this.drogRect.y = v.dpos[1]
                let line = {
                  tx: v.dpos[0],
                  ty: v.dpos[1],
                  x: v.dpos[2],
                  y: v.dpos[3],
                }
                this.drogLine.path = getSpaceNodePath(line, this.lineStyle.type)
              }
            },
          },
          mounted() {
            this.updateSvgLine()
          },
          methods: {
            updateSvgLine() {
              // console.log('updateSvgLine', this.node)
              if (this.node.cw) {
                this.pathList = executeXmindNodeLineDate(this.node, this.lineStyle)
              } else {
                this.pathList = []
              }
            },
          },
        }
      </script>
      
      <style scoped lang="scss"></style>
      

        

      posted @ 2024-01-25 15:13  小凡的天空  閱讀(448)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 美女把尿囗扒开让男人添| 类乌齐县| 成人国产亚洲精品一区二| 日产一区日产2区| 色久综合色久综合色久综合| 国产线播放免费人成视频播放| 欧美另类精品xxxx人妖| 亚洲AV永久无码嘿嘿嘿嘿| 成人无码特黄特黄AV片在线| 亚洲综合伊人久久大杳蕉| 狠狠色噜噜狠狠狠狠2021| 国产360激情盗摄全集| 免费无遮挡无码永久在线观看视频| 亚洲国产片一区二区三区| 肥臀浪妇太爽了快点再快点| 97人妻中文字幕总站| 日韩午夜无码精品试看| 九九成人免费视频| 中文字幕 日韩 人妻 无码| 8x国产精品视频| 国产在线午夜不卡精品影院| 综合偷自拍亚洲乱中文字幕| 精品视频在线观自拍自拍| 乱人伦中文字幕成人网站在线 | 国产精品午夜福利资源| 久久中文字幕国产精品| 亚洲人成电影网站 久久影视| 激情 自拍 另类 亚洲| 中文字幕久久人妻熟人妻| 乱中年女人伦av三区| 国产成人午夜精品影院| 巢湖市| 四虎成人在线观看免费| 一区二区三区四区五区自拍| 大伊香蕉精品一区二区| 国产日产亚洲系列av| 51妺嘿嘿午夜福利| 国产精品一区 在线播放| 午夜视频免费试看| 欧美成本人视频免费播放| 深夜宅男福利免费在线观看|