
<template>
  <div>
    <div class="super-flow-demo1">
      <div class="node-container">
        <p class="label_head">节点类型</p>
        <p class="label_explanation">请拖拽添加到流程中</p>
        <el-input-number
          v-model="scale_num"
          @change="handleChange"
          :step="10"
          :step-strictly="true"
          :min="50"
          :max="150"
          label="描述文字"
        ></el-input-number>
        <span
          class="node-item"
          v-for="(item, index) in nodeItemList"
          :key="index"
          @mousedown="evt => nodeItemMouseDown(evt, item.value)"
        >{{item.label}}</span>
      </div>
      <div class="flow-container" :class="`scale${scale_num}`" ref="flowContainer">
        <super-flow
          ref="superFlow"
          :node-list="nodeList"
          :link-list="linkList"
          :link-menu="linkMenu"
          :link-base-style="linkBaseStyle"
          :link-style="linkStyle"
          :link-desc="linkDesc"
          :origin="origin"
        >
          <template v-slot:node="{meta}">
            <div
              :class="{'flow-node-begin': meta.type == 'begin', 'flow-node-end': meta.type == 'end', 'flow-node-default': meta.type == 'default'}"
              :id="meta.id"
              @click="clickItem(meta)"
            >{{meta.name}}</div>
          </template>
        </super-flow>
      </div>
    </div>
  </div>
</template>

<script>
const drawerType = {
  node: 0,
  link: 1,
};
export default {
  data() {
    return {
      scale_num: 100,
      origin: [0, 0],
      nodeList: [],
      linkList: [],
      drawerType,
      drawerConf: {
        title: "",
        visible: false,
        type: null,
        info: null,
        open: (type, info) => {
          const conf = this.drawerConf;
          conf.visible = true;
          conf.type = type;
          conf.info = info;
          if (conf.type === drawerType.node) {
            conf.title = "节点";
            if (this.$refs.nodeSetting) this.$refs.nodeSetting.resetFields();
            this.$set(this.nodeSetting, "name", info.meta.name);
            this.$set(this.nodeSetting, "desc", info.meta.desc);
          } else {
            conf.title = "连线";
            if (this.$refs.linkSetting) this.$refs.linkSetting.resetFields();
            this.$set(
              this.linkSetting,
              "desc",
              info.meta ? info.meta.desc : ""
            );
          }
        },
        cancel: () => {
          this.drawerConf.visible = false;
          if (this.drawerConf.type === drawerType.node) {
            this.$refs.nodeSetting.clearValidate();
          } else {
            this.$refs.linkSetting.clearValidate();
          }
        },
      },
      linkSetting: {
        desc: "",
      },
      nodeSetting: {
        name: "",
        desc: "",
      },
      dragConf: {
        isDown: false,
        isMove: false,
        offsetTop: 0,
        offsetLeft: 0,
        clientX: 0,
        clientY: 0,
        ele: null,
        info: null,
      },
      nodeItemList: [
        {
          label: "开始",
          value: {
            width: 120,
            height: 40,
            meta: {
              label: "开始开始开始开始开始",
              name: "开始开始开始开始开始",
              type: "begin",
            },
          },
        },
        {
          label: "结束",
          value: {
            width: 120,
            height: 40,
            meta: {
              label: "结束",
              name: "结束",
              type: "end",
            },
          },
        },
        {
          label: "普通节点",
          value: {
            width: 120,
            height: 40,
            meta: {
              label: "普通节点",
              name: "普通节点",
              type: "default",
            },
          },
        },
      ],
      linkMenu: [
        [
          {
            label: "删除",
            selected: (link) => {
              console.log(link);
              link.remove();
            },
          },
          {
            label: "编辑",
            selected: (link) => {
              this.drawerConf.open(drawerType.link, link);
            },
          },
        ],
      ],
      linkBaseStyle: {
        color: "#666666", // line 颜色
        hover: "#FF0000", // line hover 的颜色
        textColor: "#666666", // line 描述文字颜色
        textHover: "#FF0000", // line 描述文字 hover 颜色
        font: "14px Arial", // line 描述文字 字体设置 参考 canvas font
        dotted: false, // 是否是虚线
        lineDash: [4, 4], // 虚线时生效
        background: "rgba(255,255,255,0.6)", // 描述文字背景色
      },
    };
  },
  mounted() {
    document.addEventListener("mousemove", this.docMousemove);
    document.addEventListener("mouseup", this.docMouseup);
    this.$once("hook:beforeDestroy", () => {
      document.removeEventListener("mousemove", this.docMousemove);
      document.removeEventListener("mouseup", this.docMouseup);
    });
  },
  methods: {
    linkStyle(link) {
      return {
        // hover: '#FF00FF'
      };
    },
    linkDesc(link) {
      return link.meta ? link.meta.desc : "";
    },
    docMousemove({ clientX, clientY }) {
      const conf = this.dragConf;
      if (conf.isMove) {
        conf.ele.style.top = clientY - conf.offsetTop + "px";
        conf.ele.style.left = clientX - conf.offsetLeft + "px";
      } else if (conf.isDown) {
        // 鼠标移动量大于 5 时 移动状态生效
        conf.isMove =
          Math.abs(clientX - conf.clientX) > 5 ||
          Math.abs(clientY - conf.clientY) > 5;
      }
    },
    docMouseup({ clientX, clientY }) {
      const conf = this.dragConf;
      conf.isDown = false;
      if (conf.isMove) {
        const {
          top,
          right,
          bottom,
          left,
        } = this.$refs.flowContainer.getBoundingClientRect();
        // 判断鼠标是否进入 flow container
        if (
          clientX > left &&
          clientX < right &&
          clientY > top &&
          clientY < bottom
        ) {
        } else if (clientX <= left) {
          clientX = left;
        } else if (clientX >= right) {
          clientX = right;
        } else if (clientY <= top) {
          clientY = top;
        } else if (clientY >= bottom) {
          clientY = bottom;
        }
        // 获取拖动元素左上角相对 super flow 区域原点坐标
        console.log(top, right, bottom, left, clientX, clientY);
        const coordinate = this.$refs.superFlow.getMouseCoordinate(
          clientX  - conf.offsetLeft,
          clientY - conf.offsetTop
        );
        // 添加节点
        this.$refs.superFlow.addNode({
          coordinate,
          ...conf.info,
        });
        conf.isMove = false;
      }
      if (conf.ele) {
        conf.ele.remove();
        conf.ele = null;
      }
    },
    nodeItemMouseDown(evt, info) {
      info.meta.id = parseInt(Math.random() * 1000 * 1000);
      console.log(evt, info);
      const { clientX, clientY, currentTarget } = evt;
      const { top, left } = evt.currentTarget.getBoundingClientRect();
      const conf = this.dragConf;
      const ele = currentTarget.cloneNode(true);
      Object.assign(this.dragConf, {
        offsetLeft: clientX - left,
        offsetTop: clientY - top,
        clientX: clientX,
        clientY: clientY,
        info,
        ele,
        isDown: true,
      });
      ele.style.position = "fixed";
      ele.style.margin = "0";
      ele.style.top = clientY - conf.offsetTop + "px";
      ele.style.left = clientX - conf.offsetLeft + "px";
      this.$el.appendChild(this.dragConf.ele);
    },
    clickItem(item) {
      console.log(item);
    },
    getData() {
      console.log(this.$refs.superFlow.toJSON());
    },
    handleChange() {},
  },
};
</script>

<style lang="less">
.link-base-style-form {
  .el-form-item {
    margin-bottom: 12px;
  }
  padding-bottom: 20px;
  border-bottom: 1px solid #dcdcdc;
}
.super-flow-demo1 {
  margin-top: 20px;
  width: 100%;
  height: 800px;
  background-color: #f5f5f5;
  @list-width: 200px;
  > .node-container {
    width: @list-width;
    position: absolute;
    z-index: 2;
    left: 0;
    height: 400px;
    text-align: center;
    background-color: #ffffff;
    .label_head {
      font-weight: bold;
      font-size: 18px;
      text-align: center;
      padding: 20px 0;
    }
    .label_explanation {
      font-size: 16px;
      text-align: center;
      padding-bottom: 5px;
    }
  }
  > .flow-container {
    width: 100%;
    float: left;
    height: 100%;
    overflow: hidden;
  }
  .super-flow__node {
    box-shadow: none;
    border: none;
    background-color: transparent;
    .flow-node-begin {
      width: 100%;
      height: 100%;
      line-height: 36px;
      padding: 0 6px;
      font-size: 12px;
      text-align: center;
      overflow: hidden;
      white-space: nowrap;
      text-overflow: ellipsis;
      border-radius: 8px;
      border: 2px solid #444;
      &:focus {
        border: 2px solid #0f0;
      }
    }
    .flow-node-end {
      width: 100%;
      line-height: 36px;
      padding: 0 6px;
      font-size: 12px;
      text-align: center;
      overflow: hidden;
      white-space: nowrap;
      text-overflow: ellipsis;
      border-radius: 8px;
      border: 2px solid #f80;
      &:focus {
        border: 2px solid #0f0;
      }
    }
    .flow-node-default {
      width: 100%;
      line-height: 36px;
      padding: 0 6px;
      font-size: 12px;
      text-align: center;
      overflow: hidden;
      white-space: nowrap;
      text-overflow: ellipsis;
      border-radius: 8px;
      border: 2px solid #3a9;
      &:focus {
        border: 2px solid #0f0;
      }
    }
  }
}
.node-item {
  @node-item-height: 30px;
  font-size: 14px;
  display: inline-block;
  height: @node-item-height;
  width: 120px;
  margin-top: 20px;
  background-color: #ffffff;
  line-height: @node-item-height;
  box-shadow: 1px 1px 4px rgba(0, 0, 0, 0.3);
  cursor: pointer;
  user-select: none;
  text-align: center;
  z-index: 6;
  &:hover {
    box-shadow: 1px 1px 8px rgba(0, 0, 0, 0.4);
  }
  &:focus {
    background-color: chocolate;
  }
}
</style>

<style scoped>
.scale60 {
  transform: scale(0.6, 0.6);
}
.scale70 {
  transform: scale(0.7, 0.7);
}
.scale80 {
  transform: scale(0.8, 0.8);
}
.scale90 {
  transform: scale(0.9, 0.9);
}
.scale100 {
  transform: scale(1, 1);
}
</style>