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; 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; } 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) { 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 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); // const x = this.x + this._offX * Math.abs(this.scaleX); // const y = this.y + this._offY * Math.abs(this.scaleY); // const width = this.width * Math.abs(this.scaleX); // const height = this.height * Math.abs(this.scaleY); return {x, y, width, height}; } } 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 { 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(); } 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; 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. } // setShadow(offX = 0, offY = 2, blur = 2, color = 'rgba(0, 0, 0, 0.2)') { // // this._shadowFlag = true; // this._shadowColor = color; // // 将阴影向右移动15px,向上移动10px // this._shadowOffsetX = 5; // this._shadowOffsetY = 5; // // 轻微模糊阴影 // this._shadowBlur = 5; // } setOutline(width = 5, color = '#ffffff') { this._outlineFlag = true; this._outLineWidth = width; this._outLineColor = color; } drawText() { // console.log('in drawText', this.text); if (!this.text) { return; } // if (this._shadowFlag) { // // this.ctx.shadowColor = this._shadowColor; // // 将阴影向右移动15px,向上移动10px // this.ctx.shadowOffsetX = this._shadowOffsetX; // this.ctx.shadowOffsetY = this._shadowOffsetY; // // 轻微模糊阴影 // this.ctx.shadowBlur = this._shadowBlur; // } 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 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) { 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 --------------------