<template>
  <div :id="maxContainerId" class="graphParentContainer"></div>
</template>
<script>
import * as PIXI from "pixi.js";

export default {
  props: [],
  data() {
    return {
      maxContainerId:
        new Date().getTime().toString() +
        "_" +
        Math.random().toString().substring(2),
      /*
       * 设备数组格式如下
       * {
            id: "",
            name:'',
            legendObj: {
              content: "图的地址或base64串",
              size: {
                width: 12,
                height: 12,
              },
            },
            //设备的绝对位置
            absolutePosition: {
              x: 1,
              y: 1,
            },
            anchorArr:[{
              name:'锚点名称',
              //锚点相对于设备图例的位置
              relativePosition:{
                x:1,y:1
              }
            }]
          }
      */
      nodeArr: [],
      //线数组
      lineArr: [],
      //文本数组
      labelArr: [],
      //存放图形用的一些信息点
      canvasProObj: {
        //基于canvas画布的中心点坐标，需要动态计算得到
        centerPointerPx: { x: 0, y: 0 },
        //原始缩放比例，动态计算得到的，因为图形默认显示时是要适应容器大小的，所以相比原始坐标会有比例变化
        originalScale: 1,
        //x轴差值，通过此值让x轴左右两端对称
        xJiaValue: 0,
        //y轴差值，通过此值让y轴上下两端对称
        yJiaValue: 0,
        //缓存纹理对象
        textureSource: {},
        //缩放系数
        pixiScale: 1,
        //原点X坐标
        positionPxX: 0,
        //原点Y坐标
        positionPxY: 0,
        //缩放时每次变化的递进值
        deep: 0.1,
        //鼠标状态，0 普通状态；-1 鼠标按下
        mouseState: 0,
        //上一个鼠标位置信息
        prevMousePosition: {},
      },
    };
  },
  computed: {},
  methods: {
    //绘图入口
    drawEntry: function (graphInfo) {
      //把原始数据转为易于绘图的数据
      var graphDataObj = this.parseDataToDraw(graphInfo);
      this.nodeArr = graphDataObj.nodeArr;
      this.lineArr = graphDataObj.lineArr;
      this.labelArr = graphDataObj.labelArr;

      this.drawGraph();
    },
    //重绘
    resetDraw: function () {
      this.drawGraph();
    },
    //绘图
    drawGraph: function () {
      var _this = this;
      // let type = "WebGL";
      // if (!PIXI.utils.isWebGLSupported()) {
      //   type = "canvas";
      // }

      var pixiContainer = document.getElementById(this.maxContainerId);

      //--------------------------------------------创建舞台
      //存在舞台时，先清空舞台内的所有元素
      if (!!_this.pixiApp) {
        while (_this.pixiApp.stage.children.length > 0) {
          _this.pixiApp.stage.removeChildAt(0);
        }
      }

      var pixiApp;
      if (_this.pixiApp == null) {
        pixiApp = new PIXI.Application({
          width: pixiContainer.clientWidth, // default: 800 宽度
          height: pixiContainer.clientHeight, // default: 600 高度
          antialias: true, // default: false 反锯齿
          transparent: true, // default: false 透明度
          resolution: 1, // default: 1 分辨率
          //backgroundColor: "0xffffff",
        });
        pixiApp.renderer.autoResize = true;
        pixiContainer.appendChild(pixiApp.view);
        _this.pixiApp = pixiApp;
      } else pixiApp = _this.pixiApp;

      _this.computeOriginZuobPosition();

      //图例
      _this.nodeArr.forEach((_dataObj) => {
        //2022.1.30版，图例用矩形框代替
        var graphicsRect = new PIXI.Graphics();
        graphicsRect.lineStyle({
          width: 1,
          color: "0x0091ff",
          alpha: 1,
          alignment: 0.5,
        });
        let newCordObj = _this.convertCoordToLeftOrigina({
          x: _dataObj.absolutePosition.x,
          y: _dataObj.absolutePosition.y,
        });
        var newWidth =
          _dataObj.legendObj.size.width * _this.canvasProObj.originalScale;
        var newHeight =
          _dataObj.legendObj.size.height * _this.canvasProObj.originalScale;
        graphicsRect.drawRect(newCordObj.x, newCordObj.y, newWidth, newHeight);
        graphicsRect.hitArea = graphicsRect.getBounds();

        graphicsRect.name = _dataObj.id;
        //启用事件
        graphicsRect.interactive = true;
        graphicsRect.on("click", (event) => {
          _this.clickEventCall(event, 1);
        });

        pixiApp.stage.addChild(graphicsRect);
        return;

        var _legendObj = _dataObj.legendObj;
        // 创建一个纹理
        if (!_this.canvasProObj.textureSource[_legendObj.image.content]) {
          _this.canvasProObj.textureSource[_legendObj.image.content] =
            PIXI.Texture.from(_legendObj.image.content);
        }

        //加载纹理
        var spriteInstanceCoord = _this.convertCoordToLeftOrigina({
          x: _dataObj.position.x,
          y: _dataObj.position.y,
        });
        var spriteWidth =
          _legendObj.defaultSize.width * _this.canvasProObj.originalScale;
        var spriteHeight =
          _legendObj.defaultSize.height * _this.canvasProObj.originalScale;

        var legendSprite = new PIXI.Sprite(
          _this.canvasProObj.textureSource[_legendObj.image.content]
        );
        legendSprite.x = spriteInstanceCoord.x;
        legendSprite.y = spriteInstanceCoord.y;
        legendSprite.width = spriteWidth;
        legendSprite.height = spriteHeight;
        pixiApp.stage.addChild(legendSprite);
      });

      return;
      //画线
      _this.dataSource.view.diagram.lines.forEach((_cLine) => {
        var lineColor = "0x" + _cLine.style.lineColor.substring(1);
        var lineInstance = new PIXI.Graphics();
        lineInstance.lineStyle(_cLine.style.lineWidth, lineColor, 1, 0, false);

        var _newStart = _this.convertCoordToLeftOrigina({
          x: _cLine.path[0].x,
          y: _cLine.path[0].y,
        });

        var _newEnd = _this.convertCoordToLeftOrigina({
          x: _cLine.path[1].x,
          y: _cLine.path[1].y,
        });

        lineInstance.moveTo(_newStart.x, _newStart.y);
        lineInstance.lineTo(_newEnd.x, _newEnd.y);

        pixiApp.stage.addChild(lineInstance);
      });
    },
    /**
     * 解析数据成易于图形使用的格式
     */
    parseDataToDraw: function (graphInfo) {
      var nodeArr = [];
      //线数组
      var lineArr = [];
      //文本数组
      var labelArr = [];

      var rootContainerArr = graphInfo.template.frame.children;

      parseNode(rootContainerArr, graphInfo.template.frame.location);

      return {
        nodeArr,
        lineArr,
        labelArr,
      };

      /**
       * 递归解析设备(node)、文本(label)
       * dataArr 参照后台接口返回的diagram对象里的graphInfo.template.frame.children
       * absolutePosition 绝对位置{x:1,y:1}    其值是compType为"container"的每一级的location相加得出的值
       */
      function parseNode(dataArr, absolutePosition) {
        dataArr.forEach((_dataObj) => {
          var newAbsolutePosition = {
            x: _dataObj.location.x + absolutePosition.x,
            y: _dataObj.location.y + absolutePosition.y,
          };
          switch (_dataObj.compType) {
            //容器
            case "container":
              parseNode(_dataObj.children, newAbsolutePosition);
              break;
            //设备
            case "equipmentNode":
              let anchorArr = [];
              let anchorKeys = Object.keys(_dataObj.anchorLocations || {});
              anchorKeys.forEach((_anchorKey) => {
                anchorArr.push({
                  name: _anchorKey,
                  //锚点相对于设备图例的位置
                  relativePosition: _dataObj.anchorLocations[_anchorKey],
                });
              });

              nodeArr.push({
                id: _dataObj.id,
                name: _dataObj.dataObject.localName,
                //2022.1.30版本图例以矩形框代替
                legendObj: {
                  content: "图的地址或base64串",
                  size: {
                    width: _dataObj.size.x,
                    height: _dataObj.size.y,
                  },
                },
                //设备的绝对位置
                absolutePosition: newAbsolutePosition,
                anchorArr: anchorArr,
              });
              break;
          }
        });
      }
    },
    /**
     * 1、X轴的原始坐标两端可能是不对称的；Y轴的原始坐标两端也可能是不对称的，所以计算各自的差值，以便把两端对称起来，以此把图形显示到正中间
     * 2、计算原始坐标值的缩放系数，因为原始坐标和像素坐标是不对应的，所以要根据最大原始坐标(每一个坐标的绝对值进行比较)和最大像素坐标做比率缩放
     * 3、计算中心点像素坐标
     */
    computeOriginZuobPosition: function () {
      var _this = this;

      var pixiContainer = document.getElementById(this.maxContainerId);
      var maxPxX = pixiContainer.clientWidth;
      var maxPxY = pixiContainer.clientHeight;
      //基于canvas画布的中心点坐标
      _this.canvasProObj.centerPointerPx = {
        x: maxPxX / 2,
        y: maxPxY / 2,
      };

      var originaMinX = null, //原始最小坐标X
        originaMaxX = null, //原始最大坐标X
        originaMinY = null, //原始最小坐标Y
        originaMaxY = null; //原始最大坐标Y

      /**
       * 取得X轴的原始最小坐标和最大坐标、
       * 取得Y轴的原始最小坐标和最大坐标、
       */
      compute();

      //计算X轴差值
      var xJiaValue = (maxPxX - originaMaxX - originaMinX) / 2;
      xJiaValue = originaMinX + xJiaValue < 0 ? 0 - originaMinX : xJiaValue;

      //计算Y轴差值
      var yJiaValue = (maxPxY - originaMaxY - originaMinY) / 2;
      yJiaValue = originaMinY + yJiaValue < 0 ? 0 - originaMinY : yJiaValue;

      _this.canvasProObj.xJiaValue = xJiaValue;
      _this.canvasProObj.yJiaValue = yJiaValue;

      //让每一个的X、Y坐标加上差值，改为在画图时再加差值，这样就减少了此处的循环
      setScale();

      /**
       * 取得X轴的原始最小坐标和最大坐标、
       * 取得Y轴的原始最小坐标和最大坐标、
       */
      function compute() {
        _this.nodeArr.forEach((_c) => {
          var _legendObj = _c.legendObj;
          originaMinX =
            originaMinX == null
              ? _c.absolutePosition.x
              : Math.min(originaMinX, _c.absolutePosition.x);
          originaMaxX =
            originaMaxX == null
              ? _c.absolutePosition.x + _legendObj.size.width
              : Math.max(
                  originaMaxX,
                  _c.absolutePosition.x + _legendObj.size.width
                );

          originaMinY =
            originaMinY == null ? _c.absolutePosition.y : Math.min(originaMinY);

          originaMaxY =
            originaMaxY == null
              ? _c.absolutePosition.y + _legendObj.size.height
              : Math.max(
                  originaMaxY,
                  _c.absolutePosition.y + _legendObj.size.height
                );
        });

        _this.lineArr.forEach((_cLine) => {
          _cLine.path.forEach((_c) => {
            originaMinX =
              originaMinX == null ? _c.x : Math.min(originaMinX, _c.x);
            originaMaxX =
              originaMaxX == null ? _c.x : Math.max(originaMaxX, _c.x);

            originaMinY =
              originaMinY == null ? _c.y : Math.min(originaMinY, _c.y);
            originaMaxY =
              originaMaxY == null ? _c.y : Math.max(originaMaxY, _c.y);
          });
        });
      }

      //计算缩放系数
      function setScale() {
        var xScale = maxPxX / (originaMaxX + xJiaValue);
        var yScale = maxPxY / (originaMaxY + yJiaValue);
        _this.canvasProObj.originalScale = Math.min(xScale, yScale);
        //当图形区域能显示全的时候不再进行缩放
        _this.canvasProObj.originalScale = Math.min(
          1,
          _this.canvasProObj.originalScale
        );
      }
    },
    /**
     * 把坐标转为缩放后的坐标
     * _obj:{x:1,y:1}
     */
    convertCoordToLeftOrigina: function (_obj) {
      _obj.x =
        (_obj.x + this.canvasProObj.xJiaValue) *
        this.canvasProObj.originalScale;
      _obj.y =
        (_obj.y + this.canvasProObj.yJiaValue) *
        this.canvasProObj.originalScale;

      return _obj;
    },

    /**
     * 设备、线、文本点击事件的回调
     * type 1 设备；  2 线；  3 文本
     */
    clickEventCall: function (event, type) {
      var graphInstance = event.target || event.currentTarget;
      var dataId = graphInstance.name;
      var dataArr =
        type == 1
          ? this.nodeArr
          : type == 2
          ? this.lineArr
          : type == 3
          ? this.labelArr
          : [];
      var dataObj = dataArr.filter((_data) => {
        return _data.id == dataId;
      })[0];
      this.$emit("click", dataObj, type);
    },
  },
  created() {},

  mounted() {},
  components: {},
};
</script>

<style scoped>
.graphParentContainer {
  width: 100%;
  height: 100%;
  background: #ffffff;
}
</style>