class Canvas {
  el = null;
  ctx = null;
  options = {};
  constructor(el, options) {
    if (!(el instanceof HTMLCanvasElement)) {
      throw Error('使用了非canvas元素初始化对象！');
    }
    this.el = el;
    this.options = options;
    this.ctx = this.el.getContext('2d');
    this.ctx.strokeStyle = 'red';
    this._initResizeEvent();
  }

  get content() {
    return this.ctx;
  }

  get canvas() {
    return this.el;
  }

  drawRect(x, y, w, h, type = 'position') {
    if (!this.ctx) {
      return;
    }
    this.ctx.strokeStyle = 'red';
    if (type === 'position') {
      this.ctx.strokeRect(x, y, w, h);
    } else {
      if (!this.el) {
        return;
      }
      this.ctx.strokeRect(x * this.el.width, y * this.el.height, w * this.el.width, h * this.el.height);
    }
  }

  drawLine(lineArr, type = 'relative') {
    const line = (arr) => {
      if (!this.ctx || lineArr.length === 0) {
        return;
      }
      this.ctx.beginPath();
      this.ctx.strokeStyle = 'red';
      const [{ x1, y1 }, ...nextArr] = arr;
      this.ctx.moveTo(x1, y1);
      for (let i = 0; i < nextArr.length; i++) {
        const { x, y } = nextArr[i];
        this.ctx.lineTo(x, y);
      }
      this.ctx.stroke();
    };
    if (type === 'relative') {
      line(lineArr.map((item) => {
        if (!this.el) {
          return;
        }
        item.x = (0.5 + (item.x * this.el.width)) << 0;
        item.y = (0.5 + (item.y * this.el.height)) << 0;
        return item;
      }));
    } else {
      line(lineArr);
    }
  }

  clearCanvas() {
    if (!this.ctx || !this.el) {
      return;
    }
    this.ctx.clearRect(0, 0, this.el.width, this.el.height);
  }

  _initResizeEvent() {
    const resizeEvent = () => {
      if (!this.el) {
        return;
      }
      const {
        offsetWidth: width,
        offsetHeight: height
      } = this.el;
      this.reDrawCanvas(width, height);
    };
    resizeEvent();

    window.addEventListener('resize', resizeEvent);
  }

  reDrawCanvas(width, height) {
    if (!this.el) {
      return;
    }
    this.el.width = width;
    this.el.height = height;
  }

  // 绘制框

  drawItem(rectItem) {
    this.filterValue(rectItem);
    const [x, y, w, h] = rectItem.data;
    // 将小数点四舍五入，尽量减少框抖动
    this.drawItemRect((0.5 + x) << 0, (0.5 + y) << 0, (0.5 + w) << 0, (0.5 + h) << 0)
      .drawTag(x, y)
      .drawFont(x, y, rectItem.label);
  }

  filterValue(rectItem) {
    if (rectItem.dataType === 'absolute') {
      return;
    }
    const {
      width,
      height
    } = this.canvas;
    rectItem.data = rectItem.data.map((item, index) => index % 2 ? item * height : item * width);
  }

  getOne(x, y, z = 10, w = 10) {
    const ctx = this.content;
    ctx.lineWidth = 1;
    ctx.strokeStyle = 'white';
    ctx.beginPath();
    ctx.moveTo(x + z, y);
    ctx.lineTo(x, y);
    ctx.lineTo(x, y + w);
    ctx.stroke();
    ctx.restore();
  }

  drawFont(x, y, label) {
    const ctx = this.content;
    y = y - 7;
    x = x + 3;
    ctx.font = '14px bold 黑体';
    ctx.fillStyle = '#fff';
    ctx.textAlign = 'left';
    ctx.textBaseline = 'bottom';
    ctx.fillText(label, x, y);
    ctx.restore();
  }

  drawItemRect(x, y, width, height) {
    this.getOne(x, y);
    this.getOne(x + width, y, -10);
    this.getOne(x, y + height, 10, -10);
    this.getOne(x + width, y + height, -10, -10);
    return this;
  }

  drawTag(x, y) {
    const ctx = this.content;
    ctx.lineWidth = 1;
    ctx.strokeStyle = 'white';
    ctx.fillStyle = 'rgba(0, 0, 0, 0.4)';
    const r = 12;
    y = y - 2 * r - 3;
    // const w = width - (2*r);
    const w = 50;
    const angle = (value) => Math.PI / 180 * value;
    ctx.beginPath();
    ctx.moveTo(x + r, y);
    ctx.lineTo(x + w + r, y);
    ctx.arc(x + w + r, y + r, r, angle(270), angle(0));
    ctx.arc(x + w + r, y + r, r, angle(0), angle(90));
    ctx.lineTo(x + r, y + (2 * r));
    ctx.arc(x + r, y + r, r, angle(90), angle(180));
    ctx.arc(x + r, y + r, r, angle(180), angle(270));
    ctx.closePath();
    ctx.fill();
    return this;
  }
}