<!--
 * @Description: kgBuilder
 * @Author: tanc
 * @Date: 2021-12-26 16:50:07
 * @LastEditors: Please set LastEditors
 * @LastEditTime: 2022-03-29 11:23:25
-->
<template>
  <div class="mind-box">
    <!-- 左侧 -->
    <el-scrollbar class="mind-l">
      <div class="ml-m">
        <h2 class="ml-ht">图谱列表</h2>
        <el-button
          type="info"
          style="margin: 2px 0 4px 2px;"
          plain
          size="small"
          @click="createDomain"
        >新建图谱</el-button>
        <div
          class="ml-a-box"
          style="min-height:280px"
        >
          <a
            @click="matchDomainGraph(m, $event)"
            v-for="(m, index) in pageModel.nodeList"
            :key="index"
            href="javascript:void(0)"
            :title="m.name"
          >
            <el-tag
              v-if="m.commend == 0"
              closable
              style="margin:2px"
              @close="deleteDomain(m.id, m.name)"
            >{{ m.name }}</el-tag>
          </a>
        </div>
        <div class="fr">
          <a
            href="javascript:void(0)"
            class="svg-a-sm"
            v-show="pageModel.pageIndex > 1"
            @click="prev"
          >上一页</a>
          <a
            href="javascript:void(0)"
            class="svg-a-sm"
            v-show="pageModel.pageIndex < pageModel.totalPage"
            @click="next"
          >下一页</a>
        </div>
        <!-- 关注及交流 -->
        <div>
          <kg-focus ref="kg_focus"></kg-focus>
        </div>
      </div>
    </el-scrollbar>
    <!-- 左侧over -->
    <!-- 右侧 -->
    <div class="mind-con">
      <!-- 头部工具栏 -->
      <div class="mind-top clearfix">
        <div
          v-show="domain != ''"
          class="fl"
          style="display: flex"
        >
          <div class="search">
            <el-button @click="getDomainGraph(0)">
              <svg
                class="icon"
                aria-hidden="true"
              >
                <use xlink:href="#icon-search"></use>
              </svg>
            </el-button>
            <el-input
              placeholder="请输入关键词"
              v-model="nodeName"
              @keyup.enter.native="getDomainGraph"
            ></el-input>
          </div>
          <span>
            <span class="dibmr">
              <span>显示节点个数:</span>
              <a
                v-for="(m, index) in pageSizeList"
                :key="index"
                @click="setMatchSize(m)"
                :title="m.size"
                href="javascript:void(0)"
                :class="[m.isActive ? 'sd-active' : '', 'sd']"
              >{{ m.size }}</a>
            </span>
          </span>
        </div>
        <div class="fr">
          <a
            href="javascript:void(0)"
            @click="showJsonData"
            class="svg-a-sm"
          >
            <i class="el-icon-tickets">查看数据</i>
          </a>

          <a
            href="javascript:void(0)"
            @click="saveImage"
            class="svg-a-sm"
          >
            <i class="el-icon-camera-solid">截图</i>
          </a>
          <a
            href="javascript:void(0)"
            @click="importGraph"
            class="svg-a-sm"
          >
            <i class="el-icon-upload">导入</i>
          </a>
          <a
            href="javascript:void(0)"
            @click="exportGraph"
            class="svg-a-sm"
          >
            <i class="el-icon-download">导出</i>
          </a>
          <a
            href="javascript:void(0)"
            @click="requestFullScreen"
            class="svg-a-sm"
          >
            <i class="el-icon-monitor">全屏</i>
          </a>
          <a
            href="javascript:void(0)"
            @click="help"
            class="svg-a-sm"
          >
            <i class="el-icon-info">帮助</i>
          </a>
          <a
            href="javascript:void(0)"
            @click="wanted"
            class="svg-a-sm"
          >
            <i class="el-icon-question">反馈</i>
          </a>
        </div>
      </div>
      <!-- 头部over -->
      <!-- 中部 -->
      <el-scrollbar
        class="mind-cen"
        id="graphcontainerdiv"
      >
        <div
          id="nodeDetail"
          class="node_detail"
        >
          <h5>详细数据</h5>
          <span
            class="node_pd"
            v-for="(m, k) in nodeDetail"
            :key="k"
          >{{ k }}:{{ m }}</span>
        </div>
        <!-- 中部图谱画布 -->
        <div
          id="graphContainer"
          class="graphContainer"
          @click="initContainerLeftClick"
          @contextmenu.prevent="initContainerRightClick"
        ></div>
      </el-scrollbar>
      <!-- 中部over -->
      <div class="svg-set-box"></div>
      <!-- 底部 -->

      <!-- 底部over -->
    </div>
    <!-- 右侧over -->
    <!-- 空白处右键 -->
    <div>
      <menu-blank
        ref="menu_blank"
        @btnAddSingle="btnAddSingle"
        @btnQuickAddNode="btnQuickAddNode"
      ></menu-blank>
    </div>
    <!-- 连线按钮组 -->
    <div>
      <menu-link
        ref="menu_link"
        @updateLinkName="updateLinkName"
        @deleteLink="deleteLink"
      ></menu-link>
    </div>
    <!--编辑窗口-->
    <div>
      <kg-form
        ref="kg_form"
        @batchCreateNode="batchCreateNode"
        @batchCreateChildNode="batchCreateChildNode"
        @batchCreateSameNode="batchCreateSameNode"
        @createNode="createNode"
        @initNodeImage="initNodeImage"
        @initNodeContent="initNodeContent"
        @getDomain="getDomain"
      >
      </kg-form>
    </div>
    <!-- 富文本展示 -->
    <div>
      <node-richer ref="node_richer"></node-richer>
    </div>
    <div>
      <kg-json
        ref="kg_json"
        :data="graph"
      ></kg-json>
    </div>
    <div>
      <kg-help ref="kg_help"></kg-help>
    </div>
    <div>
      <kg-wanted ref="kg_wanted"></kg-wanted>
    </div>
  </div>
</template>
<script>
import _ from "lodash";
import * as d3 from "d3";
import { kgBuilderApi } from "@/api";
import MenuBlank from "@/views/kgbuilder/components/menu_blank";
import MenuLink from "@/views/kgbuilder/components/menu_link";
import KgForm from "@/views/kgbuilder/components/kg_form";
import NodeRicher from "@/views/kgbuilder/components/node_richer";
import KgFocus from "@/components/KGFocus";
import KgWanted from "@/components/KGWanted";
import KgJson from "@/views/kgbuilder/components/kg_json";
import KgHelp from "@/views/kgbuilder/components/kg_help";
import html2canvas from "html2canvas";
export default {
  name: "kgBuilder",
  components: {
    MenuBlank,
    MenuLink,
    KgForm,
    NodeRicher,
    KgFocus,
    KgJson,
    KgHelp,
    KgWanted
  },
  data () {
    return {
      svg: null,
      timer: null,
      simulation: null,
      linkGroup: null,
      linkTextGroup: null,
      nodeGroup: null,
      nodeTextGroup: null,
      nodeSymbolGroup: null,
      nodeButtonGroup: null,
      nodeButtonAction: "",
      tooltip: null,
      mouserPos: { left: "-1000px", top: "-1000px" },
      nodeDetail: null,
      pageSizeList: [
        { size: 500, isActive: true },
        { size: 1000, isActive: false },
        { size: 2000, isActive: false },
        { size: 5000, isActive: false }
      ],
      isAddLink: false,
      isDeleteLink: false,
      selectNode: {
        nodeId: "",
        nodeName: "",
        fx: "",
        fy: ""
      },
      selectSourceNodeId: 0,
      selectTargetNodeId: 0,
      domain: "",
      domainId: 0,
      nodeName: "",
      pageSize: 500,
      activeNode: null,
      nodeImageList: [],
      showImageList: [],
      editorContent: "",
      pageModel: {
        pageIndex: 1,
        pageSize: 30,
        totalCount: 0,
        totalPage: 0,
        nodeList: []
      },
      graph: {
        nodes: [],
        links: []
      },
      jsonShow: false,
      helpShow: false
    };
  },
  filters: {
    labelFormat: function (value) {
      let domain = value.substring(1, value.length - 1);
      return domain;
    }
  },
  mounted () {
    this.$nextTick(_ => {
      this.initGraph();
    });
  },
  created () {
    this.getDomain();
  },
  methods: {
    prev () {
      if (this.pageModel.pageIndex > 1) {
        this.pageModel.pageIndex--;
        this.getDomain();
      }
    },
    next () {
      if (this.pageModel.pageIndex < this.pageModel.totalPage) {
        this.pageModel.pageIndex++;
        this.getDomain();
      }
    },
    //初始化画布
    initGraph () {
      let graphContainer = d3.select(".graphContainer");
      let width = graphContainer._groups[0][0].offsetWidth;
      let height = window.screen.height; //
      this.svg = graphContainer.append("svg");
      this.svg.attr("width", width);
      this.svg.attr("height", height);
      this.svg.attr('preserveAspectRatio', 'xMidYMidmeet')
      this.simulation = d3
        .forceSimulation()
        .force(
          "link",
          d3
            .forceLink()
            .distance(function (d) {
               return 60
              //return Math.floor(Math.random() * (700 - 200)) + 200;
            })
            .id(function (d) {
              return d.uuid;
            })
        )
        .force("charge", d3.forceManyBody().strength(-400))
        .force("collide", d3.forceCollide())
        .force("center", d3.forceCenter(width / 2, (height - 200) / 2));
      this.linkGroup = this.svg.append("g").attr("class", "line");
      this.linkTextGroup = this.svg.append("g").attr("class", "lineText");
      this.nodeGroup = this.svg.append("g").attr("class", "node");
      this.nodeTextGroup = this.svg.append("g").attr("class", "nodeText");
      this.nodeSymbolGroup = this.svg.append("g").attr("class", "nodeSymbol");
      this.nodeButtonGroup = this.svg.append("g").attr("class", "nodeButton");
      this.addMaker();
      this.tooltip = this.svg.append("div").style("opacity", 0);
      this.svg.on(
        "click",
        function () {
          d3.selectAll(".buttongroup").classed("circle_none", true);
        },
        "false"
      );
    },
    //初始化画布数据
    updateGraph () {
      let lks = this.graph.links;
      let nodes = this.graph.nodes;
      let links = [];
      //由后端传过来的节点坐标，固定节点，由于是字符串，需要转换
      nodes.forEach(function (n) {
        if (typeof n.fx == "undefined" || n.fx == "" || n.fx == null) {
          n.fx = null;
        }
        if (typeof n.fy == "undefined" || n.fy == "" || n.fy == null) {
          n.fy = null;
        }
        if (typeof n.fx == "string") n.fx = parseFloat(n.fx);
        if (typeof n.fy == "string") n.fy = parseFloat(n.fy);
        if (typeof n.r == "string") n.r = parseInt(n.r);
      });
      lks.forEach(function (m) {
        let sourceNode = nodes.filter(function (n) {
          return n.uuid === m.sourceId;
        })[0];
        if (typeof sourceNode == "undefined") return;
        let targetNode = nodes.filter(function (n) {
          return n.uuid === m.targetId;
        })[0];
        if (typeof targetNode == "undefined") return;
        links.push({ source: sourceNode.uuid, target: targetNode.uuid, lk: m });
      });
      //为每一个节点定制按钮组
      this.addNodeButton();
      if (links.length > 0) {
        _.each(links, function (link) {
          let same = _.filter(links, {
            source: link.source,
            target: link.target
          });
          let sameAlt = _.filter(links, {
            source: link.target,
            target: link.source
          });
          let sameAll = same.concat(sameAlt);
          _.each(sameAll, function (s, i) {
            s.sameIndex = i + 1;
            s.sameTotal = sameAll.length;
            s.sameTotalHalf = s.sameTotal / 2;
            s.sameUneven = s.sameTotal % 2 !== 0;
            s.sameMiddleLink =
              s.sameUneven === true &&
              Math.ceil(s.sameTotalHalf) === s.sameIndex;
            s.sameLowerHalf = s.sameIndex <= s.sameTotalHalf;
            s.sameArcDirection = 1;
            //s.sameArcDirection = s.sameLowerHalf ? 0 : 1;
            s.sameIndexCorrected = s.sameLowerHalf
              ? s.sameIndex
              : s.sameIndex - Math.ceil(s.sameTotalHalf);
          });
        });
        let maxSame = _.chain(links)
          .sortBy(function (x) {
            return x.sameTotal;
          })
          .last()
          .value().sameTotal;

        _.each(links, function (link) {
          link.maxSameHalf = Math.round(maxSame / 2);
        });
      }
      // 更新连线 links
      let link = this.linkGroup
        .selectAll(".line >path")
        .data(links, function (d) {
          return d.uuid;
        });
      link.exit().remove();
      let linkEnter = this.drawLink(link);
      link = linkEnter.merge(link);
      // 更新连线文字
    d3.selectAll(".lineText >g").remove();
      const linktext = this.linkTextGroup.selectAll("g").data(links);
      linktext.exit().remove();
      this.drawLinkText(linktext);
      // 更新节点按钮组
      d3.selectAll(".nodeButton >g").remove();
      let nodeButton = this.nodeButtonGroup
        .selectAll(".nodeButton")
        .data(nodes, function (d) {
          return d;
        });
      nodeButton.exit().remove();
      let nodeButtonEnter = this.drawNodeButton(nodeButton);
      nodeButton = nodeButtonEnter.merge(nodeButton);
      // 更新节点
      let node = this.nodeGroup
        .selectAll(".node >circle")
        .data(nodes, function (d) {
          return d.uuid + "_" + d.r + "_" + d.color; //d3数据驱动，r,color是表单中的可改变项，如果此处只设置了uuid,改变项可能不生效
        });
      node.exit().remove();
      let nodeEnter = this.drawNode(node);
      node = nodeEnter.merge(node).text(function (d) {
        return d.name;
      });
      // 更新节点文字
      let nodeText = this.nodeTextGroup
        .selectAll("text")
        .data(nodes, function (d) {
          return d.uuid;
        });
      nodeText.exit().remove();
      let nodeTextEnter = this.drawNodeText(nodeText);
      nodeText = nodeTextEnter.merge(nodeText)
      nodeText
        .append("title") // 为每个节点设置title
        .text(function (d) {
          return d.name;
        });
      // 更新节点标识
      let nodeSymbol = this.nodeSymbolGroup
        .selectAll("path")
        .data(nodes, function (d) {
          return d.uuid;
        });
      nodeSymbol.exit().remove();
      let nodeSymbolEnter = this.drawNodeSymbol(nodeSymbol);
      nodeSymbol = nodeSymbolEnter.merge(nodeSymbol);
      nodeSymbol.attr("fill", "#e15500");
      nodeSymbol.attr("display", function (d) {
        if (typeof d.hasFile != "undefined" && d.hasFile > 0) {
          return "block";
        }
        return "none";
      });
      this.simulation.nodes(nodes).on("tick", ticked);
      this.simulation.force("link").links(links);
      this.simulation.alphaTarget(1).restart();
      function linkArc (d) {
        let dx = d.target.x - d.source.x,
          dy = d.target.y - d.source.y,
          dr = Math.sqrt(dx * dx + dy * dy),
          unevenCorrection = d.sameUneven ? 0 : 0.5;
        let curvature = 2,
          arc =
            (1.0 / curvature) *
            ((dr * d.maxSameHalf) / (d.sameIndexCorrected - unevenCorrection));
        if (d.sameMiddleLink) {
          arc = 0;
        }
        let dd =
          "M" +
          d.source.x +
          "," +
          d.source.y +
          "A" +
          arc +
          "," +
          arc +
          " 0 0," +
          d.sameArcDirection +
          " " +
          d.target.x +
          "," +
          d.target.y;
        return dd;
      }
  const linkTextList = this.linkTextGroup.selectAll("g");
      const linkText = this.linkTextGroup.selectAll("g >text");
      function ticked () {
        link.attr("d", linkArc);
        // 更新节点坐标
        node
          .attr("cx", function (d) {
            return d.x;
          })
          .attr("cy", function (d) {
            return d.y;
          });
        // 更新节点操作按钮组坐标
        nodeButton
          .attr("cx", function (d) {
            return d.x;
          })
          .attr("cy", function (d) {
            return d.y;
          });
        nodeButton.attr("transform", function (d) {
          return "translate(" + d.x + "," + d.y + ") scale(1)";
        });

        // 更新文字坐标
        nodeText
          .attr("x", function (d) {
            return d.x;
          })
          .attr("y", function (d) {
            return d.y;
          });
        // 更新回形针坐标
        nodeSymbol.attr("transform", function (d) {
          return (
            "translate(" + (d.x + 8) + "," + (d.y - 30) + ") scale(0.015,0.015)"
          );
        });
           linkText.attr("dy", 5);
        linkTextList.attr("transform", function(d) {
          if (d.target.x < d.source.x) {
            const bbox = this.getBBox();
            const rx = bbox.x + bbox.width / 2;
            const ry = bbox.y + bbox.height / 2;
            return "rotate(180 " + rx + " " + ry + ")";
          } else {
            return "rotate(360)";
          }
        });
      }
      // 鼠标滚轮缩放
      //this.svg.call(d3.zoom().transform, d3.zoomIdentity);//缩放至初始倍数
      this.svg.call(
        d3.zoom().on("zoom", function () {
          d3.select("#link_menubar").style("display", "none");
          d3.select("#nodeDetail").style("display", "none");
          d3.selectAll(".node").attr("transform", d3.event.transform);
          d3.selectAll(".nodeText").attr("transform", d3.event.transform);
          d3.selectAll(".line").attr("transform", d3.event.transform);
          d3.selectAll(".lineText").attr("transform", d3.event.transform);
          d3.selectAll(".nodeSymbol").attr("transform", d3.event.transform);
          d3.selectAll(".nodeButton").attr("transform", d3.event.transform);
          //this.svg.selectAll("g").attr("transform", d3.event.transform);
        })
      );
      this.svg.on("dblclick.zoom", null); // 静止双击缩放
      //按钮组事件
      let _this = this;
      this.svg.selectAll(".buttongroup").on("click", function (d, i) {
        if (_this.nodeButtonAction) {
          switch (_this.nodeButtonAction) {
            case "EDIT":
              let formNode = {
                uuid: d.uuid,
                name: d.name,
                r: d.r,
                color: d.color
              };
              _this.$refs.kg_form.initNode(
                true,
                "nodeEdit",
                formNode,
                _this.domainId
              );
              break;
            case "MORE":
              _this.getMoreNode();
              break;
            case "CHILD":
              _this.$refs.kg_form.init(true, "batchAddChild");
              break;
            case "LINK":
              _this.isAddLink = true;
              _this.selectSourceNodeId = d.uuid;
              break;
            case "DELETE":
              _this.selectNode.nodeId = d.uuid;
              let out_buttongroup_id = ".out_buttongroup_" + d.uuid + "_" + i;
              _this.deleteNode(out_buttongroup_id);
              break;
          }
          //ACTION = '';//重置 ACTION
        }
      });
      //按钮组事件绑定
      this.svg.selectAll(".action_0").on("click", function (d) {
        _this.nodeButtonAction = "EDIT";
      });
      this.svg.selectAll(".action_1").on("click", function (d) {
        _this.nodeButtonAction = "MORE";
      });
      this.svg.selectAll(".action_2").on("click", function (d) {
        _this.nodeButtonAction = "CHILD";
      });
      this.svg.selectAll(".action_3").on("click", function (d) {
        _this.nodeButtonAction = "LINK";
      });
      this.svg.selectAll(".action_4").on("click", function (d) {
        _this.nodeButtonAction = "DELETE";
      });
    },
    //创建节点
    createNode (graphNode) {
      let data = graphNode;
      data.domain = this.domain;
      let _this = this;
      kgBuilderApi.createNode(data).then(result => {
        if (result.code == 200) {
          //删除旧节点，由于我们改变的是属性，不是uuid,此处我们需要更新属性，或者删除节点重新添加
          let newNode = result.data;
          for (let i = 0; i < _this.graph.nodes.length; i++) {
            if (_this.graph.nodes[i].uuid == _this.activeNode.uuid) {
              _this.graph.nodes.splice(i, 1);
            }
          }
          _this.graph.nodes.push(newNode);
          _this.updateGraph();
        }
      });
    },
    //画布直接添加节点
    createSingleNode (left, top) {
      let data = { name: "", r: 30 };
      data.domain = this.domain;
      kgBuilderApi.createNode(data).then(result => {
        if (result.code == 200) {
          let newNode = result.data;
          _.assignIn(newNode, {
            x: left,
            y: top,
            fx: left,
            fy: top,
            r: parseInt(newNode.r)
          });
          this.graph.nodes.push(newNode);
          this.updateGraph();
        }
      });
    },
    //添加箭头
    addMaker () {
      let arrowMarker = this.svg
        .append("marker")
        .attr("id", "arrow")
        .attr("markerUnits", "strokeWidth")
        .attr("markerWidth", "20") //
        .attr("markerHeight", "20")
        .attr("viewBox", "0 -5 10 10")
        .attr("refX", "22") // 13
        .attr("refY", "0")
        .attr("orient", "auto");
      let arrow_path = "M0,-5L10,0L0,5"; // 定义箭头形状
      arrowMarker
        .append("path")
        .attr("d", arrow_path)
        .attr("fill", "#fce6d4");
    },
    //绘制节点按钮
    addNodeButton (r) {
      //先删除所有为节点自定义的按钮组
      d3.selectAll("svg >defs").remove();
      let nodes = this.graph.nodes;
      let database = [1, 1, 1, 1, 1];
      let pie = d3.pie();
      let piedata = pie(database);
      let nodeButton = this.svg.append("defs");
      nodes.forEach(function (m) {
        let nBtng = nodeButton.append("g").attr("id", "out_circle" + m.uuid); //为每一个节点定制一个按钮组，在画按钮组的时候为其指定该id
        let buttonEnter = nBtng
          .selectAll(".buttongroup")
          .data(piedata)
          .enter()
          .append("g")
          .attr("class", function (d, i) {
            return "action_" + i;
          });
        let defaultR = 30;
        if (typeof m.r == "undefined") {
          m.r = defaultR;
        }
        let arc = d3
          .arc()
          .innerRadius(m.r)
          .outerRadius(m.r + 30);
        buttonEnter
          .append("path")
          .attr("d", function (d) {
            return arc(d);
          })
          .attr("fill", "#D2D5DA")
          .style("opacity", 0.6)
          .attr("stroke", "#f0f0f4")
          .attr("stroke-width", 2);
        buttonEnter
          .append("text")
          .attr("transform", function (d, i) {
            return "translate(" + arc.centroid(d) + ")";
          })
          .attr("text-anchor", "middle")
          .text(function (d, i) {
            let zi = new Array();
            zi[0] = "编辑";
            zi[1] = "展开";
            zi[2] = "追加";
            zi[3] = "连线";
            zi[4] = "删除";
            return zi[i];
          })
          .attr("font-size", 10);
      });
    },
    //拖拽开始
    dragStarted (d) {
      if (!d3.event.active) this.simulation.alphaTarget(0.3).restart();
       d.x = d3.event.x
      d.y = d3.event.y
      // d.fx = d.x;
      // d.fy = d.y;
      //d.fixed = true;
    },
    //拖拽中
    dragged (d) {
           let vx=d3.event.x-d.x;//x轴偏移量
      let vy=d3.event.y-d.y;//y轴偏移量
      d.x = d3.event.x
      d.y = d3.event.y
      d.fx = d3.event.x
      d.fy = d3.event.y
      let targetNodeIds=this.graph.links.filter(n=>n.sourceId==d.uuid).map(m=>m.targetId)
      if(targetNodeIds&&targetNodeIds.length>0){
        targetNodeIds.forEach(x=>{
         this.graph.nodes.filter(n=>n.uuid==x).map(m=>{
            m.fx=m.fx+vx;
            m.fy=m.fy+vy;
            m.x=m.x+vx;
            m.y=m.y+vy;
            return m;
          })
        })
      }
    },
    //拖拽结束
    dragEnded (d) {
     if (!d3.event.active) this.simulation.alphaTarget(0.3)
      let moveNodes=[];
      moveNodes.push({uuid:d.uuid,fx:d.fx,fy:d.fy})
      let relevantNodes=this.graph.links.filter(n=>n.sourceId==d.uuid)
      if(relevantNodes&&relevantNodes.length>0){
        relevantNodes.forEach(x=>{
          let targetNodes=this.graph.nodes.filter(n=>n.uuid==x.targetId).map(m=>{
            let item={uuid:m.uuid,fx:m.fx,fy:m.fy}
            return item;
          })
          moveNodes=moveNodes.concat(targetNodes)
        })
      }
      console.log(moveNodes)
      //批量更新本次移动的节点坐标
      let data={domain:this.domain,nodes:moveNodes}
      kgBuilderApi.updateCoordinateOfNode(data).then(result => { });
    },
    //绘制节点
    drawNode (node) {
      let _this = this;
      let nodeEnter = node.enter().append("circle");
      nodeEnter.attr("r", function (d) {
        if (typeof d.r != "undefined" && d.r != "") {
          if (typeof d.r == "string") d.r = parseInt(d.r);
          return d.r;
        }
        return 30;
      });
      nodeEnter.attr("fill", function (d) {
        if (typeof d.color != "undefined" && d.color != "") {
          return d.color;
        }
        return "#ff4500";
      });
      //nodeEnter.style("opacity", 0.8);
      nodeEnter.style("opacity", 1);
      nodeEnter.style("stroke", function (d) {
        if (typeof d.color != "undefined" && d.color != "") {
          return d.color;
        }
        return "#ff4500";
      });
      nodeEnter.style("stroke-opacity", 0.6);
      nodeEnter
        .append("title") // 为每个节点设置title
        .text(function (d) {
          return d.name;
        });
      nodeEnter.on("mouseover", function (d, i) {
        _this.nodeDetail = d;
        _this.timer = setTimeout(function () {
          _this.editorContent = "";
          _this.showImageList = [];
          _this.getNodeDetail(d.uuid, d.x, d.y);
        }, 2000);
      });
      nodeEnter.on("mouseout", function (d, i) {
        clearTimeout(_this.timer);
      });
      nodeEnter.on("dblclick", function (d) {
        _this.updateNodeName(d); // 双击更新节点名称
      });
      nodeEnter.on("mouseenter", function (d) {
        let aa = d3.select(this)._groups[0][0];
        if (aa.classList.contains("selected")) return;
        d3.select(this).style("stroke-width", "6");
      });
      nodeEnter.on("mouseleave", function (d) {
        let aa = d3.select(this)._groups[0][0];
        if (aa.classList.contains("selected")) return;
        d3.select(this).style("stroke-width", "2");
      });
      nodeEnter.on("click", function (d) {
        d3.select("#nodeDetail").style("display", "block");
        let out_buttongroup_id = ".out_buttongroup_" + d.uuid ;
        _this.svg.selectAll(".buttongroup").classed("circle_none", true);
        _this.svg.selectAll(out_buttongroup_id).classed("circle_none", false);
        _this.selectNode.nodeId = d.uuid;
        _this.selectNode.name = d.name;
        _this.activeNode = d;
        // 添加连线状态
        if (_this.isAddLink) {
          _this.selectTargetNodeId = d.uuid;
          if (
            _this.selectSourceNodeId == _this.selectTargetNodeId ||
            _this.selectSourceNodeId == 0 ||
            _this.selectTargetNodeId == 0
          )
            return;
          _this.createLink(
            _this.selectSourceNodeId,
            _this.selectTargetNodeId,
            "RE"
          );
          _this.selectSourceNodeId = 0;
          _this.selectTargetNodeId = 0;
          d.fixed = false;
          d3.event.stopPropagation();
          d3.event.preventDefault();
        }
      });
      nodeEnter.call(
        d3
          .drag()
          .on("start", this.dragStarted)
          .on("drag", this.dragged)
          .on("end", this.dragEnded)
      );
      return nodeEnter;
    },
    //绘制节点文字
    drawNodeText (nodeText) {
      let _this = this;
     const nodeTextEnter = nodeText
        .enter()
        .append('text')
        .style('fill', '#fff')
        // .attr('dx', function(d){
        //   return -1*(parseInt(d.r)-10)
        // })//设置居中不用偏移
        .attr('dy', 4)//文字是站在水平半径这条线上的，所以向下偏移一些，具体值应该是文字高度的一半
        .attr('font-family', '微软雅黑')
        .attr('text-anchor', 'middle')//设置文字居中
        nodeTextEnter.text(function (d) {
            let text=d.name
            const len = text.length;
            if (d.image) {
               return ''
            }else{
              //取圆的半径r，两边各空出5px,然后求出文字能放的最大长度(parseInt(d.r)-5)*2,一个文字占16px(系统默认font-size=16px),
              //相除得到最多能放多少汉字，font-size换算比有待考证，文字两边和圆边框的间距忽大忽小，有缘者来优化
              let dr=(parseInt(d.r)-5)*2/16;
                  if(dr<len){
                    return  text.substring(0, dr) + '...';
                  }else{
                    return d.name
                  }
              }
         })
      // nodeTextEnter.on("mouseover", function(d, i) {

      // });

      nodeTextEnter.on("dblclick", function (d) {
        _this.updateNodeName(d); // 双击更新节点名称
      });
      nodeTextEnter.on("click", function (d) {
        _this.selectNode.nodeId = d.uuid;
        // 添加连线状态
        if (_this.isAddLink) {
          _this.selectTargetNodeId = d.uuid;
          if (
            _this.selectSourceNodeId == _this.selectTargetNodeId ||
            _this.selectSourceNodeId == 0 ||
            _this.selectTargetNodeId == 0
          )
            return;
          _this.createLink(
            _this.selectSourceNodeId,
            _this.selectTargetNodeId,
            "RE"
          );
          _this.selectSourceNodeId = 0;
          _this.selectTargetNodeId = 0;
          d.fixed = false;
          d3.event.stopPropagation();
        }
      });
      nodeTextEnter.call(
        d3
          .drag()
          .on('start', this.dragStarted)
          .on('drag', this.dragged)
          .on('end', this.dragEnded)
      )
      return nodeTextEnter;
    },
    //给节点画上标识
    drawNodeSymbol (nodeSymbol) {
      let symbol_path =
        "M566.92736 550.580907c30.907733-34.655573 25.862827-82.445653 25.862827-104.239787 0-108.086613-87.620267-195.805867-195.577173-195.805867-49.015467 0-93.310293 18.752853-127.68256 48.564907l-0.518827-0.484693-4.980053 4.97664c-1.744213 1.64864-3.91168 2.942293-5.59104 4.72064l0.515413 0.484693-134.69696 133.727573L216.439467 534.8352l0 0 137.478827-136.31488c11.605333-10.410667 26.514773-17.298773 43.165013-17.298773 36.051627 0 65.184427 29.197653 65.184427 65.24928 0 14.032213-5.33504 26.125653-12.73856 36.829867l-131.754667 132.594347 0.515413 0.518827c-10.31168 11.578027-17.07008 26.381653-17.07008 43.066027 0 36.082347 29.16352 65.245867 65.184427 65.245867 16.684373 0 31.460693-6.724267 43.035307-17.07008l0.515413 0.512M1010.336427 343.49056c0-180.25472-145.882453-326.331733-325.911893-326.331733-80.704853 0-153.77408 30.22848-210.418347 79.0528l0.484693 0.64512c-12.352853 11.834027-20.241067 28.388693-20.241067 46.916267 0 36.051627 29.16352 65.245867 65.211733 65.245867 15.909547 0 29.876907-6.36928 41.192107-15.844693l0.38912 0.259413c33.624747-28.030293 76.301653-45.58848 123.511467-45.58848 107.99104 0 195.549867 87.6544 195.549867 195.744427 0 59.815253-27.357867 112.71168-69.51936 148.503893l0 0-319.25248 317.928107 0 0c-35.826347 42.2912-88.654507 69.710507-148.340053 69.710507-107.956907 0-195.549867-87.68512-195.549867-195.805867 0-59.753813 27.385173-112.646827 69.515947-148.43904l-92.18048-92.310187c-65.69984 59.559253-107.700907 144.913067-107.700907 240.749227 0 180.28544 145.885867 326.301013 325.915307 326.301013 95.218347 0 180.02944-41.642667 239.581867-106.827093l0.13312 0.129707 321.061547-319.962453-0.126293-0.13312C968.69376 523.615573 1010.336427 438.71232 1010.336427 343.49056L1010.336427 343.49056 1010.336427 343.49056zM1010.336427 343.49056"; // 定义回形针形状
      let nodeSymbolEnter = nodeSymbol
        .enter()
        .append("path")
        .attr("d", symbol_path);
      nodeSymbolEnter.call(
        d3
          .drag()
          .on("start", this.dragStarted)
          .on("drag", this.dragged)
          .on("end", this.dragEnded)
      );
      return nodeSymbolEnter;
    },
    //构建节点环形按钮组
    drawNodeButton (nodeButton) {
      let nodeButtonEnter = nodeButton
        .enter()
        .append("g")
        .append("use") //  为每个节点组添加一个 use 子元素
        .attr("r", function (d) {
          return d.r;
        })
        .attr("xlink:href", function (d) {
          return "#out_circle" + d.uuid;
        }) //  指定 use 引用的内容
        .attr("class", function (d, i) {
          return "buttongroup out_buttongroup_" + d.uuid;
        })
        .classed("circle_none", true);

      return nodeButtonEnter;
    },
    //构建连线，绑定事件
    drawLink (link) {
      let _this = this;
      let linkEnter = link
        .enter()
        .append("path")
        .attr("stroke-width", 1)
        .attr("stroke", "#fce6d4")
        .attr("fill", "none")
        .attr("id", function (d) {
          return (
            "invis_" + d.lk.sourceId + "-" + d.lk.name + "-" + d.lk.targetId
          );
        })
        .attr("marker-end", "url(#arrow)"); // 箭头
      //连线双击
      linkEnter.on("dblclick", function (d) {
        _this.selectNode.nodeId = d.lk.uuid;
        _this.updateLinkName();
      });
      //连线右键菜单
      linkEnter.on("contextmenu", function (d, p, x, z) {
        //let dd = d3.mouse(this);
        _this.selectNode.nodeId = d.lk.uuid;
        _this.selectlinkname = d.lk.name;
        var e = window.event;
        let link = {
          left: e.clientX,
          top: e.clientY,
          show: true
        };
        _this.$refs.menu_link.init(link);
        d3.event.preventDefault(); // 禁止系统默认右键
        d3.event.stopPropagation(); // 禁止空白处右键
      });
      //连线鼠标滑入
      linkEnter.on("mouseenter", function (d) {
        d3.select(this)
          .style("stroke-width", "12")
          .attr("stroke", "#ff9e9e")
          .attr("marker-end", "");
        _this.nodeDetail = d.lk;
        d3.select("#nodeDetail").style("display", "block");
      });
      //连线鼠标离开
      linkEnter.on("mouseleave", function (d) {
        d3.select(this)
          .style("stroke-width", "1")
          .attr("stroke", "#fce6d4")
          .attr("marker-end", "url(#arrow)");
      });
      return linkEnter;
    },
    //构建连线上的文字，并绑定事件
    drawLinkText (link) {
       const _this = this;
      const linkTextEnter = link
        .enter()
        .append("g")
        .attr("class", function(d) {
          return "TextLink_" + d.lk.id;
        });
      linkTextEnter
        .append("text")
        .append("textPath")
        .attr("filter", "url(#Linktext)")
        .attr("startOffset", "50%")
        .attr("text-anchor", "middle")
        .attr("xlink:href", function(d) {
          return (
            "#invis_" + d.lk.sourceId + "-" + d.lk.name + "-" + d.lk.targetId
          );
        })
        .style("font-family", "SimSun")
        .style("fill", "#434343")
        .style("stroke", "#434343")
        .style("font-size", 13)
        .text(function(d) {
          if (d.lk.name != "") {
            return d.lk.name;
          }
        });
      linkTextEnter.on("mouseover", function(d) {
        _this.selectNode.nodeId = d.lk.uuid;
        _this.selectlinkname = d.lk.name;
        var e = window.event;
        let link = {
          left: e.pageX,
          top: e.pageY,
          show: true
        };
        _this.$refs.menu_link.init(link);
      });

      const linkTextSS = linkTextEnter.insert("filter", "text");
      const linkTextSQ = linkTextSS
        .attr("id", "Linktext")
        .attr("height", "110%")
        .attr("width", "110%");
      linkTextSQ
        .append("feFlood")
        .attr("flood-color", "#ffffff")
        .attr("flood-opacity", 1);
      linkTextSQ
        .append("feComposite")
        .attr("in", "SourceGraphic")
        .attr("in2", "floodFill");
      return linkTextSQ;
    },
    //删除节点
    deleteNode (out_buttongroup_id) {
      let _this = this;
      _this
        .$confirm(
          "此操作将删除该节点及周边关系(不可恢复), 是否继续?",
          "三思而后行",
          {
            confirmButtonText: "确定",
            cancelButtonText: "取消",
            type: "warning"
          }
        )
        .then(function () {
          let data = { domain: _this.domain, nodeId: _this.selectNode.nodeId };
          kgBuilderApi.deleteNode(data).then(result => {
            if (result.code == 200) {
              _this.svg.selectAll(out_buttongroup_id).remove();
              let rShips = result.data;
              // 删除节点对应的关系
              for (let m = 0; m < rShips.length; m++) {
                for (let i = 0; i < _this.graph.links.length; i++) {
                  if (_this.graph.links[i].uuid == rShips[m].uuid) {
                    _this.graph.links.splice(i, 1);
                    i = i - 1;
                  }
                }
              }
              // 找到对应的节点索引
              let j = -1;
              for (let i = 0; i < _this.graph.nodes.length; i++) {
                if (_this.graph.nodes[i].uuid == _this.selectNode.nodeId) {
                  j = i;
                  break;
                }
              }
              if (j >= 0) {
                _this.selectNode.nodeId = 0;
                _this.graph.nodes.splice(j, 1); // 根据索引删除该节点
                _this.updateGraph();
                _this.$message({
                  type: "success",
                  message: "操作成功!"
                });
              }
            }
          });
        })
        .catch(function () {
          _this.$message({
            type: "info",
            message: "已取消删除"
          });
        });
    },
    //删除连线
    deleteLink () {
      let _this = this;
      _this
        .$confirm("此操作将删除该关系(不可恢复), 是否继续?", "三思而后行", {
          confirmButtonText: "确定",
          cancelButtonText: "取消",
          type: "warning"
        })
        .then(function () {
          let data = { domain: _this.domain, shipId: _this.selectNode.nodeId };
          kgBuilderApi.deleteLink(data).then(result => {
            if (result.code == 200) {
              let j = -1;
              for (let i = 0; i < _this.graph.links.length; i++) {
                if (_this.graph.links[i].uuid == _this.selectNode.nodeId) {
                  j = i;
                  break;
                }
              }
              if (j >= 0) {
                _this.selectNode.nodeId = 0;
                _this.graph.links.splice(j, 1);
                _this.updateGraph();
                _this.isDeleteLink = false;
              }
            }
          });
        })
        .catch(function () {
          _this.$message({
            type: "info",
            message: "已取消删除"
          });
        });
    },
    //添加连线
    createLink (sourceId, targetId, ship) {
      let data = {
        domain: this.domain,
        sourceId: sourceId,
        targetId: targetId,
        ship: ship
      };
      kgBuilderApi.createLink(data).then(result => {
        if (result.code == 200) {
          let newShip = result.data;
          this.graph.links.push(newShip);
          this.updateGraph();
          this.isAddLink = false;
        }
      });
    },
    //更新连线名称
    updateLinkName () {
      let _this = this;
      this.$prompt("请输入关系名称", "提示", {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        inputValue: this.selectlinkname
      })
        .then(function (res) {
          let value = res.value;
          let data = {
            domain: _this.domain,
            shipId: _this.selectNode.nodeId,
            shipName: value
          };
          kgBuilderApi.updateLink(data).then(result => {
            if (result.code == 200) {
              let newShip = result.data;
              _this.graph.links.forEach(function (m) {
                if (m.uuid == newShip.uuid) {
                  m.name = newShip.name;
                }
              });
              _this.selectNode.nodeId = 0;
              _this.updateGraph();
              _this.isAddLink = false;
              _this.selectlinkname = "";
            }
          });
        })
        .catch(function () {
          _this.$message({
            type: "info",
            message: "取消输入"
          });
        });
    },
    //更新节点名称
    updateNodeName (d) {
      let _this = this;
      _this
        .$prompt("编辑节点名称", "提示", {
          confirmButtonText: "确定",
          cancelButtonText: "取消",
          inputValue: d.name
        })
        .then(function (res) {
          let value = res.value;
          let data = { domain: _this.domain, nodeId: d.uuid, nodeName: value };
          kgBuilderApi.updateNodeName(data).then(result => {
            if (result.code == 200) {
              if (d.uuid != 0) {
                for (let i = 0; i < _this.graph.nodes.length; i++) {
                  if (_this.graph.nodes[i].uuid == d.uuid) {
                    _this.graph.nodes[i].name = value;
                  }
                }
              }
              _this.updateGraph();
              _this.$message({
                message: "操作成功",
                type: "success"
              });
            }
          });
        })
        .catch(function () {
          _this.$message({
            type: "info",
            message: "取消操作"
          });
        });
    },
    //初始化节点富文本内容
    initNodeContent () {
      let data = { domainId: this.domainId, nodeId: this.selectNode.nodeId };
      kgBuilderApi.getNodeContent(data).then(response => {
        if (response.code == 200) {
          if (response.data) {
            this.$refs.kg_form.initContent(response.data.content);
          } else {
            this.$message.warning("暂时没有更多数据");
          }
        }
      });
    },
    //初始化节点添加的图片
    initNodeImage () {
      let data = { domainId: this.domainId, nodeId: this.selectNode.nodeId };
      kgBuilderApi.getNodeImage(data).then(response => {
        if (response.code == 200) {
          if (response.data) {
            let nodeImageList = [];
            for (let i = 0; i < response.data.length; i++) {
              nodeImageList.push({
                file: response.data[i].fileName,
                imageType: response.data[i].imageType
              });
              this.$refs.kg_form.initImage(nodeImageList);
            }
          } else {
            this.$message.warning("暂时没有更多数据");
          }
        }
      });
    },
    //一次性获取富文本和图片
    getNodeDetail (nodeId, left, top) {
      let data = { domainId: this.domainId, nodeId: nodeId };
      kgBuilderApi.getNodeDetail(data).then(result => {
        if (result.code == 200) {
          if (result.data) {
            this.$refs.node_richer.init(
              result.data.content,
              result.data.imageList,
              left,
              top
            );
          } else {
            this.$message.warning("暂时没有更多数据");
          }
        }
      });
    },
    //全屏
    requestFullScreen () {
      let element = document.getElementById("graphcontainerdiv");
      let width = window.screen.width;
      let height = window.screen.height;
      this.svg.attr("width", width);
      this.svg.attr("height", height);
      if (element.requestFullscreen) {
        element.requestFullscreen();
      }
      // FireFox
      else if (element.mozRequestFullScreen) {
        element.mozRequestFullScreen();
      }
      // Chrome等
      else if (element.webkitRequestFullScreen) {
        element.webkitRequestFullScreen();
      }
      // IE11
      else if (element.msRequestFullscreen) {
        element.msRequestFullscreen();
      }
    },
    //获取图谱节点及关系
    getDomainGraph () {
      this.loading = true;
      let data = {
        domain: this.domain,
        nodeName: this.nodeName,
        pageSize: this.pageSize
      };
      kgBuilderApi.getDomainGraph(data).then(result => {
        if (result.code == 200) {
          if (result.data != null) {
            this.graph.nodes = result.data.node;
            this.graph.links = result.data.relationship;
            this.updateGraph();
          }
        }
      });
    },
    //添加单个节点，改变鼠标样式为+
    btnAddSingle () {
      d3.select(".graphContainer").style("cursor", "crosshair"); //进入新增模式，鼠标变成＋
    },
    //删除连线
    btnDeleteLink () {
      this.isDeleteLink = true;
      d3.select(".link").attr("class", "link linkDelete"); // 修改鼠标样式为"+"
    },
    //展开更多节点
    getMoreNode () {
      let data = { domain: this.domain, nodeId: this.selectNode.nodeId };
      kgBuilderApi.getMoreRelationNode(data).then(result => {
        if (result.code == 200) {
          //把不存在于画布的节点添加到画布
          this.mergeNodeAndLink(result.data.node, result.data.relationship);
          //重新绘制
          this.updateGraph();
        }
      });
    },
    //快速添加
    btnQuickAddNode () {
      this.$refs.kg_form.init(true, "batchAdd",this.domain);
    },
    //删除领域
    deleteDomain (id, value) {
      this.$confirm(
        "此操作将删除该标签及其下节点和关系(不可恢复), 是否继续?",
        "三思而后行",
        {
          confirmButtonText: "确定",
          cancelButtonText: "取消",
          type: "warning"
        }
      )
        .then(function (res) {
          let data = { domainId: id, domain: value };
          kgBuilderApi.deleteDomain(data).then(result => {
            if (result.code == 200) {
              this.getDomain();
              this.domain = "";
            }
          });
        })
        .catch(() => {
          this.$message({
            type: "info",
            message: "已取消删除"
          });
        });
    },
    //创建新领域
    createDomain (value) {
      this.$prompt("请输入领域名称", "提示", {
        confirmButtonText: "确定",
        cancelButtonText: "取消"
      })
        .then(res => {
          value = res.value;
          let data = { domain: value, type: 0 };
          kgBuilderApi.createDomain(data).then(result => {
            if (result.code == 200) {
              this.getDomain();
              this.domain = value;
              this.getDomainGraph();
            }
          });
        })
        .catch(() => {
          this.$message({
            type: "info",
            message: "取消输入"
          });
        });
    },
    //获取领域标签
    getLabels (data) {
      kgBuilderApi.getDomains(data).then(result => {
        if (result.code == 200) {
          this.pageModel = result.data;
          this.pageModel.totalPage =
            parseInt((result.data.totalCount - 1) / result.data.pageSize) + 1;
        }
      });
    },
    getDomain (pageIndex) {
      this.pageModel.pageIndex = pageIndex
        ? pageIndex
        : this.pageModel.pageIndex;
      let data = {
        pageIndex: this.pageModel.pageIndex,
        pageSize: this.pageModel.pageSize,
        command: 0
      };
      this.getLabels(data);
    },
    matchDomainGraph (domain) {
      this.domain = domain.name;
      this.domainId = domain.id;
      this.getDomainGraph();
    },
    //保存图片
    saveImage () {
      html2canvas(document.querySelector(".graphContainer"), {
        width: document.querySelector(".graphContainer").offsetWidth, // canvas画板的宽度 一般都是要保存的那个dom的宽度
        height: document.querySelector(".graphContainer").offsetHeight, // canvas画板的高度  同上
        scale: 1
      }).then(function (canvas) {
        let a = document.createElement("a");
        a.href = canvas.toDataURL("image/png"); //将画布内的信息导出为png图片数据
        let timeStamp = Date.parse(new Date());
        a.download = timeStamp; //设定下载名称
        a.click(); //点击触发下载
      });
    },
    showJsonData () {
      this.$refs.kg_json.init();
    },
    wanted () {
      this.$refs.kg_wanted.init();
    },
    //导入图谱
    importGraph () {
       if (!this.domain || this.domain == '') {
        this.$message.warning("请选择一个领域");
        return;
      }
      this.$refs.kg_form.init(true, "import",this.domain);
    },
    exportGraph () {
      if (!this.domain || this.domain == '') {
        this.$message.warning("请选择一个领域");
        return;
      }
      let data = { domain: this.domain };
      kgBuilderApi.exportGraph(data).then(result => {
        if (result.code == 200) {
          window.location.href = result.fileName
        }
      });
    },
    help () {
      this.$refs.kg_help.init();
    },
    //设置画布内最大的点个数
    setMatchSize (m) {
      for (let i = 0; i < this.pageSizeList.length; i++) {
        this.pageSizeList[i].isActive = false;
        if (this.pageSizeList[i].size == m.size) {
          this.pageSizeList[i].isActive = true;
        }
      }
      this.pageSize = m.size;
      this.getDomainGraph();
    },
    //合并节点和连线
    mergeNodeAndLink (newNodes, newLinks) {
      let _this = this;
      newNodes.forEach(function (m) {
        let sobj = _this.graph.nodes.find(function (x) {
          return x.uuid === m.uuid;
        });
        if (typeof sobj == "undefined") {
          _this.graph.nodes.push(m);
        }
      });
      newLinks.forEach(function (m) {
        let sobj = _this.graph.links.find(function (x) {
          return x.uuid === m.uuid;
        });
        if (typeof sobj == "undefined") {
          _this.graph.links.push(m);
        }
      });
    },
    //批量添加节点
    batchCreateNode (param) {
      let data = {
        domain: this.domain,
        sourceName: param.sourceNodeName,
        targetNames: param.targetNodeNames,
        relation: param.relation
      };
      kgBuilderApi.batchCreateNode(data).then(result => {
        if (result.code == 200) {
          //把不存在于画布的节点添加到画布
          this.mergeNodeAndLink(result.data.nodes, result.data.ships);
          //重新绘制
          this.updateGraph();
          this.$message({
            message: "操作成功",
            type: "success"
          });
        }
      });
    },
    //批量添加子节点
    batchCreateChildNode (param) {
      let data = {
        domain: this.domain,
        sourceId: this.selectNode.nodeId,
        targetNames: param.targetNodeNames,
        relation: param.relation
      };
      kgBuilderApi.batchCreateChildNode(data).then(result => {
        if (result.code == 200) {
          //把不存在于画布的节点添加到画布
          this.mergeNodeAndLink(result.data.nodes, result.data.ships);
          //重新绘制
          this.updateGraph();
          this.$message({
            message: "操作成功",
            type: "success"
          });
        }
      });
    },
    //批量添加同级节点
    batchCreateSameNode (param) {
      let data = {
        domain: this.domain,
        sourceNames: param.sourceNodeName
      };
      kgBuilderApi.batchCreateSameNode(data).then(result => {
        if (result.code == 200) {
          //把不存在于画布的节点添加到画布
          this.mergeNodeAndLink(result.data, null);
          //重新绘制
          this.updateGraph();
          this.$message({
            message: "操作成功",
            type: "success"
          });
        }
      });
    },
    //画布右击
    initContainerRightClick (event) {
      let _this = this;
      _this.mouserPos = {
        left: event.clientX,
        top: event.clientY
      };
      let menuBar = {
        left: event.clientX,
        top: event.clientY,
        show: true
      };
      _this.$refs.menu_blank.init(menuBar);
      event.preventDefault();
    },
    //画布点击
    initContainerLeftClick (event) {
      let _this = this;
      _this.mouserPos = {
        left: event.clientX,
        top: event.clientY
      };
      _this.$refs.menu_blank.init({ show: false });
      _this.$refs.menu_link.init({ show: false });
      _this.$refs.node_richer.close();
      if (event.target.tagName != "circle" && event.target.tagName != "link") {
        d3.select("#nodeDetail").style("display", "none");
      }
      let cursor = document.getElementById("graphContainer").style.cursor;
      if (cursor == "crosshair") {
        d3.select(".graphContainer").style("cursor", "");
        _this.createSingleNode(event.offsetX, event.offsetY);
      }
      event.preventDefault();
    }
  }
};
</script>
<style>
.mind-box {
  height: calc(100vh - 85px);
  overflow: hidden;
}
.mind-l {
  width: 300px;
  float: left;
  background: #f7f9fc;
  height: 100%;
  border-right: 1px solid #d3e2ec;
}
.ml-ht {
  padding-top: 20px;
  line-height: 50px;
  font-size: 16px;
  font-weight: 400;
  text-align: center;
  color: #333;
  border-bottom: 1px solid #d3e2ec;
}
.ml-a-box {
  margin: 10px;
}
.ml-a {
  display: inline-block;
  min-width: 46px;
  line-height: 1;
  padding: 6px 8px 6px 8px;
  margin: 0 4px 5px 0;
  background: #fff;
  border: 1px solid #e3e3e3;
  box-sizing: border-box;
  transition: 0.3s;
}
.ml-a span {
  max-width: 190px;
  display: inline-block;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  vertical-align: middle;
}
.ml-a-all {
  display: block;
  margin: 10px 10px 0;
  text-align: center;
}
.ml-a span:empty:before {
  content: '閺堫亜鎳￠崥锟�';
  color: #adadad;
}
.ml-a small {
  color: #999;
}
.ml-a:hover {
  background: #f4f4f4;
}
.ml-a.cur,
.ml-a.cur small {
  background: #156498;
  color: #fff;
}
.ml-btn-box {
  text-align: right;
  padding: 0 10px;
  margin-bottom: 20px;
}
.ml-btn {
  padding: 0 5px;
  color: #156498;
}
.mind-con {
  height: calc(100vh - 40px);
  overflow: hidden;
  background: #fff;
  display: -webkit-flex;
  display: flex;
  flex-direction: column;
  padding: 5px;
}
.mind-top {
  /* line-height: 70px;
  height: 70px; */
  padding: 0 22px;
  border-bottom: 1px solid #ededed;
}
.mt-m {
  color: #666;
  margin-right: 30px;
}
.mt-m i {
  font-size: 18px;
  color: #333;
  font-weight: 700;
  font-style: normal;
}
.mb-con .search,
.mind-top .search {
  border: 1px solid #e2e2e2;
}
.svg-a-sm {
  font-size: 14px;
  color: #156498;
  margin-right: 30px;
  cursor: pointer;
}
.mind-cen {
  height: calc(100% - 70px);
}
.half-auto {
  height: 40%;
}
.mind-bottom {
  height: 490px;
  box-sizing: border-box;
  border-top: 1px solid #ededed;
}
.ss-d {
  display: inline-block;
  vertical-align: middle;
  margin-right: 10px;
  border-radius: 50%;
  background: #dedede;
}
.sd {
  margin: 2px;
}
.sd-active {
  color: red !important;
  background: none !important;
}
.btn-line + .btn-line {
  margin-left: 10px;
}
.co {
  color: #ee8407 !important;
}
a {
  text-decoration: none;
}
.a {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.fl {
  float: left;
}
.fr {
  float: right;
  margin: 7px;
}
.tl {
  text-align: left;
}
.pl-20 {
  padding-left: 20px;
}
text {
  cursor: pointer;
  max-width: 25px;
  display: inline-block;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  vertical-align: middle;
}
circle {
  cursor: pointer;
}
#graphcontainerdiv {
  background: #fff;
}
.el-color-picker__panel {
  left: 812px !important;
}
.wange-toolbar {
  border: 1px solid #ccc;
}
.wangeditor-form {
  border: 1px solid #ccc;
  height: 350px;
  min-height: 340px;
}
.el-tag {
  max-width: 80px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.mind-fj-box {
  display: inline-block;
  width: 290px;
  padding: 5px;
  border: 1px solid #e6e6e6;
  box-shadow: 0 0 8px rgba(206, 205, 201, 0.38);
}
.mind-fj-p {
  color: #666;
  line-height: 24px;
  padding: 5px;
  background: rgba(255, 255, 255, 0.85);
}
.mind-carousel + .mind-fj-p .el-scrollbar__wrap {
  height: auto;
  max-height: 220px;
  min-height: 0;
}
.carous-img {
  height: 100%;
  background: rgba(0, 0, 0, 0.1);
  line-height: 197px;
  text-align: center;
}
.carous-img img {
  max-width: 100%;
  max-height: 100%;
  line-height: 197px;
  vertical-align: middle;
}

.node_detail {
  position: absolute;
  width: 100%;
  line-height: 35px;
  -webkit-border-radius: 10px;
  -moz-border-radius: 10px;
  border-radius: 10px;
  font-size: 12px;
  padding-bottom: 10px;
  background: rgba(198, 226, 255, 0.2);
  display: none;
}
.node_pd {
  padding: 4px;
  font-size: 13px;
  font-family: -webkit-body;
  font-weight: 600;
}
.operatetips {
  position: absolute;
  right: 10px;
  float: right;
  top: 0;
  width: 335px;
  padding: 30px;
  border: 2px #ee7942 solid;
  border-radius: 4px;
}
.jsoncontainer {
  position: absolute;
  right: 30%;
  float: right;
  top: 0;
  width: 60%;
  height: 60%;
  padding: 30px;
  border: 2px #ee7942 solid;
  border-radius: 4px;
  background: #fff;
}
.cypher_toolbar {
  line-height: 70px;
  height: 85px;
  padding: 0 22px;
  border-bottom: 1px solid #ededed;
}
.hometitle {
  font-size: 18px;
  color: #282828;
  font-weight: 600;
  margin: 0;
  text-transform: uppercase;
  padding-bottom: 15px;
  margin-bottom: 25px;
  position: relative;
}

.el-scrollbar {
  overflow: hidden;
  position: relative;
}
ul {
  padding: 0px;
}
.icon {
  width: 1em;
  height: 1em;
  vertical-align: -0.15em;
  fill: currentColor;
  overflow: hidden;
}
.el-button {
  display: inline-block;
  line-height: 1;
  white-space: nowrap;
  cursor: pointer;
  background: #fff;
  border: 1px solid #d8dce5;
  color: #5a5e66;
  -webkit-appearance: none;
  text-align: center;
  -webkit-box-sizing: border-box;
  box-sizing: border-box;
  outline: 0;
  margin: 0;
  -webkit-transition: 0.1s;
  transition: 0.1s;
  font-weight: 500;
  padding: 12px 20px;
  font-size: 14px;
  border-radius: 4px;
}
.search {
  position: relative;
  width: 220px;
  height: 32px;
  border-radius: 32px;
  overflow: hidden;
}
.search .el-input__inner {
  box-sizing: border-box;
  padding-left: 15px;
  height: 32px;
  line-height: 32px;
  padding-right: 40px;
  background: transparent;
  border-radius: 32px;
  border: none;
  transition: background 0.3s;
}
.search .el-button--default {
  position: absolute;
  right: 1px;
  float: right;
  padding: 0 10px;
  font-size: 22px;
  line-height: 29px;
  color: #7c9cb2;
  background: transparent;
  border: none;
  z-index: 1;
}
.search .el-button--default:hover {
  color: #156498;
  background: transparent;
  border: none;
}
.top .search {
  margin-left: 30px;
  background: rgba(0, 0, 0, 0.25);
  display: none;
}
.circle_none {
  display: none;
}
.dibmr {
  padding: 4px;
  display: inline-block;
  line-height: 30px;
}
text {
    cursor: pointer;
    max-width: 30px;
    display: inline-block;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    vertical-align: middle;
  }
  circle {
    cursor: pointer;
  }

</style>
