From 2aac77781548a1e66dc1d40d375b71b2378c137c Mon Sep 17 00:00:00 2001 From: lmz <limingzhe@iplayabc.com> Date: Mon, 22 Jun 2020 09:37:23 +0800 Subject: [PATCH] fix: custom-hot-zone --- src/app/common/custom-hot-zone/Unit.ts | 2869 +++++++++++++++-- .../custom-hot-zone.component.html | 63 +- .../custom-hot-zone.component.scss | 7 + .../custom-hot-zone.component.ts | 401 ++- tsconfig.app.json | 4 +- 5 files changed, 2940 insertions(+), 404 deletions(-) diff --git a/src/app/common/custom-hot-zone/Unit.ts b/src/app/common/custom-hot-zone/Unit.ts index 5823ac0..7b99189 100644 --- a/src/app/common/custom-hot-zone/Unit.ts +++ b/src/app/common/custom-hot-zone/Unit.ts @@ -1,6 +1,11 @@ import TWEEN from '@tweenjs/tween.js'; +interface AirWindow extends Window { + air: any; + curCtx: any; +} +declare let window: AirWindow; class Sprite { x = 0; @@ -12,8 +17,12 @@ class Sprite { angle = 0; ctx; - constructor(ctx) { - this.ctx = ctx; + constructor(ctx = null) { + if (!ctx) { + this.ctx = window.curCtx; + } else { + this.ctx = ctx; + } } update($event) { this.draw(); @@ -30,25 +39,45 @@ class Sprite { export class MySprite extends Sprite { - width = 0; - height = 0; + _width = 0; + _height = 0; _anchorX = 0; _anchorY = 0; _offX = 0; _offY = 0; scaleX = 1; scaleY = 1; - alpha = 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) { + + init(imgObj = null, anchorX: number = 0.5, anchorY: number = 0.5) { if (imgObj) { @@ -56,6 +85,8 @@ export class MySprite extends Sprite { this.width = this.img.width; this.height = this.img.height; + + } this.anchorX = anchorX; @@ -63,11 +94,35 @@ export class MySprite extends Sprite { } + 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.draw(); + if (!this.visible && this.childDepandVisible) { + return; } + + this.draw(); + } draw() { @@ -78,6 +133,8 @@ export class MySprite extends Sprite { this.updateChildren(); this.ctx.restore(); + + } drawInit() { @@ -90,26 +147,73 @@ export class MySprite extends Sprite { 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) { - this.ctx.drawImage(this.img, this._offX, this._offY); + + 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 (let i = 0; i < this.children.length; i++) { - - if (this.children[i] === this) { - - this.drawSelf(); + for (const child of this.children) { + if (child === this) { + if (this.visible) { + this.drawSelf(); + } } else { - - this.children[i].update(); + child.update(); } } } @@ -140,6 +244,11 @@ export class MySprite extends Sprite { return a._z - b._z; }); + + if (this.childDepandAlpha) { + child.alpha = this.alpha; + } + } removeChild(child) { const index = this.children.indexOf(child); @@ -148,229 +257,1715 @@ export class MySprite extends Sprite { } } - set anchorX(value) { - this._anchorX = value; - this.refreshAnchorOff(); + 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; } - get anchorX() { - return this._anchorX; + if (mx === px && my > py) {// é¼ æ ‡åœ¨yè½´è´Ÿæ–¹å‘上 + angle = 180; } - set anchorY(value) { - this._anchorY = value; - this.refreshAnchorOff(); + if (mx > px && my === py) {// é¼ æ ‡åœ¨xè½´æ£æ–¹å‘上 + angle = 90; } - get anchorY() { - return this._anchorY; + if (mx < px && my > py) {// é¼ æ ‡åœ¨ç¬¬ä¸‰è±¡é™ + angle = 180 + angle; } - refreshAnchorOff() { - this._offX = -this.width * this.anchorX; - this._offY = -this.height * this.anchorY; + if (mx < px && my === py) {// é¼ æ ‡åœ¨xè½´è´Ÿæ–¹å‘ + angle = 270; } - - setScaleXY(value) { - this.scaleX = this.scaleY = value; + if (mx < px && my < py) {// é¼ æ ‡åœ¨ç¬¬äºŒè±¡é™ + angle = 360 - angle; } - getBoundingBox() { + // console.log('angle: ', angle); + return angle; - 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 function removeItemFromArr(arr, item) { + const index = arr.indexOf(item); + if (index !== -1) { + arr.splice(index, 1); + } } -export class Item extends MySprite { - baseX; +export function circleMove(item, x0, y0, time = 2, addR = 360, xPer = 1, yPer = 1, callBack = null, easing = null) { - move(targetY, callBack) { + const r = getPosDistance(item.x, item.y, x0, y0); + let a = getAngleByPos(item.x, item.y, x0, y0); + a += 90; + const obj = {r, a}; - const self = this; + item._circleAngle = a; + const targetA = a + addR; - const tween = new TWEEN.Tween(this) - .to({ y: targetY }, 2500) - .easing(TWEEN.Easing.Quintic.Out) - .onComplete(function() { - - self.hide(callBack); - // if (callBack) { - // callBack(); - // } - }) - .start(); + const tween = new TWEEN.Tween(item).to({_circleAngle: targetA}, time * 1000); + if (callBack) { + tween.onComplete(() => { + callBack(); + }); + } + if (easing) { + tween.easing(easing); } - show(callBack = null) { + tween.onUpdate( (item, progress) => { - 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. + // 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); - hide(callBack = null) { + item.x = x; + item.y = y; - 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. - } + // obj.a ++; + }); + tween.start(); +} - shake(id) { +export function getPosDistance(sx, sy, ex, ey) { - if (!this.baseX) { - this.baseX = this.x; - } + const _x = ex - sx; + const _y = ey - sy; + const len = Math.sqrt( Math.pow(_x, 2) + Math.pow(_y, 2) ); + return len; +} - 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}, +export function delayCall(callback, second) { + const tween = new TWEEN.Tween(this) + .delay(second * 1000) + .onComplete(() => { + if (callback) { + callback(); + } + }) + .start(); +} - ]; +export function formatTime(fmt, date) { - const self = this; + // "yyyy-MM-dd HH:mm:ss"; - function runSequence() { + 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; +} - if (self['shakeTween']) { - self['shakeTween'].stop(); - } +export function getMinScale(item, maxLen) { + const sx = maxLen / item.width; + const sy = maxLen / item.height; + const minS = Math.min(sx, sy); + return minS; +} - 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; - } - } +export function jelly(item, time = 0.7) { - runSequence(); + 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(); +} + - drop(targetY, callBack = null) { +export function showPopParticle(img, pos, parent, num = 20, minLen = 40, maxLen = 80, showTime = 0.4) { - const self = this; - const time = Math.abs(targetY - this.y) * 2.4; + for (let i = 0; i < num; i ++) { - this.alpha = 1; + const particle = new MySprite(); + particle.init(img); + particle.x = pos.x; + particle.y = pos.y; + parent.addChild(particle); - const tween = new TWEEN.Tween(this) - .to({ y: targetY }, time) - .easing(TWEEN.Easing.Cubic.In) - .onComplete(function() { + const randomR = 360 * Math.random(); + particle.rotation = randomR; - // self.hideItem(callBack); - if (callBack) { - callBack(); - } - }) - .start(); + 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, () => { -} -export class EndSpr extends MySprite { + }, TWEEN.Easing.Exponential.Out); - show(s) { + // scaleItem(particle, 0, 0.6, () => { + // + // }); - this.scaleX = this.scaleY = 0; - this.alpha = 0; + scaleItem(particle, randomS, 0.6, () => { - 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() { + }, TWEEN.Easing.Exponential.Out); + + setTimeout(() => { + + hideItem(particle, 0.4, () => { + + }, TWEEN.Easing.Cubic.In); + + }, showTime * 0.5 * 1000); - }) - .start(); // Start the tween immediately. } } -export class ShapeRect extends MySprite { +export function shake(item, time = 0.5, callback = null, rate = 1) { - fillColor = '#FF0000'; + if (item.shakeTween) { + return; + } - setSize(w, h) { - this.width = w; - this.height = h; + 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; - console.log('w:', w); - console.log('h:', h); - } - drawShape() { + const move4 = () => { + moveItem(item, baseX, baseY, time / 4, () => { + item.shakeTween = false; + if (callback) { + callback(); + } + }, easing); + }; - this.ctx.fillStyle = this.fillColor; - this.ctx.fillRect(this._offX, this._offY, this.width, this.height); + 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(); - drawSelf() { - super.drawSelf(); - this.drawShape(); - } } +// --------------- custom class -------------------- + + export class HotZoneItem extends MySprite { + lineDashFlag = false; arrow: MySprite; label: Label; - text; + 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; @@ -391,7 +1986,7 @@ export class HotZoneItem extends MySprite { if (!this.label) { this.label = new Label(this.ctx); this.label.anchorY = 0; - this.label.fontSize = '40px'; + this.label.fontSize = 40; this.label.textAlign = 'center'; this.addChild(this.label); // this.label.scaleX = 1 / this.scaleX; @@ -403,8 +1998,8 @@ export class HotZoneItem extends MySprite { if (text) { this.label.text = text; - } else if (this.text) { - this.label.text = this.text; + } else if (this.title) { + this.label.text = this.title; } this.label.visible = true; @@ -532,12 +2127,86 @@ export class HotZoneItem extends MySprite { } } +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; + label: Label; text; showLabel(text = null) { @@ -546,7 +2215,7 @@ export class EditorItem extends MySprite { if (!this.label) { this.label = new Label(this.ctx); this.label.anchorY = 0; - this.label.fontSize = '50px'; + this.label.fontSize = 50; this.label.textAlign = 'center'; this.addChild(this.label); this.label.setScaleXY(1 / this.scaleX); @@ -657,109 +2326,783 @@ export class EditorItem extends MySprite { -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; - -} +// +// +// 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; +// +// } diff --git a/src/app/common/custom-hot-zone/custom-hot-zone.component.html b/src/app/common/custom-hot-zone/custom-hot-zone.component.html index 273e0d5..9028527 100644 --- a/src/app/common/custom-hot-zone/custom-hot-zone.component.html +++ b/src/app/common/custom-hot-zone/custom-hot-zone.component.html @@ -1,14 +1,11 @@ <div class="p-image-children-editor"> - <h5 style="margin-left: 2.5%;"> preview: </h5> <div class="preview-box" #wrap> <canvas id="canvas" #canvas></canvas> </div> - - <div nz-row nzType="flex" nzAlign="middle"> <div nz-col nzSpan="5" nzOffset="1"> @@ -20,41 +17,53 @@ (imageUploaded)="onBackgroundUploadSuccess($event)"> </app-upload-image-with-preview> </div> - </div> + <div nz-col nzSpan="5" nzOffset="1" class="img-box" + *ngFor="let it of hotZoneArr; let i = index"> + <div + style="margin: auto; padding: 5px; margin-top: 30px; width:90%; border: 2px dashed #ddd; border-radius: 10px"> + <span style="margin-left: 40%;"> item-{{i + 1}} + </span> + <button style="float: right;" nz-button nzType="danger" nzSize="small" (click)="deleteBtnClick(i)"> + X + </button> - <div nz-col nzSpan="5" nzOffset="1" class="img-box" - *ngFor="let it of hotZoneArr; let i = index" > - - <div style=" height: 40px;"> - <h5> item-{{i+1}} + <nz-divider style="margin-top: 10px;"></nz-divider> - <i style="margin-left: 20px; margin-top: 2px; float: right; cursor:pointer" (click)="deleteItem($event, i)" - nz-icon [nzTheme]="'twotone'" [nzType]="'close-circle'" [nzTwotoneColor]="'#ff0000'"></i> - </h5> - </div> + <div style="margin-top: -20px; margin-bottom: 5px"> + <nz-radio-group [ngModel]="it.itemType" (ngModelChange)="radioChange($event, it)"> + <label *ngIf="isHasRect" nz-radio nzValue="rect">矩形</label> + <label *ngIf="isHasPic" nz-radio nzValue="pic">图片</label> + <label *ngIf="isHasText" nz-radio nzValue="text">文本</label> + </nz-radio-group> + </div> - <!--<div class="img-box-upload">--> - <!--<app-upload-image-with-preview--> - <!--[picUrl]="it.pic_url"--> - <!--(imageUploaded)="onImgUploadSuccessByImg($event, it)">--> - <!--</app-upload-image-with-preview>--> - <!--</div>--> + <div *ngIf="it.itemType == 'pic'"> + <app-upload-image-with-preview + [picUrl]="it?.pic_url" + (imageUploaded)="onItemImgUploadSuccess($event, it)"> + </app-upload-image-with-preview> + </div> + <div *ngIf="it.itemType == 'text'"> + <input type="text" nz-input [(ngModel)]="it.text" (blur)="saveText(it)"> + </div> - <!--<app-audio-recorder--> - <!--[audioUrl]="it.audio_url ? it.audio_url : null "--> - <!--(audioUploaded)="onAudioUploadSuccessByImg($event, it)"--> - <!--></app-audio-recorder>--> + <div style="width: 100%; margin-top: 5px;"> + <app-audio-recorder + [audioUrl]="it.audio_url" + (audioUploaded)="onItemAudioUploadSuccess($event, it)" + ></app-audio-recorder> + </div> + </div> </div> - <div nz-col nzSpan="5" nzOffset="1"> <div class="bg-box"> @@ -75,7 +84,7 @@ <div class="save-box"> <button class="save-btn" nz-button nzType="primary" [nzSize]="'large'" nzShape="round" - (click)="saveClick()"> + (click)="saveClick()" > <i nz-icon nzType="save"></i> Save </button> @@ -83,7 +92,9 @@ </div> - </div> +<label style="opacity: 0; position: absolute; top: 0px; font-family: 'BRLNSR_1'">1</label> + + diff --git a/src/app/common/custom-hot-zone/custom-hot-zone.component.scss b/src/app/common/custom-hot-zone/custom-hot-zone.component.scss index dbfd8a6..9e2c2bf 100644 --- a/src/app/common/custom-hot-zone/custom-hot-zone.component.scss +++ b/src/app/common/custom-hot-zone/custom-hot-zone.component.scss @@ -87,6 +87,13 @@ h5 { +@font-face +{ + font-family: 'BRLNSR_1'; + src: url("/assets/font/BRLNSR_1.TTF") ; +} + + diff --git a/src/app/common/custom-hot-zone/custom-hot-zone.component.ts b/src/app/common/custom-hot-zone/custom-hot-zone.component.ts index 6eed242..dc2a4cf 100644 --- a/src/app/common/custom-hot-zone/custom-hot-zone.component.ts +++ b/src/app/common/custom-hot-zone/custom-hot-zone.component.ts @@ -1,8 +1,21 @@ -import {Component, ElementRef, EventEmitter, HostListener, Input, OnChanges, OnDestroy, OnInit, Output, ViewChild} from '@angular/core'; +import { + Component, + ElementRef, + EventEmitter, + HostListener, + Input, + OnChanges, + OnDestroy, + OnInit, + Output, + ViewChild +} from '@angular/core'; import {Subject} from 'rxjs'; import {debounceTime} from 'rxjs/operators'; -import {EditorItem, HotZoneItem, Label, MySprite} from './Unit'; +import {EditorItem, HotZoneImg, HotZoneItem, HotZoneLabel, Label, MySprite, removeItemFromArr} from './Unit'; import TWEEN from '@tweenjs/tween.js'; +import {getMinScale} from "../../play/Unit"; +import {tar} from "compressing"; @Component({ @@ -13,89 +26,85 @@ import TWEEN from '@tweenjs/tween.js'; export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { - - - _bgItem = null; - - @Input() - set bgItem(v) { - this._bgItem = v; - - this.init(); - } - get bgItem() { - return this._bgItem; - } - @Input() imgItemArr = null; - @Input() hotZoneItemArr = null; - - - @Input() hotZoneArr = null; - - @Output() save = new EventEmitter(); + @ViewChild('canvas', {static: true}) canvas: ElementRef; + @ViewChild('wrap', {static: true}) wrap: ElementRef; - @ViewChild('canvas', {static: true }) canvas: ElementRef; - @ViewChild('wrap', {static: true }) wrap: ElementRef; - // @HostListener('window:resize', ['$event']) + @Input() + isHasRect = true; + @Input() + isHasPic = true; + @Input() + isHasText = true; + @Input() + hotZoneFontObj = { + size: 50, + name: 'BRLNSR_1', + color: '#8f3758' + } + @Input() + defaultItemType = 'text'; + + @Input() + hotZoneImgSize = 190; + + saveDisabled = true; canvasWidth = 1280; canvasHeight = 720; - canvasBaseW = 1280; + // @HostListener('window:resize', ['$event']) canvasBaseH = 720; mapScale = 1; - ctx; mx; my; // ç‚¹å‡»åæ ‡ - - - // èµ„æº - // rawImages = new Map(res); - // 声音 bgAudio = new Audio(); - - images = new Map(); - animationId: any; - // winResizeEventStream = new Subject(); + + // èµ„æº + // rawImages = new Map(res); + winResizeEventStream = new Subject(); canvasLeft; canvasTop; - renderArr; - imgArr = []; - oldPos; - - - + radioValue; curItem; bg: MySprite; changeSizeFlag = false; changeTopSizeFlag = false; changeRightSizeFlag = false; + constructor() { + } + _bgItem = null; - constructor() { + get bgItem() { + return this._bgItem; } + @Input() + set bgItem(v) { + this._bgItem = v; + this.init(); + } onResize(event) { - // this.winResizeEventStream.next(); + this.winResizeEventStream.next(); } @@ -118,13 +127,22 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { } - onBackgroundUploadSuccess(e) { console.log('e: ', e); this.bgItem.url = e.url; this.refreshBackground(); } + onItemImgUploadSuccess(e, item) { + item.pic_url = e.url; + this.loadHotZonePic(item.pic, e.url); + } + + onItemAudioUploadSuccess(e, item) { + item.audio_url = e.url; + } + + refreshBackground(callBack = null) { if (!this.bg) { @@ -162,14 +180,25 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { const item = this.getHotZoneItem(); this.hotZoneArr.push(item); + this.refreshItem(item); + + this.refreshHotZoneId(); + + } + + deleteBtnClick(index) { + + const item = this.hotZoneArr.splice(index, 1)[0]; + removeItemFromArr(this.renderArr, item.pic); + removeItemFromArr(this.renderArr, item.textLabel); + this.refreshHotZoneId(); - console.log('hotZoneArr:', this.hotZoneArr); } onImgUploadSuccessByImg(e, img) { img.pic_url = e.url; - this.refreshImage (img); + this.refreshImage(img); } refreshImage(img) { @@ -188,7 +217,7 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { this.hotZoneArr[i].index = i; if (this.hotZoneArr[i]) { - this.hotZoneArr[i].text = 'item-' + (i + 1); + this.hotZoneArr[i].title = 'item-' + (i + 1); } } @@ -206,7 +235,7 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { } - getHotZoneItem( saveData = null) { + getHotZoneItem(saveData = null) { const itemW = 200; @@ -219,18 +248,46 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { item.x = this.canvasWidth / 2; item.y = this.canvasHeight / 2; + item.itemType = this.defaultItemType; + if (saveData) { const saveRect = saveData.rect; item.scaleX = saveRect.width / item.width; item.scaleY = saveRect.height / item.height; - item.x = saveRect.x + saveRect.width / 2 ; + item.x = saveRect.x + saveRect.width / 2; item.y = saveRect.y + saveRect.height / 2; } item.showLineDash(); + const pic = new HotZoneImg(this.ctx); + pic.visible = false; + item['pic'] = pic; + if (saveData && saveData.pic_url) { + this.loadHotZonePic(pic, saveData.pic_url); + } + pic.x = item.x; + pic.y = item.y; + this.renderArr.push(pic); + + const textLabel = new HotZoneLabel(this.ctx); + textLabel.fontSize = this.hotZoneFontObj.size; + textLabel.fontName = this.hotZoneFontObj.name; + textLabel.fontColor = this.hotZoneFontObj.color; + textLabel.textAlign = 'center'; + // textLabel.setOutline(); + // console.log('saveData:', saveData); + item['textLabel'] = textLabel; + textLabel.setScaleXY(this.mapScale); + if (saveData && saveData.text) { + textLabel.text = saveData.text; + textLabel.refreshSize(); + } + textLabel.x = item.x; + textLabel.y = item.y; + this.renderArr.push(textLabel); return item; } @@ -240,7 +297,7 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { const item = new EditorItem(this.ctx); - item.load(img.pic_url).then( img => { + item.load(img.pic_url).then(img => { let maxW, maxH; if (this.bg) { @@ -266,7 +323,7 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { const saveRect = saveData.rect; item.setScaleXY(saveRect.width / item.width); - item.x = saveRect.x + saveRect.width / 2 ; + item.x = saveRect.x + saveRect.width / 2; item.y = saveRect.y + saveRect.height / 2; } else { @@ -291,9 +348,29 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { } + radioChange(e, item) { + item.itemType = e; + + this.refreshItem(item); + // console.log(' in radioChange e: ', e); + } + refreshItem(item) { + switch (item.itemType) { + case 'rect': + this.setRectState(item); + break; + case 'pic': + this.setPicState(item); + break; + case 'text': + this.setTextState(item); + break; + default: + } + } init() { @@ -367,20 +444,25 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { // img['audio_url'] = arr[i].audio_url; // this.imgArr.push(img); - const item = this.getHotZoneItem( data); + const item = this.getHotZoneItem(data); + item.audio_url = data.audio_url; + item.pic_url = data.pic_url; + item.text = data.text; + item.itemType = data.itemType; + this.refreshItem(item); + console.log('item: ', item); this.hotZoneArr.push(item); } this.refreshHotZoneId(); + // this.refreshImageId(); } - - initImgArr() { console.log('this.imgItemArr: ', this.imgItemArr); @@ -446,34 +528,40 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { this.oldPos = {x: this.mx, y: this.my}; - const arr = this.hotZoneArr; - - for (let i = arr.length - 1; i >= 0 ; i--) { - const item = arr[i]; + for (let i = 0; i < this.hotZoneArr.length; i++) { - if (item) { - if (this.checkClickTarget(item)) { + const item = this.hotZoneArr[i]; + let callback; + let target; + switch (item.itemType) { + case 'rect': + target = item; + callback = this.clickedHotZoneRect.bind(this); + break; + case 'pic': + target = item.pic; + callback = this.clickedHotZonePic.bind(this); + break; + case 'text': + target = item.textLabel; + callback = this.clickedHotZoneText.bind(this); + break; + } - if (item.lineDashFlag && this.checkClickTarget(item.arrow)) { - this.changeItemSize(item); - } else if (item.lineDashFlag && this.checkClickTarget(item.arrowTop)) { - this.changeItemTopSize(item); - } else if (item.lineDashFlag && this.checkClickTarget(item.arrowRight)) { - this.changeItemRightSize(item); - } else { - this.changeCurItem(item); - } - return; - } + if (this.checkClickTarget(target)) { + callback(target); + return; } } - // this.hideAllLineDash(); } + mapMove(event) { - if (!this.curItem) { return; } + if (!this.curItem) { + return; + } if (this.changeSizeFlag) { this.changeSize(); @@ -493,6 +581,9 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { } this.oldPos = {x: this.mx, y: this.my}; + + this.saveDisabled = true; + } mapUp(event) { @@ -503,13 +594,11 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { } - - changeSize() { const rect = this.curItem.getBoundingBox(); - let lenW = ( this.mx - (rect.x + rect.width / 2) ) * 2; - let lenH = ( (rect.y + rect.height / 2) - this.my ) * 2; + let lenW = (this.mx - (rect.x + rect.width / 2)) * 2; + let lenH = ((rect.y + rect.height / 2) - this.my) * 2; let minLen = 20; @@ -538,7 +627,7 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { const rect = this.curItem.getBoundingBox(); // let lenW = ( this.mx - (rect.x + rect.width / 2) ) * 2; - let lenH = ( (rect.y + rect.height / 2) - this.my ) * 2; + let lenH = ((rect.y + rect.height / 2) - this.my) * 2; let minLen = 20; @@ -550,10 +639,10 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { // s = lenW / this.curItem.width; // // } else { - if (lenH < minLen) { - lenH = minLen; - } - s = lenH / this.curItem.height; + if (lenH < minLen) { + lenH = minLen; + } + s = lenH / this.curItem.height; // } @@ -565,7 +654,7 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { changeRightSize() { const rect = this.curItem.getBoundingBox(); - let lenW = ( this.mx - (rect.x + rect.width / 2) ) * 2; + let lenW = (this.mx - (rect.x + rect.width / 2)) * 2; // let lenH = ( (rect.y + rect.height / 2) - this.my ) * 2; let minLen = 20; @@ -634,6 +723,7 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { // } this.updateArr(this.hotZoneArr); + this.updatePos() TWEEN.update(); @@ -648,7 +738,6 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { } - renderAfterResize() { this.canvasWidth = this.wrap.nativeElement.clientWidth; this.canvasHeight = this.wrap.nativeElement.clientHeight; @@ -657,11 +746,11 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { initListener() { - // this.winResizeEventStream - // .pipe(debounceTime(500)) - // .subscribe(data => { - // this.renderAfterResize(); - // }); + this.winResizeEventStream + .pipe(debounceTime(500)) + .subscribe(data => { + this.renderAfterResize(); + }); if (this.IsPC()) { @@ -767,41 +856,38 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { if (this.bg) { bgItem['rect'] = this.bg.getBoundingBox(); } else { - bgItem['rect'] = {x: 0, y: 0, width: Math.round(this.canvasWidth * 100) / 100, height: Math.round(this.canvasHeight * 100) / 100}; + bgItem['rect'] = { + x: 0, + y: 0, + width: Math.round(this.canvasWidth * 100) / 100, + height: Math.round(this.canvasHeight * 100) / 100 + }; } - - // const imgItemArr = []; - // const imgArr = this.imgArr; - // for (let i = 0; i < imgArr.length; i++) { - // - // const imgItem = { - // id: imgArr[i].id, - // pic_url: imgArr[i].pic_url, - // audio_url: imgArr[i].audio_url, - // }; - // if (imgArr[i].picItem) { - // imgItem['rect'] = imgArr[i].picItem.getBoundingBox(); - // imgItem['rect'].x -= bgItem['rect'].x; - // imgItem['rect'].y -= bgItem['rect'].y; - // } - // imgItemArr.push(imgItem); - // } - - const hotZoneItemArr = []; const hotZoneArr = this.hotZoneArr; for (let i = 0; i < hotZoneArr.length; i++) { const hotZoneItem = { index: hotZoneArr[i].index, + pic_url: hotZoneArr[i].pic_url, + text: hotZoneArr[i].text, + audio_url: hotZoneArr[i].audio_url, + itemType: hotZoneArr[i].itemType, + fontSize: this.hotZoneFontObj.size, + fontName: this.hotZoneFontObj.name, + fontColor: this.hotZoneFontObj.color, + fontScale: hotZoneArr[i].textLabel ? hotZoneArr[i].textLabel.scaleX : 1, + imgScale: hotZoneArr[i].pic ? hotZoneArr[i].pic.scaleX : 1, + mapScale: this.mapScale }; hotZoneItem['rect'] = hotZoneArr[i].getBoundingBox(); - hotZoneItem['rect'].x = Math.round( (hotZoneItem['rect'].x - bgItem['rect'].x) * 100) / 100; - hotZoneItem['rect'].y = Math.round( (hotZoneItem['rect'].y - bgItem['rect'].y) * 100) / 100; - hotZoneItem['rect'].width = Math.round( (hotZoneItem['rect'].width) * 100) / 100; - hotZoneItem['rect'].height = Math.round( (hotZoneItem['rect'].height) * 100) / 100; + hotZoneItem['rect'].x = Math.round((hotZoneItem['rect'].x - bgItem['rect'].x) * 100) / 100; + hotZoneItem['rect'].y = Math.round((hotZoneItem['rect'].y - bgItem['rect'].y) * 100) / 100; + hotZoneItem['rect'].width = Math.round((hotZoneItem['rect'].width) * 100) / 100; + hotZoneItem['rect'].height = Math.round((hotZoneItem['rect'].height) * 100) / 100; + hotZoneItemArr.push(hotZoneItem); } @@ -810,4 +896,91 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { this.save.emit({bgItem, hotZoneItemArr}); } + + private updatePos() { + this.hotZoneArr.forEach((item) => { + let x, y; + switch (item.itemType) { + case 'rect': + x = item.x; + y = item.y; + break; + + case 'pic': + x = item.pic.x; + y = item.pic.y; + break; + + case 'text': + x = item.textLabel.x; + y = item.textLabel.y; + break; + } + + item.x = x; + item.y = y; + item.pic.x = x; + item.pic.y = y; + item.textLabel.x = x; + item.textLabel.y = y; + }); + } + + private setPicState(item: any) { + item.visible = false; + item.textLabel.visible = false; + item.pic.visible = true; + } + + private setRectState(item: any) { + item.visible = true; + item.textLabel.visible = false; + item.pic.visible = false; + } + + private setTextState(item: any) { + item.visible = false; + item.pic.visible = false; + item.textLabel.visible = true; + } + + private clickedHotZoneRect(item: any) { + if (this.checkClickTarget(item)) { + + if (item.lineDashFlag && this.checkClickTarget(item.arrow)) { + this.changeItemSize(item); + } else if (item.lineDashFlag && this.checkClickTarget(item.arrowTop)) { + this.changeItemTopSize(item); + } else if (item.lineDashFlag && this.checkClickTarget(item.arrowRight)) { + this.changeItemRightSize(item); + } else { + this.changeCurItem(item); + } + return; + } + } + + private clickedHotZonePic(item: any) { + if (this.checkClickTarget(item)) { + this.curItem = item; + } + } + + private clickedHotZoneText(item: any) { + if (this.checkClickTarget(item)) { + this.curItem = item; + } + } + + saveText(item) { + item.textLabel.text = item.text; + } + + private loadHotZonePic(pic: HotZoneImg, url) { + const baseLen = this.hotZoneImgSize * this.mapScale; + pic.load(url).then(() => { + const s = getMinScale(pic, baseLen); + pic.setScaleXY(s); + }); + } } diff --git a/tsconfig.app.json b/tsconfig.app.json index 565a11a..8fe350f 100644 --- a/tsconfig.app.json +++ b/tsconfig.app.json @@ -2,7 +2,9 @@ "extends": "./tsconfig.json", "compilerOptions": { "outDir": "./out-tsc/app", - "types": [] + "types": [ + "node" + ] }, "files": [ "src/main.ts", -- 2.21.0