<template>
  <div>
    <el-button @click="show">展示</el-button>
    <el-button @click="create">创建</el-button>
    <el-button @click="edit">编辑</el-button>
    <canvas id="editPolygon" width="800" height="400" tabindex="0" />
  </div>
</template>
<script lang='ts'>
import { SGraphItem, SGraphView, SGraphScene } from "@persagy-web/graph/";
import { SMouseEvent } from "@persagy-web/base/";
import {
  SColor,
  SLineCapStyle,
  SPainter,
  SPath,
  SPoint,
  SPolygonUtil,
  SRect,
  SLine
} from "@persagy-web/draw";
import { SRelationState } from "@persagy-web/big/lib/enums/SRelationState";
import { SMathUtil } from "@persagy-web/big/lib/utils/SMathUtil";

export default {
  data() {
    return {
      scene: null,
      view: null
    };
  },
  mounted(): void {
    this.view = new SGraphView("editPolygon");
  },
  methods: {
    show() {
      const scene = new SGraphScene();
      this.view.scene = scene;
      const spolygonItem = new SPolygonItem(null);
      spolygonItem.setStatus = SRelationState.Normal;
      const PointList: SPoint[] = [
        new SPoint(0, 0),
        new SPoint(50, 0),
        new SPoint(50, 50),
        new SPoint(0, 50)
      ];
      spolygonItem.setPointList = PointList;
      scene.addItem(spolygonItem);
      this.view.fitSceneToView();
    },
    create() {
      const scene = new SGraphScene();
      this.view.scene = scene;
      const spolygonItem = new SPolygonItem(null);
      spolygonItem.setStatus = SRelationState.Create;
      scene.addItem(spolygonItem);
      scene.grabItem = spolygonItem;
      this.view.fitSceneToView();
    },
    edit() {
      const scene = new SGraphScene();
      this.view.scene = scene;
      const spolygonItem = new SPolygonItem(null);
      spolygonItem.setStatus = SRelationState.Edit;
      const PointList: SPoint[] = [
        new SPoint(0, 0),
        new SPoint(50, 0),
        new SPoint(50, 60),
        new SPoint(0, 50)
      ];
      spolygonItem.setPointList = PointList;
      scene.addItem(spolygonItem);
      scene.grabItem = spolygonItem;
      this.view.fitSceneToView();
    }
  }
};

/**
 * @author hanyaolong
 */

class SPolygonItem extends SGraphItem {
  /** X坐标最小值  */
  private minX = Number.MAX_SAFE_INTEGER;
  /** X坐标最大值  */
  private maxX = Number.MIN_SAFE_INTEGER;
  /** Y坐标最小值  */
  private minY = Number.MAX_SAFE_INTEGER;
  /** Y坐标最大值  */
  private maxY = Number.MIN_SAFE_INTEGER;
  /** 轮廓线坐标  */
  private pointList: SPoint[] = [];
  // 获取当前状态
  get getPointList(): SPoint[] {
    return this.pointList;
  }
  // 编辑当前状态
  set setPointList(arr: SPoint[]) {
    this.pointList = arr;
    if (arr) {
      this._xyzListToSPointList(arr);
    }
    this.update();
  }
  /** 是否闭合    */
  closeFlag: boolean = false;
  // 当前状态 1：show 2 创建中，3 编辑中
  _status: number = SRelationState.Normal;
  // 获取当前状态
  get getStatus(): number {
    return this._status;
  }
  // 编辑当前状态
  set setStatus(value: number) {
    this._status = value;
    this.update();
  }
  /** 边框颜色 */
  borderColor: SColor = new SColor("#0091FF");
  /** 填充颜色 */
  brushColor: SColor = new SColor("#1EE887");
  /** border宽 只可输入像素宽*/
  borderLine: number = 4;
  /** 鼠标移动点  */
  private lastPoint = new SPoint();
  /** 当前鼠标获取顶点对应索引 */
  private curIndex: number = -1;
  /** 灵敏像素 */
  private len: number = 15;
  /** 场景像素  */
  private scenceLen: number = 15;
  /** 场景像素  */
  private isAlt: boolean = false;

  /**
   * 构造函数
   *
   * @param parent    指向父对象
   */

  constructor(parent: SGraphItem | null) {
    super(parent);
  }

  ///////////////以下为对pointList 数组的操作方法

  /**
   * 储存新的多边形顶点
   * @param x   点位得x坐标
   * @param y   点位得y坐标
   * @param i   储存所在索引
   * @return SPoint
   */

  insertPoint(x: number, y: number, i: number | null = null): SPoint {
    const point = new SPoint(x, y);
    if (i == null) {
      this.pointList.push(point);
    } else {
      this.pointList.splice(i, 0, point);
    }
    this.update();
    return point;
  }

  /**
   * 删除点位
   * @param i   删除点所在的索引
   * @return SPoint
   */

  deletePoint(i: number | null = null): SPoint | null | undefined {
    let point = null;
    if (i != null) {
      if (this.pointList.length - 1 >= i) {
        point = this.pointList[i];
        this.pointList.splice(i, 1);
      } else {
        point = null;
      }
    } else {
      point = this.pointList.pop();
    }
    this.update();
    return point;
  }

  /**
   * 多边形顶点的移动位置
   * @param x   点位得x坐标
   * @param y   点位得y坐标
   * @param i   点位得i坐标
   * @return SPoint
   */

  movePoint(x: number, y: number, i: number): SPoint | null | undefined {
    let point = null;
    if (this.pointList.length) {
      this.pointList[i].x = x;
      this.pointList[i].y = y;
    }
    point = this.pointList[i];
    return point;
  }

  /**
   * 打印出多边形数组
   * @return SPoint[]
   */

  PrintPointList(): SPoint[] {
    return this.pointList;
  }

  ///////////////////////////

  /**
   * xyz数据转换为SPoint格式函数；获取外接矩阵参数
   *
   * @param arr    外层传入的数据PointList
   */

  protected _xyzListToSPointList(arr: SPoint[]): void {
    if (arr.length) {
      this.pointList = arr.map(it => {
        let x = it.x,
          y = it.y;
        if (x < this.minX) {
          this.minX = x;
        }
        if (y < this.minY) {
          this.minY = y;
        }
        if (x > this.maxX) {
          this.maxX = x;
        }
        if (y > this.maxY) {
          this.maxY = y;
        }
        return new SPoint(x, y);
      });
    } else {
      this.pointList = [];
    }
  }

  ////////////以下为三种状态下的绘制多边形方法

  /**
   * 展示状态 --绘制多边形数组
   * @param painter    绘制类
   * @param pointList    绘制多边形数组
   *
   */

  protected drawShowPolygon(painter: SPainter, pointList: SPoint[]): void {
    painter.pen.lineCapStyle = SLineCapStyle.Square;
    painter.pen.color = this.borderColor;
    painter.pen.lineWidth = painter.toPx(this.borderLine);
    painter.brush.color = this.brushColor;
    painter.drawPolygon([...pointList]);
  }

  /**
   *
   * 创建状态 --绘制多边形数组
   * @param painter    绘制类
   * @param pointList    绘制多边形数组
   *
   */

  protected drawCreatePolygon(painter: SPainter, pointList: SPoint[]): void {
    painter.pen.lineCapStyle = SLineCapStyle.Square;
    painter.pen.color = this.borderColor;
    painter.pen.lineWidth = painter.toPx(4);
    painter.drawPolyline(pointList);
    if (this.lastPoint) {
      painter.drawLine(pointList[pointList.length - 1], this.lastPoint);
    }
    painter.pen.color = SColor.Transparent;
    painter.brush.color = this.brushColor;
    painter.pen.lineWidth = painter.toPx(4);
    painter.drawPolygon([...pointList, this.lastPoint]);
  }

  /**
   *
   * 编辑状态 --绘制多边形数组
   *
   * @param painter    绘制类
   * @param pointList    绘制多边形数组
   *
   * */

  protected drawEditPolygon(painter: SPainter, pointList: SPoint[]): void {
    // 展示多边形
    this.drawShowPolygon(painter, pointList);
    // 绘制顶点块
    pointList.forEach((item, index) => {
      painter.drawCircle(item.x, item.y, painter.toPx(8));
    });
  }

  ////////////////////////////////

  /**
   * 编辑状态操作多边形数组
   *
   * @param event    鼠标事件
   *
   *
   * */

  protected editPolygonPoint(event: SMouseEvent): void {
    //  判断是否为删除状态 isAlt = true为删除状态
    if (this.isAlt) {
      // 1 判断是否点击在多边形顶点
      let lenIndex = -1; // 当前点击到的点位索引；
      let curenLen = this.scenceLen; // 当前的灵敏度
      this.pointList.forEach((item, index) => {
        let dis = SMathUtil.pointDistance(event.x, event.y, item.x, item.y);
        if (dis < curenLen) {
          curenLen = dis;
          lenIndex = index;
        }
      });
      // 若点击到，对该索引对应的点做删除
      if (lenIndex != -1) {
        if (this.pointList.length <= 3) {
          return;
        }
        this.deletePoint(lenIndex);
      }
    } else {
      // 1 判断是否点击在多边形顶点
      this.curIndex = -1;
      let lenIndex = -1; // 当前点击到的点位索引；
      let curenLen = this.scenceLen; // 当前的灵敏度
      this.pointList.forEach((item, index) => {
        let dis = SMathUtil.pointDistance(event.x, event.y, item.x, item.y);
        if (dis < curenLen) {
          curenLen = dis;
          lenIndex = index;
        }
      });
      this.curIndex = lenIndex;

      // 2判断是否点击在多边形得边上
      if (-1 == lenIndex) {
        let len = SMathUtil.pointToLine(
            new SPoint(event.x, event.y),
            new SLine(this.pointList[0], this.pointList[1])
          ),
          index = 0;
        if (this.pointList.length > 2) {
          for (let i = 1; i < this.pointList.length; i++) {
            let dis = SMathUtil.pointToLine(
              new SPoint(event.x, event.y),
              new SLine(this.pointList[i], this.pointList[i + 1])
            );
            if (i + 1 == this.pointList.length) {
              dis = SMathUtil.pointToLine(
                new SPoint(event.x, event.y),
                new SLine(this.pointList[i], this.pointList[0])
              );
            }
            if (dis.MinDis < len.MinDis) {
              len = dis;
              index = i;
            }
          }
        }
        // 如果再线上则为新增点
        if (len.Point) {
          if (len.MinDis <= this.scenceLen) {
            this.pointList.splice(index + 1, 0, len.Point);
          }
        }
      }
      // 刷新视图
      this.update();
    }
  }

  ///////////////////////////////以下为鼠标事件

  /**
   * 鼠标双击事件
   *
   * @param	event         事件参数
   * @return	boolean
   */

  onDoubleClick(event: SMouseEvent): boolean {
    // 如果位show状态 双击改对象则需改为编辑状态
    if (SRelationState.Normal == this._status) {
      this._status = SRelationState.Edit;
    } else if (SRelationState.Edit == this._status) {
      this._status = SRelationState.Normal;
    }
    this.update();
    return true;
  } // Function onDoubleClick()

  /**
   * 键盘事件
   *
   * @param	event         事件参数
   * @return	boolean
   */

  onKeyDown(event: KeyboardEvent): boolean {
    console.log(event);
    if (this._status == SRelationState.Normal) {
      return false;
    } else if (this._status == SRelationState.Create) {
      if (event.code == "Enter") {
        this._status = SRelationState.Normal;
      }
    } else if (this._status == SRelationState.Edit) {
      if (event.key == "Alt") {
        this.isAlt = true;
      }
    } else {
    }
    this.update();
    return true;
  } // Function onKeyDown()

  /**
   * 键盘键抬起事件
   *
   * @param	event         事件参数
   * @return	boolean
   */
  onKeyUp(event: KeyboardEvent): boolean {
    if (this._status == SRelationState.Edit) {
      if (event.key == "Alt") {
        this.isAlt = false;
      }
    }
    this.update();
    return true;
  } // Function onKeyUp()

  /**
   * 鼠标按下事件
   *
   * @param	event         事件参数
   * @return	boolean
   */
  onMouseDown(event: SMouseEvent): boolean {
    console.log("aaaaaa");
    // 如果状态为编辑状态则添加点
    if (this._status == SRelationState.Create) {
      // 新增顶点
      this.insertPoint(event.x, event.y);
    } else if (this._status == SRelationState.Edit) {
      // 对多边形数组做编辑操作
      this.editPolygonPoint(event);
    }
    return true;
  } // Function onMouseDown()

  /**
   * 鼠标移入事件
   *
   * @param	event         事件参数
   * @return	boolean
   */
  onMouseEnter(event: SMouseEvent): boolean {
    return true;
  } // Function onMouseEnter()

  /**
   * 鼠标移出事件
   *
   * @param	event         事件参数
   * @return	boolean
   */

  onMouseLeave(event: SMouseEvent): boolean {
    return true;
  } // Function onMouseLeave()

  /**
   * 鼠标移动事件
   *
   * @param	event         事件参数
   * @return	boolean
   */

  onMouseMove(event: SMouseEvent): boolean {
    if (this._status == SRelationState.Create) {
      this.lastPoint.x = event.x;
      this.lastPoint.y = event.y;
    } else if (this._status == SRelationState.Edit) {
      if (-1 != this.curIndex) {
        this.pointList[this.curIndex].x = event.x;
        this.pointList[this.curIndex].y = event.y;
      }
    }
    this.update();
    return true;
  } // Function onMouseMove()

  /**
   * 鼠标抬起事件
   *
   * @param	event         事件参数
   * @return	boolean
   */

  onMouseUp(event: SMouseEvent): boolean {
    if (this._status == SRelationState.Edit) {
      this.curIndex = -1;
    }
    return true;
  } // Function onMouseUp()

  /**
   * 适配事件
   *
   * @param	event         事件参数
   * @return	boolean
   */

  onResize(event: SMouseEvent): boolean {
    return true;
  } // Function onResize()

  /**
   * Item对象边界区域
   *
   * @return SRect
   */
  boundingRect(): SRect {
    return new SRect(
      this.minX,
      this.minY,
      this.maxX - this.minX,
      this.maxY - this.minY
    );
  } // Function boundingRect()

  /**
   * Item绘制操作
   *
   * @param   painter       painter对象
   */

  onDraw(painter: SPainter): void {
    this.scenceLen = painter.toPx(this.len);
    // 当状态为展示状态
    if (this._status == SRelationState.Normal) {
      // 闭合多边形
      this.drawShowPolygon(painter, this.pointList);
    } else if (this._status == SRelationState.Create) {
      // 创建状态
      this.drawCreatePolygon(painter, this.pointList);
    } else {
      // 编辑状态
      this.drawEditPolygon(painter, this.pointList);
    }
  } // Function onDraw()
}
</script>
