<template>
  <div class="paint">
    <canvas ref="canvas" v-show="show"></canvas>
    <!-- <div class="toolbar" v-show="showPaint">
      <ul>
        <li @click="onDraw('drawStart')" v-show="show == false">
          <i class="iconfont icontagging"></i>
          <div>画笔</div>
        </li>
        <li @click="onDraw('drawUndo')" v-if="show" :class="{ disable: !canUndo }">
          <i class="iconfont icon_cancel"></i>
          <div>撤回</div>
        </li>
        <li @click="onDraw('drawStop')" v-if="show">
          <i class="iconfont iconclose"></i>
          <div>关闭</div>
        </li>
      </ul>
    </div> -->
  </div>
</template>
<script>
import { getRole, sendToH5 } from "../../../rtc_socket";
import { objects } from "@/core/base";
import math from "@/core/util/math";
import convertTool from "@/core/util/convertTool";

export default {
  props: {
    showPaint: Boolean,
  },
  data() {
    return {
      role: getRole(),
      show: false,
      canUndo: false,
      colorA: "#02c8ae",
      colorB: "#2e98fe",
    };
  },
  watch: {
    showPaint() {
      if (this.showPaint) {
        this.role = getRole();
      }
    },
    show() {
      this.$bus.emit("shop/header/disable", this.show);
    },
  },
  created() {
    this.$bus.on("shop/sync/action", (data) => {
      if (data.type == "drawStart") {
        this.show = true;
        this.draw = [];
        this.drawHistory = [];
        this.$nextTick(() => {
          this.onDrawStart();
        });
      } else if (data.type == "drawStop") {
        this.show = false;
        this.draw = null;
        this.drawHistory = null;
      } else if (data.type == "drawing") {
        const draw = this.transformTo2d(data.data.drawing);
        if (data.data.role != this.role) {
          this.drawHistory.push(JSON.parse(JSON.stringify(draw)));
          this.drawing(draw);
        }
      } else if (data.type == "drawUndo") {
        this.drawUndo(data.data.role);
      }
    });
  },
  mounted() {
    this.canvas = this.$refs.canvas;
    this.context = this.canvas.getContext("2d");
    this.canvas.onmousedown = (e) => {
      if (!this.show || this.role != "leader") {
        return;
      }
      e.preventDefault();
      this.beginStroke({
        x: e.clientX,
        y: e.clientY,
      });
    };
    this.canvas.onmouseup = (e) => {
      if (!this.show || this.role != "leader") {
        return;
      }
      e.preventDefault();
      this.endStroke();
    };
    this.canvas.onmouseout = (e) => {
      if (!this.show || this.role != "leader") {
        return;
      }
      e.preventDefault();
      this.endStroke();
    };
    this.canvas.onmousemove = (e) => {
      if (!this.show || this.role != "leader") {
        return;
      }
      e.preventDefault();
      if (this._mouseDown) {
        this.moveStroke({
          x: e.clientX,
          y: e.clientY,
        });
      }
    };

    let touch;

    // 移动端触控
    this.canvas.addEventListener("touchstart", (e) => {
      if (!this.show || this.role != "leader") {
        return;
      }
      e.preventDefault();
      touch = e.touches[0];
      this.beginStroke({
        x: touch.pageX,
        y: touch.pageY,
      });
    });
    this.canvas.addEventListener("touchmove", (e) => {
      if (!this.show || this.role != "leader") {
        return;
      }
      e.preventDefault();
      if (this._mouseDown) {
        touch = e.touches[0];
        this.moveStroke({
          x: touch.pageX,
          y: touch.pageY,
        });
      }
    });

    this.canvas.addEventListener("touchend", (e) => {
      if (!this.show || this.role != "leader") {
        return;
      }
      e.preventDefault();
      this.endStroke();
    });

    this.mouse = new THREE.Vector2();
  },
  methods: {
    /**
     * 2d数据转3d数据
     */
    transformTo3d(draw) {
      const data = [];
      if (draw.length == 0) {
        return [];
      }
      draw.forEach((item, index) => {
        math.convertScreenPositionToNDC(item.x, item.y, this.mouse);

        var intersect = convertTool.getMouseIntersect(
          objects.player.camera,
          [this.intersectPlane],
          this.mouse
        );

        if (!intersect) {
          console.error("no intersect ??");
        } else {
          item.pos3d = intersect.point;
          data.push(item);
        }
      });

      return data;
    },
    /**
     * 3d数据转2d数据
     */
    transformTo2d(draw) {
      const data = [];
      draw.forEach((item) => {
        var pos3d = new THREE.Vector3(item.pos3d.x, item.pos3d.y, item.pos3d.z);
        var pos2d = convertTool.getPos2d(pos3d, objects.player.camera);
        //delete item.pos3d;
        item.x = pos2d.pos.x;
        item.y = pos2d.pos.y;
        data.push(item);
      });
      return data;
    },
    onDraw(type) {
      if (type == "drawStart") {
        this.show = true;
        this.draw = [];
        this.drawHistory = [];
        this.$nextTick(() => {
          this.onDrawStart();
        });
      } else if (type == "drawStop") {
        this.show = false;
        this.draw = null;
        this.drawHistory = null;
      } else if (type == "drawing") {
        const draw = this.transformTo2d(data.content.drawing);
        if (data.role != role) {
          this.drawHistory.push(JSON.parse(JSON.stringify(draw)));
          //this.drawing(draw);
        }
      } else if (type == "drawUndo") {
        this.drawUndo(this.role);
      }
      sendToH5({
        type,
        data: {
          role: this.role,
        },
      });
    },
    onPainting() {
      const draw = this.transformTo3d(this.draw);
      this.drawHistory.push(JSON.parse(JSON.stringify(draw)));
      sendToH5({
        type: "drawing",
        data: {
          drawing: draw,
        },
      });
      this.draw = [];
      this.canUndo = true;
      this._endTime = 0;
      this._mouseDown = false;
      this._lastTimestamp = 0;
      this.$emit("sendCanUndo", this.canUndo);
    },
    beginStroke(point) {
      this._mouseDown = true;
      this._lastTimestamp = Date.now();
      this._lastPosition = this.windowToCanvas(point.x, point.y);
      this.draw.push({
        role: this.role,
        width: 0,
        x: this._lastPosition.x,
        y: this._lastPosition.y,
        t: 5, //this._lastTimestamp - this._endTime
      });
    },
    onDrawStart() {
      let dpr = window.devicePixelRatio || 1;
      let rect = this.canvas.getBoundingClientRect();
      this.ratio = 1; // window.innerWidth / 375;
      this.canvas.width = rect.width * dpr;
      this.canvas.height = rect.height * dpr;
      this.context.scale(dpr, dpr);
      this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
      this._endTime = 0;
      this._mouseDown = false;
      this._lastTimestamp = 0;
      this._lastLineWidth = -1;
      this._lastPosition = {
        x: 0,
        y: 0,
      };

      math.convertScreenPositionToNDC(0, 0, this.mouse); //取屏幕中点
      var intersect = convertTool.getMouseIntersect(
        objects.player.camera,
        [objects.model.skybox, objects.sceneRenderer.scene.skyboxBG],
        this.mouse
      );
      this.placeIntersectPlane(intersect && intersect.point);
    },
    moveStroke(point) {
      let timestamp = Date.now();
      let position = this.windowToCanvas(point.x, point.y);
      let s = this.calcDistance(position, this._lastPosition);
      let t = timestamp - this._lastTimestamp;
      let lineWidth = this.calcLineWidth(t, s);

      //draw
      this.context.beginPath();
      this.context.moveTo(this._lastPosition.x, this._lastPosition.y);
      this.context.lineTo(position.x, position.y);

      this.draw.push({
        role: this.role,
        width: lineWidth,
        x: position.x,
        y: position.y,
        t: 5, //t
      });

      this.context.strokeStyle = this.colorA;
      this.context.lineWidth = lineWidth;
      this.context.lineCap = "round";
      this.context.linJoin = "round";
      this.context.stroke();

      //每次过程结束时，将结束值赋给初始值，一直延续
      this._lastPosition = position;
      this._lastTimestamp = timestamp;
      this._lastLineWidth = lineWidth;
    },
    endStroke() {
      this.draw.push({
        role: this.role,
        width: 0,
        x: this._lastPosition.x,
        y: this._lastPosition.y,
        t: 0,
      });
      this.onPainting();
      this._mouseDown = false;
      this._endTime = Date.now();
    },
    calcLineWidth(t, s) {
      let v = s / t;
      let resultLineWidth;

      if (v <= 0.1) {
        resultLineWidth = 6;
      } else if (v >= 3) {
        resultLineWidth = 2;
      } else {
        resultLineWidth = 6 - ((v - 0.1) / (3 - 0.1)) * (6 - 4);
      }
      if (this._lastLineWidth == -1) {
        return resultLineWidth;
      }
      return (this._lastLineWidth * 2) / 3 + (resultLineWidth * 1) / 3;
    },
    calcDistance(pos1, pos2) {
      return Math.sqrt(
        (pos1.x - pos2.x) * (pos1.x - pos2.x) +
          (pos1.y - pos2.y) * (pos1.y - pos2.y)
      ); //通过起始结束坐标x,y值计算路程长度
    },
    windowToCanvas(x, y) {
      var bbox = this.canvas.getBoundingClientRect(); //获取canvas的位置信息
      return {
        x: Math.round(x - bbox.left),
        y: Math.round(y - bbox.top),
      }; //返回当前鼠标相对于canvas的位置
    },
    drawing(draw) {
      for (let i = 0; i < draw.length - 1; i++) {
        draw[i].t &&
          setTimeout(() => {
            this.context.beginPath();
            this.context.strokeStyle =
              draw[i].role == this.role ? this.colorA : this.colorB;
            this.context.moveTo(draw[i].x * this.ratio, draw[i].y * this.ratio);
            this.context.lineTo(
              draw[i + 1].x * this.ratio,
              draw[i + 1].y * this.ratio
            );
            this.context.lineWidth = draw[i].width * this.ratio;
            this.context.lineCap = "round";
            this.context.linJoin = "round";
            this.context.stroke();
          }, 5);
      }
    },
    drawUndo(sender) {
      this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
      for (let i = this.drawHistory.length - 1; i >= 0; i--) {
        if (this.drawHistory[i][0].role == sender) {
          this.drawHistory.splice(i, 1);
          break;
        }
      }
      this.drawHistory.forEach((draw) => {
        for (let i = 0; i < draw.length - 1; i++) {
          if (draw[i].t) {
            this.context.beginPath();
            this.context.strokeStyle =
              draw[i].role == this.role ? this.colorA : this.colorB;
            this.context.moveTo(draw[i].x * this.ratio, draw[i].y * this.ratio);
            this.context.lineTo(
              draw[i + 1].x * this.ratio,
              draw[i + 1].y * this.ratio
            );
            this.context.lineWidth = draw[i].width * this.ratio;
            this.context.lineCap = "round";
            this.context.linJoin = "round";
            this.context.stroke();
          }
        }
      });
      this.canUndo = this.drawHistory.some((item) => item[0].role == this.role);
    },
    placeIntersectPlane(pos) {
      //用于判断mesh拖拽移动距离的平面 需要和视线垂直，以保证遮住视野范围
      if (!this.intersectPlane) {
        var geo = new THREE.PlaneGeometry(8000, 80000, 1, 1);
        //var geo = new THREE.PlaneGeometry(3,3,1,1);
        this.intersectPlane = new THREE.Mesh(
          geo,
          new THREE.MeshBasicMaterial({
            transparent: true,
            wireframe: false,
            opacity: 0,
            side: THREE.DoubleSide,
            depthTest: false,
          })
        );
        this.intersectPlane.lookAt(new THREE.Vector3(0, 1, 0));
        this.intersectPlane.name = "intersectPlane";
        objects.model.add(this.intersectPlane);
      }
      if (pos) {
        this.intersectPlane.position.copy(pos);
        var cameraDir = objects.player.getDirection(
          null,
          objects.player.camera
        ); //向里
        this.intersectPlane.lookAt(pos.clone().add(cameraDir)); //看向相机
      }
    },
  },
};
</script>
<style lang="scss" scoped>
.paint {
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  z-index: 2000;
  pointer-events: none !important;
  canvas {
    width: 100vw;
    height: 100vh;
    image-rendering: pixelated;
    image-rendering: crisp-edges;
    pointer-events: auto;
    position: fixed;
    top: 0;
    left: 0;
  }
  .toolbar {
    pointer-events: auto;
    position: absolute;
    right: 0.35rem;
    bottom: 4.5rem;
    padding: 0.4rem 0.2rem;
    border-radius: 30px;
    z-index: 100;
    background-color: rgba(0, 0, 0, 0.3);
    ul,
    li {
      margin: 0;
      padding: 0;
      list-style: none;
    }
    li {
      padding: 0.3px;
      text-align: center;
      font-size: 14px;
      margin-bottom: 0.5rem;
      &:last-child {
        margin-bottom: 0;
      }
      i {
        font-size: 20px;
        &.icon_cancel {
          font-size: 22px;
        }
        &.iconclose {
          font-size: 14px;
        }
      }
    }
  }
}
</style>
