<template>
  <div id="svg-component" ref="svgComponent">
    <!-- 批注工具条 -->
    <div v-if="toolbarShow" id="toolbar-show">
      <AnnTool ref="AnnToolbar" @closeAnn="closeAnnMode" :src="currentSvg"></AnnTool>
    </div>
    <embed v-show="canvasShow" type="image/svg+xml" id="svg-tigger" :src="currentSvg" />
  </div>
</template>
<script>
import svgPanZoom from 'svg-pan-zoom';
import html2canvas from 'html2canvas';
import AnnTool from './component/ann-tool.vue';
var svgCon = {},
  svgTigger = {},
  svgEmbed = {};
var preTargetCon = [],
  preTargetStyle = [];
var firstTime = 0,
  lastTime = 0;
var inspectionRect = null,
  pointerRect = null;
export default {
  name: 'FlSvg',
  props: {
    src: {
      typeof: String,
      default: '',
    },
  },
  watch: {
    src(newVal) {
      this.currentSvg = newVal;
    },
  },
  components: {
    AnnTool,
  },
  data() {
    return {
      currentSvg: '',
      activeObj: null,
      canvasShow: true,
      toolbarShow: false,
      svgInitStyle: {},
    };
  },
  created() {
    this.currentSvg = this.src;
  },
  mounted() {
    this.$nextTick(() => {
      svgEmbed = document.getElementById('svg-tigger');
      svgEmbed.style.width = this.$refs.svgComponent.clientWidth + 'px';
      svgEmbed.style.height = this.$refs.svgComponent.clientHeight + 'px';
      svgEmbed.addEventListener('resize', () => {
        this.onWindowResize;
      });
      svgEmbed.addEventListener('load', () => {
        preTargetCon.splice(0);
        preTargetStyle.splice(0);
        svgTigger = svgPanZoom('#svg-tigger', {
          viewportSelector: '.svg-pan-zoom_viewport',
          panEnabled: true,
          zoomEnabled: true,
          preventMouseEventsDefault: false,
          fit: true,
          center: true,
        });
        svgCon = svgEmbed.getSVGDocument().querySelector('svg');
        svgCon.style = 'cursor: pointer;user-select: none;';
        this.svgInitStyle = svgEmbed
          .getSVGDocument()
          .getElementsByClassName('svg-pan-zoom_viewport')[0]
          .getBoundingClientRect();
        svgCon.setAttribute('viewBox', '0 0 ' + svgEmbed.offsetWidth + ' ' + svgEmbed.offsetHeight);
        inspectionRect = svgCon.createSVGRect();
        inspectionRect.width = 10;
        inspectionRect.height = 10;
        pointerRect = svgCon.createSVGPoint();
        this.onWindowResize();
        // 禁止右键菜单栏
        svgCon.addEventListener('contextmenu', e => {
          e.preventDefault();
        });
        // 鼠标的按下与抬起事件
        svgCon.addEventListener('mousedown', this.mousedown);
        svgCon.addEventListener('mouseup', this.mouseup);
        // 加载完成后会通知
        this.$emit('loaded');
      });
    });
  },
  methods: {
    changeSvg(url) {
      this.$set(this, 'currentSvg', url);
      preTargetCon.splice(0);
      preTargetStyle.splice(0);
    },
    // 改变窗口大小
    onWindowResize() {
      svgCon.removeAttribute('width');
      svgCon.removeAttribute('height');
    },
    // 鼠标按下
    mousedown() {
      firstTime = new Date().getTime();
    },
    // 鼠标抬起
    mouseup(evt) {
      evt.stopPropagation();
      lastTime = new Date().getTime();
      let targetElement = null;
      // 判断鼠标按下到抬起的时间间隔是否超过300ms 没有超过 则判断为点击
      if (lastTime - firstTime <= 300) {
        if (evt.target.nodeName !== 'svg') {
          targetElement = evt.target;
        } else {
          pointerRect.x = evt.clientX;
          pointerRect.y = evt.clientY;
          const tp = pointerRect.matrixTransform(svgCon.getScreenCTM());
          inspectionRect.x = tp.x;
          inspectionRect.y = tp.y;
          const intersectionList = svgCon.getIntersectionList(inspectionRect, null);
          targetElement =
            intersectionList.length > 0 ? intersectionList[intersectionList.length - 1] : null;
        }
        if (targetElement && !targetElement.id) {
          this.searchSvgId(targetElement.parentNode);
        } else {
          this.activeObj = targetElement;
        }
        if (evt.button === 0) {
          this.$emit('leftClick', this.activeObj);
        } else if (evt.button === 2) {
          console.log('rightClick');
          this.$emit('rightClick', {
            event: evt,
            targetObj: this.activeObj,
          });
        }
      }
    },
    // 查找对象的id
    searchSvgId(dom) {
      if (!dom.id) {
        this.searchSvgId(dom.parentNode);
      } else if (dom.id) {
        this.activeObj = dom;
      }
    },
    // 高亮目标元素
    /*
      参数：svgIds: [], 需要高亮的id的集合， flag: true / false, 是否要定位目标元素, color: '', 高亮的颜色
    */
    highLight(svgIds, flag = false, color) {
      if (svgIds === null || svgIds === undefined) {
        throw new Error('svgIds should be an array');
      } else {
        for (let index = 0; index < svgIds.length; index++) {
          let element = svgIds[index];
          let targetCon = svgCon.getElementById(element.svgId);
          console.log(targetCon);
          if (!targetCon) return;
          this.depthTraversal(targetCon.children, color);
        }
        if (flag) {
          svgTigger.reset();
          let firstCon = svgCon.getElementById(svgIds[0].svgId);
          setTimeout(() => {
            svgTigger.zoomAtPoint(4, {
              x: firstCon.getBoundingClientRect().x,
              y: firstCon.getBoundingClientRect().y,
            });
          }, 100);
        }
      }
    },
    // pid组高亮 深度遍历
    depthTraversal(svgCon, color) {
      for (let i = 0; i < svgCon.length; i++) {
        if (svgCon[i].children.length > 0) {
          this.depthTraversal(svgCon[i].children, color);
        } else {
          preTargetCon.push(svgCon[i]);
          preTargetStyle.push({
            // fillOpacity: svgCon[i].style.fillOpacity,
            stroke: svgCon[i].style.stroke,
            // strokeWidth: svgCon[i].style.strokeWidth,
            fill: svgCon[i].style.fill,
          });
          // svgCon[i].style.fillOpacity = '0';
          svgCon[i].style.stroke = color;
          if (
            svgCon[i].nodeName === 'text' ||
            (svgCon[i].style.fill && svgCon[i].style.fill !== 'none')
          ) {
            svgCon[i].style.fill = color;
          }
          // svgCon[i].style.strokeWidth = 0.5;
        }
      }
    },
    // 清除上一次的高亮
    resetHightLight() {
      for (let i = 0; i < preTargetCon.length; i++) {
        // preTargetCon[i].style.fillOpacity = preTargetStyle[i].fillOpacity;
        preTargetCon[i].style.stroke = preTargetStyle[i].stroke;
        // preTargetCon[i].style.strokeWidth = preTargetStyle[i].strokeWidth;
        preTargetCon[i].style.fill = preTargetStyle[i].fill;
      }
      preTargetStyle.splice(0);
      preTargetCon.splice(0);
    },
    // 修改颜色要区分text text填充为fill
    // 设置对象的属性 obj是需要被修改的对象， properties是需要修改的属性{}
    setPorperty(obj, properties) {
      if (obj.children.length > 0) {
        let arr = obj.children;
        for (let index = 0; index < arr.length; index++) {
          const element = arr[index];
          if (element.nodeName !== 'g') {
            for (const key in properties) {
              // 记录一下原始状态
              element.setAttribute(`data-${key}`, element['style'][key]);
              if (key === 'fill') {
                if (
                  element.nodeName === 'text' ||
                  (element.style.fill && element.style.fill !== 'none')
                ) {
                  element['style']['fill'] = properties[key];
                }
              } else {
                element['style'][key] = properties[key];
              }
            }
          }
          if (element.children && element.children.length > 0) {
            this.setPorperty(element, properties);
          }
        }
      } else {
        if (obj.nodeName !== 'g') {
          for (const key in properties) {
            if (key === 'fill') {
              if (
                element.nodeName === 'text' ||
                (element.style.fill && element.style.fill !== 'none')
              ) {
                element['style']['fill'] = properties[fill];
              }
            } else {
              element['style'][key] = properties[key];
            }
          }
        }
      }
    },
    resetPorperty(obj, properties) {
      if (obj.children.length > 0) {
        let arr = obj.children;
        for (let index = 0; index < arr.length; index++) {
          const element = arr[index];
          if (element.nodeName !== 'g') {
            properties.forEach(item => {
              element['style'][item] = element.getAttribute(`data-${item}`);
            });
          }
          if (element.children && element.children.length > 0) {
            this.resetPorperty(element, properties);
          }
        }
      } else {
        if (obj.nodeName !== 'g') {
          properties.forEach(item => {
            element['style'][item] = element.getAttribute(`data-${item}`);
          });
        }
      }
    },
    getAllNode() {
      let node = svgCon.querySelector('.svg-pan-zoom_viewport');
      if (node) {
        return node.children;
      } else {
        return [];
      }
    },
    getNodeById(id) {
      return svgCon.getElementById(id);
    },
    // 更新图纸/切换图纸
    /*
      参数：url: 图纸的路径
    */
    switchSvg(url) {
      this.$set(this, 'currentSvg', url);
      preTargetCon.splice(0);
      preTargetStyle.splice(0);
      inspectionRect = null;
      pointerRect = null;
    },
    // 图纸恢复到主视图
    resetView() {
      svgTigger.reset();
    },
    saveCanvas(canvasStyle) {
      this.$refs.AnnToolbar.toolbarShow = false; // 关闭画板工具条
      svgTigger.reset();
      svgTigger.zoom(canvasStyle.width / this.svgInitStyle.width);
      svgTigger.pan({ x: -canvasStyle.scrollLeft, y: -canvasStyle.scrollTop });
      this.$nextTick(() => {
        this.screenShot(); // 保存批注
      });
    },
    // 截图导出
    screenShot() {
      let shotObj = this.$refs.svgComponent;
      html2canvas(shotObj, { allowTaint: true, useCORS: true }).then(canvas => {
        const link = document.createElement('a');
        link.href = canvas.toDataURL('image/png');
        link.download = 'screenshot.png';
        link.click();
      });
    },
    // 打开批注模式
    openAnnToolbar() {
      console.log('openAnnToolbar');
      this.canvasShow = false;
      this.toolbarShow = true;
    },
    closeAnnMode() {
      this.canvasShow = true;
      this.toolbarShow = false;
      this.$emit('closeAnn');
    },
  },
};
</script>
<style lang="scss" scoped>
#svg-component,
#svg-tigger {
  cursor: pointer;
  height: 100%;
  width: 100%;
  position: relative;
}
#toolbar-show {
  z-index: 20;
  position: absolute;
  width: 100%;
  height: 100%;
  top: 0;
  left: 0;
  overflow: hidden;
  background: #fff;
}
</style>
