<!--
 * @FileDescription: vue-konva
 * @Author: hcy
 * @Date: 2023-03-29
-->
<script setup lang="ts">
import { reactive, onMounted } from 'vue';
import { getBoundingBox } from 'src/common/utils';
import Konva from 'konva';
import Decimal from 'decimal.js';

const state = reactive({
  stage: null as any,
  layer: null as any,
  group: null as any,
  // shape: null as any,
  //   boundingBox: null as any,
  //   box: null as any,
  shapePath: [
    {
      name: 'test1',
      color: '#00D2FF',
      path: [
        { x: 100, y: 100 },
        { x: 200, y: 100 },
        { x: 200, y: 200 },
        { x: 0, y: 300 },
      ],
    },
    {
      name: 'test2',
      color: '#4CAF50',
      path: [
        { x: 300, y: 200 },
        { x: 200, y: 400 },
        { x: 100, y: 600 },
        { x: 400, y: 600 },
        { x: 500, y: 200 },
      ],
    },
    {
      name: 'test3',
      color: '#FF8A80',
      path: [
        { x: 600, y: 200 },
        { x: 500, y: 400 },
        { x: 300, y: 100 },
      ],
    },
  ] as any[],
});

const stageSize = reactive({
  width: 1200,
  height: 800,
  gridGap: 100,
});

onMounted(() => {
  // const hit = Collide2D.collidePointPoint(100, 100, 100, 100);
  // console.log('hit', Collide2D);

  drawGrid();
  handleData();

  console.log('数据', state.shapePath);

  state.stage = new Konva.Stage({
    container: 'stage-container',
    width: stageSize.width,
    height: stageSize.height,
  });

  state.layer = new Konva.Layer();
  state.stage.add(state.layer);

  for (const item of state.shapePath) {
    let shape = createShape(item);
    if (shape) {
      state.layer.add(shape);
    }
  }

  state.layer.on('dragmove', layerDragmove);
});

function createShape(itemData: any) {
  const path = itemData.path || [];
  const fillColor = itemData.color || '#000000';
  const name = itemData.name;
  const boundingBox = itemData.boundingBox || {};
  const boundingBoxPath = itemData.boundingBox?.path || [];

  if (boundingBoxPath.length < 2) {
    console.warn('小于两个点,不能构成多边形,没有边界框');
  } else {
    let group = new Konva.Group({
      x: 0,
      y: 0,
      draggable: true,
    });

    let rectBox = new Konva.Rect({
      x: boundingBoxPath[0].x,
      y: boundingBoxPath[0].y,
      width: boundingBox.width,
      height: boundingBox.height,
      stroke: 'red',
      // fill: 'grey',
      strokeWidth: 4,
    });

    // 如果添加到group,则坐标的相对位置时基于group的位置
    let shape: any = new Konva.Shape({
      sceneFunc: function (context, shape) {
        context.beginPath();

        let index = 0;
        for (const i of path) {
          const x = i.x;
          const y = i.y;
          if (index === 0) {
            context.moveTo(x, y);
          } else {
            context.lineTo(x, y);
          }
          //   context.quadraticCurveTo(150, 100, 260, 170); 弧线
          index++;
        }
        context.closePath();
        // (!) Konva specific method, it is very important
        context.fillStrokeShape(shape);
      },
      fill: fillColor,
      name,
      // stroke: 'white',
      // strokeWidth: 10,
    });
    group.add(rectBox);
    group.add(shape);

    return group;
  }
}
function layerDragmove(e: any) {
  let target = e.target;
  state.layer.children.forEach(function (group: any) {
    // do not check intersection with itself
    // 不检查与自身相交
    if (group._id == target._id) {
      return;
    }
  });
}

function handleData() {
  for (const item of state.shapePath) {
    item.path = removeAngleRepeat(item.path || []);
    item.boundingBox = getBoundingBox(item.path || []);
  }
}

// 一条线上有多个点,只保留起点和终点
function removeAngleRepeat(path: any[]) {
  let length = path.length;

  if (length >= 2) {
    let myMap = new Map();

    let index = 1;
    for (const item of path) {
      let x1, y1, x2, y2;
      if (index < length) {
        x1 = item.x;
        y1 = item.y;
        x2 = path[index].x;
        y2 = path[index].y;
      } else {
        // 最后一个点连第一个点
        x1 = item.x;
        y1 = item.y;
        x2 = path[0].x;
        y2 = path[0].y;
      }
      let du = getAngle(x1, y1, x2, y2, true);

      if (!myMap.has(du)) {
        myMap.set(du, item);
      }

      // console.log('du', du);
      index++;
    }

    let newArr: any[] = [];
    for (const value of myMap.values()) {
      newArr.push(value);
    }

    return newArr;
  } else {
    return path;
  }
}

/**
 * 计算从x1y1到x2y2的直线,与水平线形成的夹角
 * 计算规则为顺时针从左侧0°到与该直线形成的夹角
 * @param {Object} x1
 * @param {Object} y1
 * @param {Object} x2
 * @param {Object} y2
 * @param {Boolean} toAngle 是否转换为角度值,默认false
 */
function getAngle(
  x1: number,
  y1: number,
  x2: number,
  y2: number,
  toAngle = false
) {
  let x = Decimal.sub(x1, x2);
  let y = Decimal.sub(y1, y2);
  if (!x.toNumber() && !y.toNumber()) {
    return 0;
  }

  // 弧度 radian = 角度 * Math.PI / 180
  // 角度 angle = 弧度 * 180 / Math.PI

  let res;

  // 角度
  // let angle = (180 + (Math.atan2(-y, -x) * 180) / Math.PI + 360) % 360;
  let _atan2 = Decimal.atan2(y.negated(), x.negated());
  let _angle = Decimal.div(Decimal.mul(_atan2, 180), Math.PI);
  let angle = Decimal.mod(Decimal.add(180, _angle).plus(360), 360);

  res = Decimal.sub(360, angle);

  if (!toAngle) {
    res = Decimal.mul(res, Math.PI).div(180);
  }
  return res.toNumber();
}

// 网格线
function drawGrid() {
  let canvas: any = document.getElementById('canvas-grid');
  let pen = canvas.getContext('2d');

  // 绘制网格
  const step = stageSize.gridGap;
  const h = stageSize.height;
  const w = stageSize.width;
  const w_l = w / step;
  const h_l = h / step;

  // 横着的线
  for (let i = 0; i <= h_l; i++) {
    pen.beginPath();
    pen.moveTo(0, i * step);
    pen.lineTo(w, i * step);
    pen.stroke();
  }
  // 竖着的线
  for (let i = 0; i <= w_l; i++) {
    pen.beginPath();
    pen.moveTo(i * step, 0);
    pen.lineTo(i * step, h);
    pen.stroke();
  }
}
</script>
<template>
  <div class="konva-main-page container-height center">
    <div>666</div>
    <div class="canvas-box">
      <canvas
        id="canvas-grid"
        :width="stageSize.width"
        :height="stageSize.height"
        style="position: absolute"
      ></canvas>
      <div id="stage-container"></div>
    </div>
  </div>
</template>

<style lang="scss" scoped>
.konva-main-page {
}
.canvas-box {
  box-sizing: border-box;
  width: 1200px;
  height: 800px;
  border: 1px solid #000;
  // background: pink;
}
</style>