Commit 7e8eb8a3 authored by Li Mingzhe's avatar Li Mingzhe

feat: 首次提交

parent 8a51c964
This source diff could not be displayed because it is too large. You can view the blob instead.
import { ErrorHandler } from '@angular/core';
export class MyErrorHandler implements ErrorHandler {
handleError(error) {
console.log(error.stack);
(<any> window).courseware.sendErrorLog(error);
}
}
\ No newline at end of file
import { BrowserModule } from '@angular/platform-browser';
import { NgModule, ErrorHandler } from '@angular/core';
import {MyErrorHandler} from './MyError';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { NgZorroAntdModule, NZ_I18N, zh_CN } from 'ng-zorro-antd';
......@@ -52,10 +50,7 @@ registerLocaleData(zh);
BrowserAnimationsModule,
FontAwesomeModule
],
providers: [
{provide: ErrorHandler, useClass: MyErrorHandler},
{ provide: NZ_I18N, useValue: zh_CN }
],
providers: [{ provide: NZ_I18N, useValue: zh_CN }],
bootstrap: [AppComponent]
})
export class AppModule {
......
......@@ -22,8 +22,8 @@ export class AudioRecorderComponent implements OnInit, OnChanges, OnDestroy {
@Input()
withRmBtn = false;
uploadUrl;
uploadData;
uploadUrl = (window as any).courseware.uploadUrl();
uploadData = (window as any).courseware.uploadData();
@Input()
needRemove = false;
......@@ -55,13 +55,7 @@ export class AudioRecorderComponent implements OnInit, OnChanges, OnDestroy {
constructor( private nzMessageService: NzMessageService ) {
this.uploadUrl = (<any> window).courseware.uploadUrl();
this.uploadData = (<any> window).courseware.uploadData();
window['air'].getUploadCallback = (url, data) => {
this.uploadUrl = url;
this.uploadData = data;
};
}
init() {
......
import TWEEN from '@tweenjs/tween.js';
interface AirWindow extends Window {
air: any;
curCtx: any;
}
declare let window: AirWindow;
class Sprite {
x = 0;
......@@ -17,12 +12,8 @@ class Sprite {
angle = 0;
ctx;
constructor(ctx = null) {
if (!ctx) {
this.ctx = window.curCtx;
} else {
this.ctx = ctx;
}
constructor(ctx) {
this.ctx = ctx;
}
update($event) {
this.draw();
......@@ -39,45 +30,25 @@ 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) {
......@@ -85,8 +56,6 @@ export class MySprite extends Sprite {
this.width = this.img.width;
this.height = this.img.height;
}
this.anchorX = anchorX;
......@@ -94,35 +63,11 @@ 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.childDepandVisible) {
return;
if (this.visible) {
this.draw();
}
this.draw();
}
draw() {
......@@ -133,8 +78,6 @@ export class MySprite extends Sprite {
this.updateChildren();
this.ctx.restore();
}
drawInit() {
......@@ -147,73 +90,26 @@ 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) {
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);
}
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();
}
for (let i = 0; i < this.children.length; i++) {
if (this.children[i] === this) {
this.drawSelf();
} else {
child.update();
this.children[i].update();
}
}
}
......@@ -244,1728 +140,237 @@ 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);
if (index !== -1) {
this.children.splice(index, 1);
}
}
removeChildren() {
for (let i = 0; i < this.children.length; i++) {
if (this.children[i]) {
if (this.children[i] !== this) {
this.children.splice(i, 1);
i --;
}
}
}
}
_changeChildAlpha(alpha) {
for (const child of this.children) {
if (child !== this) {
child.alpha = alpha;
}
}
}
set btimapFlag(v) {
this._bitmapFlag = v;
}
get btimapFlag() {
return this._bitmapFlag;
}
set alpha(v) {
this._alpha = v;
if (this.childDepandAlpha) {
this._changeChildAlpha(v);
}
}
get alpha() {
return this._alpha;
}
set width(v) {
this._width = v;
this.refreshAnchorOff();
}
get width() {
return this._width;
}
set height(v) {
this._height = v;
this.refreshAnchorOff();
}
get height() {
return this._height;
}
set anchorX(value) {
this._anchorX = value;
this.refreshAnchorOff();
}
get anchorX() {
return this._anchorX;
}
set anchorY(value) {
this._anchorY = value;
this.refreshAnchorOff();
}
get anchorY() {
return this._anchorY;
}
refreshAnchorOff() {
this._offX = -this._width * this.anchorX;
this._offY = -this._height * this.anchorY;
}
setScaleXY(value) {
this.scaleX = this.scaleY = value;
}
getBoundingBox() {
const getParentData = (item) => {
let px = item.x;
let py = item.y;
let sx = item.scaleX;
let sy = item.scaleY;
const parent = item.parent;
if (parent) {
const obj = getParentData(parent);
const _x = obj.px;
const _y = obj.py;
const _sx = obj.sx;
const _sy = obj.sy;
px = _x + item.x * _sx;
py = _y + item.y * _sy;
sx *= _sx;
sy *= _sy;
}
return {px, py, sx, sy};
};
const data = getParentData(this);
const x = data.px + this._offX * Math.abs(data.sx);
const y = data.py + this._offY * Math.abs(data.sy);
const width = this.width * Math.abs(data.sx);
const height = this.height * Math.abs(data.sy);
return {x, y, width, height};
}
}
export class RoundSprite extends MySprite {
_newCtx;
init(imgObj = null, anchorX: number = 0.5, anchorY: number = 0.5) {
if (imgObj) {
this.img = imgObj;
this.width = this.img.width;
this.height = this.img.height;
}
this.anchorX = anchorX;
this.anchorY = anchorY;
const canvas = window['curCanvas'];
const w = canvas.nativeElement.width;
const h = canvas.nativeElement.height;
this._offCanvas = document.createElement('canvas');
this._offCanvas.width = w;
this._offCanvas.height = h;
this._offCtx = this._offCanvas.getContext('2d');
// this._newCtx = this.ctx;
// this.ctx = this._offCtx;
}
drawSelf() {
//
// if (this._shadowFlag) {
//
// this.ctx.shadowOffsetX = this._shadowOffsetX;
// this.ctx.shadowOffsetY = this._shadowOffsetY;
// this.ctx.shadowBlur = this._shadowBlur;
// this.ctx.shadowColor = this._shadowColor;
// } else {
// this.ctx.shadowOffsetX = 0;
// this.ctx.shadowOffsetY = 0;
// this.ctx.shadowBlur = null;
// this.ctx.shadowColor = null;
// }
if (this._radius) {
const r = this._radius;
const w = this.width;
const h = this.height;
const x = -this._offX;
const y = -this._offY;
this._offCtx.lineTo(x - w / 2, y + h / 2); // 创建水平线
this._offCtx.arcTo(x - w / 2, y - h / 2, x - w / 2 + r, y - h / 2, r);
this._offCtx.arcTo(x + w / 2, y - h / 2, x + w / 2, y - h / 2 + r, r);
this._offCtx.arcTo(x + w / 2, y + h / 2, x + w / 2 - r, y + h / 2, r);
this._offCtx.arcTo(x - w / 2, y + h / 2, x - w / 2, y + h / 2 - r, r);
this._offCtx.clip();
}
if (this.img) {
this._offCtx.drawImage(this.img, 0, 0);
this.ctx.drawImage(this._offCanvas,this._offX, this._offX);
}
}
}
export class ColorSpr extends MySprite {
r = 0;
g = 0;
b = 0;
createGSCanvas() {
if (!this.img) {
return;
}
const rect = this.getBoundingBox();
if (rect.width <= 1 || rect.height <= 1) {
return;
}
const c = this.ctx.getImageData(rect.x, rect.y, rect.width, rect.height);
for ( let i = 0; i < c.height; i++) {
for ( let j = 0; j < c.width; j++) {
const x = (i * 4) * c.width + ( j * 4 );
const r = c.data[x];
const g = c.data[x + 1];
const b = c.data[x + 2];
c.data[x] = this.r;
c.data[x + 1] = this.g;
c.data[x + 2] = this.b;
// c.data[x] = c.data[x + 1] = c.data[x + 2] = (r + g + b) / 3 ;
// // c.data[x + 3] = 255;
}
}
this.ctx.putImageData(c, rect.x, rect.y, 0, 0, rect.width, rect.height);
}
drawSelf() {
super.drawSelf();
this.createGSCanvas();
}
}
export class GrayscaleSpr extends MySprite {
grayScale = 120;
createGSCanvas() {
if (!this.img) {
return;
}
const rect = this.getBoundingBox();
const c = this.ctx.getImageData(rect.x, rect.y, rect.width, rect.height);
for ( let i = 0; i < c.height; i++) {
for ( let j = 0; j < c.width; j++) {
const x = (i * 4) * c.width + ( j * 4 );
const r = c.data[x];
const g = c.data[x + 1];
const b = c.data[x + 2];
// const a = c.data[x + 3];
c.data[x] = c.data[x + 1] = c.data[x + 2] = this.grayScale; // (r + g + b) / 3;
// c.data[x + 3] = 255;
}
}
this.ctx.putImageData(c, rect.x, rect.y, 0, 0, rect.width, rect.height);
}
drawSelf() {
super.drawSelf();
this.createGSCanvas();
}
}
export class BitMapLabel extends MySprite {
labelArr;
baseUrl;
setText(data, text) {
this.labelArr = [];
const labelArr = [];
const tmpArr = text.split('');
let totalW = 0;
let h = 0;
for (const tmp of tmpArr) {
const label = new MySprite(this.ctx);
label.init(data[tmp], 0);
this.addChild(label);
labelArr.push(label);
totalW += label.width;
h = label.height;
}
this.width = totalW;
this.height = h;
let offX = -totalW / 2;
for (const label of labelArr) {
label.x = offX;
offX += label.width;
}
this.labelArr = labelArr;
}
}
export class Label extends MySprite {
private _text: string;
// fontSize:String = '40px';
fontName = 'Verdana';
textAlign = 'left';
fontSize = 40;
fontColor = '#000000';
fontWeight = 900;
_maxWidth;
outline = 0;
outlineColor = '#ffffff';
// _shadowFlag = false;
// _shadowColor;
// _shadowOffsetX;
// _shadowOffsetY;
// _shadowBlur;
_outlineFlag = false;
_outLineWidth;
_outLineColor;
constructor(ctx = null) {
super(ctx);
this.init();
}
get text(): string {
return this._text;
}
set text(value: string) {
this._text = value;
this.refreshSize();
}
refreshSize() {
this.ctx.save();
this.ctx.font = `${this.fontSize * this.scaleX}px ${this.fontName}`;
this.ctx.textAlign = this.textAlign;
this.ctx.textBaseline = 'middle';
this.ctx.fontWeight = this.fontWeight;
this._width = this.ctx.measureText(this.text).width;
this._height = this.fontSize;
this.refreshAnchorOff();
this.ctx.restore();
}
setMaxSize(w) {
this._maxWidth = w;
this.refreshSize();
if (this.width >= w) {
this.scaleX *= w / this.width;
this.scaleY *= w / this.width;
}
}
show(callBack = null) {
this.visible = true;
if (this.alpha >= 1) {
return;
}
const tween = new TWEEN.Tween(this)
.to({ alpha: 1 }, 800)
// .easing(TWEEN.Easing.Quadratic.Out) // Use an easing function to make the animation smooth.
.onComplete(() => {
if (callBack) {
callBack();
}
})
.start(); // Start the tween immediately.
}
setOutline(width = 5, color = '#ffffff') {
this._outlineFlag = true;
this._outLineWidth = width;
this._outLineColor = color;
}
drawText() {
if (!this.text) { return; }
this.ctx.font = `${this.fontSize}px ${this.fontName}`;
this.ctx.textAlign = this.textAlign;
this.ctx.textBaseline = 'middle';
this.ctx.fontWeight = this.fontWeight;
if (this._outlineFlag) {
this.ctx.lineWidth = this._outLineWidth;
this.ctx.strokeStyle = this._outLineColor;
this.ctx.strokeText(this.text, 0, 0);
}
this.ctx.fillStyle = this.fontColor;
if (this.outline > 0) {
this.ctx.lineWidth = this.outline;
this.ctx.strokeStyle = this.outlineColor;
this.ctx.strokeText(this.text, 0, 0);
}
this.ctx.fillText(this.text, 0, 0);
}
drawSelf() {
super.drawSelf();
this.drawText();
}
}
export class RichTextOld extends Label {
textArr = [];
fontSize = 40;
setText(text: string, words) {
let newText = text;
for (const word of words) {
const re = new RegExp(word, 'g');
newText = newText.replace( re, `#${word}#`);
// newText = newText.replace(word, `#${word}#`);
}
this.textArr = newText.split('#');
this.text = newText;
// this.setSize();
}
refreshSize() {
this.ctx.save();
this.ctx.font = `${this.fontSize}px ${this.fontName}`;
this.ctx.textAlign = this.textAlign;
this.ctx.textBaseline = 'middle';
this.ctx.fontWeight = this.fontWeight;
let curX = 0;
for (const text of this.textArr) {
const w = this.ctx.measureText(text).width;
curX += w;
}
this.width = curX;
this.height = this.fontSize;
this.refreshAnchorOff();
this.ctx.restore();
}
show(callBack = null) {
// console.log(' in show ');
this.visible = true;
// this.alpha = 0;
const tween = new TWEEN.Tween(this)
.to({ alpha: 1 }, 800)
// .easing(TWEEN.Easing.Quadratic.Out) // Use an easing function to make the animation smooth.
.onComplete(() => {
if (callBack) {
callBack();
}
})
.start(); // Start the tween immediately.
}
drawText() {
// console.log('in drawText', this.text);
if (!this.text) { return; }
this.ctx.font = `${this.fontSize}px ${this.fontName}`;
this.ctx.textAlign = this.textAlign;
this.ctx.textBaseline = 'middle';
this.ctx.fontWeight = 900;
this.ctx.lineWidth = 5;
this.ctx.strokeStyle = '#ffffff';
// this.ctx.strokeText(this.text, 0, 0);
this.ctx.fillStyle = '#000000';
// this.ctx.fillText(this.text, 0, 0);
let curX = 0;
for (let i = 0; i < this.textArr.length; i++) {
const w = this.ctx.measureText(this.textArr[i]).width;
if ((i + 1) % 2 === 0) {
this.ctx.fillStyle = '#c8171e';
} else {
this.ctx.fillStyle = '#000000';
}
this.ctx.fillText(this.textArr[i], curX, 0);
curX += w;
}
}
}
export class RichText extends Label {
disH = 30;
constructor(ctx?: any) {
super(ctx);
// this.dataArr = dataArr;
}
drawText() {
if (!this.text) {
return;
}
this.ctx.font = `${this.fontSize}px ${this.fontName}`;
this.ctx.textAlign = this.textAlign;
this.ctx.textBaseline = 'middle';
this.ctx.fontWeight = this.fontWeight;
this.ctx.fillStyle = this.fontColor;
const selfW = this.width * this.scaleX;
const chr = this.text.split(' ');
let temp = '';
const row = [];
const w = selfW - 80;
const disH = (this.fontSize + this.disH) * this.scaleY;
for (const c of chr) {
if (this.ctx.measureText(temp).width < w && this.ctx.measureText(temp + (c)).width <= w) {
temp += ' ' + c;
} else {
row.push(temp);
temp = ' ' + c;
}
}
row.push(temp);
const x = 0;
const y = -row.length * disH / 2;
// for (let b = 0 ; b < row.length; b++) {
// this.ctx.strokeText(row[b], x, y + ( b + 1 ) * disH ); // 每行字体y坐标间隔20
// }
if (this._outlineFlag) {
this.ctx.lineWidth = this._outLineWidth;
this.ctx.strokeStyle = this._outLineColor;
for (let b = 0 ; b < row.length; b++) {
this.ctx.strokeText(row[b], x, y + ( b + 1 ) * disH ); // 每行字体y坐标间隔20
}
// this.ctx.strokeText(this.text, 0, 0);
}
// this.ctx.fillStyle = '#ff7600';
for (let b = 0 ; b < row.length; b++) {
this.ctx.fillText(row[b], x, y + ( b + 1 ) * disH ); // 每行字体y坐标间隔20
}
}
drawSelf() {
super.drawSelf();
this.drawText();
}
}
export class LineRect extends MySprite {
lineColor = '#ffffff';
lineWidth = 10;
setSize(w, h) {
this.width = w;
this.height = h;
}
drawLine() {
this.ctx.beginPath();
this.ctx.moveTo(this._offX, this._offY);
this.ctx.lineTo(this._offX + this.width, this._offY);
this.ctx.lineTo(this._offX + this.width, this._offY + this.height);
this.ctx.lineTo(this._offX, this._offY + this.height);
this.ctx.closePath();
this.ctx.lineWidth = this.lineWidth;
// this.ctx.fillStyle = "rgb(2,33,42)"; //指定填充颜色
// this.ctx.fill(); //对多边形进行填充
this.ctx.strokeStyle = this.lineColor; // "#ffffff";
this.ctx.stroke();
}
drawSelf() {
super.drawSelf();
this.drawLine();
}
}
export class ShapeRect extends MySprite {
fillColor = '#FF0000';
setSize(w, h) {
this.width = w;
this.height = h;
// console.log('w:', w);
// console.log('h:', h);
}
drawShape() {
this.ctx.fillStyle = this.fillColor;
this.ctx.fillRect(this._offX, this._offY, this.width, this.height);
}
drawSelf() {
super.drawSelf();
this.drawShape();
}
}
export class Line extends MySprite {
lineWidth = 5;
lineColor = '#000000';
_pointArr = [];
roundFlag = true;
_pointS = 1;
imgObj;
bitMap;
_offCtx;
_offCanvas;
lastPointIndex = 0;
init() {
const canvas = window['curCanvas'];
const w = canvas.nativeElement.width;
const h = canvas.nativeElement.height;
console.log('w: ', w);
console.log('h: ', h);
this._offCanvas = document.createElement('canvas');
this._offCanvas.width = w;
this._offCanvas.height = h;
// this._offCanvas = _offCanvas;
// this._offCtx = this._offCanvas.getContext('2d');
// this._offCanvas = new OffscreenCanvas(w, h);
this._offCtx = this._offCanvas.getContext('2d');
}
addPoint(x, y) {
this._pointArr.push([x, y]);
if (this._pointArr.length < 2) {
return;
}
//
// const lastP = this._pointArr[this._pointArr.length - 1];
//
//
// const context = this._offCtx;
// context.moveTo (lastP[0], lastP[1]); // 设置起点状态
// context.lineTo (x, y); // 设置末端状态
//
// context.lineWidth = this.lineWidth; //设置线宽状态
// context.strokeStyle = this.lineColor;
// context.stroke();
//
//
// this.bitMap = this._offCanvas.transferToImageBitmap();
// const tmpLine = new MySprite(this._offCtx);
// tmpLine.init(this.imgObj);
// tmpLine.anchorY = 1;
// tmpLine.anchorX = 0.5;
// tmpLine.x = lastP[0];
// tmpLine.y = lastP[1];
//
// const disH = getPosDistance(lastP[0], lastP[1], x, y);
// tmpLine.scaleX = this.lineWidth / tmpLine.width;
// tmpLine.scaleY = disH / tmpLine.height * 1.1;
//
// const angle = getAngleByPos(lastP[0], lastP[1], x, y);
// tmpLine.rotation = angle;
//
// this.addChild(tmpLine);
}
setPointArr(arr, imgObj) {
this.removeChildren();
if (arr.length < 2) {
return;
}
let p1 = arr[0];
let p2;
for (let i = 1; i < arr.length; i++) {
p2 = arr[i];
const tmpLine = new MySprite();
tmpLine.init(imgObj);
tmpLine.anchorY = 1;
tmpLine.anchorX = 0.5;
tmpLine.x = p1[0];
tmpLine.y = p1[1];
const disH = getPosDistance(p1[0], p1[1], p2[0], p2[1]);
tmpLine.scaleX = this.lineWidth / tmpLine.width;
tmpLine.scaleY = disH / tmpLine.height * 1.1;
const angle = getAngleByPos(p1[0], p1[1], p2[0], p2[1]);
tmpLine.rotation = angle;
this.addChild(tmpLine);
p1 = p2;
}
}
drawLine() {
if (this._pointArr.length < 2) {
return;
}
const curMaxPointIndex = this._pointArr.length - 1;
if (curMaxPointIndex > this.lastPointIndex) {
const arr = this._pointArr;
const context = this._offCtx;
context.moveTo (arr[this.lastPointIndex][0] * this._pointS, arr[this.lastPointIndex][1] * this._pointS); // 设置起点状态
for (let i = this.lastPointIndex + 1; i < arr.length; i++) {
context.lineTo (arr[i][0] * this._pointS, arr[i][1] * this._pointS); // 设置末端状态
}
if (this.roundFlag) {
context.lineCap = "round";
}
context.lineWidth = this.lineWidth; //设置线宽状态
context.strokeStyle = this.lineColor;
context.stroke();
this.lastPointIndex = curMaxPointIndex;
// this.bitMap = this._offCanvas.transferToImageBitmap();
}
// this.ctx.drawImage(this.bitMap, this._offX, this._offY);
this.ctx.drawImage(this._offCanvas, this._offX, this._offY);
}
drawSelf() {
super.drawSelf();
this.drawLine();
// if (this.img) {
// this.ctx.drawImage(this._offCanvas, 0, 0, this.width, this.height);
// }
// if (this.bitMap) {
// this.bitMap = this._offCanvas.transferToImageBitmap();
// this.ctx.drawImage(this.bitMap, 0, 0, this.width, this.height);
// }
}
}
export class ShapeCircle extends MySprite {
fillColor = '#FF0000';
radius = 0;
setRadius(r) {
this.anchorX = this.anchorY = 0.5;
this.radius = r;
this.width = r * 2;
this.height = r * 2;
}
drawShape() {
this.ctx.beginPath();
this.ctx.fillStyle = this.fillColor;
this.ctx.arc(0, 0, this.radius, 0, angleToRadian(360));
this.ctx.fill();
}
drawSelf() {
super.drawSelf();
this.drawShape();
}
}
export class ShapeRectNew extends MySprite {
radius = 0;
fillColor = '#ffffff';
strokeColor = '#000000';
fill = true;
stroke = false;
lineWidth = 1;
setSize(w, h, r) {
this.width = w;
this.height = h;
this.radius = r;
}
setOutLine(color, lineWidth) {
this.stroke = true;
this.strokeColor = color;
this.lineWidth = lineWidth;
}
drawShape() {
const ctx = this.ctx;
const width = this.width;
const height = this.height;
const radius = this.radius;
ctx.save();
ctx.beginPath(0);
// 从右下角顺时针绘制,弧度从0到1/2PI
ctx.arc(width - radius, height - radius, radius, 0, Math.PI / 2);
// 矩形下边线
ctx.lineTo(radius, height);
// 左下角圆弧,弧度从1/2PI到PI
ctx.arc(radius, height - radius, radius, Math.PI / 2, Math.PI);
// 矩形左边线
ctx.lineTo(0, radius);
// 左上角圆弧,弧度从PI到3/2PI
ctx.arc(radius, radius, radius, Math.PI, Math.PI * 3 / 2);
// 上边线
ctx.lineTo(width - radius, 0);
// 右上角圆弧
ctx.arc(width - radius, radius, radius, Math.PI * 3 / 2, Math.PI * 2);
// 右边线
ctx.lineTo(width, height - radius);
ctx.closePath();
if (this.fill) {
ctx.fillStyle = this.fillColor;
ctx.fill();
}
if (this.stroke) {
ctx.lineWidth = this.lineWidth;
ctx.strokeStyle = this.strokeColor;
ctx.stroke();
}
ctx.restore();
}
drawSelf() {
super.drawSelf();
this.drawShape();
}
}
export class MyAnimation extends MySprite {
frameArr = [];
frameIndex = 0;
playFlag = false;
lastDateTime;
curDelay = 0;
loop = false;
playEndFunc;
delayPerUnit = 1;
restartFlag = false;
reverseFlag = false;
addFrameByImg(img) {
const spr = new MySprite(this.ctx);
spr.init(img);
this._refreshSize(img);
spr.visible = false;
this.addChild(spr);
this.frameArr.push(spr);
this.frameArr[this.frameIndex].visible = true;
}
addFrameByUrl(url) {
const spr = new MySprite(this.ctx);
spr.load(url).then(img => {
this._refreshSize(img);
});
spr.visible = false;
this.addChild(spr);
this.frameArr.push(spr);
this.frameArr[this.frameIndex].visible = true;
}
_refreshSize(img: any) {
if (this.width < img.width) {
this.width = img.width;
}
if (this.height < img.height) {
this.height = img.height;
}
}
play() {
this.playFlag = true;
this.lastDateTime = new Date().getTime();
}
stop() {
this.playFlag = false;
}
replay() {
this.restartFlag = true;
this.play();
}
reverse() {
this.reverseFlag = !this.reverseFlag;
this.frameArr.reverse();
this.frameIndex = 0;
}
showAllFrame() {
for (const frame of this.frameArr ) {
frame.alpha = 1;
}
}
hideAllFrame() {
for (const frame of this.frameArr) {
frame.alpha = 0;
}
}
playEnd() {
this.playFlag = false;
this.curDelay = 0;
this.frameArr[this.frameIndex].visible = true;
if (this.playEndFunc) {
this.playEndFunc();
this.playEndFunc = null;
}
}
updateFrame() {
if (this.frameArr[this.frameIndex]) {
this.frameArr[this.frameIndex].visible = false;
}
this.frameIndex ++;
if (this.frameIndex >= this.frameArr.length) {
if (this.loop) {
this.frameIndex = 0;
} else if (this.restartFlag) {
this.restartFlag = false;
this.frameIndex = 0;
} else {
this.frameIndex -- ;
this.playEnd();
return;
}
}
this.frameArr[this.frameIndex].visible = true;
}
_updateDelay(delay) {
this.curDelay += delay;
if (this.curDelay < this.delayPerUnit) {
return;
}
this.curDelay -= this.delayPerUnit;
this.updateFrame();
}
_updateLastDate() {
if (!this.playFlag) { return; }
let delay = 0;
if (this.lastDateTime) {
delay = (new Date().getTime() - this.lastDateTime) / 1000;
}
this.lastDateTime = new Date().getTime();
this._updateDelay(delay);
}
update($event: any = null) {
super.update($event);
this._updateLastDate();
}
}
// --------=========== util func =============-------------
export function tweenChange(item, obj, time = 0.8, callBack = null, easing = null, update = null) {
const tween = new TWEEN.Tween(item).to(obj, time * 1000);
if (callBack) {
tween.onComplete(() => {
callBack();
});
}
if (easing) {
tween.easing(easing);
}
if (update) {
tween.onUpdate( (a, b) => {
update(a, b);
});
}
tween.start();
return tween;
}
export function rotateItem(item, rotation, time = 0.8, callBack = null, easing = null) {
const tween = new TWEEN.Tween(item).to({ rotation }, time * 1000);
if (callBack) {
tween.onComplete(() => {
callBack();
});
}
if (easing) {
tween.easing(easing);
}
tween.start();
}
export function scaleItem(item, scale, time = 0.8, callBack = null, easing = null) {
const tween = new TWEEN.Tween(item).to({ scaleX: scale, scaleY: scale}, time * 1000);
if (callBack) {
tween.onComplete(() => {
callBack();
});
}
if (easing) {
tween.easing(easing);
}
tween.start();
return tween;
}
export function moveItem(item, x, y, time = 0.8, callBack = null, easing = null) {
const tween = new TWEEN.Tween(item).to({ x, y}, time * 1000);
if (callBack) {
tween.onComplete(() => {
callBack();
});
}
if (easing) {
tween.easing(easing);
}
tween.start();
return tween;
}
export function endShow(item, s = 1) {
item.scaleX = item.scaleY = 0;
item.alpha = 0;
const tween = new TWEEN.Tween(item)
.to({ alpha: 1, scaleX: s, scaleY: s }, 800)
.easing(TWEEN.Easing.Elastic.Out) // Use an easing function to make the animation smooth.
.onComplete(() => {
})
.start();
}
export function hideItem(item, time = 0.8, callBack = null, easing = null) {
if (item.alpha === 0) {
return;
}
const tween = new TWEEN.Tween(item)
.to({alpha: 0}, time * 1000)
// .easing(TWEEN.Easing.Quadratic.Out) // Use an easing function to make the animation smooth.
.onComplete(() => {
if (callBack) {
callBack();
}
});
if (easing) {
tween.easing(easing);
}
tween.start();
}
export function showItem(item, time = 0.8, callBack = null, easing = null) {
if (item.alpha === 1) {
if (callBack) {
callBack();
}
return;
}
item.visible = true;
const tween = new TWEEN.Tween(item)
.to({alpha: 1}, time * 1000)
// .easing(TWEEN.Easing.Quadratic.Out) // Use an easing function to make the animation smooth.
.onComplete(() => {
if (callBack) {
callBack();
}
});
if (easing) {
tween.easing(easing);
}
tween.start();
}
export function alphaItem(item, alpha, time = 0.8, callBack = null, easing = null) {
const tween = new TWEEN.Tween(item)
.to({alpha}, time * 1000)
// .easing(TWEEN.Easing.Quadratic.Out) // Use an easing function to make the animation smooth.
.onComplete(() => {
if (callBack) {
callBack();
}
});
if (easing) {
tween.easing(easing);
}
tween.start();
}
export function showStar(item, time = 0.8, callBack = null, easing = null) {
const tween = new TWEEN.Tween(item)
.to({alpha: 1, scale: 1}, time * 1000)
// .easing(TWEEN.Easing.Quadratic.Out) // Use an easing function to make the animation smooth.
.onComplete(() => {
if (callBack) {
callBack();
}
});
if (easing) {
tween.easing(easing);
}
tween.start();
}
export function randomSortByArr(arr) {
if (!arr) {
return;
}
const newArr = [];
const tmpArr = arr.concat();
while (tmpArr.length > 0) {
const randomIndex = Math.floor( tmpArr.length * Math.random() );
newArr.push(tmpArr[randomIndex]);
tmpArr.splice(randomIndex, 1);
}
return newArr;
}
export function radianToAngle(radian) {
return radian * 180 / Math.PI;
// 角度 = 弧度 * 180 / Math.PI;
}
export function angleToRadian(angle) {
return angle * Math.PI / 180;
// 弧度= 角度 * Math.PI / 180;
}
export function getPosByAngle(angle, len) {
const radian = angle * Math.PI / 180;
const x = Math.sin(radian) * len;
const y = Math.cos(radian) * len;
return {x, y};
}
export function getAngleByPos(px, py, mx, my) {
const x = Math.abs(px - mx);
const y = Math.abs(py - my);
const z = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
const cos = y / z;
const radina = Math.acos(cos); // 用反三角函数求弧度
let angle = Math.floor(180 / (Math.PI / radina) * 100) / 100; // 将弧度转换成角度
if (mx > px && my > py) {// 鼠标在第四象限
angle = 180 - angle;
this.children.splice(index, 1);
}
}
if (mx === px && my > py) {// 鼠标在y轴负方向上
angle = 180;
set anchorX(value) {
this._anchorX = value;
this.refreshAnchorOff();
}
if (mx > px && my === py) {// 鼠标在x轴正方向上
angle = 90;
get anchorX() {
return this._anchorX;
}
if (mx < px && my > py) {// 鼠标在第三象限
angle = 180 + angle;
set anchorY(value) {
this._anchorY = value;
this.refreshAnchorOff();
}
if (mx < px && my === py) {// 鼠标在x轴负方向
angle = 270;
get anchorY() {
return this._anchorY;
}
if (mx < px && my < py) {// 鼠标在第二象限
angle = 360 - angle;
refreshAnchorOff() {
this._offX = -this.width * this.anchorX;
this._offY = -this.height * this.anchorY;
}
// console.log('angle: ', angle);
return angle;
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;
export function removeItemFromArr(arr, item) {
const index = arr.indexOf(item);
if (index !== -1) {
arr.splice(index, 1);
return {x, y, width, height};
}
}
export class Item extends MySprite {
export function circleMove(item, x0, y0, time = 2, addR = 360, xPer = 1, yPer = 1, callBack = null, easing = null) {
baseX;
const r = getPosDistance(item.x, item.y, x0, y0);
let a = getAngleByPos(item.x, item.y, x0, y0);
a += 90;
const obj = {r, a};
move(targetY, callBack) {
item._circleAngle = a;
const targetA = a + addR;
const self = this;
const tween = new TWEEN.Tween(item).to({_circleAngle: targetA}, time * 1000);
const tween = new TWEEN.Tween(this)
.to({ y: targetY }, 2500)
.easing(TWEEN.Easing.Quintic.Out)
.onComplete(function() {
self.hide(callBack);
// if (callBack) {
// callBack();
// }
})
.start();
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();
}
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.
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;
}
hide(callBack = null) {
export function delayCall(callback, second) {
const tween = new TWEEN.Tween(this)
.delay(second * 1000)
.onComplete(() => {
if (callback) {
callback();
}
})
.start();
}
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.
}
export function formatTime(fmt, date) {
shake(id) {
// "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)));
if (!this.baseX) {
this.baseX = this.x;
}
}
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;
}
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 jelly(item, time = 0.7) {
const self = this;
if (item.jellyTween) {
TWEEN.remove(item.jellyTween);
}
function runSequence() {
const t = time / 9;
const baseSX = item.scaleX;
const baseSY = item.scaleY;
let index = 0;
if (self['shakeTween']) {
self['shakeTween'].stop();
}
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();
}
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 showPopParticle(img, pos, parent, num = 20, minLen = 40, maxLen = 80, showTime = 0.4) {
runSequence();
}
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;
drop(targetY, callBack = null) {
const randomS = 0.3 + Math.random() * 0.7;
particle.setScaleXY(randomS * 0.3);
const self = this;
const randomX = Math.random() * 20 - 10;
particle.x += randomX;
const time = Math.abs(targetY - this.y) * 2.4;
const randomY = Math.random() * 20 - 10;
particle.y += randomY;
this.alpha = 1;
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, () => {
const tween = new TWEEN.Tween(this)
.to({ y: targetY }, time)
.easing(TWEEN.Easing.Cubic.In)
.onComplete(function() {
// self.hideItem(callBack);
if (callBack) {
callBack();
}
})
.start();
}, TWEEN.Easing.Exponential.Out);
}
// scaleItem(particle, 0, 0.6, () => {
//
// });
scaleItem(particle, randomS, 0.6, () => {
}
}, TWEEN.Easing.Exponential.Out);
setTimeout(() => {
export class EndSpr extends MySprite {
hideItem(particle, 0.4, () => {
show(s) {
}, TWEEN.Easing.Cubic.In);
this.scaleX = this.scaleY = 0;
this.alpha = 0;
}, showTime * 0.5 * 1000);
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 function shake(item, time = 0.5, callback = null, rate = 1) {
if (item.shakeTween) {
return;
}
export class ShapeRect extends MySprite {
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;
fillColor = '#FF0000';
setSize(w, h) {
this.width = w;
this.height = h;
const move4 = () => {
moveItem(item, baseX, baseY, time / 4, () => {
item.shakeTween = false;
if (callback) {
callback();
}
}, easing);
};
console.log('w:', w);
console.log('h:', h);
}
const move3 = () => {
moveItem(item, baseX + offX / 4, baseY + offY / 4, time / 4, () => {
move4();
}, easing);
};
drawShape() {
const move2 = () => {
moveItem(item, baseX - offX / 4 * 3, baseY - offY / 4 * 3, time / 4, () => {
move3();
}, easing);
};
this.ctx.fillStyle = this.fillColor;
this.ctx.fillRect(this._offX, this._offY, this.width, this.height);
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;
title;
text;
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;
......@@ -1986,7 +391,7 @@ export class HotZoneItem extends MySprite {
if (!this.label) {
this.label = new Label(this.ctx);
this.label.anchorY = 0;
this.label.fontSize = 40;
this.label.fontSize = '40px';
this.label.textAlign = 'center';
this.addChild(this.label);
// this.label.scaleX = 1 / this.scaleX;
......@@ -1998,8 +403,8 @@ export class HotZoneItem extends MySprite {
if (text) {
this.label.text = text;
} else if (this.title) {
this.label.text = this.title;
} else if (this.text) {
this.label.text = this.text;
}
this.label.visible = true;
......@@ -2127,86 +532,12 @@ 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) {
......@@ -2215,7 +546,7 @@ export class EditorItem extends MySprite {
if (!this.label) {
this.label = new Label(this.ctx);
this.label.anchorY = 0;
this.label.fontSize = 50;
this.label.fontSize = '50px';
this.label.textAlign = 'center';
this.addChild(this.label);
this.label.setScaleXY(1 / this.scaleX);
......@@ -2326,783 +657,109 @@ export class EditorItem extends MySprite {
//
//
// 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;
//
// }
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;
}
<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">
......@@ -13,57 +16,45 @@
<div class="bg-box">
<app-upload-image-with-preview
[picUrl]="bgItem?.url"
[picUrl]="bgItem.url"
(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>
<nz-divider style="margin-top: 10px;"></nz-divider>
<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}}
<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 *ngIf="it.itemType == 'pic'">
<app-upload-image-with-preview
[picUrl]="it?.pic_url"
(imageUploaded)="onItemImgUploadSuccess($event, it)">
</app-upload-image-with-preview>
</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 == 'text'">
<input type="text" nz-input [(ngModel)]="it.text" (blur)="saveText(it)">
</div>
<div style="width: 100%; margin-top: 5px;">
<app-audio-recorder
[audioUrl]="it.audio_url"
(audioUploaded)="onItemAudioUploadSuccess($event, it)"
></app-audio-recorder>
</div>
<!--<app-audio-recorder-->
<!--[audioUrl]="it.audio_url ? it.audio_url : null "-->
<!--(audioUploaded)="onAudioUploadSuccessByImg($event, it)"-->
<!--&gt;</app-audio-recorder>-->
</div>
</div>
<div nz-col nzSpan="5" nzOffset="1">
<div class="bg-box">
......@@ -84,17 +75,15 @@
<div class="save-box">
<button class="save-btn" nz-button nzType="primary" [nzSize]="'large'" nzShape="round"
(click)="saveClick()" >
<i nz-icon nzType="save"></i>
(click)="saveClick()" [disabled]="saveDisabled">
<i nz-icon type="save"></i>
Save
</button>
</div>
</div>
<label style="opacity: 0; position: absolute; top: 0px; font-family: 'BRLNSR_1'">1</label>
</div>
......@@ -87,13 +87,6 @@ h5 {
@font-face
{
font-family: 'BRLNSR_1';
src: url("/assets/font/BRLNSR_1.TTF") ;
}
......
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, HotZoneImg, HotZoneItem, HotZoneLabel, Label, MySprite, removeItemFromArr} from './Unit';
import {EditorItem, HotZoneItem, Label, MySprite} from './Unit';
import TWEEN from '@tweenjs/tween.js';
import {getMinScale} from "../../play/Unit";
import {tar} from "compressing";
@Component({
......@@ -26,85 +13,94 @@ import {tar} from "compressing";
export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
// @Input()
// bgItem = null;
_bgItem = null;
@Input()
set bgItem(v) {
this._bgItem = v;
this.init();
}
get bgItem() {
return this._bgItem;
}
// @Input()
imgItemArr = null;
@Input()
hotZoneItemArr = null;
@Input()
// @Input()
hotZoneArr = null;
@Output()
save = new EventEmitter();
@ViewChild('canvas', {static: true}) canvas: ElementRef;
@ViewChild('wrap', {static: true}) wrap: ElementRef;
@Input()
isHasRect = true;
@Input()
isHasPic = true;
@Input()
isHasText = true;
@Input()
hotZoneFontObj = {
size: 50,
name: 'BRLNSR_1',
color: '#8f3758'
}
@Input()
defaultItemType = 'text';
@Input()
hotZoneImgSize = 190;
@Output()
save = new EventEmitter();
saveDisabled = true;
// @ViewChild('canvas') canvas: ElementRef;
// @ViewChild('wrap') wrap: ElementRef;
@ViewChild('canvas', {static: true }) canvas: ElementRef;
@ViewChild('wrap', {static: true }) wrap: ElementRef;
// @HostListener('window:resize', ['$event'])
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;
animationId: any;
// winResizeEventStream = new Subject();
// 资源
// rawImages = new Map(res);
winResizeEventStream = new Subject();
canvasLeft;
canvasTop;
renderArr;
imgArr = [];
oldPos;
radioValue;
saveDisabled = true;
curItem;
bg: MySprite;
bg;
changeSizeFlag = false;
changeTopSizeFlag = false;
changeRightSizeFlag = false;
constructor() {
}
_bgItem = null;
get bgItem() {
return this._bgItem;
constructor() {
}
@Input()
set bgItem(v) {
this._bgItem = v;
this.init();
}
onResize(event) {
this.winResizeEventStream.next();
// this.winResizeEventStream.next();
}
......@@ -112,7 +108,6 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
this.initListener();
// this.init();
this.update();
}
......@@ -127,22 +122,15 @@ 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;
this.saveDisabled = false;
}
refreshBackground(callBack = null) {
if (!this.bg) {
......@@ -180,36 +168,16 @@ 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);
console.log('hotZoneArr:', this.hotZoneArr);
this.refreshHotZoneId();
}
onImgUploadSuccessByImg(e, img) {
img.pic_url = e.url;
this.refreshImage(img);
this.saveDisabled = false;
}
refreshImage(img) {
this.hideAllLineDash();
img.picItem = this.getPicItem(img);
this.refreshImageId();
}
refreshHotZoneId() {
......@@ -217,25 +185,16 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
this.hotZoneArr[i].index = i;
if (this.hotZoneArr[i]) {
this.hotZoneArr[i].title = 'item-' + (i + 1);
this.hotZoneArr[i].text = 'item-' + (i + 1);
}
}
}
refreshImageId() {
for (let i = 0; i < this.imgArr.length; i++) {
this.imgArr[i].id = i;
if (this.imgArr[i].picItem) {
this.imgArr[i].picItem.text = 'Image-' + (i + 1);
}
}
}
getHotZoneItem(saveData = null) {
getHotZoneItem( saveData = null) {
const itemW = 200;
......@@ -248,96 +207,29 @@ 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['key'] = saveData.key;
}
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);
if (!item['key']) {
item['key'] = Date.now().toString();
}
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;
}
getPicItem(img, saveData = null) {
const item = new EditorItem(this.ctx);
item.load(img.pic_url).then(img => {
let maxW, maxH;
if (this.bg) {
maxW = this.bg.width * this.bg.scaleX;
maxH = this.bg.height * this.bg.scaleY;
} else {
maxW = this.canvasWidth;
maxH = this.canvasHeight;
}
let scaleX = maxW / 3 / item.width;
let scaleY = maxH / 3 / item.height;
if (item.height * scaleX < this.canvasHeight) {
item.setScaleXY(scaleX);
} else {
item.setScaleXY(scaleY);
}
item.x = this.canvasWidth / 2;
item.y = this.canvasHeight / 2;
if (saveData) {
const saveRect = saveData.rect;
item.setScaleXY(saveRect.width / item.width);
item.x = saveRect.x + saveRect.width / 2;
item.y = saveRect.y + saveRect.height / 2;
item.showLineDash();
} else {
item.showLineDash();
}
});
return item;
}
onAudioUploadSuccessByImg(e, img) {
img.audio_url = e.url;
}
deleteItem(e, i) {
// this.imgArr.splice(i , 1);
......@@ -345,32 +237,14 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
this.hotZoneArr.splice(i, 1);
this.refreshHotZoneId();
}
this.saveDisabled = false;
}
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() {
......@@ -444,65 +318,20 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
// img['audio_url'] = arr[i].audio_url;
// this.imgArr.push(img);
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);
const item = this.getHotZoneItem( data);
console.log('item: ', item);
this.hotZoneArr.push(item);
}
this.refreshHotZoneId();
// this.refreshImageId();
}
initImgArr() {
console.log('this.imgItemArr: ', this.imgItemArr);
let curBgRect;
if (this.bg) {
curBgRect = this.bg.getBoundingBox();
} else {
curBgRect = {x: 0, y: 0, width: this.canvasWidth, height: this.canvasHeight};
}
let oldBgRect = this.bgItem.rect;
if (!oldBgRect) {
oldBgRect = curBgRect;
}
const rate = curBgRect.width / oldBgRect.width;
console.log('rate: ', rate);
this.imgArr = [];
const arr = this.imgItemArr.concat();
for (let i = 0; i < arr.length; i++) {
const data = JSON.parse(JSON.stringify(arr[i]));
const img = {pic_url: data.pic_url};
data.rect.x *= rate;
data.rect.y *= rate;
data.rect.width *= rate;
data.rect.height *= rate;
data.rect.x += curBgRect.x;
data.rect.y += curBgRect.y;
img['picItem'] = this.getPicItem(img, data);
img['audio_url'] = arr[i].audio_url;
this.imgArr.push(img);
}
this.refreshImageId();
}
initData() {
......@@ -528,40 +357,34 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
this.oldPos = {x: this.mx, y: this.my};
for (let i = 0; i < this.hotZoneArr.length; i++) {
const arr = this.hotZoneArr;
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;
}
for (let i = arr.length - 1; i >= 0 ; i--) {
const item = arr[i];
if (item) {
if (this.checkClickTarget(item)) {
if (this.checkClickTarget(target)) {
callback(target);
return;
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;
}
}
}
// this.hideAllLineDash();
}
mapMove(event) {
if (!this.curItem) {
return;
}
if (!this.curItem) { return; }
if (this.changeSizeFlag) {
this.changeSize();
......@@ -580,10 +403,9 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
this.curItem.y += addY;
}
this.oldPos = {x: this.mx, y: this.my};
this.saveDisabled = true;
this.saveDisabled = false;
this.oldPos = {x: this.mx, y: this.my};
}
mapUp(event) {
......@@ -594,11 +416,13 @@ 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;
......@@ -627,7 +451,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;
......@@ -654,7 +478,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;
......@@ -685,26 +509,16 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
changeCurItem(item) {
this.hideAllLineDash();
this.curItem = item;
this.curItem.showLineDash();
}
hideAllLineDash() {
for (let i = 0; i < this.imgArr.length; i++) {
if (this.imgArr[i].picItem) {
this.imgArr[i].picItem.hideLineDash();
}
}
}
update() {
if (!this.ctx) {
return;
}
this.animationId = window.requestAnimationFrame(this.update.bind(this));
......@@ -723,7 +537,6 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
// }
this.updateArr(this.hotZoneArr);
this.updatePos()
TWEEN.update();
......@@ -738,6 +551,7 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
}
renderAfterResize() {
this.canvasWidth = this.wrap.nativeElement.clientWidth;
this.canvasHeight = this.wrap.nativeElement.clientHeight;
......@@ -746,11 +560,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()) {
......@@ -852,42 +666,31 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
saveClick() {
this.saveDisabled = true;
const bgItem = this.bgItem;
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 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
key: hotZoneArr[i].key
};
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);
}
......@@ -896,91 +699,4 @@ 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);
});
}
}
......@@ -29,19 +29,10 @@ export class UploadImageWithPreviewComponent implements OnDestroy, OnChanges {
@Input()
disableUpload = false;
uploadUrl;
uploadData;
uploadUrl = (<any> window).courseware.uploadUrl();
uploadData = (<any> window).courseware.uploadData();
constructor(private nzMessageService: NzMessageService) {
this.uploadUrl = (<any> window).courseware.uploadUrl();
this.uploadData = (<any> window).courseware.uploadData();
window['air'].getUploadCallback = (url, data) => {
this.uploadUrl = url;
this.uploadData = data;
};
}
ngOnChanges() {
if (!this.picItem) {
......
......@@ -47,8 +47,8 @@ export class UploadVideoComponent implements OnChanges, OnDestroy {
item: any;
// videoItem = null;
uploadUrl;
uploadData;
uploadUrl = (window as any).courseware.uploadUrl();
uploadData = (window as any).courseware.uploadData();
constructor(private nzMessageService: NzMessageService,
private sanitization: DomSanitizer
......@@ -58,16 +58,6 @@ export class UploadVideoComponent implements OnChanges, OnDestroy {
this.uploading = false;
this.videoFile = null;
this.uploadUrl = (<any> window).courseware.uploadUrl();
this.uploadData = (<any> window).courseware.uploadData();
window['air'].getUploadCallback = (url, data) => {
this.uploadUrl = url;
this.uploadData = data;
};
}
ngOnChanges() {
// if (!this.videoFile || this.showUploadBtn) {
......
......@@ -2,24 +2,304 @@
<div class="model-content">
<div style="position: absolute; left: 200px; top: 100px; width: 800px;">
<input type="text" nz-input [(ngModel)]="item.text" (blur)="save()">
<app-upload-image-with-preview
[picUrl]="item.pic_url"
(imageUploaded)="onImageUploadSuccess($event, 'pic_url')"
></app-upload-image-with-preview>
<app-audio-recorder
[audioUrl]="item.audio_url"
(audioUploaded)="onAudioUploadSuccess($event, 'audio_url')"
></app-audio-recorder>
<app-custom-hot-zone></app-custom-hot-zone>
<app-upload-video></app-upload-video>
<app-lesson-title-config></app-lesson-title-config>
<button style="margin: 4vw; display: flex; align-items: center" nz-button nzType="primary" nzGhost (click)="guideBtnClick(true)">
<i nz-icon type="play-circle"></i>
1分钟简易教程
</button>
<app-custom-hot-zone
[bgItem]="bgItem"
[hotZoneItemArr]="hotZoneItemArr"
(save)="saveData($event)"
>
</app-custom-hot-zone>
<p style="padding-bottom: 5vw">
</p>
<div *ngFor="let it of picArr; let i = index">
<div style="padding: 2vw">
<div style="display: flex; align-items: center; width: 70%">
<span style="padding-right: 5px; width: 120px;"> question-{{i+1}}: </span>
<input type="text" nz-input placeholder="" [(ngModel)]="it.text" (blur)="saveItem()">
<app-audio-recorder
[audioUrl]="it.audio_url"
(audioUploaded)="onAudioUploadSuccessByItem($event, it)">
</app-audio-recorder>
<button style="margin-left: 10px;" nz-button nzType="danger" (click)="deleteItem(it)">
<i nz-icon type="close"></i>
</button>
</div>
<div style="display: flex; align-items: center; width: 70%">
<span style="padding-right: 5px; width: 120px;"> answer-{{i+1}}: </span>
<nz-checkbox-group [(ngModel)]="it.options" (ngModelChange)="changeOptions(it.options)"></nz-checkbox-group>
</div>
</div>
<!--<div class="item-box">-->
<!---->
<!--<app-upload-image-with-preview-->
<!--style="width: 100%"-->
<!--[picUrl]="it.pic_url"-->
<!--(imageUploaded)="onImageUploadSuccessByItem($event, it)"-->
<!--&gt;</app-upload-image-with-preview>-->
<!--<div style="display: flex; justify-items: center; padding-top: 10px">-->
<!--<app-audio-recorder-->
<!--[audioUrl]="it.audio_url"-->
<!--(audioUploaded)="onAudioUploadSuccessByItem($event, it)">-->
<!--</app-audio-recorder>-->
<!--<button style="margin-left: 10px;" nz-button nzType="danger" (click)="deleteItem(it)">-->
<!--<i nz-icon type="close"></i>-->
<!--</button>-->
<!--</div>-->
<!--</div>-->
<!--<h5> id-{{i+1}} </h5>-->
<!--<div style="display: flex; align-items: center; justify-content: center; padding-bottom: 5px">-->
<!--<input type="text" nz-input placeholder="" [(ngModel)]="it.text" (blur)="saveItem()">-->
<!--<button style="margin-left: 10px;" nz-button nzType="danger" (click)="deleteItem(it)">-->
<!--<i nz-icon type="close"></i>-->
<!--</button>-->
<!--</div>-->
<!--<app-upload-image-with-preview-->
<!--style="width: 100%"-->
<!--[picUrl]="it.pic_url"-->
<!--(imageUploaded)="onImageUploadSuccessByItem($event, it)"-->
<!--&gt;</app-upload-image-with-preview>-->
<!--<div style="display: flex; align-items: center; justify-content: center">-->
<!--<span style="width: 80px;">-->
<!--question:-->
<!--</span>-->
<!--<app-audio-recorder-->
<!--[audioUrl]="it['q_audio_url']"-->
<!--(audioUploaded)="onAudioUploadSuccessByItem($event, it, 'q')">-->
<!--</app-audio-recorder>-->
<!--</div>-->
<!--<div style="display: flex; align-items: center; justify-content: center">-->
<!--<span style="width: 80px;">-->
<!--answer:-->
<!--</span>-->
<!--<app-audio-recorder-->
<!--[audioUrl]="it['a_audio_url']"-->
<!--(audioUploaded)="onAudioUploadSuccessByItem($event, it, 'a')">-->
<!--</app-audio-recorder>-->
<!--</div>-->
<!--<nz-radio-group [(ngModel)]="it.radioValue" >-->
<!--<label nz-radio nzValue="A" (click)="radioClick(it, 'A')"> <i nz-icon nzType="check" nzTheme="outline"></i> </label>-->
<!--<label nz-radio nzValue="B" (click)="radioClick(it, 'B')"> <i nz-icon nzType="close" nzTheme="outline"></i> </label>-->
<!--</nz-radio-group>-->
</div>
<div nz-col nzSpan="8" class="add-btn-box" >
<!--<div style="width: 100%; height: 100%;">-->
<button style=" margin: auto; width: 60%; height: 60%;" nz-button nzType="dashed" class="add-btn"
(click)="addPic()">
<i nz-icon nzType="plus-circle" nzTheme="outline"></i>
Add
</button>
<!--</div>-->
</div>
<!--<div style="padding-bottom: 30px;">-->
<!--<h5> title-sound: </h5>-->
<!--<app-audio-recorder-->
<!--[audioUrl]="item.contentObj.title_audio_url"-->
<!--(audioUploaded)="onAudioUploadSuccessByItem($event, item.contentObj, 'title')">-->
<!--</app-audio-recorder>-->
<!--</div>-->
<!--<div style="padding-bottom: 30px;">-->
<!--<h5> bg-sound: </h5>-->
<!--<app-audio-recorder-->
<!--[audioUrl]="item.contentObj.bg_audio_url"-->
<!--(audioUploaded)="onAudioUploadSuccessByItem($event, item.contentObj, 'bg')">-->
<!--</app-audio-recorder>-->
<!--</div>-->
<!--<span style="margin-bottom: 20px"> 10 : 23 </span>-->
<!--<div *ngFor="let it of picArr; let i = index">-->
<!--<span> pic-{{i + 1}}: </span>-->
<!--<div style="display: flex; align-items: center; padding-bottom: 20px">-->
<!--<div style="width: 40%; padding-right: 20px">-->
<!--<app-upload-image-with-preview-->
<!--[picUrl]="it.pic_url"-->
<!--(imageUploaded)="onImageUploadSuccessByItem($event, it)"-->
<!--&gt;</app-upload-image-with-preview>-->
<!--</div>-->
<!--<div class="pic-sound-box">-->
<!--<div nz-row style="width: 50%; padding-bottom: 20px;">-->
<!--<div *ngFor="let it2 of it.soundArr; let i2 = index" nz-col nzSpan="8">-->
<!--<label nz-checkbox nzValue="{{'answer_' + (i2 + 1)}}" [(ngModel)]="it2.answer" (ngModelChange)="clickCheckBox()" >{{i2 + 1}}</label>-->
<!--</div>-->
<!--</div>-->
<!--<div *ngFor="let it2 of it.soundArr; let i2 = index" style="display: flex; align-items: center; padding-bottom: 5px">-->
<!--<span style="padding-right: 10px">sound-{{i2 + 1}}:</span>-->
<!--<app-audio-recorder-->
<!--[audioUrl]="it2.audio_url"-->
<!--(audioUploaded)="onAudioUploadSuccessByItem($event, it2)">-->
<!--</app-audio-recorder>-->
<!--</div>-->
<!--</div>-->
<!--</div>-->
<!--</div>-->
<!--<div style="margin: auto; width: 95%;" nz-row nzType="flex" nzJustify="start" nzAlign="middle">-->
<!--<div *ngFor="let it of picArr; let i = index"-->
<!--nz-col nzSpan="8" >-->
<!--<div class="item-box">-->
<!--<h5> id-{{i+1}} </h5>-->
<!--<div style="display: flex; align-items: center; justify-content: center; padding-bottom: 5px">-->
<!--<input type="text" nz-input placeholder="" [(ngModel)]="it.text" (blur)="saveItem()">-->
<!--<button style="margin-left: 10px;" nz-button nzType="danger" (click)="deleteItem(it)">-->
<!--<i nz-icon type="close"></i>-->
<!--</button>-->
<!--</div>-->
<!--<app-upload-image-with-preview-->
<!--style="width: 100%"-->
<!--[picUrl]="it.pic_url"-->
<!--(imageUploaded)="onImageUploadSuccessByItem($event, it)"-->
<!--&gt;</app-upload-image-with-preview>-->
<!--<div style="display: flex; align-items: center; justify-content: center">-->
<!--<span style="width: 80px;">-->
<!--question:-->
<!--</span>-->
<!--<app-audio-recorder-->
<!--[audioUrl]="it['q_audio_url']"-->
<!--(audioUploaded)="onAudioUploadSuccessByItem($event, it, 'q')">-->
<!--</app-audio-recorder>-->
<!--</div>-->
<!--<div style="display: flex; align-items: center; justify-content: center">-->
<!--<span style="width: 80px;">-->
<!--answer:-->
<!--</span>-->
<!--<app-audio-recorder-->
<!--[audioUrl]="it['a_audio_url']"-->
<!--(audioUploaded)="onAudioUploadSuccessByItem($event, it, 'a')">-->
<!--</app-audio-recorder>-->
<!--</div>-->
<!--<nz-radio-group [(ngModel)]="it.radioValue" >-->
<!--<label nz-radio nzValue="A" (click)="radioClick(it, 'A')"> <i nz-icon nzType="check" nzTheme="outline"></i> </label>-->
<!--<label nz-radio nzValue="B" (click)="radioClick(it, 'B')"> <i nz-icon nzType="close" nzTheme="outline"></i> </label>-->
<!--</nz-radio-group>-->
<!--</div>-->
<!--</div>-->
</div>
\ No newline at end of file
<div *ngIf="showGuideAudio" style="position: absolute; left: 0; top: 0; width: 100%; height: 100%; display: flex; align-items: center; justify-items: center; background: rgba(0,0,0,.7)" (click)="guideBtnClick(false)">
<div style="margin: auto;">
<video style="width: 60vw; height: auto" src="assets/guide/guide.mp4" controls="controls" type="video/mp4">
您的浏览器不支持 audio 标签。
</video>
</div>
</div>
@import '../style/common_mixin';
.model-content {
//width: 100%;
//height: 100%;
.item-box{
width: 100%;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
padding: 10px;
padding-bottom: 5vw;
padding-top: 5vw;
}
.pic-sound-box {
width: 50%;
display: flex;
//align-items: center;
flex-direction: column
}
.add-btn-box {
display: flex;
align-items: center;
justify-content: center;
//width: 180px;
height: 20vw;
//background: #FFDC00;
padding: 10px;
padding-top: 5vw;
}
}
import {Component, EventEmitter, Input, OnDestroy, OnChanges, OnInit, Output, ApplicationRef, ChangeDetectorRef} from '@angular/core';
import {
Component,
EventEmitter,
Input,
OnDestroy,
OnChanges,
OnInit,
Output,
ApplicationRef,
ChangeDetectorRef
} from '@angular/core';
@Component({
selector: 'app-form',
templateUrl: './form.component.html',
styleUrls: ['./form.component.css']
styleUrls: ['./form.component.scss']
})
export class FormComponent implements OnInit, OnChanges, OnDestroy {
// 储存数据用
saveKey = "test_0011";
// 储存对象
item;
picArr = [];
_item: any;
constructor(private appRef: ApplicationRef,private changeDetectorRef: ChangeDetectorRef) {
KEY = 'hw_008';
showGuideAudio;
// @Input()
set item(item) {
this._item = item;
// this.init();
}
get item() {
return this._item;
}
@Output()
update = new EventEmitter();
bgItem;
hotZoneItemArr;
constructor(private appRef: ApplicationRef,
public changeDetectorRef: ChangeDetectorRef) {
}
......@@ -23,75 +60,215 @@ export class FormComponent implements OnInit, OnChanges, OnDestroy {
ngOnInit() {
this.item = {};
this.item.contentObj = {};
// 获取存储的数据
(<any> window).courseware.getData((data) => {
const getData = (<any> window).courseware.getData;
getData((data) => {
if (data) {
this.item = data;
} else {
this.item = {};
}
if ( !this.item.contentObj ) {
this.item.contentObj = {};
}
console.log('~data:', data);
this.init();
this.changeDetectorRef.markForCheck();
this.changeDetectorRef.detectChanges();
this.refresh();
}, this.saveKey);
}, this.KEY);
// this.initData();
}
ngOnChanges() {
}
ngOnDestroy() {
}
init() {
if (this.item.contentObj.picArr) {
this.picArr = this.item.contentObj.picArr;
} else {
this.picArr = this.getDefaultPicArr();
this.item.contentObj.picArr = this.picArr;
}
this.bgItem = this.item.contentObj.bgItem || {};
this.hotZoneItemArr = this.item.contentObj.hotZoneItemArr || [];
console.log('item:' , this.item);
// this.picArr = this.getDefaultPicArr();
// this.item.contentObj.picArr = this.picArr;
// console.log('this.item:;', this.picArr);
}
getDefaultPicArr() {
const arr = [];
return arr;
}
changeOptions(data) {
console.log('data: ', data);
this.save();
}
/**
* 储存图片数据
* @param e
*/
onImageUploadSuccess(e, key) {
this.item[key] = e.url;
this.save();
getOptions() {
const options = [];
const arr = this.hotZoneItemArr;
for (let i = 0; i < arr.length; i++) {
const data = {};
data['key'] = arr[i]['key'];
data['index'] = arr[i]['index'];
data['label'] = 'item-' + (arr[i]['index'] + 1);
data['value'] = arr[i]['index'];
options.push(data);
}
return options;
}
/**
* 储存音频数据
* @param e
*/
onAudioUploadSuccess(e, key) {
refreshOptions() {
const picArr = this.picArr;
for (let i = 0; i < picArr.length; i++) {
picArr[i].options = this.getOptions();
}
}
deleteItem(data, arr = null) {
if (!arr) {
arr = this.picArr;
}
const index = arr.indexOf(data);
if (index !== -1) {
arr.splice(index, 1);
}
// this.update.emit(this.item);
// this.refreshOptions();
this.save();
}
onImageUploadSuccessByItem(e, item, id = null) {
if (id != null) {
item[id + '_pic_url'] = e.url;
} else {
item.pic_url = e.url;
}
this.item[key] = e.url;
this.save();
// this.update.emit(this.item);
// console.log('this.item: ', this.item);
}
/**
* 储存数据
*/
onAudioUploadSuccessByItem(e, item, id = null) {
if (id != null) {
item[id + '_audio_url'] = e.url;
} else {
item.audio_url = e.url;
}
// this.update.emit(this.item);
this.save();
}
addPic() {
this.picArr.push({
pic_url: '',
audio_url: '',
text: '',
options: this.getOptions()
// text: '',
// radioValue: 'A'
});
// this.refreshOptions();
this.saveItem();
}
radioClick(it, radioValue) {
it.radioValue = radioValue;
this.saveItem();
}
clickCheckBox() {
console.log(' in clickCheckBox');
this.saveItem();
}
saveItem() {
// this.update.emit(this.item);
this.save();
}
saveData(e) {
console.log('savedata e:', e);
this.bgItem = e.bgItem;
this.hotZoneItemArr = e.hotZoneItemArr;
this.item.contentObj.bgItem = this.bgItem;
this.item.contentObj.hotZoneItemArr = this.hotZoneItemArr;
this.refreshOptions();
this.save();
}
save() {
(<any> window).courseware.setData(this.item, null, this.saveKey);
(<any> window).courseware.setData(this.item, null, this.KEY);
this.refresh();
}
/**
* 刷新 渲染页面
*/
refresh() {
setTimeout(() => {
this.appRef.tick();
}, 1);
}
guideBtnClick(value) {
this.showGuideAudio = value;
}
}
import TWEEN from '@tweenjs/tween.js';
interface AirWindow extends Window {
air: any;
curCtx: any;
}
declare let window: AirWindow;
class Sprite {
x = 0;
......@@ -19,7 +15,7 @@ class Sprite {
constructor(ctx = null) {
if (!ctx) {
this.ctx = window.curCtx;
this.ctx = window['curCtx'];
} else {
this.ctx = ctx;
}
......@@ -70,7 +66,7 @@ export class MySprite extends Sprite {
_z = 0;
init(imgObj = null, anchorX: number = 0.5, anchorY: number = 0.5) {
init(imgObj = null, anchorX:number = 0.5, anchorY:number = 0.5) {
if (imgObj) {
......@@ -188,13 +184,16 @@ export class MySprite extends Sprite {
if (this.children.length <= 0) { return; }
for (const child of this.children) {
if (child === this) {
for (let i = 0; i < this.children.length; i++) {
if (this.children[i] === this) {
if (this.visible) {
this.drawSelf();
}
} else {
child.update();
this.children[i].update();
}
}
}
......@@ -241,7 +240,7 @@ export class MySprite extends Sprite {
removeChildren() {
for (let i = 0; i < this.children.length; i++) {
if (this.children[i]) {
if (this.children[i] !== this) {
if (this.children[i] != this) {
this.children.splice(i, 1);
i --;
}
......@@ -250,9 +249,9 @@ export class MySprite extends Sprite {
}
_changeChildAlpha(alpha) {
for (const child of this.children) {
if (child !== this) {
child.alpha = alpha;
for (let i = 0; i < this.children.length; i++) {
if (this.children[i] != this) {
this.children[i].alpha = alpha;
}
}
}
......@@ -363,7 +362,7 @@ export class ColorSpr extends MySprite {
g = 0;
b = 0;
createGSCanvas() {
createGSCanvas(){
if (!this.img) {
return;
......@@ -378,8 +377,8 @@ export class ColorSpr extends MySprite {
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++) {
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];
......@@ -413,7 +412,7 @@ export class GrayscaleSpr extends MySprite {
grayScale = 120;
createGSCanvas() {
createGSCanvas(){
if (!this.img) {
return;
......@@ -424,8 +423,8 @@ export class GrayscaleSpr extends MySprite {
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++) {
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];
......@@ -468,10 +467,10 @@ export class BitMapLabel extends MySprite {
const tmpArr = text.split('');
let totalW = 0;
let h = 0;
for (const tmp of tmpArr) {
for (let i = 0; i < tmpArr.length; i++) {
const label = new MySprite(this.ctx);
label.init(data[tmp], 0);
label.init(data[tmpArr[i]], 0);
this.addChild(label);
labelArr.push(label);
......@@ -484,9 +483,9 @@ export class BitMapLabel extends MySprite {
this.height = h;
let offX = -totalW / 2;
for (const label of labelArr) {
label.x = offX;
offX += label.width;
for (let i = 0; i < labelArr.length; i++) {
labelArr[i].x = offX;
offX += labelArr[i].width;
}
this.labelArr = labelArr;
......@@ -499,10 +498,10 @@ export class BitMapLabel extends MySprite {
export class Label extends MySprite {
text: string;
text: String;
// fontSize:String = '40px';
fontName = 'Verdana';
textAlign = 'left';
fontName: String = 'Verdana';
textAlign: String = 'left';
fontSize = 40;
fontColor = '#000000';
fontWeight = 900;
......@@ -564,7 +563,7 @@ export class Label extends MySprite {
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(() => {
.onComplete(function() {
if (callBack) {
callBack();
}
......@@ -650,10 +649,11 @@ export class RichTextOld extends Label {
textArr = [];
fontSize = 40;
setText(text: string, words) {
setText(text:string, words) {
let newText = text;
for (const word of words) {
for (let i = 0; i < words.length; i++) {
const word = words[i];
const re = new RegExp(word, 'g');
newText = newText.replace( re, `#${word}#`);
......@@ -676,8 +676,8 @@ export class RichTextOld extends Label {
this.ctx.fontWeight = this.fontWeight;
let curX = 0;
for (const text of this.textArr) {
const w = this.ctx.measureText(text).width;
for (let i = 0; i < this.textArr.length; i++) {
const w = this.ctx.measureText(this.textArr[i]).width;
curX += w;
}
......@@ -699,7 +699,7 @@ export class RichTextOld extends Label {
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(() => {
.onComplete(function() {
if (callBack) {
callBack();
}
......@@ -735,7 +735,7 @@ export class RichTextOld extends Label {
const w = this.ctx.measureText(this.textArr[i]).width;
if ((i + 1) % 2 === 0) {
if ((i + 1) % 2 == 0) {
this.ctx.fillStyle = '#c8171e';
} else {
this.ctx.fillStyle = '#000000';
......@@ -760,7 +760,7 @@ export class RichText extends Label {
disH = 30;
constructor(ctx?: any) {
constructor(ctx) {
super(ctx);
// this.dataArr = dataArr;
......@@ -794,12 +794,12 @@ export class RichText extends Label {
for (const c of chr) {
if (this.ctx.measureText(temp).width < w && this.ctx.measureText(temp + (c)).width <= w) {
temp += ' ' + c;
for (let a = 0; a < chr.length; a++) {
if (this.ctx.measureText(temp).width < w && this.ctx.measureText(temp + (chr[a])).width <= w) {
temp += ' ' + chr[a];
} else {
row.push(temp);
temp = ' ' + c;
temp = ' ' + chr[a];
}
}
row.push(temp);
......@@ -841,7 +841,7 @@ export class RichText extends Label {
export class LineRect extends MySprite {
lineColor = '#ffffff';
lineColor = "#ffffff";
lineWidth = 10;
setSize(w, h) {
......@@ -931,83 +931,7 @@ export class ShapeCircle extends MySprite {
}
}
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 {
......@@ -1054,13 +978,13 @@ export class MyAnimation extends MySprite {
this.frameArr[this.frameIndex].visible = true;
}
_refreshSize(img: any) {
_refreshSize(img) {
if (this.width < img.width) {
this.width = img.width;
if (this.width < img['width']) {
this.width = img['width'];
}
if (this.height < img.height) {
this.height = img.height;
if (this.height < img['height']) {
this.height = img['height'];
}
}
......@@ -1089,14 +1013,14 @@ export class MyAnimation extends MySprite {
}
showAllFrame() {
for (const frame of this.frameArr ) {
frame.alpha = 1;
for (let i = 0; i < this.frameArr.length; i++) {
this.frameArr[i].alpha = 1;
}
}
hideAllFrame() {
for (const frame of this.frameArr) {
frame.alpha = 0;
for (let i = 0; i < this.frameArr.length; i++) {
this.frameArr[i].alpha = 0;
}
}
......@@ -1189,7 +1113,7 @@ export function tweenChange(item, obj, time = 0.8, callBack = null, easing = nul
}
if (update) {
tween.onUpdate( (a, b) => {
update(a, b);
update(a, b);
});
}
......@@ -1242,7 +1166,7 @@ export function moveItem(item, x, y, time = 0.8, callBack = null, easing = null)
if (callBack) {
tween.onComplete(() => {
callBack();
callBack();
});
}
if (easing) {
......@@ -1268,7 +1192,7 @@ export function endShow(item, s = 1) {
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(() => {
.onComplete(function() {
})
.start();
......@@ -1276,14 +1200,14 @@ export function endShow(item, s = 1) {
export function hideItem(item, time = 0.8, callBack = null, easing = null) {
if (item.alpha === 0) {
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(() => {
.onComplete(function () {
if (callBack) {
callBack();
}
......@@ -1299,7 +1223,7 @@ export function hideItem(item, time = 0.8, callBack = null, easing = null) {
export function showItem(item, time = 0.8, callBack = null, easing = null) {
if (item.alpha === 1) {
if (item.alpha == 1) {
if (callBack) {
callBack();
}
......@@ -1310,7 +1234,7 @@ export function showItem(item, time = 0.8, callBack = null, easing = null) {
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(() => {
.onComplete(function () {
if (callBack) {
callBack();
}
......@@ -1328,9 +1252,9 @@ export function alphaItem(item, alpha, time = 0.8, callBack = null, easing = nul
const tween = new TWEEN.Tween(item)
.to({alpha}, time * 1000)
.to({alpha: alpha}, time * 1000)
// .easing(TWEEN.Easing.Quadratic.Out) // Use an easing function to make the animation smooth.
.onComplete(() => {
.onComplete(function () {
if (callBack) {
callBack();
}
......@@ -1350,7 +1274,7 @@ 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(() => {
.onComplete(function () {
if (callBack) {
callBack();
}
......@@ -1406,22 +1330,22 @@ export function getAngleByPos(px, py, mx, my) {
const radina = Math.acos(cos); // 用反三角函数求弧度
let angle = Math.floor(180 / (Math.PI / radina) * 100) / 100; // 将弧度转换成角度
if (mx > px && my > py) {// 鼠标在第四象限
if(mx > px && my > py) {// 鼠标在第四象限
angle = 180 - angle;
}
if (mx === px && my > py) {// 鼠标在y轴负方向上
if(mx === px && my > py) {// 鼠标在y轴负方向上
angle = 180;
}
if (mx > px && my === py) {// 鼠标在x轴正方向上
if(mx > px && my === py) {// 鼠标在x轴正方向上
angle = 90;
}
if (mx < px && my > py) {// 鼠标在第三象限
if(mx < px && my > py) {// 鼠标在第三象限
angle = 180 + angle;
}
if (mx < px && my === py) {// 鼠标在x轴负方向
if(mx < px && my === py) {// 鼠标在x轴负方向
angle = 270;
}
if (mx < px && my < py) {// 鼠标在第二象限
if(mx < px && my < py) {// 鼠标在第二象限
angle = 360 - angle;
}
......@@ -1433,7 +1357,7 @@ export function getAngleByPos(px, py, mx, my) {
export function removeItemFromArr(arr, item) {
const index = arr.indexOf(item);
if (index !== -1) {
if (index != -1) {
arr.splice(index, 1);
}
}
......@@ -1443,7 +1367,7 @@ export function removeItemFromArr(arr, item) {
export function circleMove(item, x0, y0, time = 2, addR = 360, xPer = 1, yPer = 1, callBack = null, easing = null) {
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);
......@@ -1508,20 +1432,18 @@ 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() // 毫秒
"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)));
}
}
if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (date.getFullYear() + "").substr(4 - RegExp.$1.length));
for (var 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;
}
......
.game-container {
width: 100%;
height: 100%;
//background-image: url("/assets/listen-read-circle/bg.jpg");
background: #ffffff;
background-repeat: no-repeat;
background-size: cover;
}
#canvas {
}
@font-face
{
font-family: 'BRLNSDB';
src: url("../../assets/font/BRLNSDB.TTF") ;
}
//
//
//@font-face
//{
// font-family: 'RoundedBold';
// src: url("../../assets/font/ArialRoundedBold.otf") ;
//}
import {Component, ElementRef, ViewChild, OnInit, Input, OnDestroy, HostListener} from '@angular/core';
import {
MySprite,
Label,
MySprite, tweenChange,
moveItem,
rotateItem,
removeItemFromArr,
ShapeRect, scaleItem, tweenChange, showPopParticle, hideItem, showItem, LineRect, shake, MyAnimation,
} from './Unit';
import {res, resAudio} from './resources';
......@@ -10,6 +14,7 @@ import {res, resAudio} from './resources';
import {Subject} from 'rxjs';
import {debounceTime} from 'rxjs/operators';
import * as _ from 'lodash';
import TWEEN from '@tweenjs/tween.js';
......@@ -18,26 +23,39 @@ import TWEEN from '@tweenjs/tween.js';
@Component({
selector: 'app-play',
templateUrl: './play.component.html',
styleUrls: ['./play.component.css']
styleUrls: ['./play.component.scss']
})
export class PlayComponent implements OnInit, OnDestroy {
// 数据
_data;
@ViewChild('canvas', {static: true }) canvas: ElementRef;
@ViewChild('wrap', {static: true }) wrap: ElementRef;
@Input()
set data(data) {
this._data = data;
}
get data() {
return this._data;
}
// 数据
data;
@Input()
sid;
@ViewChild('canvas') canvas: ElementRef;
@ViewChild('wrap') wrap: ElementRef;
canvasWidth = 1280;
canvasHeight = 720;
canvasBaseW = 1280;
canvasBaseH = 720;
ctx;
fps = 0;
frametime = 0; // 上一帧动画的时间, 两帧时间差
canvasWidth = 1280; // canvas实际宽度
canvasHeight = 720; // canvas实际高度
canvasBaseW = 1280; // canvas 资源预设宽度
canvasBaseH = 720; // canvas 资源预设高度
mx;
my; // 点击坐标
mx; // 点击x坐标
my; // 点击y坐标
// 资源
......@@ -49,124 +67,1048 @@ export class PlayComponent implements OnInit, OnDestroy {
animationId: any;
winResizeEventStream = new Subject();
audioObj = {};
audioObj = {};
renderArr;
mapScale = 1;
canvasLeft;
canvasTop;
saveKey = 'test_0011';
canTouch = true;
btnLeft;
btnRight;
pic1;
pic2;
KEY = 'hw_008';
// -----
picArr;
titleLabel;
light;
particleLayer;
shadowArr;
answerTarget;
answerCurrent;
bgRect;
starBgArr;
clickedSuccessArr;
pageLabel;
leftBtn;
rightBtn;
bgLayer;
curPageIndex;
hotZoneArr;
picIndex = 0;
bgArr;
endPageArr;
gameEndFlag;
showPetalFlag;
bg;
canTouch = true;
curPic;
@HostListener('window:resize', ['$event'])
onResize(event) {
this.winResizeEventStream.next();
}
ngOnInit() {
this.data = {};
// 获取数据
const getData = (<any> window).courseware.getData;
getData((data) => {
const getData = (<any> window).courseware.getData;
getData((data) => {
if (data && typeof data == 'object') {
this.data = data;
} else {
this.data = {};
}
console.log('data:' , data);
if (!this.data.contentObj) {
this.data.contentObj = {};
}
this.initDefaultData();
this.initAudio();
this.initImg();
// this.initListener();
}, this.KEY);
//
// // this.initAudio();
// this.initImg();
// this.initListener();
}
initDefaultData() {
let picArr = this.data.contentObj.picArr;
// console.log('picArr: ', picArr);
if (!picArr || picArr.length == 0) {
const bgItem = {
rect: {
height: 472,
width: 839.8576512455516,
x: 222.57117437722422,
y: 0
},
url: 'assets/play/default/pic.jpg'
};
const hotZoneItemArr = [
{
index: 0,
key: "1575362511657",
rect: {
height: 103.49,
width: 115.49,
x: 481.21,
y: 316
}
},
{
index: 1,
key: "1575362515047",
rect: {
height: 119.08,
width: 119.08,
x: 257.3,
y: 312.99
}
},
{
index: 2,
key: "1575363832858",
rect: {
height: 107.35,
width: 108.66,
x: 415.77,
y: 199
}
},
{
index: 3,
key: "1575515846460",
rect: {
height: 103,
width: 103,
x: 709.43,
y: 319.5
}
}
];
let picArr = [];
for (let i = 0; i < 3; i++) {
const pic = {};
const options = JSON.parse( JSON.stringify(hotZoneItemArr) );
switch ( i ) {
case 0:
options[0].checked = true;
pic['text'] = 'Where is the pig ?';
break;
case 1:
options[1].checked = true;
pic['text'] = 'Where is the fish ?';
break;
case 2:
options[2].checked = true;
options[3].checked = true;
pic['text'] = 'Please find the fruit .';
break;
}
pic['options'] = options;
picArr.push(pic);
}
this.data.contentObj.picArr = picArr;
this.data.contentObj.bgItem = bgItem;
this.data.contentObj.hotZoneItemArr = hotZoneItemArr;
}
}
ngOnDestroy() {
window['curCtx'] = null;
window.cancelAnimationFrame(this.animationId);
this.gameEndFlag = true;
}
initData() {
this.canvasWidth = this.wrap.nativeElement.clientWidth;
this.canvasHeight = this.wrap.nativeElement.clientHeight;
this.canvas.nativeElement.width = this.wrap.nativeElement.clientWidth;
this.canvas.nativeElement.height = this.wrap.nativeElement.clientHeight;
const sx = this.canvasWidth / this.canvasBaseW;
const sy = this.canvasHeight / this.canvasBaseH;
const s = Math.min(sx, sy);
this.mapScale = s;
// this.mapScale = this.canvasWidth / this.canvasBaseW;
// this.mapScale = this.canvasHeight / this.canvasBaseH;
this.renderArr = [];
console.log(' in initData', this.data);
this.canTouch = true;
this.curPageIndex = 0;
// this.downFlag = false;
this.endPageArr = [];
this.shadowArr = [];
this.starBgArr = [];
// this.clockUpdateFlag = false;
if (!this.data.contentObj.picArr) {
this.data.contentObj.picArr = [];
}
this.picArr = this.data.contentObj.picArr;
this.picIndex = 0;
}
initAudio() {
const contentObj = this.data.contentObj;
if (!contentObj) { return; }
const addUrlToAudioObj = (audioUrl) => {
if (audioUrl) {
// console.log('audioUrl:', audioUrl);
const audio = new Audio();
audio.src = audioUrl;
audio.load();
this.audioObj[audioUrl] = audio;
}
};
let arr = contentObj.picArr;
if (arr) {
// console.log('arr: ', arr);
for (let i = 0; i < arr.length; i++) {
addUrlToAudioObj(arr[i].audio_url);
}
}
const audioObj = this.audioObj;
const addOneAudio = (key, url, vlomue = 1, loop = false, callback = null) => {
const audio = new Audio();
audio.src = url;
audio.load();
audio.loop = loop;
audio.volume = vlomue;
audioObj[key] = audio;
if (callback) {
audio.onended = () => {
callback();
};
}
};
addOneAudio('click', this.rawAudios.get('click'), 0.3);
addOneAudio('right', this.rawAudios.get('right'), 0.3);
addOneAudio('wrong', this.rawAudios.get('wrong'), 0.3);
addOneAudio('star', this.rawAudios.get('star'), 1);
addOneAudio('tip', this.rawAudios.get('tip'), 0.3);
addOneAudio('finish', this.rawAudios.get('finish'), 0.5);
}
initImg() {
const contentObj = this.data.contentObj;
if (contentObj) {
const addPicUrl = (url) => {
if (url) {
this.rawImages.set(url, url);
}
};
let arr = this.data.contentObj.picArr;
if (arr) {
for (let i = 0; i < arr.length; i++) {
addPicUrl( arr[i].pic_url);
}
}
addPicUrl(contentObj.bgItem.url);
}
// this.initFontImg();
// 预加载资源
this.loadResources().then(() => {
// this.setfontData();
window['air'].hideAirClassLoading(this.KEY, this.data);
this.init();
this.initListener();
this.update();
});
}
initFontImg() {
}
setfontData() {
}
init() {
this.initData();
this.initCtx();
this.initView();
}
initCtx() {
this.ctx = this.canvas.nativeElement.getContext('2d');
this.canvas.nativeElement.width = this.canvasWidth;
this.canvas.nativeElement.height = this.canvasHeight;
window['curCtx'] = this.ctx;
}
initView() {
this.initBg();
this.initHotZone();
this.initPic();
this.initTitle();
this.initLight();
this.refreshAnswerNum();
}
initTitle() {
const label = new Label();
label.fontSize = 42 * this.mapScale;
label.fontName = 'BRLNSDB';
label.textAlign = 'center';
label.setMaxSize(this.canvasWidth * 0.9);
label.x = this.canvasWidth / 2;
label.y = (this.bgRect.y - this.bgRect.height / 2 * this.bgRect.scaleY) * 7 / 12;
// label.fontColor = '#fff143';
label.fontColor = '#ffffff';
label.setShadow(0, 5, 5, 'rgba(0,0,0,0.3)');
this.titleLabel = label;
this.renderArr.push(label);
const disH = 5 * this.mapScale;
const starBg = new MySprite();
starBg.init(this.images.get('top_star_bg'));
starBg.setScaleXY(this.mapScale);
const disW = starBg.width / 3 * starBg.scaleX;
const num = this.picArr.length;
const itemW = starBg.width * starBg.scaleX;
const totalW = (starBg.width) * starBg.scaleX * num + disW * (num - 1);
const offX = this.canvasWidth / 2 - totalW / 2 + itemW / 2;
this.starBgArr = [];
for (let i = 0; i < num; i ++) {
const starBg = new MySprite();
starBg.init(this.images.get('top_star_bg'));
starBg.setScaleXY(this.mapScale);
starBg.x = offX + (itemW + disW) * i;
starBg.y = label.y - starBg.height / 2 * starBg.scaleY - disH / 2;
// this.renderArr.push(starBg);
const star = new MySprite();
star.init(this.images.get('top_star'));
star.visible = false;
starBg['star'] = star;
starBg.addChild(star);
this.starBgArr.push(starBg);
}
label.y += label.height / 2 * label.scaleY + disH / 2;
let offsetY = label.height * label.scaleY + disH / 2;
const textBg = new MySprite();
textBg.init(this.images.get('text_bg'));
textBg.setScaleXY(this.mapScale);
textBg.x = label.x;
textBg.y = label.y - offsetY * 5 / 4;
this.renderArr.push(textBg);
// label.y += offsetY;
const pageLabel = new Label();
pageLabel.text = '0 / 0';
pageLabel.fontName = 'BRLNSDB';
pageLabel.fontColor = '#ffffff';
pageLabel.textAlign = 'center';
pageLabel.fontSize = 46;
textBg.addChild(pageLabel);
this.pageLabel = pageLabel;
this.refreshTitleLabel();
this.refreshPageLabel();
}
refreshTitleLabel(animaFlag = false) {
const data = this.picArr[this.curPageIndex];
if (animaFlag) {
hideItem(this.titleLabel, 0.2, () => {
this.titleLabel.text = data.text;
showItem(this.titleLabel, 0.3);
this.playAudio('tip', true);
});
} else {
this.titleLabel.text = data.text;
}
}
refreshPageLabel() {
// const label = this.pageLabel;
// label.text = (this.curPageIndex + 1) + ' / ' + this.picArr.length;
for (let i = 0; i < this.curPageIndex; i++) {
const starBg = this.starBgArr[i];
if (starBg) {
const star = starBg.star;
if (!star.visible) {
star.visible = true;
star.setScaleXY(3);
star.alpha = 0;
tweenChange(star, {scaleX: 1, scaleY: 1, alpha: 1}, 1, () => {
}, TWEEN.Easing.Exponential.In);
}
}
}
let max = this.starBgArr.length;
let current = 0;
for (let i = 0; i < this.curPageIndex; i++) {
const starBg = this.starBgArr[i];
if (starBg) {
const star = starBg.star;
if (star.visible) {
current++
}
}
}
this.pageLabel.text = Math.min(max, current + 1) + ' / ' + max;
}
showAudio() {
const data = this.picArr[this.curPageIndex];
const audio = this.audioObj[data.audio_url];
if (audio) {
audio.play();
}
}
initPic() {
}
initLight() {
const light = new LineRect();
light.init();
light.visible = false;
light.setShadow(0, 0, 15 * this.mapScale, 'rgba(255, 255, 0, 1)')
light.lineWidth = 7 * this.mapScale;
this.light = light;
this.renderArr.push(light);
}
initBg() {
this.bgArr = [];
const bg = new MySprite();
bg.init(this.images.get('bg'));
bg.x = this.canvasWidth / 2;
bg.y = this.canvasHeight / 2;
let sx = this.canvasWidth / bg.width;
let sy = this.canvasHeight / bg.height;
let s = Math.max(sx, sy);
bg.setScaleXY(s);
this.renderArr.push(bg);
const bgItem = new MySprite();
bgItem.init(this.images.get(this.data.contentObj.bgItem.url));
bgItem.x = this.canvasWidth / 2;
// bgItem.y = this.canvasHeight / 10 * 5.5;
bgItem.y = this.canvasHeight / 10 * 5.8;
const maxW = this.canvasWidth * 0.75;
const maxH = this.canvasHeight * 0.75;
// const maxH = this.canvasHeight * 0.8;
sx = maxW / bgItem.width;
sy = maxH / bgItem.height;
s = Math.min(sx, sy);
bgItem.setScaleXY(s);
bgItem.setShadow(5, 5, 10);
// bgItem.setShadow(15, 15, 20, 'rgba(0,0,0,0.5)');
this.bg = bgItem;
const edge = 20;
const shapeRect = new ShapeRect();
shapeRect.init();
shapeRect.setSize(bgItem.width * bgItem.scaleX + edge * this.mapScale, bgItem.height * bgItem.scaleY + edge * this.mapScale);
shapeRect.fillColor = '#ffffff';
shapeRect.setShadow(0, 5, 10);
shapeRect.x = bgItem.x;
shapeRect.y = bgItem.y;
this.bgRect = shapeRect;
this.renderArr.push(shapeRect);
bgItem.x = 0;
bgItem.y = 0;
shapeRect.addChild(bgItem);
// this.renderArr.push(bgItem);
const particleLayer = new MySprite();
particleLayer.width = this.canvasWidth;
particleLayer.height = this.canvasHeight;
this.particleLayer = particleLayer;
this.addSpeaker();
}
speakerIcon;
speakerAnima;
addSpeaker() {
const speakerIcon = new MySprite();
speakerIcon.init(this.images.get('speaker_1'));
speakerIcon.x = this.canvasWidth - (this.canvasWidth - this.bgRect.width) / 4
speakerIcon.y = this.bgRect.y;
speakerIcon.setScaleXY(this.mapScale);
this.speakerIcon = speakerIcon;
const speakerAnima = new MyAnimation();
speakerAnima.setScaleXY(this.mapScale);
this.speakerAnima = speakerAnima;
speakerAnima.init(this.images.get('speaker_1'))
for (let i = 1 ; i <= 4; i++) {
speakerAnima.addFrameByImg(this.images.get('speaker_' + i))
}
speakerAnima.delayPerUnit = 0.2;
speakerAnima.loop = true;
speakerAnima.x = speakerIcon.x;
speakerAnima.y = speakerIcon.y;
// speakerAnima.play();
speakerAnima.visible = false;
this.renderArr.push(speakerAnima);
this.renderArr.push(speakerIcon);
}
mapDown(event) {
if (!this.canTouch) {
return;
}
this.canTouch = false;
for (let i = 0; i < this.hotZoneArr.length; i ++) {
if (this.checkClickTarget(this.hotZoneArr[i])) {
this.clickHotZone(i);
return;
}
}
if (this.checkClickTarget(this.speakerIcon)) {
this.clickedSpeaker();
return;
}
this.clickWrong();
}
mapMove(event) {
}
mapUp(event) {
}
clickedSpeaker() {
this.speakerIcon.visible = false;
this.speakerAnima.visible = true;
this.speakerAnima.replay();
// this.speakerAnima.frameIndex = 0;
const data = this.picArr[this.curPageIndex];
this.playAudio(data.audio_url, true, () => {
this.speakerIcon.visible = true;
this.speakerAnima.visible = false;
this.speakerAnima.stop();
})
this.canTouch = true;
}
clickHotZone(index) {
if (this.clickedSuccessArr.indexOf(index) != -1) {
console.log('return');
this.canTouch = true;
return;
}
this.clickedSuccessArr.push(index);
const data = this.picArr[this.curPageIndex];
const options = data.options;
if (options[index] && options[index].checked) {
console.log('right');
this.showFrame(index);
} else {
console.log('wrong');
this.clickWrong();
}
}
clickWrong() {
this.playAudio('wrong', true);
shake(this.bgRect, 0.5, () => {
this.canTouch = true;
});
}
showFrame(index) {
this.playAudio('right', true);
const light = this.light;
light.setScaleXY(0);
light.alpha = 0;
light.visible = true;
const hotZone = this.hotZoneArr[index];
const px = hotZone.x + hotZone.width / 2;
const py = hotZone.y + hotZone.height / 2;
light.x = px;
light.y = py;
const edge = 48;
light.setSize(hotZone.width, hotZone.height);
tweenChange(light, {
scaleX: 1, // hotZone.width / (light.width - edge * 2),
scaleY: 1, // hotZone.height / (light.height - edge * 2),
alpha: 1
}, 0.5, () => {
setTimeout(() => {
hideItem(light, 0.3, () => {
}, TWEEN.Easing.Quadratic.In);
}, 200);
}, TWEEN.Easing.Quadratic.Out);
setTimeout(() => {
this.playAudio('star', true);
showPopParticle(this.images.get('star'), {x: px, y: py},
this.particleLayer, 20, 50 * this.mapScale, 100 * this.mapScale, 1);
}, 400);
setTimeout( () => {
this.showShadow(hotZone);
}, 1000);
}
showShadow(hotZone) {
const shadow = new MySprite();
shadow.init(this.images.get('shadow'));
shadow.alpha = 0;
shadow.x = hotZone.x + hotZone.width / 2;
shadow.y = hotZone.y + hotZone.height / 2;
shadow.childDepandAlpha = true;
this.renderArr.push(shadow);
const lineRect = new LineRect();
lineRect.init();
lineRect.lineWidth = 2 * this.mapScale;
lineRect.lineColor = '#c2ff39';
lineRect.setSize(hotZone.width - lineRect.lineWidth, hotZone.height - lineRect.lineWidth);
shadow.addChild(lineRect);
const sx = hotZone.width / (shadow.width - 360);
const sy = hotZone.height / (shadow.height - 360);
shadow.scaleX = sx;
shadow.scaleY = sy;
lineRect.scaleX = 1 / sx;
lineRect.scaleY = 1 / sy;
showItem(shadow, 0.5, () => {
this.checkGameEnd();
});
this.shadowArr.push(shadow);
}
checkGameEnd() {
this.answerCurrent ++;
if (this.answerCurrent < this.answerTarget) {
this.canTouch = true;
return;
}
this.curPageIndex ++;
this.refreshPageLabel();
if (this.curPageIndex >= this.picArr.length) {
this.gameEnd();
return;
}
setTimeout(() => {
for (let i = 0; i < this.shadowArr.length; i++) {
const shadow = this.shadowArr[i];
hideItem(shadow, 0.2, () => {
removeItemFromArr(this.renderArr, shadow);
});
}
this.shadowArr = [];
// this.refreshPageLabel();
this.refreshTitleLabel(true);
this.refreshAnswerNum();
this.canTouch = true;
}, 2500);
}
refreshAnswerNum() {
this.answerCurrent = 0;
this.answerTarget = 0;
this.clickedSuccessArr = [];
const data = this.picArr[this.curPageIndex];
const options = data.options;
console.log('options: ', options);
for (let i = 0; i < options.length; i++) {
// console.log('options:', options[i]);
if (options[i].checked) {
this.answerTarget ++;
}
}
}
gameEnd() {
this.playAudio('finish', true);
this.showEndPetal();
setTimeout(( ) => {
this.showPetalFlag = false;
}, 5000);
if ( (<any> window).courseware ) {
(<any> window).courseware.sendEvent('gameEnd');
console.log('send gameEnd event')
}
}
update() {
this.animationId = window.requestAnimationFrame(this.update.bind(this));
// 清除画布内容
this.ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight);
TWEEN.update();
this.updateArr(this.renderArr);
this.updateItem(this.particleLayer);
this.updateArr(this.endPageArr);
}
updateItem(item) {
if (item) {
item.update();
}
}
updateArr(arr) {
if (!arr) {
return;
}
for (let i = 0; i < arr.length; i++) {
arr[i].update(this);
}
}
initHotZone() {
let curBgRect;
if (this.bg) {
curBgRect = this.bg.getBoundingBox();
}
let oldBgRect = this.data.contentObj.bgItem.rect;
if (!oldBgRect) {
oldBgRect = curBgRect;
}
const rate = curBgRect.width / oldBgRect.width;
// this.imgArr = [];
// const arr = this.data.contentObj.imgItemArr;
this.hotZoneArr = [];
const arr = this.data.contentObj.hotZoneItemArr;
if (!arr) return;
for (let i = 0; i < arr.length; i++) {
if (data && typeof data == 'object') {
this.data = data;
}
// console.log('data:' , data);
const data = JSON.parse(JSON.stringify(arr[i]));
// const img = {pic_url: data.pic_url};
// 初始化 各事件监听
this.initListener();
data.rect.x *= rate;
data.rect.y *= rate;
data.rect.width *= rate;
data.rect.height *= rate;
// 若无数据 则为预览模式 需要填充一些默认数据用来显示
this.initDefaultData();
data.rect.x += curBgRect.x;
data.rect.y += curBgRect.y;
// 初始化 音频资源
this.initAudio();
// 初始化 图片资源
this.initImg();
// 开始预加载资源
this.load();
const hotZone = this.getHotZoneItem(data);
hotZone.alpha = 0;
this.hotZoneArr.push(hotZone);
}, this.saveKey);
}
}
ngOnDestroy() {
window['curCtx'] = null;
window.cancelAnimationFrame(this.animationId);
}
getHotZoneItem(data) {
const saveRect = data.rect;
const item = new ShapeRect(this.ctx);
item.setSize(saveRect.width, saveRect.height);
item.x = saveRect.x ;
item.y = saveRect.y ;
item['data'] = data;
load() {
this.renderArr.push(item);
// 预加载资源
this.loadResources().then(() => {
window["air"].hideAirClassLoading(this.saveKey, this.data);
this.init();
this.update();
});
return item;
}
init() {
showEndPetal() {
this.endPageArr = [];
this.showPetalFlag = true;
this.addPetal();
}
this.initCtx();
this.initData();
this.initView();
stopEndPetal() {
this.endPageArr = [];
this.showPetalFlag = false;
}
initCtx() {
this.canvasWidth = this.wrap.nativeElement.clientWidth;
this.canvasHeight = this.wrap.nativeElement.clientHeight;
this.canvas.nativeElement.width = this.wrap.nativeElement.clientWidth;
this.canvas.nativeElement.height = this.wrap.nativeElement.clientHeight;
addPetal() {
if (!this.showPetalFlag) {
return;
}
const petal = this.getPetal();
this.endPageArr.push(petal);
this.ctx = this.canvas.nativeElement.getContext('2d');
this.canvas.nativeElement.width = this.canvasWidth;
this.canvas.nativeElement.height = this.canvasHeight;
moveItem(petal, petal.x, this.canvasHeight + petal.height * petal.scaleY, petal['time'], () => {
removeItemFromArr(this.endPageArr, petal);
});
window['curCtx'] = this.ctx;
}
rotateItem(petal, petal['tr'], petal['time']);
setTimeout(() => {
this.addPetal();
}, 100);
}
getPetal() {
const petal = new MySprite(this.ctx);
updateItem(item) {
if (item) {
item.update();
}
}
const id = Math.ceil( Math.random() * 3 );
petal.init(this.images.get('petal_' + id));
updateArr(arr) {
if (!arr) {
return;
}
for (let i = 0; i < arr.length; i++) {
arr[i].update(this);
}
}
const randomS = (Math.random() * 0.4 + 0.6) * this.mapScale;
petal.setScaleXY(randomS);
const randomR = Math.random() * 360;
petal.rotation = randomR;
const randomX = Math.random() * this.canvasWidth;
petal.x = randomX;
petal.y = -petal.height / 2 * petal.scaleY;
const randomT = 0.5 + Math.random() * 2.5;
petal['time'] = randomT;
let randomTR = 360 * Math.random(); // - 180;
if (Math.random() < 0.5) { randomTR *= -1; }
petal['tr'] = randomTR;
return petal;
}
initListener() {
......@@ -177,7 +1119,6 @@ export class PlayComponent implements OnInit, OnDestroy {
this.renderAfterResize();
});
// ---------------------------------------------
const setParentOffset = () => {
const rect = this.canvas.nativeElement.getBoundingClientRect();
......@@ -209,6 +1150,7 @@ export class PlayComponent implements OnInit, OnDestroy {
firstTouch = false;
removeMouseListener();
}
console.log('touch down');
setMxMyByTouch(e);
this.mapDown(e);
};
......@@ -226,6 +1168,7 @@ export class PlayComponent implements OnInit, OnDestroy {
firstTouch = false;
removeTouchListener();
}
console.log('mouse down');
setMxMyByMouse(e);
this.mapDown(e);
};
......@@ -290,6 +1233,43 @@ export class PlayComponent implements OnInit, OnDestroy {
showArr(arr) {
if (!arr) {
return;
}
for (let i = 0; i < arr.length; i++) {
arr[i].visible = true;
}
}
hideArr(arr) {
if (!arr) {
return;
}
for (let i = 0; i < arr.length; i++) {
arr[i].visible = false;
}
}
IsPC() {
if (window['ELECTRON']) {
return false; // 封装客户端标记
}
if (document.body.ontouchmove !== undefined && document.body.ontouchmove !== undefined) {
return false;
} else {
return true;
}
}
loadResources() {
const pr = [];
this.rawImages.forEach((value, key) => {// 预加载图片
......@@ -303,7 +1283,7 @@ export class PlayComponent implements OnInit, OnDestroy {
pr.push(p);
});
this.rawAudios.forEach((value, key) => {// 预加载音频
this.rawAudios.forEach((value, key) => {// 预加载图片
const a = this.preloadAudio(value)
.then(() => {
......@@ -349,8 +1329,6 @@ export class PlayComponent implements OnInit, OnDestroy {
checkClickTarget(target) {
const rect = target.getBoundingBox();
......@@ -383,297 +1361,22 @@ export class PlayComponent implements OnInit, OnDestroy {
return false;
}
getPosByAngle(angle, len) {
const radian = angle * Math.PI / 180;
const x = Math.sin(radian) * len;
const y = Math.cos(radian) * len;
addUrlToAudioObj(key, url = null, vlomue = 1, loop = false, callback = null) {
const audioObj = this.audioObj;
if (url == null) {
url = key;
}
this.rawAudios.set(key, url);
const audio = new Audio();
audio.src = url;
audio.load();
audio.loop = loop;
audio.volume = vlomue;
audioObj[key] = audio;
if (callback) {
audio.onended = () => {
callback();
};
}
}
addUrlToImages(url) {
this.rawImages.set(url, url);
}
// ======================================================编写区域==========================================================================
/**
* 添加默认数据 便于无数据时的展示
*/
initDefaultData() {
if (!this.data.pic_url) {
this.data.pic_url = 'assets/play/default/pic.jpg';
this.data.pic_url_2 = 'assets/play/default/pic.jpg';
}
}
/**
* 添加预加载图片
*/
initImg() {
this.addUrlToImages(this.data.pic_url);
this.addUrlToImages(this.data.pic_url_2);
}
/**
* 添加预加载音频
*/
initAudio() {
// 音频资源
this.addUrlToAudioObj(this.data.audio_url);
this.addUrlToAudioObj(this.data.audio_url_2);
// 音效
this.addUrlToAudioObj('click', this.rawAudios.get('click'), 0.3);
}
/**
* 初始化数据
*/
initData() {
const sx = this.canvasWidth / this.canvasBaseW;
const sy = this.canvasHeight / this.canvasBaseH;
const s = Math.min(sx, sy);
this.mapScale = s;
// this.mapScale = sx;
// this.mapScale = sy;
this.renderArr = [];
}
/**
* 初始化试图
*/
initView() {
this.initPic();
this.initBottomPart();
}
initBottomPart() {
const btnLeft = new MySprite();
btnLeft.init(this.images.get('btn_left'));
btnLeft.x = this.canvasWidth - 150 * this.mapScale;
btnLeft.y = this.canvasHeight - 100 * this.mapScale;
btnLeft.setScaleXY(this.mapScale);
this.renderArr.push(btnLeft);
this.btnLeft = btnLeft;
const btnRight = new MySprite();
btnRight.init(this.images.get('btn_right'));
btnRight.x = this.canvasWidth - 50 * this.mapScale;
btnRight.y = this.canvasHeight - 100 * this.mapScale;
btnRight.setScaleXY(this.mapScale);
this.renderArr.push(btnRight);
this.btnRight = btnRight;
}
initPic() {
const maxW = this.canvasWidth * 0.7;
const pic1 = new MySprite();
pic1.init(this.images.get(this.data.pic_url));
pic1.x = this.canvasWidth / 2;
pic1.y = this.canvasHeight / 2;
pic1.setScaleXY(maxW / pic1.width);
this.renderArr.push(pic1);
this.pic1 = pic1;
const label1 = new Label();
label1.text = this.data.text;
label1.textAlign = 'center';
label1.fontSize = 50;
label1.fontName = 'BRLNSDB';
label1.fontColor = '#ffffff';
pic1.addChild(label1);
const pic2 = new MySprite();
pic2.init(this.images.get(this.data.pic_url_2));
pic2.x = this.canvasWidth / 2 + this.canvasWidth;
pic2.y = this.canvasHeight / 2;
pic2.setScaleXY(maxW / pic2.width);
this.renderArr.push(pic2);
this.pic2 = pic2;
this.curPic = pic1;
}
btnLeftClicked() {
this.lastPage();
}
btnRightClicked() {
this.nextPage();
}
lastPage() {
if (this.curPic == this.pic1) {
return;
}
this.canTouch = false;
const moveLen = this.canvasWidth;
tweenChange(this.pic1, {x: this.pic1.x + moveLen}, 1);
tweenChange(this.pic2, {x: this.pic2.x + moveLen}, 1, () => {
this.canTouch = true;
this.curPic = this.pic1;
});
}
nextPage() {
if (this.curPic == this.pic2) {
return;
}
this.canTouch = false;
const moveLen = this.canvasWidth;
tweenChange(this.pic1, {x: this.pic1.x - moveLen}, 1);
tweenChange(this.pic2, {x: this.pic2.x - moveLen}, 1, () => {
this.canTouch = true;
this.curPic = this.pic2;
});
}
pic1Clicked() {
this.playAudio(this.data.audio_url);
}
pic2Clicked() {
this.playAudio(this.data.audio_url_2);
}
mapDown(event) {
if (!this.canTouch) {
return;
}
if ( this.checkClickTarget(this.btnLeft) ) {
this.btnLeftClicked();
return;
}
if ( this.checkClickTarget(this.btnRight) ) {
this.btnRightClicked();
return;
}
if ( this.checkClickTarget(this.pic1) ) {
this.pic1Clicked();
return;
}
if ( this.checkClickTarget(this.pic2) ) {
this.pic2Clicked();
return;
}
}
mapMove(event) {
}
mapUp(event) {
return {x, y};
}
getPosDistance(sx, sy, ex, ey) {
update() {
// ----------------------------------------------------------
this.animationId = window.requestAnimationFrame(this.update.bind(this));
// 清除画布内容
this.ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight);
// tween 更新动画
TWEEN.update();
// ----------------------------------------------------------
this.updateArr(this.renderArr);
const _x = ex - sx;
const _y = ey - sy;
const len = Math.sqrt( Math.pow(_x, 2) + Math.pow(_y, 2) );
return len;
}
}
const res = [
// ['bg', "assets/play/bg.jpg"],
['btn_left', "assets/play/btn_left.png"],
['btn_right', "assets/play/btn_right.png"],
// ['text_bg', "assets/play/text_bg.png"],
['bg', "assets/play/bg.png"],
['text_bg', "assets/play/text_bg.png"],
['light', "assets/play/light.png"],
['star', "assets/play/star.png"],
['shadow', "assets/play/shadow.png"],
['text_bg', "assets/play/rectangle-7.png"],
['top_star', "assets/play/top_star.png"],
['top_star_bg', "assets/play/top_star_bg.png"],
['petal_1', "assets/default/petal_1.png"],
['petal_2', "assets/default/petal_2.png"],
['petal_3', "assets/default/petal_3.png"],
['speaker_1', "assets/play/speaker/1.png"],
['speaker_2', "assets/play/speaker/2.png"],
['speaker_3', "assets/play/speaker/3.png"],
['speaker_4', "assets/play/speaker/4.png"],
];
const resAudio = [
['click', "assets/play/music/click.mp3"],
['right', "assets/play/music/right.mp3"],
['wrong', "assets/play/music/wrong.mp3"],
['star', "assets/play/music/star.mp3"],
['tip', "assets/play/music/tip.mp3"],
['finish', "assets/play/music/finish.mp3"],
];
......
@mixin hide-overflow-text {
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
@mixin k-no-select {
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
@mixin k-img-bg {
background-repeat: no-repeat;
background-position: center;
background-size: contain;
}
.anticon{
vertical-align: .1em!important;
}
src/assets/play/default/pic.jpg

28.7 KB | W: | H:

src/assets/play/default/pic.jpg

35.9 KB | W: | H:

src/assets/play/default/pic.jpg
src/assets/play/default/pic.jpg
src/assets/play/default/pic.jpg
src/assets/play/default/pic.jpg
  • 2-up
  • Swipe
  • Onion skin
......@@ -2,9 +2,7 @@
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "./out-tsc/app",
"types": [
"node"
]
"types": []
},
"files": [
"src/main.ts",
......
This source diff could not be displayed because it is too large. You can view the blob instead.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment