import TWEEN from '@tweenjs/tween.js';

interface AirWindow  extends Window {
  air: any;
  curCtx: any;
}
declare let window: AirWindow;

class Sprite {
  x = 0;
  y = 0;
  color = '';
  radius = 0;
  alive = false;
  margin = 0;
  angle = 0;
  ctx;

  constructor(ctx = null) {
    if (!ctx) {
      this.ctx = window.curCtx;
    } else {
      this.ctx = ctx;
    }
  }
  update($event) {
    this.draw();
  }
  draw() {

  }

}





export class MySprite extends Sprite {

  _width = 0;
  _height = 0;
  _anchorX = 0;
  _anchorY = 0;
  _offX = 0;
  _offY = 0;
  scaleX = 1;
  scaleY = 1;
  _alpha = 1;
  rotation = 0;
  visible = true;
  skewX = 0;
  skewY = 0;

  _shadowFlag = false;
  _shadowColor;
  _shadowOffsetX = 0;
  _shadowOffsetY = 0;
  _shadowBlur = 5;

  _radius = 0;

  children = [this];

  childDepandVisible = true;
  childDepandAlpha = false;

  img;
  _z = 0;

  _showRect;


  _bitmapFlag = false;
  _offCanvas;
  _offCtx;


  init(imgObj = null, anchorX: number = 0.5, anchorY: number = 0.5) {

    if (imgObj) {

      this.img = imgObj;

      this.width = this.img.width;
      this.height = this.img.height;


    }

    this.anchorX = anchorX;
    this.anchorY = anchorY;
  }


  setShowRect(rect) {
    this._showRect = rect;
  }

  setShadow(offX, offY, blur, color = 'rgba(0, 0, 0, 0.3)') {


    this._shadowFlag = true;
    this._shadowColor = color;
    this._shadowOffsetX = offX;
    this._shadowOffsetY = offY;
    this._shadowBlur = blur;

  }

  setRadius(r) {
    this._radius = r;
  }




  update($event = null) {
    if (!this.visible && this.childDepandVisible) {
      return;
    }

    this.draw();

  }
  draw() {

    this.ctx.save();

    this.drawInit();

    this.updateChildren();

    this.ctx.restore();


  }

  drawInit() {

    this.ctx.translate(this.x, this.y);

    this.ctx.rotate(this.rotation * Math.PI / 180);

    this.ctx.scale(this.scaleX, this.scaleY);

    this.ctx.globalAlpha = this.alpha;

    this.ctx.transform(1, this.skewX, this.skewY, 1, 0, 0);




    //
    // if (this._radius) {
    //
    //   const r = this._radius;
    //   const w = this.width;
    //   const h = this.height;
    //
    //   this.ctx.lineTo(-w / 2, h / 2);          // 创建水平线
    //   this.ctx.arcTo(-w / 2, -h / 2, -w / 2 + r, -h / 2, r);
    //   this.ctx.arcTo(w / 2, -h / 2, w / 2, -h / 2 + r, r);
    //   this.ctx.arcTo(w / 2, h / 2, w / 2 - r, h / 2, r);
    //   this.ctx.arcTo(-w / 2, h / 2, -w / 2, h / 2 - r, r);
    //
    //   this.ctx.clip();
    // }

  }

  drawSelf() {



    if (this._shadowFlag) {

      this.ctx.shadowOffsetX = this._shadowOffsetX;
      this.ctx.shadowOffsetY = this._shadowOffsetY;
      this.ctx.shadowBlur = this._shadowBlur;
      this.ctx.shadowColor = this._shadowColor;
    } else {
      this.ctx.shadowOffsetX = 0;
      this.ctx.shadowOffsetY = 0;
      this.ctx.shadowBlur = null;
      this.ctx.shadowColor = null;
    }


    if (this.img) {

      if (this._showRect) {
        const rect = this._showRect;
        this.ctx.drawImage(this.img, rect.x, rect.y, rect.width, rect.height, this._offX, this._offY + rect.y, this.width, rect.height);
      } else {
        this.ctx.drawImage(this.img, this._offX, this._offY);
      }
    }




  }

  updateChildren() {

    if (this.children.length <= 0) { return; }

    for (const child of  this.children) {
      if (child === this) {
        if (this.visible) {
          this.drawSelf();
        }
      } else {
        child.update();
      }
    }
  }


  load(url, anchorX = 0.5, anchorY = 0.5) {

    return new Promise((resolve, reject) => {
      const img = new Image();
      img.onload = () => resolve(img);
      img.onerror = reject;
      img.src = url;
    }).then(img => {

      this.init(img, anchorX, anchorY);
      return img;
    });
  }

  addChild(child, z = 1) {
    if (this.children.indexOf(child) === -1) {
      this.children.push(child);
      child._z = z;
      child.parent = this;
    }

    this.children.sort((a, b) => {
      return a._z - b._z;
    });


    if (this.childDepandAlpha) {
      child.alpha = this.alpha;
    }

  }
  removeChild(child) {
    const index = this.children.indexOf(child);
    if (index !== -1) {
      this.children.splice(index, 1);
    }
  }

  removeChildren() {
    for (let i = 0; i < this.children.length; i++) {
      if (this.children[i]) {
        if (this.children[i] !== this) {
          this.children.splice(i, 1);
          i --;
        }
      }
    }
  }

  _changeChildAlpha(alpha) {
    for (const child of  this.children) {
      if (child !== this) {
        child.alpha = alpha;
      }
    }
  }


  set btimapFlag(v) {
    this._bitmapFlag = v;
  }
  get btimapFlag() {
    return this._bitmapFlag;
  }
  set alpha(v) {
    this._alpha = v;
    if (this.childDepandAlpha) {
      this._changeChildAlpha(v);
    }
  }
  get alpha() {
    return this._alpha;
  }
  set width(v) {
    this._width = v;
    this.refreshAnchorOff();
  }
  get width() {
    return this._width;
  }
  set height(v) {
    this._height = v;
    this.refreshAnchorOff();
  }
  get height() {
    return this._height;
  }
  set anchorX(value) {
    this._anchorX = value;
    this.refreshAnchorOff();
  }
  get anchorX() {
    return this._anchorX;
  }
  set anchorY(value) {
    this._anchorY = value;
    this.refreshAnchorOff();
  }
  get anchorY() {
    return this._anchorY;
  }
  refreshAnchorOff() {
    this._offX = -this._width * this.anchorX;
    this._offY = -this._height * this.anchorY;
  }

  setScaleXY(value) {
    this.scaleX = this.scaleY = value;
  }

  getBoundingBox() {

    const getParentData = (item) => {

      let px = item.x;
      let py = item.y;

      let sx = item.scaleX;
      let sy = item.scaleY;
      const parent = item.parent;
      if (parent) {

        const obj = getParentData(parent);

        const _x = obj.px;
        const _y = obj.py;
        const _sx = obj.sx;
        const _sy = obj.sy;

        px = _x + item.x * _sx;
        py = _y + item.y * _sy;

        sx *= _sx;
        sy *= _sy;

      }

      return {px, py, sx, sy};
    };


    const data = getParentData(this);


    const x = data.px + this._offX * Math.abs(data.sx);
    const y = data.py + this._offY * Math.abs(data.sy);
    const width = this.width * Math.abs(data.sx);
    const height = this.height * Math.abs(data.sy);

    return {x, y, width, height};
  }

}


export class RoundSprite extends MySprite {

  _newCtx;

  init(imgObj = null, anchorX: number = 0.5, anchorY: number = 0.5) {

    if (imgObj) {

      this.img = imgObj;

      this.width = this.img.width;
      this.height = this.img.height;


    }

    this.anchorX = anchorX;
    this.anchorY = anchorY;

    const canvas = window['curCanvas'];
    const w = canvas.nativeElement.width;
    const h = canvas.nativeElement.height;


    this._offCanvas = document.createElement('canvas');
    this._offCanvas.width = w;
    this._offCanvas.height = h;

    this._offCtx = this._offCanvas.getContext('2d');

    // this._newCtx = this.ctx;
    // this.ctx = this._offCtx;

  }



  drawSelf() {
    //
    // if (this._shadowFlag) {
    //
    //   this.ctx.shadowOffsetX = this._shadowOffsetX;
    //   this.ctx.shadowOffsetY = this._shadowOffsetY;
    //   this.ctx.shadowBlur = this._shadowBlur;
    //   this.ctx.shadowColor = this._shadowColor;
    // } else {
    //   this.ctx.shadowOffsetX = 0;
    //   this.ctx.shadowOffsetY = 0;
    //   this.ctx.shadowBlur = null;
    //   this.ctx.shadowColor = null;
    // }


    if (this._radius) {

      const r = this._radius;
      const w = this.width;
      const h = this.height;
      const x = -this._offX;
      const y = -this._offY;

      this._offCtx.lineTo(x - w / 2, y + h / 2);          // 创建水平线
      this._offCtx.arcTo(x - w / 2, y - h / 2, x - w / 2 + r, y - h / 2, r);
      this._offCtx.arcTo(x + w / 2, y - h / 2, x + w / 2, y - h / 2 + r, r);
      this._offCtx.arcTo(x + w / 2, y + h / 2, x + w / 2 - r, y + h / 2, r);
      this._offCtx.arcTo(x - w / 2, y + h / 2, x - w / 2, y + h / 2 - r, r);

      this._offCtx.clip();
    }


    if (this.img) {

      this._offCtx.drawImage(this.img, 0, 0);
      this.ctx.drawImage(this._offCanvas,this._offX, this._offX);
    }

  }
}





export class ColorSpr extends MySprite {

  r = 0;
  g = 0;
  b = 0;

  createGSCanvas() {

    if (!this.img) {
      return;
    }



    const rect = this.getBoundingBox();
    if (rect.width <= 1 || rect.height <= 1) {
      return;
    }


    const c = this.ctx.getImageData(rect.x, rect.y, rect.width, rect.height);
    for ( let i = 0; i < c.height; i++) {
      for ( let j = 0; j < c.width; j++) {

        const x = (i * 4) * c.width + ( j * 4 );
        const r = c.data[x];
        const g = c.data[x + 1];
        const b = c.data[x + 2];

        c.data[x] = this.r;
        c.data[x + 1] = this.g;
        c.data[x + 2] = this.b;



        // c.data[x] = c.data[x + 1] = c.data[x + 2] = (r + g + b) / 3 ;
        // // c.data[x + 3] = 255;
      }
    }

    this.ctx.putImageData(c, rect.x, rect.y, 0, 0, rect.width, rect.height);
  }


  drawSelf() {
    super.drawSelf();
    this.createGSCanvas();
  }

}


export class GrayscaleSpr extends MySprite {

  grayScale = 120;

  createGSCanvas() {

    if (!this.img) {
      return;
    }



    const rect = this.getBoundingBox();

    const c = this.ctx.getImageData(rect.x, rect.y, rect.width, rect.height);
    for ( let i = 0; i < c.height; i++) {
      for ( let j = 0; j < c.width; j++) {

        const x = (i * 4) * c.width + ( j * 4 );
        const r = c.data[x];
        const g = c.data[x + 1];
        const b = c.data[x + 2];
        // const a = c.data[x + 3];

        c.data[x] = c.data[x + 1] = c.data[x + 2] = this.grayScale; // (r + g + b) / 3;
        // c.data[x + 3] = 255;
      }
    }

    this.ctx.putImageData(c, rect.x, rect.y, 0, 0, rect.width, rect.height);
  }


  drawSelf() {
    super.drawSelf();
    this.createGSCanvas();
  }

}






export class BitMapLabel extends MySprite {


  labelArr;
  baseUrl;

  setText(data, text) {

    this.labelArr = [];

    const labelArr = [];
    const tmpArr = text.split('');
    let totalW = 0;
    let h = 0;
    for (const tmp of tmpArr) {

      const label = new MySprite(this.ctx);
      label.init(data[tmp], 0);
      this.addChild(label);
      labelArr.push(label);

      totalW += label.width;
      h = label.height;
    }


    this.width = totalW;
    this.height = h;

    let offX = -totalW / 2;
    for (const label of  labelArr) {
      label.x = offX;
      offX += label.width;
    }

    this.labelArr = labelArr;
  }

}




export class Label extends MySprite {
  private _text: string;

  // fontSize:String = '40px';
  fontName = 'Verdana';
  textAlign = 'left';
  fontSize = 40;
  fontColor = '#000000';
  fontWeight = 900;
  _maxWidth;
  outline = 0;
  outlineColor = '#ffffff';
  // _shadowFlag = false;
  // _shadowColor;
  // _shadowOffsetX;
  // _shadowOffsetY;
  // _shadowBlur;

  _outlineFlag = false;

  _outLineWidth;
  _outLineColor;
  constructor(ctx = null) {
    super(ctx);
    this.init();
  }


  get text(): string {
    return this._text;
  }

  set text(value: string) {
    this._text = value;
    this.refreshSize();
  }

  refreshSize() {

    this.ctx.save();

    this.ctx.font = `${this.fontSize * this.scaleX}px ${this.fontName}`;
    this.ctx.textAlign = this.textAlign;
    this.ctx.textBaseline = 'middle';
    this.ctx.fontWeight = this.fontWeight;

    this._width = this.ctx.measureText(this.text).width;
    this._height = this.fontSize;
    this.refreshAnchorOff();

    this.ctx.restore();

  }

  setMaxSize(w) {

    this._maxWidth = w;
    this.refreshSize();
    if (this.width >= w) {
      this.scaleX *= w / this.width;
      this.scaleY *= w / this.width;
    }
  }

  show(callBack = null) {

    this.visible = true;

    if (this.alpha >= 1) {
      return;
    }

    const tween = new TWEEN.Tween(this)
      .to({ alpha: 1 }, 800)
      // .easing(TWEEN.Easing.Quadratic.Out) // Use an easing function to make the animation smooth.
      .onComplete(() => {
        if (callBack) {
          callBack();
        }
      })
      .start(); // Start the tween immediately.
  }

  setOutline(width = 5, color = '#ffffff') {

    this._outlineFlag = true;
    this._outLineWidth = width;
    this._outLineColor = color;

  }

  drawText() {


    if (!this.text) { return; }


    this.ctx.font = `${this.fontSize}px ${this.fontName}`;
    this.ctx.textAlign = this.textAlign;
    this.ctx.textBaseline = 'middle';
    this.ctx.fontWeight = this.fontWeight;

    if (this._outlineFlag) {
      this.ctx.lineWidth = this._outLineWidth;
      this.ctx.strokeStyle = this._outLineColor;
      this.ctx.strokeText(this.text, 0, 0);
    }

    this.ctx.fillStyle = this.fontColor;



    if (this.outline > 0) {
      this.ctx.lineWidth = this.outline;
      this.ctx.strokeStyle = this.outlineColor;
      this.ctx.strokeText(this.text, 0, 0);

    }

    this.ctx.fillText(this.text, 0, 0);


  }


  drawSelf() {
    super.drawSelf();
    this.drawText();
  }

}

export class RichTextOld extends Label {

  textArr = [];
  fontSize = 40;

  setText(text: string, words) {

    let newText = text;
    for (const word of words) {

      const re = new RegExp(word, 'g');
      newText = newText.replace( re, `#${word}#`);
      // newText = newText.replace(word, `#${word}#`);
    }

    this.textArr = newText.split('#');
    this.text = newText;

    // this.setSize();
  }

  refreshSize() {

    this.ctx.save();

    this.ctx.font = `${this.fontSize}px ${this.fontName}`;
    this.ctx.textAlign = this.textAlign;
    this.ctx.textBaseline = 'middle';
    this.ctx.fontWeight = this.fontWeight;

    let curX = 0;
    for (const text of this.textArr) {
      const w = this.ctx.measureText(text).width;
      curX += w;
    }

    this.width = curX;
    this.height = this.fontSize;
    this.refreshAnchorOff();

    this.ctx.restore();

  }


  show(callBack = null) {

    // console.log(' in show ');
    this.visible = true;
    // this.alpha = 0;

    const tween = new TWEEN.Tween(this)
      .to({ alpha: 1 }, 800)
      // .easing(TWEEN.Easing.Quadratic.Out) // Use an easing function to make the animation smooth.
      .onComplete(() => {
        if (callBack) {
          callBack();
        }
      })
      .start(); // Start the tween immediately.

  }



  drawText() {

    // console.log('in drawText', this.text);

    if (!this.text) { return; }


    this.ctx.font = `${this.fontSize}px ${this.fontName}`;
    this.ctx.textAlign = this.textAlign;
    this.ctx.textBaseline = 'middle';
    this.ctx.fontWeight = 900;

    this.ctx.lineWidth = 5;
    this.ctx.strokeStyle = '#ffffff';
    // this.ctx.strokeText(this.text, 0, 0);

    this.ctx.fillStyle = '#000000';
    // this.ctx.fillText(this.text, 0, 0);


    let curX = 0;
    for (let i = 0; i < this.textArr.length; i++) {

      const w = this.ctx.measureText(this.textArr[i]).width;

      if ((i + 1) % 2 === 0) {
        this.ctx.fillStyle = '#c8171e';
      } else {
        this.ctx.fillStyle = '#000000';
      }

      this.ctx.fillText(this.textArr[i], curX, 0);
      curX += w;

    }


  }

}





export class RichText extends Label {


  disH =  30;

  constructor(ctx?: any) {
    super(ctx);

    // this.dataArr = dataArr;
  }



  drawText() {

    if (!this.text) {
      return;
    }


    this.ctx.font = `${this.fontSize}px ${this.fontName}`;
    this.ctx.textAlign = this.textAlign;
    this.ctx.textBaseline = 'middle';
    this.ctx.fontWeight = this.fontWeight;
    this.ctx.fillStyle = this.fontColor;


    const selfW = this.width * this.scaleX;


    const chr = this.text.split(' ');
    let temp = '';
    const row = [];
    const w = selfW - 80;
    const disH = (this.fontSize + this.disH) * this.scaleY;




    for (const c of  chr) {
      if (this.ctx.measureText(temp).width < w && this.ctx.measureText(temp + (c)).width <= w) {
        temp += ' ' + c;
      } else {
        row.push(temp);
        temp = ' ' + c;
      }
    }
    row.push(temp);

    const x = 0;
    const y = -row.length * disH / 2;
    // for (let b = 0 ; b < row.length; b++) {
    //   this.ctx.strokeText(row[b], x, y + ( b + 1 ) * disH ); // 每行字体y坐标间隔20
    // }


    if (this._outlineFlag) {
      this.ctx.lineWidth = this._outLineWidth;
      this.ctx.strokeStyle = this._outLineColor;
      for (let b = 0 ; b < row.length; b++) {
        this.ctx.strokeText(row[b], x, y + ( b + 1 ) * disH ); // 每行字体y坐标间隔20
      }
      // this.ctx.strokeText(this.text, 0, 0);
    }


    // this.ctx.fillStyle = '#ff7600';
    for (let b = 0 ; b < row.length; b++) {
      this.ctx.fillText(row[b], x, y + ( b + 1 ) * disH ); // 每行字体y坐标间隔20
    }

  }


  drawSelf() {
    super.drawSelf();
    this.drawText();
  }

}




export class LineRect extends MySprite {

  lineColor = '#ffffff';
  lineWidth = 10;

  setSize(w, h) {
    this.width = w;
    this.height = h;
  }

  drawLine() {

    this.ctx.beginPath();
    this.ctx.moveTo(this._offX, this._offY);
    this.ctx.lineTo(this._offX + this.width, this._offY);
    this.ctx.lineTo(this._offX + this.width, this._offY + this.height);
    this.ctx.lineTo(this._offX, this._offY + this.height);
    this.ctx.closePath();

    this.ctx.lineWidth = this.lineWidth;
    // this.ctx.fillStyle = "rgb(2,33,42)";  //指定填充颜色
    // this.ctx.fill();   //对多边形进行填充

    this.ctx.strokeStyle = this.lineColor; // "#ffffff";
    this.ctx.stroke();

  }


  drawSelf() {
    super.drawSelf();
    this.drawLine();
  }
}


export class ShapeRect extends MySprite {

  fillColor = '#FF0000';

  setSize(w, h) {
    this.width = w;
    this.height = h;

    // console.log('w:', w);
    // console.log('h:', h);
  }

  drawShape() {

    this.ctx.fillStyle = this.fillColor;
    this.ctx.fillRect(this._offX, this._offY, this.width, this.height);

  }


  drawSelf() {
    super.drawSelf();
    this.drawShape();
  }
}



export class Line extends MySprite {


  lineWidth = 5;
  lineColor = '#000000';
  _pointArr = [];

  roundFlag = true;

  _pointS = 1;


  imgObj;
  bitMap;
  _offCtx;
  _offCanvas;

  lastPointIndex = 0;

  init() {

    const canvas = window['curCanvas'];
    const w = canvas.nativeElement.width;
    const h = canvas.nativeElement.height;

    console.log('w: ', w);
    console.log('h: ', h);


    this._offCanvas = document.createElement('canvas');
    this._offCanvas.width = w;
    this._offCanvas.height = h;
    // this._offCanvas = _offCanvas;
    // this._offCtx = this._offCanvas.getContext('2d');


    // this._offCanvas = new OffscreenCanvas(w, h);
    this._offCtx = this._offCanvas.getContext('2d');
  }

  addPoint(x, y) {

    this._pointArr.push([x, y]);

    if (this._pointArr.length < 2) {
      return;
    }
    //
    // const lastP = this._pointArr[this._pointArr.length - 1];
    //
    //
    // const context = this._offCtx;
    // context.moveTo (lastP[0], lastP[1]);       // 设置起点状态
    // context.lineTo (x, y);       // 设置末端状态
    //
    // context.lineWidth = this.lineWidth;          //设置线宽状态
    // context.strokeStyle = this.lineColor;
    // context.stroke();
    //
    //
    // this.bitMap = this._offCanvas.transferToImageBitmap();



    // const tmpLine = new MySprite(this._offCtx);
    // tmpLine.init(this.imgObj);
    // tmpLine.anchorY = 1;
    // tmpLine.anchorX = 0.5;
    // tmpLine.x = lastP[0];
    // tmpLine.y = lastP[1];
    //
    // const disH = getPosDistance(lastP[0], lastP[1], x, y);
    // tmpLine.scaleX = this.lineWidth / tmpLine.width;
    // tmpLine.scaleY = disH / tmpLine.height * 1.1;
    //
    // const angle = getAngleByPos(lastP[0], lastP[1], x, y);
    // tmpLine.rotation = angle;
    //
    // this.addChild(tmpLine);

  }

  setPointArr(arr, imgObj) {

    this.removeChildren();

    if (arr.length < 2) {
      return;
    }

    let p1 = arr[0];
    let p2;
    for (let i = 1; i < arr.length; i++) {

      p2 = arr[i];

      const tmpLine = new MySprite();
      tmpLine.init(imgObj);
      tmpLine.anchorY = 1;
      tmpLine.anchorX = 0.5;
      tmpLine.x = p1[0];
      tmpLine.y = p1[1];

      const disH = getPosDistance(p1[0], p1[1], p2[0], p2[1]);
      tmpLine.scaleX = this.lineWidth / tmpLine.width;
      tmpLine.scaleY = disH / tmpLine.height * 1.1;

      const angle = getAngleByPos(p1[0], p1[1], p2[0], p2[1]);
      tmpLine.rotation = angle;

      this.addChild(tmpLine);

      p1 = p2;
    }
  }




  drawLine() {

    if (this._pointArr.length < 2) {
      return;
    }


    const curMaxPointIndex = this._pointArr.length - 1;
    if (curMaxPointIndex > this.lastPointIndex) {

      const arr = this._pointArr;

      const context = this._offCtx;
      context.moveTo (arr[this.lastPointIndex][0] * this._pointS, arr[this.lastPointIndex][1] * this._pointS);       // 设置起点状态
      for (let i = this.lastPointIndex + 1; i < arr.length; i++) {
        context.lineTo (arr[i][0] * this._pointS, arr[i][1] * this._pointS);       // 设置末端状态
      }

      if (this.roundFlag) {
        context.lineCap = "round";
      }
      context.lineWidth = this.lineWidth;          //设置线宽状态
      context.strokeStyle = this.lineColor;
      context.stroke();


      this.lastPointIndex = curMaxPointIndex;

      // this.bitMap = this._offCanvas.transferToImageBitmap();

    }


    // this.ctx.drawImage(this.bitMap, this._offX, this._offY);
    this.ctx.drawImage(this._offCanvas, this._offX, this._offY);

  }

  drawSelf() {
    super.drawSelf();
    this.drawLine();


    // if (this.img) {
    //   this.ctx.drawImage(this._offCanvas, 0, 0, this.width, this.height);
    // }

    // if (this.bitMap) {
    //   this.bitMap = this._offCanvas.transferToImageBitmap();
    //   this.ctx.drawImage(this.bitMap, 0, 0, this.width, this.height);
    // }

  }
}


export class ShapeCircle extends MySprite {

  fillColor = '#FF0000';
  radius = 0;


  setRadius(r) {
    this.anchorX = this.anchorY = 0.5;

    this.radius = r;
    this.width = r * 2;
    this.height = r * 2;
  }

  drawShape() {

    this.ctx.beginPath();
    this.ctx.fillStyle = this.fillColor;
    this.ctx.arc(0, 0, this.radius, 0, angleToRadian(360));
    this.ctx.fill();
  }

  drawSelf() {
    super.drawSelf();
    this.drawShape();
  }
}




export class ShapeRectNew extends MySprite {


  radius = 0;
  fillColor = '#ffffff';
  strokeColor = '#000000';
  fill = true;
  stroke = false;
  lineWidth = 1;

  setSize(w, h, r) {
    this.width = w;
    this.height = h;
    this.radius = r;
  }

  setOutLine(color, lineWidth) {
    this.stroke = true;
    this.strokeColor = color;
    this.lineWidth = lineWidth;
  }


  drawShape() {

    const ctx = this.ctx;
    const width = this.width;
    const height = this.height;
    const radius = this.radius;

    ctx.save();
    ctx.beginPath(0);
    // 从右下角顺时针绘制,弧度从0到1/2PI
    ctx.arc(width - radius, height - radius, radius, 0, Math.PI / 2);

    // 矩形下边线
    ctx.lineTo(radius, height);

    // 左下角圆弧,弧度从1/2PI到PI
    ctx.arc(radius, height - radius, radius, Math.PI / 2, Math.PI);

    // 矩形左边线
    ctx.lineTo(0, radius);

    // 左上角圆弧,弧度从PI到3/2PI
    ctx.arc(radius, radius, radius, Math.PI, Math.PI * 3 / 2);

    // 上边线
    ctx.lineTo(width - radius, 0);

    // 右上角圆弧
    ctx.arc(width - radius, radius, radius, Math.PI * 3 / 2, Math.PI * 2);

    // 右边线
    ctx.lineTo(width, height - radius);
    ctx.closePath();

    if (this.fill) {
      ctx.fillStyle = this.fillColor;
      ctx.fill();
    }
    if (this.stroke) {
      ctx.lineWidth = this.lineWidth;
      ctx.strokeStyle = this.strokeColor;
      ctx.stroke();
    }
    ctx.restore();

  }


  drawSelf() {
    super.drawSelf();
    this.drawShape();
  }

}
export class MyAnimation extends MySprite {


  frameArr = [];
  frameIndex = 0;
  playFlag = false;
  lastDateTime;
  curDelay = 0;


  loop = false;
  playEndFunc;
  delayPerUnit = 1;

  restartFlag = false;
  reverseFlag = false;

  addFrameByImg(img) {

    const spr = new MySprite(this.ctx);
    spr.init(img);
    this._refreshSize(img);

    spr.visible = false;

    this.addChild(spr);
    this.frameArr.push(spr);

    this.frameArr[this.frameIndex].visible = true;
  }

  addFrameByUrl(url) {

    const spr = new MySprite(this.ctx);
    spr.load(url).then(img => {

      this._refreshSize(img);
    });
    spr.visible = false;

    this.addChild(spr);
    this.frameArr.push(spr);

    this.frameArr[this.frameIndex].visible = true;
  }

  _refreshSize(img: any) {

    if (this.width < img.width) {
      this.width = img.width;
    }
    if (this.height < img.height) {
      this.height = img.height;
    }
  }



  play() {
    this.playFlag = true;
    this.lastDateTime = new Date().getTime();
  }

  stop() {
    this.playFlag = false;
  }


  replay() {
    this.restartFlag = true;
    this.play();
  }


  reverse() {
    this.reverseFlag = !this.reverseFlag;
    this.frameArr.reverse();
    this.frameIndex = 0;
  }

  showAllFrame() {
    for (const frame of this.frameArr ) {
      frame.alpha = 1;
    }
  }

  hideAllFrame() {
    for (const frame of this.frameArr) {
      frame.alpha = 0;
    }
  }


  playEnd() {

    this.playFlag = false;
    this.curDelay = 0;

    this.frameArr[this.frameIndex].visible = true;

    if (this.playEndFunc) {
      this.playEndFunc();
      this.playEndFunc = null;
    }
  }

  updateFrame() {
    if (this.frameArr[this.frameIndex]) {
      this.frameArr[this.frameIndex].visible = false;
    }

    this.frameIndex ++;
    if (this.frameIndex >= this.frameArr.length) {
      if (this.loop) {
        this.frameIndex = 0;
      } else if (this.restartFlag) {
        this.restartFlag = false;
        this.frameIndex = 0;
      } else {
        this.frameIndex -- ;
        this.playEnd();
        return;
      }
    }

    this.frameArr[this.frameIndex].visible = true;

  }




  _updateDelay(delay) {

    this.curDelay += delay;
    if (this.curDelay < this.delayPerUnit) {
      return;
    }
    this.curDelay -= this.delayPerUnit;
    this.updateFrame();
  }

  _updateLastDate() {
    if (!this.playFlag) { return; }

    let delay = 0;
    if (this.lastDateTime) {
      delay = (new Date().getTime() - this.lastDateTime) / 1000;
    }
    this.lastDateTime = new Date().getTime();
    this._updateDelay(delay);
  }

  update($event: any = null) {
    super.update($event);
    this._updateLastDate();
  }


}




// --------===========  util func  =============-------------


export function tweenChange(item, obj, time = 0.8, callBack = null, easing = null, update = null) {

  const tween = new TWEEN.Tween(item).to(obj, time * 1000);

  if (callBack) {
    tween.onComplete(() => {
      callBack();
    });
  }
  if (easing) {
    tween.easing(easing);
  }
  if (update) {
    tween.onUpdate( (a, b) => {
      update(a, b);
    });
  }

  tween.start();
  return tween;
}




export function rotateItem(item, rotation, time = 0.8, callBack = null, easing = null) {

  const tween = new TWEEN.Tween(item).to({ rotation }, time * 1000);

  if (callBack) {
    tween.onComplete(() => {
      callBack();
    });
  }
  if (easing) {
    tween.easing(easing);
  }

  tween.start();
}



export function scaleItem(item, scale, time = 0.8, callBack = null, easing = null) {

  const tween = new TWEEN.Tween(item).to({ scaleX: scale, scaleY: scale}, time * 1000);

  if (callBack) {
    tween.onComplete(() => {
      callBack();
    });
  }
  if (easing) {
    tween.easing(easing);
  }

  tween.start();
  return tween;
}


export function moveItem(item, x, y, time = 0.8, callBack = null, easing = null) {

  const tween = new TWEEN.Tween(item).to({ x, y}, time * 1000);

  if (callBack) {
    tween.onComplete(() => {
      callBack();
    });
  }
  if (easing) {
    tween.easing(easing);
  }

  tween.start();

  return tween;
}







export function endShow(item, s = 1) {

  item.scaleX = item.scaleY = 0;
  item.alpha = 0;

  const tween = new TWEEN.Tween(item)
    .to({ alpha: 1, scaleX: s, scaleY: s }, 800)
    .easing(TWEEN.Easing.Elastic.Out) // Use an easing function to make the animation smooth.
    .onComplete(() => {

    })
    .start();
}

export function hideItem(item, time = 0.8, callBack = null, easing = null) {

  if (item.alpha === 0) {
    return;
  }

  const tween = new TWEEN.Tween(item)
    .to({alpha: 0}, time * 1000)
    // .easing(TWEEN.Easing.Quadratic.Out) // Use an easing function to make the animation smooth.
    .onComplete(() => {
      if (callBack) {
        callBack();
      }
    });

  if (easing) {
    tween.easing(easing);
  }

  tween.start();
}


export function showItem(item, time = 0.8, callBack = null, easing = null) {

  if (item.alpha === 1) {
    if (callBack) {
      callBack();
    }
    return;
  }

  item.visible = true;
  const tween = new TWEEN.Tween(item)
    .to({alpha: 1}, time * 1000)
    // .easing(TWEEN.Easing.Quadratic.Out) // Use an easing function to make the animation smooth.
    .onComplete(() => {
      if (callBack) {
        callBack();
      }
    });

  if (easing) {
    tween.easing(easing);
  }

  tween.start();
}


export function alphaItem(item, alpha, time = 0.8, callBack = null, easing = null) {


  const tween = new TWEEN.Tween(item)
    .to({alpha}, time * 1000)
    // .easing(TWEEN.Easing.Quadratic.Out) // Use an easing function to make the animation smooth.
    .onComplete(() => {
      if (callBack) {
        callBack();
      }
    });

  if (easing) {
    tween.easing(easing);
  }

  tween.start();
}


export function showStar(item, time = 0.8, callBack = null, easing = null) {


  const tween = new TWEEN.Tween(item)
    .to({alpha: 1, scale: 1}, time * 1000)
    // .easing(TWEEN.Easing.Quadratic.Out) // Use an easing function to make the animation smooth.
    .onComplete(() => {
      if (callBack) {
        callBack();
      }
    });

  if (easing) {
    tween.easing(easing);
  }

  tween.start();
}


export function randomSortByArr(arr) {
  if (!arr) {
    return;
  }
  const newArr = [];
  const tmpArr = arr.concat();
  while (tmpArr.length > 0) {
    const randomIndex = Math.floor( tmpArr.length * Math.random() );
    newArr.push(tmpArr[randomIndex]);
    tmpArr.splice(randomIndex, 1);
  }
  return newArr;
}


export function radianToAngle(radian) {
  return radian * 180 / Math.PI;
  // 角度 = 弧度 * 180 / Math.PI;
}

export function angleToRadian(angle) {
  return angle * Math.PI / 180;
  // 弧度= 角度 * Math.PI / 180;
}

export function getPosByAngle(angle, len) {

  const radian = angle * Math.PI / 180;
  const x = Math.sin(radian) * len;
  const y = Math.cos(radian) * len;

  return {x, y};

}

export function getAngleByPos(px, py, mx, my) {

  const x = Math.abs(px - mx);
  const y = Math.abs(py - my);

  const z = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
  const cos = y / z;
  const radina = Math.acos(cos); // 用反三角函数求弧度
  let angle = Math.floor(180 / (Math.PI / radina) * 100) / 100; // 将弧度转换成角度

  if (mx > px && my > py) {// 鼠标在第四象限
    angle = 180 - angle;
  }
  if (mx === px && my > py) {// 鼠标在y轴负方向上
    angle = 180;
  }
  if (mx > px && my === py) {// 鼠标在x轴正方向上
    angle = 90;
  }
  if (mx < px && my > py) {// 鼠标在第三象限
    angle = 180 + angle;
  }
  if (mx < px && my === py) {// 鼠标在x轴负方向
    angle = 270;
  }
  if (mx < px && my < py) {// 鼠标在第二象限
    angle = 360 - angle;
  }

  // console.log('angle: ', angle);
  return angle;

}


export function removeItemFromArr(arr, item) {
  const index = arr.indexOf(item);
  if (index !== -1) {
    arr.splice(index, 1);
  }
}






export function circleMove(item, x0, y0, time = 2, addR = 360, xPer = 1, yPer = 1, callBack = null, easing = null) {

  const r = getPosDistance(item.x, item.y, x0, y0);
  let a = getAngleByPos(item.x, item.y, x0, y0);
  a += 90;
  const obj = {r, a};

  item._circleAngle = a;
  const targetA = a + addR;

  const tween = new TWEEN.Tween(item).to({_circleAngle: targetA}, time * 1000);

  if (callBack) {
    tween.onComplete(() => {
      callBack();
    });
  }
  if (easing) {
    tween.easing(easing);
  }

  tween.onUpdate( (item, progress) => {

    // console.log(item._circleAngle);
    const r = obj.r;
    const a = item._circleAngle;

    const x = x0 + r * xPer * Math.cos(a * Math.PI / 180);
    const y = y0 + r * yPer * Math.sin(a * Math.PI / 180);

    item.x = x;
    item.y = y;

    // obj.a ++;
  });

  tween.start();
}


export function getPosDistance(sx, sy, ex, ey) {

  const _x = ex - sx;
  const _y = ey - sy;
  const len = Math.sqrt( Math.pow(_x, 2) + Math.pow(_y, 2) );
  return len;
}

export function delayCall(callback, second) {
  const tween = new TWEEN.Tween(this)
    .delay(second * 1000)
    .onComplete(() => {
      if (callback) {
        callback();
      }
    })
    .start();
}


export function formatTime(fmt, date) {

  // "yyyy-MM-dd HH:mm:ss";

  const o = {
    'M+': date.getMonth() + 1, // 月份
    'd+': date.getDate(), // 日
    'h+': date.getHours(), // 小时
    'm+': date.getMinutes(), // 分
    's+': date.getSeconds(), // 秒
    'q+': Math.floor((date.getMonth() + 3) / 3), // 季度
    S: date.getMilliseconds() // 毫秒
  };
  if (/(y+)/.test(fmt)) { fmt = fmt.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length)); }
  for (const k in o) {
    if (new RegExp('(' + k + ')').test(fmt)) { fmt = fmt.replace(RegExp.$1, (RegExp.$1.length === 1)
      ? (o[k]) : (('00' + o[k]).substr(('' + o[k]).length)));
    }
  }
  return fmt;
}

export function getMinScale(item, maxLen) {
  const sx = maxLen / item.width;
  const sy = maxLen / item.height;
  const minS = Math.min(sx, sy);
  return minS;
}



export function jelly(item, time = 0.7) {


  if (item.jellyTween) {
    TWEEN.remove(item.jellyTween);
  }

  const t = time / 9;
  const baseSX = item.scaleX;
  const baseSY = item.scaleY;
  let index = 0;

  const run = () => {
    if (index >= arr.length) {
      item.jellyTween = null;
      return;
    }
    const data = arr[index];
    const t = tweenChange(item, {scaleX: data[0], scaleY: data[1]}, data[2], () => {
      index ++;
      run();
    }, TWEEN.Easing.Sinusoidal.InOut);
    item.jellyTween = t;
  };

  const arr = [
    [baseSX * 1.1, baseSY * 0.9, t],
    [baseSX * 0.98, baseSY * 1.02, t * 2],
    [baseSX * 1.02, baseSY * 0.98, t * 2],
    [baseSX * 0.99, baseSY * 1.01, t * 2],
    [baseSX * 1.0, baseSY * 1.0, t * 2],
  ];


  run();
}



export function showPopParticle(img, pos, parent, num = 20, minLen = 40, maxLen = 80, showTime = 0.4) {


  for (let i = 0; i < num; i ++) {

    const particle = new MySprite();
    particle.init(img);
    particle.x = pos.x;
    particle.y = pos.y;
    parent.addChild(particle);

    const randomR = 360 * Math.random();
    particle.rotation = randomR;

    const randomS = 0.3 + Math.random() * 0.7;
    particle.setScaleXY(randomS * 0.3);

    const randomX = Math.random() * 20 - 10;
    particle.x += randomX;

    const randomY = Math.random() * 20 - 10;
    particle.y += randomY;

    const randomL = minLen + Math.random() * (maxLen - minLen);
    const randomA = 360 * Math.random();
    const randomT = getPosByAngle(randomA, randomL);
    moveItem(particle, particle.x + randomT.x, particle.y + randomT.y, showTime, () => {



    }, TWEEN.Easing.Exponential.Out);

    // scaleItem(particle, 0, 0.6, () => {
    //
    // });

    scaleItem(particle, randomS, 0.6, () => {

    }, TWEEN.Easing.Exponential.Out);

    setTimeout(() => {

      hideItem(particle, 0.4, () => {

      }, TWEEN.Easing.Cubic.In);

    }, showTime * 0.5 * 1000);


  }
}



export function shake(item, time = 0.5, callback = null, rate = 1) {

  if (item.shakeTween) {
    return;
  }

  item.shakeTween = true;
  const offX = 15 * item.scaleX * rate;
  const offY = 15 * item.scaleX * rate;
  const baseX = item.x;
  const baseY = item.y;
  const easing = TWEEN.Easing.Sinusoidal.InOut;


  const move4 = () => {
    moveItem(item, baseX, baseY, time / 4, () => {
      item.shakeTween = false;
      if (callback) {
        callback();
      }
    }, easing);
  };

  const move3 = () => {
    moveItem(item, baseX + offX / 4, baseY + offY / 4, time / 4, () => {
      move4();
    }, easing);
  };

  const move2 = () => {
    moveItem(item, baseX - offX / 4 * 3, baseY - offY / 4 * 3, time / 4, () => {
      move3();
    }, easing);
  };

  const move1 = () => {
    moveItem(item, baseX + offX, baseY + offY, time / 7.5, () => {
      move2();
    }, easing);
  };

  move1();

}

// --------------- custom class --------------------



export class HotZoneItem extends MySprite {


  lineDashFlag = false;
  arrow: MySprite;
  label: Label;
  title;

  arrowTop;
  arrowRight;

  audio_url;
  pic_url;
  text;
  private _itemType;
  private shapeRect: ShapeRect;

  get itemType() {
    return this._itemType;
  }
  set itemType(value) {
    this._itemType = value;
  }

  setSize(w, h) {
    this.width = w;
    this.height = h;


    const rect = new ShapeRect(this.ctx);
    rect.x = -w / 2;
    rect.y = -h / 2;
    rect.setSize(w, h);
    rect.fillColor = '#ffffff';
    rect.alpha = 0.2;
    this.addChild(rect);
  }

  showLabel(text = null) {


    if (!this.label) {
      this.label = new Label(this.ctx);
      this.label.anchorY = 0;
      this.label.fontSize = 40;
      this.label.textAlign = 'center';
      this.addChild(this.label);
      // this.label.scaleX = 1 / this.scaleX;
      // this.label.scaleY = 1 / this.scaleY;

      this.refreshLabelScale();

    }

    if (text) {
      this.label.text = text;
    } else if (this.title) {
      this.label.text = this.title;
    }
    this.label.visible = true;

  }

  hideLabel() {
    if (!this.label) { return; }

    this.label.visible = false;
  }

  refreshLabelScale() {
    if (this.scaleX == this.scaleY) {
      this.label.setScaleXY(1);
    }

    if (this.scaleX > this.scaleY) {
      this.label.scaleX = this.scaleY / this.scaleX;
    } else {
      this.label.scaleY = this.scaleX / this.scaleY;
    }
  }

  showLineDash() {
    this.lineDashFlag = true;

    if (this.arrow) {
      this.arrow.visible = true;
    } else {
      this.arrow = new MySprite(this.ctx);
      this.arrow.load('assets/common/arrow.png', 1, 0);
      this.arrow.setScaleXY(0.06);

      this.arrowTop = new MySprite(this.ctx);
      this.arrowTop.load('assets/common/arrow_top.png', 0.5, 0);
      this.arrowTop.setScaleXY(0.06);

      this.arrowRight = new MySprite(this.ctx);
      this.arrowRight.load('assets/common/arrow_right.png', 1, 0.5);
      this.arrowRight.setScaleXY(0.06);
    }

    this.showLabel();
  }

  hideLineDash() {

    this.lineDashFlag = false;

    if (this.arrow) {
      this.arrow.visible = false;
    }

    this.hideLabel();
  }



  drawArrow() {
    if (!this.arrow) { return; }

    const rect = this.getBoundingBox();
    this.arrow.x = rect.x + rect.width;
    this.arrow.y = rect.y;

    this.arrow.update();


    this.arrowTop.x = rect.x + rect.width / 2;
    this.arrowTop.y = rect.y;
    this.arrowTop.update();

    this.arrowRight.x = rect.x + rect.width;
    this.arrowRight.y = rect.y + rect.height / 2;
    this.arrowRight.update();
  }

  drawFrame() {


    this.ctx.save();


    const rect = this.getBoundingBox();

    const w = rect.width;
    const h = rect.height;
    const x = rect.x + w / 2;
    const y = rect.y + h / 2;

    this.ctx.setLineDash([5, 5]);
    this.ctx.lineWidth = 2;
    this.ctx.strokeStyle = '#1bfff7';
    // this.ctx.fillStyle = '#ffffff';

    this.ctx.beginPath();

    this.ctx.moveTo( x - w / 2, y - h / 2);

    this.ctx.lineTo(x + w / 2, y - h / 2);

    this.ctx.lineTo(x + w / 2, y + h / 2);

    this.ctx.lineTo(x - w / 2, y + h / 2);

    this.ctx.lineTo(x - w / 2, y - h / 2);

    // this.ctx.fill();
    this.ctx.stroke();




    this.ctx.restore();

  }

  draw() {
    super.draw();

    if (this.lineDashFlag) {
      this.drawFrame();
      this.drawArrow();
    }
  }
}

export class HotZoneImg extends MySprite {

  drawFrame() {

    this.ctx.save();

    const rect = this.getBoundingBox();
    const w = rect.width;
    const h = rect.height;
    const x = rect.x + w / 2;
    const y = rect.y + h / 2;

    this.ctx.setLineDash([5, 5]);
    this.ctx.lineWidth = 2;
    this.ctx.strokeStyle = '#1bfff7';

    this.ctx.beginPath();
    this.ctx.moveTo( x - w / 2, y - h / 2);
    this.ctx.lineTo(x + w / 2, y - h / 2);
    this.ctx.lineTo(x + w / 2, y + h / 2);
    this.ctx.lineTo(x - w / 2, y + h / 2);
    this.ctx.lineTo(x - w / 2, y - h / 2);

    // this.ctx.fill();
    this.ctx.stroke();

    this.ctx.restore();
  }

  draw() {
    super.draw();

    this.drawFrame();
  }
}

export class HotZoneLabel extends Label {

  drawFrame() {

    this.ctx.save();

    const rect = this.getBoundingBox();
    const w = rect.width / this.scaleX;
    const h = this.height * this.scaleY;
    const x = this.x;
    const y = this.y;

    this.ctx.setLineDash([5, 5]);
    this.ctx.lineWidth = 2;
    this.ctx.strokeStyle = '#1bfff7';

    this.ctx.beginPath();
    this.ctx.moveTo( x - w / 2, y - h / 2);
    this.ctx.lineTo(x + w / 2, y - h / 2);
    this.ctx.lineTo(x + w / 2, y + h / 2);
    this.ctx.lineTo(x - w / 2, y + h / 2);
    this.ctx.lineTo(x - w / 2, y - h / 2);

    // this.ctx.fill();
    this.ctx.stroke();

    this.ctx.restore();
  }

  draw() {
    super.draw();

    this.drawFrame();
  }
}




export class EditorItem extends MySprite {

  lineDashFlag = false;
  arrow: MySprite;
  label: Label;
  text;

  showLabel(text = null) {


    if (!this.label) {
      this.label = new Label(this.ctx);
      this.label.anchorY = 0;
      this.label.fontSize = 50;
      this.label.textAlign = 'center';
      this.addChild(this.label);
      this.label.setScaleXY(1 / this.scaleX);
    }

    if (text) {
      this.label.text = text;
    } else if (this.text) {
      this.label.text = this.text;
    }
    this.label.visible = true;

  }

  hideLabel() {
    if (!this.label) { return; }

    this.label.visible = false;
  }

  showLineDash() {
    this.lineDashFlag = true;

    if (this.arrow) {
      this.arrow.visible = true;
    } else {
      this.arrow = new MySprite(this.ctx);
      this.arrow.load('assets/common/arrow.png', 1, 0);
      this.arrow.setScaleXY(0.06);

    }

    this.showLabel();
  }

  hideLineDash() {

    this.lineDashFlag = false;

    if (this.arrow) {
      this.arrow.visible = false;
    }

    this.hideLabel();
  }



  drawArrow() {
    if (!this.arrow) { return; }

    const rect = this.getBoundingBox();
    this.arrow.x = rect.x + rect.width;
    this.arrow.y = rect.y;

    this.arrow.update();
  }

  drawFrame() {


    this.ctx.save();


    const rect = this.getBoundingBox();

    const w = rect.width;
    const h = rect.height;
    const x = rect.x + w / 2;
    const y = rect.y + h / 2;

    this.ctx.setLineDash([5, 5]);
    this.ctx.lineWidth = 2;
    this.ctx.strokeStyle = '#1bfff7';
    // this.ctx.fillStyle = '#ffffff';

    this.ctx.beginPath();

    this.ctx.moveTo( x - w / 2, y - h / 2);

    this.ctx.lineTo(x + w / 2, y - h / 2);

    this.ctx.lineTo(x + w / 2, y + h / 2);

    this.ctx.lineTo(x - w / 2, y + h / 2);

    this.ctx.lineTo(x - w / 2, y - h / 2);

    // this.ctx.fill();
    this.ctx.stroke();




    this.ctx.restore();

  }

  draw() {
    super.draw();

    if (this.lineDashFlag) {
      this.drawFrame();
      this.drawArrow();
    }
  }
}



//
//
// import TWEEN from '@tweenjs/tween.js';
//
//
// class Sprite {
//   x = 0;
//   y = 0;
//   color = '';
//   radius = 0;
//   alive = false;
//   margin = 0;
//   angle = 0;
//   ctx;
//
//   constructor(ctx) {
//     this.ctx = ctx;
//   }
//   update($event) {
//     this.draw();
//   }
//   draw() {
//
//   }
//
// }
//
//
//
//
//
// export class MySprite extends Sprite {
//
//   width = 0;
//   height = 0;
//   _anchorX = 0;
//   _anchorY = 0;
//   _offX = 0;
//   _offY = 0;
//   scaleX = 1;
//   scaleY = 1;
//   alpha = 1;
//   rotation = 0;
//   visible = true;
//
//   children = [this];
//
//   img;
//   _z = 0;
//
//
//   init(imgObj = null, anchorX:number = 0.5, anchorY:number = 0.5) {
//
//     if (imgObj) {
//
//       this.img = imgObj;
//
//       this.width = this.img.width;
//       this.height = this.img.height;
//     }
//
//     this.anchorX = anchorX;
//     this.anchorY = anchorY;
//   }
//
//
//
//   update($event = null) {
//     if (this.visible) {
//       this.draw();
//     }
//   }
//   draw() {
//
//     this.ctx.save();
//
//     this.drawInit();
//
//     this.updateChildren();
//
//     this.ctx.restore();
//   }
//
//   drawInit() {
//
//     this.ctx.translate(this.x, this.y);
//
//     this.ctx.rotate(this.rotation * Math.PI / 180);
//
//     this.ctx.scale(this.scaleX, this.scaleY);
//
//     this.ctx.globalAlpha = this.alpha;
//
//   }
//
//   drawSelf() {
//     if (this.img) {
//       this.ctx.drawImage(this.img, this._offX, this._offY);
//     }
//   }
//
//   updateChildren() {
//
//     if (this.children.length <= 0) { return; }
//
//     for (let i = 0; i < this.children.length; i++) {
//
//       if (this.children[i] === this) {
//
//         this.drawSelf();
//       } else {
//
//         this.children[i].update();
//       }
//     }
//   }
//
//
//   load(url, anchorX = 0.5, anchorY = 0.5) {
//
//     return new Promise((resolve, reject) => {
//       const img = new Image();
//       img.onload = () => resolve(img);
//       img.onerror = reject;
//       img.src = url;
//     }).then(img => {
//
//       this.init(img, anchorX, anchorY);
//       return img;
//     });
//   }
//
//   addChild(child, z = 1) {
//     if (this.children.indexOf(child) === -1) {
//       this.children.push(child);
//       child._z = z;
//       child.parent = this;
//     }
//
//     this.children.sort((a, b) => {
//       return a._z - b._z;
//     });
//
//   }
//   removeChild(child) {
//     const index = this.children.indexOf(child);
//     if (index !== -1) {
//       this.children.splice(index, 1);
//     }
//   }
//
//   set anchorX(value) {
//     this._anchorX = value;
//     this.refreshAnchorOff();
//   }
//   get anchorX() {
//     return this._anchorX;
//   }
//   set anchorY(value) {
//     this._anchorY = value;
//     this.refreshAnchorOff();
//   }
//   get anchorY() {
//     return this._anchorY;
//   }
//   refreshAnchorOff() {
//     this._offX = -this.width * this.anchorX;
//     this._offY = -this.height * this.anchorY;
//   }
//
//   setScaleXY(value) {
//     this.scaleX = this.scaleY = value;
//   }
//
//   getBoundingBox() {
//
//     const x = this.x + this._offX * this.scaleX;
//     const y = this.y + this._offY * this.scaleY;
//     const width = this.width * this.scaleX;
//     const height = this.height * this.scaleY;
//
//     return {x, y, width, height};
//   }
//
// }
//
//
//
//
//
// export class Item extends MySprite {
//
//   baseX;
//
//   move(targetY, callBack) {
//
//     const self = this;
//
//     const tween = new TWEEN.Tween(this)
//       .to({ y: targetY }, 2500)
//       .easing(TWEEN.Easing.Quintic.Out)
//       .onComplete(function() {
//
//         self.hide(callBack);
//         // if (callBack) {
//         //   callBack();
//         // }
//       })
//       .start();
//
//   }
//
//   show(callBack = null) {
//
//     const tween = new TWEEN.Tween(this)
//       .to({ alpha: 1 }, 800)
//       // .easing(TWEEN.Easing.Quadratic.Out) // Use an easing function to make the animation smooth.
//       .onComplete(function() {
//         if (callBack) {
//           callBack();
//         }
//       })
//       .start(); // Start the tween immediately.
//
//   }
//
//   hide(callBack = null) {
//
//     const tween = new TWEEN.Tween(this)
//       .to({ alpha: 0 }, 800)
//       // .easing(TWEEN.Easing.Quadratic.Out) // Use an easing function to make the animation smooth.
//       .onComplete(function() {
//         if (callBack) {
//           callBack();
//         }
//       })
//       .start(); // Start the tween immediately.
//   }
//
//
//   shake(id) {
//
//
//     if (!this.baseX) {
//       this.baseX = this.x;
//     }
//
//     const baseX = this.baseX;
//     const baseTime = 50;
//     const sequence = [
//       {target: {x: baseX + 40 * id}, time: baseTime - 25},
//       {target: {x: baseX - 20 * id}, time: baseTime},
//       {target: {x: baseX + 10 * id}, time: baseTime},
//       {target: {x: baseX - 5 * id}, time: baseTime},
//       {target: {x: baseX + 2 * id}, time: baseTime},
//       {target: {x: baseX - 1 * id}, time: baseTime},
//       {target: {x: baseX}, time: baseTime},
//
//     ];
//
//
//     const self = this;
//
//     function runSequence() {
//
//       if (self['shakeTween']) {
//         self['shakeTween'].stop();
//       }
//
//       const tween = new TWEEN.Tween(self);
//
//       if (sequence.length > 0) {
//         // console.log('sequence.length: ', sequence.length);
//         const action = sequence.shift();
//         tween.to(action['target'], action['time']);
//         tween.onComplete( () => {
//           runSequence();
//         });
//         tween.start();
//
//         self['shakeTween'] = tween;
//       }
//     }
//
//     runSequence();
//
//   }
//
//
//
//   drop(targetY, callBack = null) {
//
//     const self = this;
//
//     const time = Math.abs(targetY - this.y) * 2.4;
//
//     this.alpha = 1;
//
//     const tween = new TWEEN.Tween(this)
//       .to({ y: targetY }, time)
//       .easing(TWEEN.Easing.Cubic.In)
//       .onComplete(function() {
//
//         // self.hideItem(callBack);
//         if (callBack) {
//           callBack();
//         }
//       })
//       .start();
//
//
//   }
//
//
// }
//
//
// export class EndSpr extends MySprite {
//
//   show(s) {
//
//     this.scaleX = this.scaleY = 0;
//     this.alpha = 0;
//
//     const tween = new TWEEN.Tween(this)
//       .to({ alpha: 1, scaleX: s, scaleY: s }, 800)
//       .easing(TWEEN.Easing.Elastic.Out) // Use an easing function to make the animation smooth.
//       .onComplete(function() {
//
//       })
//       .start(); // Start the tween immediately.
//
//   }
// }
//
//
//
// export class ShapeRect extends MySprite {
//
//   fillColor = '#FF0000';
//
//   setSize(w, h) {
//     this.width = w;
//     this.height = h;
//
//     console.log('w:', w);
//     console.log('h:', h);
//   }
//
//   drawShape() {
//
//     this.ctx.fillStyle = this.fillColor;
//     this.ctx.fillRect(this._offX, this._offY, this.width, this.height);
//
//   }
//
//
//   drawSelf() {
//     super.drawSelf();
//     this.drawShape();
//   }
// }
//
//
// export class HotZoneItem extends MySprite {
//
//
//   lineDashFlag = false;
//   arrow: MySprite;
//   label: Label;
//   title;
//
//   arrowTop;
//   arrowRight;
//
//   audio_url;
//   pic_url;
//   text;
//   private _itemType;
//   private shapeRect: ShapeRect;
//
//   get itemType() {
//     return this._itemType;
//   }
//   set itemType(value) {
//     this._itemType = value;
//   }
//
//   setSize(w, h) {
//     this.width = w;
//     this.height = h;
//
//
//     const rect = new ShapeRect(this.ctx);
//     rect.x = -w / 2;
//     rect.y = -h / 2;
//     rect.setSize(w, h);
//     rect.fillColor = '#ffffff';
//     rect.alpha = 0.2;
//     this.addChild(rect);
//   }
//
//   showLabel(text = null) {
//
//
//     if (!this.label) {
//       this.label = new Label(this.ctx);
//       this.label.anchorY = 0;
//       this.label.fontSize = '40px';
//       this.label.textAlign = 'center';
//       this.addChild(this.label);
//       // this.label.scaleX = 1 / this.scaleX;
//       // this.label.scaleY = 1 / this.scaleY;
//
//       this.refreshLabelScale();
//
//     }
//
//     if (text) {
//       this.label.text = text;
//     } else if (this.title) {
//       this.label.text = this.title;
//     }
//     this.label.visible = true;
//
//   }
//
//   hideLabel() {
//     if (!this.label) { return; }
//
//     this.label.visible = false;
//   }
//
//   refreshLabelScale() {
//     if (this.scaleX == this.scaleY) {
//       this.label.setScaleXY(1);
//     }
//
//     if (this.scaleX > this.scaleY) {
//       this.label.scaleX = this.scaleY / this.scaleX;
//     } else {
//       this.label.scaleY = this.scaleX / this.scaleY;
//     }
//   }
//
//   showLineDash() {
//     this.lineDashFlag = true;
//
//     if (this.arrow) {
//       this.arrow.visible = true;
//     } else {
//       this.arrow = new MySprite(this.ctx);
//       this.arrow.load('assets/common/arrow.png', 1, 0);
//       this.arrow.setScaleXY(0.06);
//
//       this.arrowTop = new MySprite(this.ctx);
//       this.arrowTop.load('assets/common/arrow_top.png', 0.5, 0);
//       this.arrowTop.setScaleXY(0.06);
//
//       this.arrowRight = new MySprite(this.ctx);
//       this.arrowRight.load('assets/common/arrow_right.png', 1, 0.5);
//       this.arrowRight.setScaleXY(0.06);
//     }
//
//     this.showLabel();
//   }
//
//   hideLineDash() {
//
//     this.lineDashFlag = false;
//
//     if (this.arrow) {
//       this.arrow.visible = false;
//     }
//
//     this.hideLabel();
//   }
//
//
//
//   drawArrow() {
//     if (!this.arrow) { return; }
//
//     const rect = this.getBoundingBox();
//     this.arrow.x = rect.x + rect.width;
//     this.arrow.y = rect.y;
//
//     this.arrow.update();
//
//
//     this.arrowTop.x = rect.x + rect.width / 2;
//     this.arrowTop.y = rect.y;
//     this.arrowTop.update();
//
//     this.arrowRight.x = rect.x + rect.width;
//     this.arrowRight.y = rect.y + rect.height / 2;
//     this.arrowRight.update();
//   }
//
//   drawFrame() {
//
//
//     this.ctx.save();
//
//
//     const rect = this.getBoundingBox();
//
//     const w = rect.width;
//     const h = rect.height;
//     const x = rect.x + w / 2;
//     const y = rect.y + h / 2;
//
//     this.ctx.setLineDash([5, 5]);
//     this.ctx.lineWidth = 2;
//     this.ctx.strokeStyle = '#1bfff7';
//     // this.ctx.fillStyle = '#ffffff';
//
//     this.ctx.beginPath();
//
//     this.ctx.moveTo( x - w / 2, y - h / 2);
//
//     this.ctx.lineTo(x + w / 2, y - h / 2);
//
//     this.ctx.lineTo(x + w / 2, y + h / 2);
//
//     this.ctx.lineTo(x - w / 2, y + h / 2);
//
//     this.ctx.lineTo(x - w / 2, y - h / 2);
//
//     // this.ctx.fill();
//     this.ctx.stroke();
//
//
//
//
//     this.ctx.restore();
//
//   }
//
//   draw() {
//     super.draw();
//
//     if (this.lineDashFlag) {
//       this.drawFrame();
//       this.drawArrow();
//     }
//   }
// }
//
//
// export class EditorItem extends MySprite {
//
//   lineDashFlag = false;
//   arrow: MySprite;
//   label:Label;
//   text;
//
//   showLabel(text = null) {
//
//
//     if (!this.label) {
//       this.label = new Label(this.ctx);
//       this.label.anchorY = 0;
//       this.label.fontSize = '50px';
//       this.label.textAlign = 'center';
//       this.addChild(this.label);
//       this.label.setScaleXY(1 / this.scaleX);
//     }
//
//     if (text) {
//       this.label.text = text;
//     } else if (this.text) {
//       this.label.text = this.text;
//     }
//     this.label.visible = true;
//
//   }
//
//   hideLabel() {
//     if (!this.label) { return; }
//
//     this.label.visible = false;
//   }
//
//   showLineDash() {
//     this.lineDashFlag = true;
//
//     if (this.arrow) {
//       this.arrow.visible = true;
//     } else {
//       this.arrow = new MySprite(this.ctx);
//       this.arrow.load('assets/common/arrow.png', 1, 0);
//       this.arrow.setScaleXY(0.06);
//
//     }
//
//     this.showLabel();
//   }
//
//   hideLineDash() {
//
//     this.lineDashFlag = false;
//
//     if (this.arrow) {
//       this.arrow.visible = false;
//     }
//
//     this.hideLabel();
//   }
//
//
//
//   drawArrow() {
//     if (!this.arrow) { return; }
//
//     const rect = this.getBoundingBox();
//     this.arrow.x = rect.x + rect.width;
//     this.arrow.y = rect.y;
//
//     this.arrow.update();
//   }
//
//   drawFrame() {
//
//
//     this.ctx.save();
//
//
//     const rect = this.getBoundingBox();
//
//     const w = rect.width;
//     const h = rect.height;
//     const x = rect.x + w / 2;
//     const y = rect.y + h / 2;
//
//     this.ctx.setLineDash([5, 5]);
//     this.ctx.lineWidth = 2;
//     this.ctx.strokeStyle = '#1bfff7';
//     // this.ctx.fillStyle = '#ffffff';
//
//     this.ctx.beginPath();
//
//     this.ctx.moveTo( x - w / 2, y - h / 2);
//
//     this.ctx.lineTo(x + w / 2, y - h / 2);
//
//     this.ctx.lineTo(x + w / 2, y + h / 2);
//
//     this.ctx.lineTo(x - w / 2, y + h / 2);
//
//     this.ctx.lineTo(x - w / 2, y - h / 2);
//
//     // this.ctx.fill();
//     this.ctx.stroke();
//
//
//
//
//     this.ctx.restore();
//
//   }
//
//   draw() {
//     super.draw();
//
//     if (this.lineDashFlag) {
//       this.drawFrame();
//       this.drawArrow();
//     }
//   }
// }
//
//
//
// export class Label extends MySprite {
//
//   text:String;
//   fontSize:String = '40px';
//   fontName:String = 'Verdana';
//   textAlign:String = 'left';
//
//
//   constructor(ctx) {
//     super(ctx);
//     this.init();
//   }
//
//   drawText() {
//
//     // console.log('in drawText', this.text);
//
//     if (!this.text) { return; }
//
//     this.ctx.font = `${this.fontSize} ${this.fontName}`;
//     this.ctx.textAlign = this.textAlign;
//     this.ctx.textBaseline = 'middle';
//     this.ctx.fontWeight = 900;
//
//     this.ctx.lineWidth = 5;
//     this.ctx.strokeStyle = '#ffffff';
//     this.ctx.strokeText(this.text, 0, 0);
//
//     this.ctx.fillStyle = '#000000';
//     this.ctx.fillText(this.text, 0, 0);
//
//
//   }
//
//
//   drawSelf() {
//     super.drawSelf();
//     this.drawText();
//   }
//
// }
//
//
//
// export function getPosByAngle(angle, len) {
//
//   const radian = angle * Math.PI / 180;
//   const x = Math.sin(radian) * len;
//   const y = Math.cos(radian) * len;
//
//   return {x, y};
//
// }
//
// export function getAngleByPos(px, py, mx, my) {
//
//   // const _x = p2x - p1x;
//   // const _y = p2y - p1y;
//   // const tan = _y / _x;
//   //
//   // const radina = Math.atan(tan); // 用反三角函数求弧度
//   // const angle = Math.floor(180 / (Math.PI / radina)); //
//   //
//   // console.log('r: ' , angle);
//   // return angle;
//   //
//
//
//
//   const x = Math.abs(px - mx);
//   const y = Math.abs(py - my);
//   // const x = Math.abs(mx - px);
//   // const y = Math.abs(my - py);
//   const z = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
//   const cos = y / z;
//   const radina = Math.acos(cos); // 用反三角函数求弧度
//   let angle = Math.floor(180 / (Math.PI / radina) * 100) / 100; // 将弧度转换成角度
//
//   if(mx > px && my > py) {// 鼠标在第四象限
//     angle = 180 - angle;
//   }
//
//   if(mx === px && my > py) {// 鼠标在y轴负方向上
//     angle = 180;
//   }
//
//   if(mx > px && my === py) {// 鼠标在x轴正方向上
//     angle = 90;
//   }
//
//   if(mx < px && my > py) {// 鼠标在第三象限
//     angle = 180 + angle;
//   }
//
//   if(mx < px && my === py) {// 鼠标在x轴负方向
//     angle = 270;
//   }
//
//   if(mx < px && my < py) {// 鼠标在第二象限
//     angle = 360 - angle;
//   }
//
//   // console.log('angle: ', angle);
//   return angle;
//
// }