Commit ecbbe282 authored by Li MingZhe's avatar Li MingZhe

feat: 首次提交

parent 9f3a2900
......@@ -24,6 +24,8 @@ import {AudioRecorderComponent} from './common/audio-recorder/audio-recorder.com
import { FontAwesomeModule, FaIconLibrary } from '@fortawesome/angular-fontawesome';
import { fas } from '@fortawesome/free-solid-svg-icons';
import { far } from '@fortawesome/free-regular-svg-icons';
import { CustomActionComponent } from './common/custom-action/custom-action.component';
import { UploadDragonBoneComponent } from './common/upload-dragon-bone/upload-dragon-bone.component';
registerLocaleData(zh);
......@@ -41,7 +43,9 @@ registerLocaleData(zh);
UploadVideoComponent,
CustomHotZoneComponent,
PlayerContentWrapperComponent
PlayerContentWrapperComponent,
CustomActionComponent,
UploadDragonBoneComponent
],
imports: [
......
......@@ -35,7 +35,8 @@
<ng-template #truthyTemplate >
<div class="btn-delete" (click)="onBtnDeleteAudio()">
<fa-icon icon="close"></fa-icon>
<!-- <fa-icon icon="close"></fa-icon> -->
<i nz-icon nzType="close" nzTheme="outline"></i>
</div>
</ng-template>
......
......@@ -26,7 +26,7 @@ export class AudioRecorderComponent implements OnInit, OnChanges, OnDestroy {
uploadData;
@Input()
needRemove = false;
needRemove = true;
@Input()
audioItem: any = null;
......@@ -62,8 +62,25 @@ export class AudioRecorderComponent implements OnInit, OnChanges, OnDestroy {
this.uploadUrl = url;
this.uploadData = data;
};
this.setUploadUrl();
}
setUploadUrl() {
if (!this.uploadUrl) {
this.uploadUrl = (<any> window).courseware.uploadUrl();
this.uploadData = (<any> window).courseware.uploadData();
setTimeout(() => {
this.setUploadUrl();
}, 500);
}
}
init() {
this.playIcon = 'play';
this.isPlaying = false;
......@@ -157,6 +174,7 @@ export class AudioRecorderComponent implements OnInit, OnChanges, OnDestroy {
onBtnDeleteAudio() {
this.audioUrl = null;
this.audioUploaded.emit({});
this.audioRemoved.emit();
}
......
<div class="position-relative">
<button nz-button (click)="setAnimaBtnClick()" style=" border-radius: 0.5rem; border: 1px solid #ddd;" >
<i nz-icon nzType="tool" nzTheme="outline"></i>
{{btnName}}
</button>
<!--配置龙骨面板-->
<nz-modal [(nzVisible)]="panelVisible" (nzAfterClose)="closePanel()" [nzTitle]="btnName" (nzOnCancel)="panelCancel()" (nzOnOk)="panelOk()" nzOkText="保存">
<div>
<h4>基础内容:</h4>
<div style="margin-bottom: 10px; width: 80%; margin: auto;">
<!-- <nz-radio-group [ngModel]="item.type" (ngModelChange)="radioChange($event)">
<label nz-radio nzValue="pic">图片</label>
<label nz-radio nzValue="text">文本</label>
</nz-radio-group> -->
<div *ngIf="item.type == 'pic'">
<app-upload-image-with-preview
[picUrl]="item?.pic_url"
(imageUploaded)="onItemImgUploadSuccess($event, item)">
</app-upload-image-with-preview>
</div>
<div *ngIf="item.type == 'text'">
<input type="text" nz-input [(ngModel)]="item.text" (blur)="saveText(item)">
</div>
<div *ngIf="item.type == 'anima'" style="margin-left: 100px;">
<app-upload-dragon-bone
[skeJsonData]=item.skeJsonData
[texJsonData]=item.texJsonData
[texPngData]=item.texPngData
(save)="saveAnima($event)"
>
</app-upload-dragon-bone>
</div>
</div>
<nz-divider style="margin-top: 10px;"></nz-divider>
<h4>状态设置:</h4>
<div style="display: flex; justify-content: space-around;">
<div style="width: 30%; display: flex; align-items: center; flex-direction: column;">
<h5> 开始状态 </h5>
<div *ngFor="let op of item.changeOption; let i = index" style="margin-bottom: 5px; ">
<div style="display: flex; align-items: center; justify-content: center;">
<span>{{op[0]}}: </span> <input type="text" nz-input [(ngModel)]="op[1]" (blur)="saveText(op)" style="margin-left: 5px;">
</div>
</div>
</div>
<div style="width: 30%; display: flex; align-items: center; flex-direction: column; ">
<h5> 切换时间 </h5>
<div style="display: flex; width: 100%; align-items: center; justify-content: center;">
<span>time: </span> <input type="text" nz-input [(ngModel)]="item.changeTime" (blur)="saveText(item.changeTime)" style="width: 80px; margin-left: 5px;">
</div>
</div>
<div style="width: 30%; display: flex; align-items: center; flex-direction: column;">
<h5> 结束状态 </h5>
<div *ngFor="let op of item.changeOption; let i = index" style="margin-bottom: 5px; ">
<div style="display: flex; align-items: center; justify-content: center;">
<span>{{op[0]}}: </span> <input [disabled]="op[2] == null" type="text" nz-input [(ngModel)]="op[2]" (blur)="saveText(op)" style="margin-left: 5px;">
</div>
</div>
</div>
</div>
<div style="display: flex; align-items: center; justify-content: center; margin-top: 10px;">
<button style="margin-left: 20px; margin-top: -5px" nz-button (click)="copyChangeData()"> 复制数据 </button>
<div style="margin-left: 20px; margin-top: -5px" >
<span>粘贴数据: </span>
<input style="width: 100px;" type="text" nz-input [(ngModel)]="pasteData" >
<button style="margin-left: 5px;" nz-button [disabled]="pasteData==''" nzType="primary" (click)="importData()">导入</button>
</div>
</div>
<nz-divider style="margin-top: 10px;"></nz-divider>
<h4> 音频设置 </h4>
<app-audio-recorder
style="margin: auto"
[audioUrl]="item?.audio_url"
(audioUploaded)="onItemAudioUploadSuccess($event, item)"
></app-audio-recorder>
</div>
<!--
<div class="anima-upload-btn">
<span style="margin-right: 10px">上传 ske_json 文件: </span>
<nz-upload [nzShowUploadList]="false"
nzAccept="application/json"
[nzAction]="uploadUrl"
[nzData]="uploadData"
(nzChange)="skeJsonHandleChange($event)">
<button nz-button><i nz-icon nzType="upload"></i><span>Upload</span></button>
</nz-upload>
<i *ngIf="isSkeJsonLoading" style="margin-left: 10px;" nz-icon [nzType]="'loading'"></i>
<span *ngIf="skeJsonData && skeJsonData['name']" style="margin-left: 10px"><u> {{skeJsonData['name']}} </u></span>
</div>
<div class="anima-upload-btn">
<span style="margin-right: 10px">上传 tex_json 文件: </span>
<nz-upload [nzShowUploadList]="false"
nzAccept="application/json"
[nzAction]="uploadUrl"
[nzData]="uploadData"
(nzChange)="texJsonHandleChange($event)">
<button nz-button><i nz-icon nzType="upload"></i><span>Upload</span></button>
</nz-upload>
<i *ngIf="isTexJsonLoading" style="margin-left: 10px;" nz-icon [nzType]="'loading'"></i>
<span *ngIf="texJsonData && texJsonData['name']" style="margin-left: 10px"><u> {{texJsonData['name']}} </u></span>
</div>
<div class="anima-upload-btn">
<span style="margin-right: 10px">上传 tex_png 文件: </span>
<nz-upload [nzShowUploadList]="false"
nzAccept = "image/*"
[nzAction]="uploadUrl"
[nzData]="uploadData"
(nzChange)="texPngHandleChange($event)">
<button nz-button><i nz-icon nzType="upload"></i><span>Upload</span></button>
</nz-upload>
<i *ngIf="isTexPngLoading" style="margin-left: 10px;" nz-icon [nzType]="'loading'"></i>
<span *ngIf="texPngData && texPngData['name']" style="margin-left: 10px"><u> {{texPngData['name']}} </u></span>
</div>
<div class="anima-upload-btn" *ngIf="animaNames && animaNames.length > 0">
提示:需包含动画: {{animaNames.toString()}}.
</div> -->
</nz-modal>
</div>
@import '../../style/common_mixin.css';
.p-image-uploader {
position: relative;
display: block;
width: 100%;
height: 0;
padding-bottom: 56.25%;
.p-box {
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
border: 2px dashed #ddd;
border-radius: 0.5rem;
background-color: #fafafa;
text-align: center;
color: #aaa;
.p-upload-icon {
text-align: center;
margin: auto;
.anticon-upload {
color: #888;
font-size: 5rem;
}
.p-progress-bar {
position: relative;
width: 20rem;
height: 1.5rem;
border: 1px solid #ccc;
border-radius: 1rem;
.p-progress-bg {
background-color: #1890ff;
border-radius: 1rem;
height: 100%;
}
.p-progress-value {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
text-shadow: 0 0 4px #000;
color: white;
text-align: center;
font-size: 0.9rem;
line-height: 1.5rem;
}
}
}
.p-preview {
width: 100%;
height: 100%;
background-size: contain;
background-repeat: no-repeat;
background-position: 50% 50%;
//background-image: url("https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png");
}
}
.d-flex{
display: flex;
}
}
.p-btn-delete {
position: absolute;
right: -0.5rem;
top: -0.5rem;
width: 2rem;
height: 2rem;
border: 0.2rem solid white;
border-radius: 50%;
font-size: 1.2rem;
background-color: #fb781a;
color: white;
text-align: center;
}
.p-upload-progress-bg {
position: absolute;
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
& .i-text {
position: absolute;
text-align: center;
color: white;
text-shadow: 0 0 2px rgba(0, 0, 0, .85);
}
& .i-bg {
position: absolute;
left: 0;
top: 0;
height: 100%;
background-color: #27b43f;
border-radius: 0.5rem;
}
}
.anima-upload-btn {
padding: 10px;
}
:host ::ng-deep .ant-upload {
display: block;
}
import {ApplicationRef, Component, EventEmitter, Input, OnChanges, OnDestroy, Output} from '@angular/core';
import { NzMessageService, UploadXHRArgs, UploadFile } from 'ng-zorro-antd';
@Component({
selector: 'app-custom-action',
templateUrl: './custom-action.component.html',
styleUrls: ['./custom-action.component.scss']
})
export class CustomActionComponent implements OnDestroy, OnChanges {
uploading = false;
progress = 0;
@Input()
btnName = '配置变化状态';
@Input()
option = []
@Input()
item;
@Input()
type = 'text'
@Output()
save = new EventEmitter();
@Output()
refreshEmitter = new EventEmitter();
uploadUrl;
uploadData;
panelVisible = false;
pasteData = '';
constructor(private appRef: ApplicationRef, private nzMessageService: NzMessageService) {
window['air'].getUploadCallback = (url, data) => {
this.uploadUrl = url;
this.uploadData = data;
};
const tmpId = setInterval(() => {
console.log(' in setInterval')
this.uploadUrl = (<any> window).courseware.uploadUrl();
this.uploadData = (<any> window).courseware.uploadData();
if (this.uploadUrl) {
clearInterval(tmpId);
}
}, 500)
}
ngOnInit() {
this.initItem();
}
ngOnChanges() {
}
initItem() {
console.log('```this.item: ', this.item);
if (!this.item) {
this.item = {
type: this.type,
skeJsonData: {},
texJsonData: {},
texPngData: {},
changeStart: [
],
changeEnd: [
],
changeTime: 0.3
};
if (this.option) {
this.item.changeOption = JSON.parse(JSON.stringify(this.option));
}
}
console.log('initItem', this.item);
}
setAnimaBtnClick() {
this.panelVisible = true;
this.refresh();
}
panelCancel() {
this.panelVisible = false;
this.refresh();
}
panelOk() {
// this.sendItemDragonBoneData();
this.panelVisible = false;
this.refresh();
this.save.emit(this.item);
}
saveText(t) {
}
radioChange(e) {
this.item.type = e;
console.log('e: ', e);
}
onItemImgUploadSuccess(e, item) {
item.pic_url = e.url;
this.refresh();
}
onItemAudioUploadSuccess(e, item) {
item.audio_url = e.url;
this.refresh();
}
saveAnima(e) {
console.log("~ e: ", e);
}
copyChangeData() {
console.log('this.item: ', this.item);
const jsonData = {
changeOption: this.item.changeOption,
changeTime : this.item.changeTime
// bgItem,
// hotZoneItemArr,
// isHasRect: this.isHasRect,
// isHasPic: this.isHasPic,
// isHasText: this.isHasText,
// isHasAudio: this.isHasAudio,
// isHasAnima: this.isHasAnima,
// hotZoneFontObj: this.hotZoneFontObj,
// defaultItemType: this.defaultItemType,
// hotZoneImgSize: this.hotZoneImgSize,
};
const oInput = document.createElement('input');
oInput.value = JSON.stringify(jsonData);
document.body.appendChild(oInput);
oInput.select(); // 选择对象
document.execCommand('Copy'); // 执行浏览器复制命令
document.body.removeChild(oInput);
this.nzMessageService.success('复制成功');
}
importData() {
if (!this.pasteData) {
return;
}
try {
const data = JSON.parse(this.pasteData);
console.log('data:', data);
const {
changeOption,
changeTime
} = data;
this.item.changeOption = changeOption;
this.item.changeTime = changeTime;
this.pasteData = '';
} catch (e) {
console.log('err: ', e);
this.nzMessageService.error('导入失败');
}
}
/**
* 刷新 渲染页面
*/
refresh() {
// this.refreshEmitter.emit();
setTimeout(() => {
this.appRef.tick();
}, 1);
}
closePanel() {
console.log(' in closePanel ');
this.refresh();
}
ngOnDestroy() {
}
}
......@@ -329,6 +329,7 @@ export class MySprite extends Sprite {
this.scaleX = this.scaleY = value;
}
getBoundingBox() {
const getParentData = (item) => {
......@@ -1956,6 +1957,10 @@ export class HotZoneItem extends MySprite {
audio_url;
pic_url;
text;
gIdx;
isAnimaStyle = false;
private _itemType;
private shapeRect: ShapeRect;
......@@ -2056,7 +2061,10 @@ export class HotZoneItem extends MySprite {
this.hideLabel();
}
setAnimaStyle(isAnimaStyle) {
this.isAnimaStyle = isAnimaStyle;
console.log('in setAnimaStyle ')
}
drawArrow() {
if (!this.arrow) { return; }
......@@ -2068,13 +2076,16 @@ export class HotZoneItem extends MySprite {
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();
if (!this.isAnimaStyle) {
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() {
......@@ -2197,8 +2208,26 @@ export class HotZoneLabel extends Label {
this.drawFrame();
}
getLabelRect() {
const rect = this.getBoundingBox();
const width = rect.width / this.scaleX;
const height = this.height * this.scaleY;
const x = this.x - width / 2;
const y = this.y - height / 2;
return {width, height, x, y};
}
}
export class HotZoneAction extends MySprite {
}
......@@ -2208,6 +2237,8 @@ export class EditorItem extends MySprite {
arrow: MySprite;
label: Label;
text;
arrowTop;
arrowRight;
showLabel(text = null) {
......@@ -2246,6 +2277,13 @@ export class EditorItem extends MySprite {
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();
......@@ -2262,16 +2300,25 @@ export class EditorItem extends MySprite {
this.hideLabel();
}
refreshLabelScale() {}
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() {
......@@ -2326,783 +2373,73 @@ 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 HotZonePoint extends HotZoneItem {
strokeColor = "#000000"
fillColor = "#00ff00"
constructor(ctx = null) {
super(ctx);
this.radius = 15;
this.width = this.radius * 2;
this.height = this.radius * 2;
this.anchorX = this.anchorY = 0.5;
}
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.scaleX;
this.ctx.strokeStyle = this.strokeColor;
// 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.setLineDash([3, 3]);
this.ctx.beginPath();
this.ctx.fillStyle = this.fillColor;
this.ctx.arc(this.x, this.y, this.radius * this.scaleX, 0, angleToRadian(360));
this.ctx.fill();
// this.ctx.fill();
this.ctx.stroke();
this.ctx.restore();
}
draw() {
super.draw();
this.drawFrame();
}
getLabelRect() {
const rect = this.getBoundingBox();
const width = rect.width / this.scaleX;
const height = this.height * this.scaleY;
const x = this.x - width / 2;
const y = this.y - height / 2;
return {width, height, x, y};
}
}
......@@ -32,33 +32,111 @@
<nz-divider style="margin-top: 10px;"></nz-divider>
<div style="margin-top: -20px; margin-bottom: 5px; width: 100%;">
<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="customTypeGroupArr">
<nz-radio-group [ngModel]="it.gIdx" (ngModelChange)="customRadioChange($event, it)" style="display: flex; align-items: center; justify-content: center; flex-wrap: wrap;">
<div *ngFor="let group of customTypeGroupArr; let gIdx = index" style="display: flex; ">
<label nz-radio nzValue="{{gIdx}}">{{group.name}}</label>
</div>
</nz-radio-group>
<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>
<!-- <div *ngIf="!customTypeGroupArr">
<nz-radio-group [ngModel]="it.itemType" (ngModelChange)="radioChange($event, it)" style="display: flex; align-items: center; justify-content: center">
<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 == '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 *ngIf="customTypeGroupArr && customTypeGroupArr[it.gIdx]">
<div *ngIf="customTypeGroupArr[it.gIdx].pic">
<app-upload-image-with-preview
[picUrl]="it?.pic_url"
(imageUploaded)="onItemImgUploadSuccess($event, it)">
</app-upload-image-with-preview>
</div>
<div *ngIf="customTypeGroupArr[it.gIdx].text" style="margin-top: 5px">
<input type="text" nz-input [(ngModel)]="it.text" (blur)="saveText(it)">
</div>
<div *ngIf="customTypeGroupArr[it.gIdx].anima" align="center" style="margin-top: 5px">
<button nz-button (click)="setAnimaBtnClick(i)" >
<i nz-icon nzType="tool" nzTheme="outline"></i>
配置龙骨动画
</button>
</div>
<div *ngIf="customTypeGroupArr[it.gIdx].animaSmall" align="center" style="margin-top: 5px">
<button nz-button (click)="setAnimaSmallBtnClick(i)" >
<i nz-icon nzType="tool" nzTheme="outline"></i>
配置龙骨动画(小)
</button>
</div>
<div *ngIf="customTypeGroupArr[it.gIdx].audio" style="display: flex;align-items: center; margin-top: 5px">
<app-audio-recorder
style="margin: auto"
[audioUrl]="it.audio_url"
(audioUploaded)="onItemAudioUploadSuccess($event, it)"
></app-audio-recorder>
</div>
<div *ngIf="customTypeGroupArr[it.gIdx]?.action" style="display: flex;align-items: center; margin-top: 5px">
<app-custom-action
style="margin: auto"
[item]="it ? it['actionData_' + it.gIdx] : {}"
[type]="customTypeGroupArr[it.gIdx].action.type"
[option]="customTypeGroupArr[it.gIdx].action.option"
(save)="onSaveCustomAction($event, it)">
></app-custom-action>
</div>
</div>
<!-- <div *ngIf="!customTypeGroupArr">
<div *ngIf="it.itemType == 'pic'">
<app-upload-image-with-preview
[picUrl]="it?.pic_url"
(imageUploaded)="onItemImgUploadSuccess($event, it)">
</app-upload-image-with-preview>
</div>
<div *ngIf="it.itemType == 'text'">
<input type="text" nz-input [(ngModel)]="it.text" (blur)="saveText(it)">
</div>
<div *ngIf="isHasAudio"
style="width: 100%; margin-top: 5px; display: flex; align-items: center; justify-items: center;">
<app-audio-recorder
style="margin: auto"
[audioUrl]="it.audio_url"
(audioUploaded)="onItemAudioUploadSuccess($event, it)"
></app-audio-recorder>
</div>
<div *ngIf="it.itemType == 'rect' && isHasAnima" align="center" style="margin-bottom: 5px">
<button nz-button (click)="setAnimaBtnClick(i)" >
<i nz-icon nzType="tool" nzTheme="outline"></i>
配置龙骨动画
</button>
</div>
</div> -->
</div>
</div>
......@@ -83,12 +161,29 @@
<div class="save-box">
<button class="save-btn" nz-button nzType="primary" [nzSize]="'large'" nzShape="round"
<button style="margin-left: 200px" class="save-btn" nz-button nzType="primary" [nzSize]="'large'" nzShape="round"
(click)="saveClick()" >
<i nz-icon nzType="save"></i>
Save
</button>
<div *ngIf="isCopyData" style="height: 40px; display: flex; justify-items: center;" >
<label style="margin-left: 40px" nz-checkbox [(ngModel)]="bgItem.isShowDebugLine">显示辅助框</label>
<button style="margin-left: 20px; margin-top: -5px" nz-button (click)="copyHotZoneData()"> 复制基础数据 </button>
<div style="margin-left: 10px; margin-top: -5px" >
<span>粘贴数据: </span>
<input style="width: 100px;" type="text" nz-input [(ngModel)]="pasteData" >
<button style="margin-left: 5px;" nz-button [disabled]="pasteData==''" nzType="primary" (click)="importData()">导入</button>
</div>
</div>
</div>
......@@ -98,3 +193,52 @@
<label style="opacity: 0; position: absolute; top: 0px; font-family: 'BRLNSR_1'">1</label>
<!--龙骨面板-->
<nz-modal [(nzVisible)]="animaPanelVisible" nzTitle="配置资源文件" (nzAfterClose)="closeAfterPanel()" (nzOnCancel)="animaPanelCancel()" (nzOnOk)="animaPanelOk()" nzOkText="保存">
<div class="anima-upload-btn">
<span style="margin-right: 10px">上传 ske_json 文件: </span>
<nz-upload [nzShowUploadList]="false"
nzAccept="application/json"
[nzAction]="uploadUrl"
[nzData]="uploadData"
(nzChange)="skeJsonHandleChange($event)">
<button nz-button><i nz-icon nzType="upload"></i><span>Upload</span></button>
</nz-upload>
<i *ngIf="isSkeJsonLoading" style="margin-left: 10px;" nz-icon [nzType]="'loading'"></i>
<span *ngIf="skeJsonData['name']" style="margin-left: 10px"><u> {{skeJsonData['name']}} </u></span>
</div>
<div class="anima-upload-btn">
<span style="margin-right: 10px">上传 tex_json 文件: </span>
<nz-upload [nzShowUploadList]="false"
nzAccept="application/json"
[nzAction]="uploadUrl"
[nzData]="uploadData"
(nzChange)="texJsonHandleChange($event)">
<button nz-button><i nz-icon nzType="upload"></i><span>Upload</span></button>
</nz-upload>
<i *ngIf="isTexJsonLoading" style="margin-left: 10px;" nz-icon [nzType]="'loading'"></i>
<span *ngIf="texJsonData['name']" style="margin-left: 10px"><u> {{texJsonData['name']}} </u></span>
</div>
<div class="anima-upload-btn">
<span style="margin-right: 10px">上传 tex_png 文件: </span>
<nz-upload [nzShowUploadList]="false"
nzAccept = "image/*"
[nzAction]="uploadUrl"
[nzData]="uploadData"
(nzChange)="texPngHandleChange($event)">
<button nz-button><i nz-icon nzType="upload"></i><span>Upload</span></button>
</nz-upload>
<i *ngIf="isTexPngLoading" style="margin-left: 10px;" nz-icon [nzType]="'loading'"></i>
<span *ngIf="texPngData['name']" style="margin-left: 10px"><u> {{texPngData['name']}} </u></span>
</div>
<div class="anima-upload-btn" *ngIf="customTypeGroupArr && customTypeGroupArr[curDragonBoneGIdx] && customTypeGroupArr[curDragonBoneGIdx].animaNames">
提示:需包含以下动画: {{customTypeGroupArr[curDragonBoneGIdx].animaNames.toString()}}
</div>
</nz-modal>
......@@ -81,19 +81,21 @@
}
}
h5 {
margin-top: 1rem;
.anima-upload-btn {
padding: 10px;
}
@font-face
{
font-family: 'BRLNSR_1';
src: url("/assets/font/BRLNSR_1.TTF") ;
h5 {
margin-top: 1rem;
}
//
//@font-face
//{
// font-family: 'BRLNSR_1';
// src: url("/assets/font/BRLNSR_1.TTF") ;
//}
......@@ -107,104 +109,3 @@ h5 {
//@import '../../../style/common_mixin';
//
//.p-image-uploader {
// position: relative;
// display: block;
// width: 100%;
// height: 0;
// padding-bottom: 56.25%;
// .p-box {
// position: absolute;
// left: 0;
// top: 0;
// right: 0;
// bottom: 0;
// border: 2px dashed #ddd;
// border-radius: 0.5rem;
// background-color: #fafafa;
// text-align: center;
// color: #aaa;
// .p-upload-icon {
// text-align: center;
// margin: auto;
// .anticon-upload {
// color: #888;
// font-size: 5rem;
// }
// .p-progress-bar {
// position: relative;
// width: 20rem;
// height: 1.5rem;
// border: 1px solid #ccc;
// border-radius: 1rem;
// .p-progress-bg {
// background-color: #1890ff;
// border-radius: 1rem;
// height: 100%;
// }
// .p-progress-value {
// position: absolute;
// top: 0;
// left: 0;
// width: 100%;
// height: 100%;
// text-shadow: 0 0 4px #000;
// color: white;
// text-align: center;
// font-size: 0.9rem;
// line-height: 1.5rem;
// }
// }
// }
// .p-preview {
// width: 100%;
// height: 100%;
// //background-image: url("https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png");
// @include k-img-bg();
// }
// }
//}
//
//.p-btn-delete {
// position: absolute;
// right: -0.5rem;
// top: -0.5rem;
// width: 2rem;
// height: 2rem;
// border: 0.2rem solid white;
// border-radius: 50%;
// font-size: 1.2rem;
// background-color: #fb781a;
// color: white;
// text-align: center;
//}
//
//.p-upload-progress-bg {
// position: absolute;
// width: 100%;
// height: 100%;
// display: flex;
// align-items: center;
// justify-content: center;
// & .i-text {
// position: absolute;
// text-align: center;
// color: white;
// text-shadow: 0 0 2px rgba(0, 0, 0, .85);
// }
// & .i-bg {
// position: absolute;
// left: 0;
// top: 0;
// height: 100%;
// background-color: #27b43f;
// border-radius: 0.5rem;
// }
//}
//
//
//:host ::ng-deep .ant-upload {
// display: block;
//}
import {
ApplicationRef,
ChangeDetectorRef,
Component,
ElementRef,
EventEmitter,
......@@ -12,10 +14,11 @@ import {
} from '@angular/core';
import {Subject} from 'rxjs';
import {debounceTime} from 'rxjs/operators';
import {EditorItem, HotZoneImg, HotZoneItem, HotZoneLabel, Label, MySprite, removeItemFromArr} from './Unit';
import {EditorItem, HotZoneImg, HotZoneItem, HotZoneLabel, HotZonePoint, Label, MySprite, removeItemFromArr, ShapeRect, ShapeRectNew} from './Unit';
import TWEEN from '@tweenjs/tween.js';
import {getMinScale} from "../../play/Unit";
import {tar} from "compressing";
import {getMinScale} from '../../play/Unit';
import {tar} from 'compressing';
import {NzMessageService} from 'ng-zorro-antd';
@Component({
......@@ -25,18 +28,14 @@ import {tar} from "compressing";
})
export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
@ViewChild('canvas', {static: true}) canvas: ElementRef;
@ViewChild('wrap', {static: true}) wrap: ElementRef;
@Input()
imgItemArr = null;
@Input()
hotZoneItemArr = null;
@Input()
hotZoneArr = null;
@Output()
save = new EventEmitter();
@ViewChild('canvas', {static: true}) canvas: ElementRef;
@ViewChild('wrap', {static: true}) wrap: ElementRef;
@Input()
isHasRect = true;
@Input()
......@@ -44,16 +43,30 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
@Input()
isHasText = true;
@Input()
hotZoneFontObj = {
size: 50,
name: 'BRLNSR_1',
color: '#8f3758'
}
isHasAudio = true;
@Input()
defaultItemType = 'text';
isHasAnima = false;
@Input()
customTypeGroupArr; // [{name:string, rect:boolean, pic:boolean, text:boolean, audio:boolean, anima:boolean, animaNames:['name1', ..]}, ...]
@Input()
hotZoneFontObj;
@Input()
isCopyData = false;
// hotZoneFontObj = {
// size: 50,
// name: 'BRLNSR_1',
// color: '#8f3758'
// }
@Input()
hotZoneImgSize = 190;
defaultItemType = 'text';
@Input()
hotZoneImgSize = 0;
@Output()
save = new EventEmitter();
saveDisabled = true;
......@@ -86,8 +99,33 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
changeSizeFlag = false;
changeTopSizeFlag = false;
changeRightSizeFlag = false;
animaPanelVisible = false;
uploadUrl;
uploadData;
skeJsonData = {};
texJsonData = {};
texPngData = {};
animaName = '';
curDragonBoneIndex;
curDragonBoneGIdx;
pasteData = '';
constructor() {
isSkeJsonLoading = false;
isTexJsonLoading = false;
isTexPngLoading = false;
isAnimaSmall = false;
constructor(private nzMessageService: NzMessageService, private appRef: ApplicationRef, private changeDetectorRef: ChangeDetectorRef) {
this.uploadUrl = (<any> window).courseware.uploadUrl();
this.uploadData = (<any> window).courseware.uploadData();
window['air'].getUploadCallback = (url, data) => {
this.uploadUrl = url;
this.uploadData = data;
};
}
_bgItem = null;
......@@ -110,11 +148,14 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
ngOnInit() {
this.initListener();
// this.init();
this.update();
this.refresh();
}
ngOnDestroy() {
......@@ -136,10 +177,12 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
onItemImgUploadSuccess(e, item) {
item.pic_url = e.url;
this.loadHotZonePic(item.pic, e.url);
this.refresh();
}
onItemAudioUploadSuccess(e, item) {
item.audio_url = e.url;
this.refresh();
}
......@@ -150,25 +193,32 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
this.renderArr.push(this.bg);
}
if (!this.bgItem.url) {
this.bgItem.url = 'http://teach.cdn.ireadabc.com/8ebb1858564340ea0936b83e3280ad7d.jpg';
}
const bg = this.bg;
if (this.bgItem.url) {
// if (this.bgItem.url) {
bg.load(this.bgItem.url).then(() => {
const rate1 = this.canvasWidth / bg.width;
const rate2 = this.canvasHeight / bg.height;
bg.load(this.bgItem.url).then(() => {
const rate1 = this.canvasWidth / bg.width;
const rate2 = this.canvasHeight / bg.height;
const rate = Math.min(rate1, rate2);
bg.setScaleXY(rate);
const rate = Math.min(rate1, rate2);
bg.setScaleXY(rate);
bg.x = this.canvasWidth / 2;
bg.y = this.canvasHeight / 2;
bg.x = this.canvasWidth / 2;
bg.y = this.canvasHeight / 2;
if (callBack) {
callBack();
}
});
}
if (callBack) {
callBack();
}
this.refresh();
});
// }
}
......@@ -191,6 +241,7 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
const item = this.hotZoneArr.splice(index, 1)[0];
removeItemFromArr(this.renderArr, item.pic);
removeItemFromArr(this.renderArr, item.textLabel);
removeItemFromArr(this.renderArr, item.point);
this.refreshHotZoneId();
......@@ -199,6 +250,7 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
onImgUploadSuccessByImg(e, img) {
img.pic_url = e.url;
this.refreshImage(img);
this.refresh();
}
refreshImage(img) {
......@@ -221,6 +273,7 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
}
}
this.refresh();
}
......@@ -245,10 +298,17 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
item.anchorX = 0.5;
item.anchorY = 0.5;
item.x = this.canvasWidth / 2;
item.y = this.canvasHeight / 2;
item.itemType = this.defaultItemType;
item.itemType = this.getDefaultItemType();
item.gIdx = '0';
item['id'] = new Date().getTime().toString();
item['data'] = saveData;
console.log('item.x: ', item.x);
if (saveData) {
......@@ -257,41 +317,183 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
item.scaleY = saveRect.height / item.height;
item.x = saveRect.x + saveRect.width / 2;
item.y = saveRect.y + saveRect.height / 2;
item.gIdx = saveData.gIdx;
item['id'] = saveData.id;
item['skeJsonData'] = saveData.skeJsonData;
item['texJsonData'] = saveData.texJsonData;
item['texPngData'] = saveData.texPngData;
item['actionData_' + item.gIdx] = saveData['actionData_' + item.gIdx];
}
console.log('item.x:~~ ', item.x);
item.showLineDash();
const pic = new HotZoneImg(this.ctx);
// const pic = new HotZoneImg(this.ctx);
this.setItemPic(item, saveData);
this.setItemLabel(item, saveData);
this.setItemAnima(item, saveData);
this.setItemPoint(item, saveData);
return item;
}
setItemPic(item, saveData) {
console.log('in setItemPic ', saveData);
const pic = new EditorItem(this.ctx);
pic.visible = false;
item['pic'] = pic;
if (saveData && saveData.pic_url) {
this.loadHotZonePic(pic, saveData.pic_url);
if (saveData) {
let picUrl = saveData.pic_url;
const actionData = saveData['actionData_' + item.gIdx];
if (actionData && actionData.type == 'pic') {
picUrl = actionData.pic_url;
}
console.log('saveData: ', saveData);
console.log('picUrl: ', picUrl);
if (picUrl) {
this.loadHotZonePic(pic, picUrl, saveData);
}
}
pic.x = item.x;
pic.y = item.y;
this.renderArr.push(pic);
}
setItemAnima(item, saveData) {
console.log('in setItemAnima ', saveData);
// const pic = new EditorItem(this.ctx);
// pic.visible = false;
// item['pic'] = pic;
// if (saveData) {
// let picUrl = saveData.pic_url;
// const actionData = saveData['actionData_' + item.gIdx];
// if (actionData && actionData.type == 'pic') {
// picUrl = actionData.pic_url;
// }
// console.log('saveData: ', saveData);
// console.log('picUrl: ', picUrl);
// if (picUrl) {
// this.loadHotZonePic(pic, picUrl, saveData.imgScale);
// }
// }
// pic.x = item.x;
// pic.y = item.y;
// this.renderArr.push(pic);
}
setItemPoint(item, saveData) {
console.log('in setItemPoint ', saveData);
const point = new HotZonePoint(this.ctx);
point.visible = false;
item['point'] = point;
item.width = point.width;
item.height = point.height;
// const pic = new EditorItem(this.ctx);
// pic.visible = false;
// item['pic'] = pic;
// if (saveData) {
// let picUrl = saveData.pic_url;
// const actionData = saveData['actionData_' + item.gIdx];
// if (actionData && actionData.type == 'pic') {
// picUrl = actionData.pic_url;
// }
// console.log('saveData: ', saveData);
// console.log('picUrl: ', picUrl);
// if (picUrl) {
// this.loadHotZonePic(pic, picUrl, saveData);
// }
// }
console.log('item.x: ', item.x);
point.setScaleXY(this.mapScale);
console.log('point.scaleX: ', point.scaleX)
point.x = item.x;
point.y = item.y;
this.renderArr.push(point);
}
setItemLabel(item, saveData) {
const textLabel = new HotZoneLabel(this.ctx);
textLabel.fontSize = this.hotZoneFontObj.size;
textLabel.fontName = this.hotZoneFontObj.name;
textLabel.fontColor = this.hotZoneFontObj.color;
if (this.hotZoneFontObj) {
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;
if (saveData) {
if (saveData.text && this.hotZoneFontObj) {
textLabel.text = saveData.text
}
this.setActionFont(textLabel, saveData['actionData_' + item.gIdx]);
textLabel.refreshSize();
}
textLabel.x = item.x;
textLabel.y = item.y;
this.renderArr.push(textLabel);
}
return item;
setActionFont(textLabel, actionData) {
if (actionData && actionData.type == 'text') {
textLabel.text = actionData.text;
for (let i=0; i<actionData.changeOption.length; i++) {
const op = actionData.changeOption[i];
textLabel[op[0]] = op[1];
}
}
}
getDefaultItemType() {
if (this.customTypeGroupArr) {
const group = this.customTypeGroupArr[0];
if (group.rect) {
return 'rect';
}
if (group.pic) {
return 'pic';
}
if (group.text) {
return 'text';
}
if (group.point) {
return 'point';
}
} else {
return this.defaultItemType;
}
}
getPicItem(img, saveData = null) {
......@@ -327,9 +529,11 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
item.y = saveRect.y + saveRect.height / 2;
} else {
item.showLineDash();
// item.showLineDash();
}
item.showLineDash();
console.log('aaa');
});
return item;
}
......@@ -337,6 +541,7 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
onAudioUploadSuccessByImg(e, img) {
img.audio_url = e.url;
this.refresh();
}
deleteItem(e, i) {
......@@ -345,15 +550,118 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
this.hotZoneArr.splice(i, 1);
this.refreshHotZoneId();
this.refresh();
}
radioChange(e, item) {
item.itemType = e;
// radioChange(e, item) {
// item.itemType = e;
this.refreshItem(item);
// this.refreshItem(item);
// this.refresh();
// // console.log(' in radioChange e: ', e);
// }
customRadioChange(e, item) {
console.log('in customRadioChange', e);
item.gIdx = -1;
setTimeout(() => {
item.gIdx = e;
this.refreshCustomItem(item);
this.refresh();
}, 1);
// const curGroup = this.customTypeGroupArr[e];
}
refreshCustomItem(item) {
this.hideHotZoneItem(item);
const group = this.customTypeGroupArr[item.gIdx];
if (!group) {
return;
}
if (group.text) {
this.showItemLabel(item);
}
if (group.rect) {
this.showItemRect(item);
}
if (group.pic && !group.anima) {
this.showItemPic(item);
}
if (group.point) {
this.showItemPoint(item);
}
if (group.action) {
if (group.action.type == 'pic') {
this.showItemPic(item);
}
if (group.action.type == 'text') {
this.showItemLabel(item);
}
if (group.action.type == 'anima') {
this.showItemRect(item);
}
}
item.setAnimaStyle(group.animaSmall)
}
setItemIsAnimaStyle(item, isAnimal) {
}
// console.log(' in radioChange e: ', e);
showItemPic(item) {
item.pic.visible = true;
item.itemType = 'pic';
this.showArrowTop(item, item.data.isShowArrowAll)
}
showItemLabel(item) {
item.textLabel.visible = true;
item.itemType = 'text';
this.showArrowTop(item, item.data.isShowArrowAll)
}
showItemRect(item) {
item.visible = true;
item.itemType = 'rect';
const isShowArrowAll = item.data.isShowArrowAll == false ? false : true;
this.showArrowTop(item, isShowArrowAll)
}
showItemPoint(item) {
item.point.visible = true;
item.itemType = 'point';
this.showArrowTop(item, false)
}
showArrowTop(item, isShowArrowTop = false) {
if (isShowArrowTop) {
item.arrowTop.visible = true;
item.arrowRight.visible = true;
} else {
item.arrowTop.visible = false;
item.arrowRight.visible = false;
}
}
hideHotZoneItem(item) {
item.visible = false;
item.pic.visible = false;
item.textLabel.visible = false;
}
refreshItem(item) {
......@@ -367,14 +675,18 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
case 'text':
this.setTextState(item);
break;
case 'point':
this.setPointState(item);
break;
default:
this.setNoneState(item);
}
}
init() {
console.log('init');
this.initData();
this.initCtx();
......@@ -382,18 +694,15 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
}
initItem() {
this.changeDetectorRef.markForCheck();
this.changeDetectorRef.detectChanges();
if (!this.bgItem) {
this.bgItem = {};
} else {
this.refreshBackground(() => {
// if (!this.imgItemArr) {
// this.imgItemArr = [];
// } else {
// this.initImgArr();
// }
// console.log('aaaaa');
if (!this.hotZoneItemArr) {
this.hotZoneItemArr = [];
......@@ -404,6 +713,7 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
});
}
this.refresh();
}
initHotZoneArr() {
......@@ -427,6 +737,7 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
this.hotZoneArr = [];
const arr = this.hotZoneItemArr.concat();
console.log('this.hotZoneItemArr: ', this.hotZoneItemArr);
for (let i = 0; i < arr.length; i++) {
const data = JSON.parse(JSON.stringify(arr[i]));
......@@ -449,9 +760,15 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
item.pic_url = data.pic_url;
item.text = data.text;
item.itemType = data.itemType;
this.refreshItem(item);
console.log('item: ', item);
if (this.customTypeGroupArr) {
this.refreshCustomItem(item);
} else {
this.refreshItem(item);
}
console.log('1 item: ', item);
this.hotZoneArr.push(item);
}
......@@ -463,48 +780,6 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
}
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() {
this.canvasWidth = this.wrap.nativeElement.clientWidth;
......@@ -528,9 +803,10 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
this.oldPos = {x: this.mx, y: this.my};
for (let i = 0; i < this.hotZoneArr.length; i++) {
for (let i = this.hotZoneArr.length - 1; i >= 0; i--) {
const item = this.hotZoneArr[i];
console.log('mapDown item: ', item);
let callback;
let target;
switch (item.itemType) {
......@@ -546,9 +822,13 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
target = item.textLabel;
callback = this.clickedHotZoneText.bind(this);
break;
case 'point':
target = item.point;
callback = this.clickedHotZonePoint.bind(this);
break;
}
if (this.checkClickTarget(target)) {
if (target && this.checkClickTarget(target)) {
callback(target);
return;
}
......@@ -582,7 +862,7 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
this.oldPos = {x: this.mx, y: this.my};
this.saveDisabled = true;
// this.saveDisabled = false;
}
......@@ -723,7 +1003,7 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
// }
this.updateArr(this.hotZoneArr);
this.updatePos()
this.updatePos();
TWEEN.update();
......@@ -833,7 +1113,9 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
checkClickTarget(target) {
if (!target || !target.visible) {
return;
}
const rect = target.getBoundingBox();
if (this.checkPointInRect(this.mx, this.my, rect)) {
return true;
......@@ -852,9 +1134,21 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
saveClick() {
const sendData = this.getSendData();
this.save.emit(sendData);
}
getSendData() {
const bgItem = this.bgItem;
if (this.bg) {
bgItem['rect'] = this.bg.getBoundingBox();
const rect = this.bg.getBoundingBox();
bgItem['rect'] = rect;
rect.x = Math.round(rect.x * 100) / 100;
rect.y = Math.round(rect.y * 100) / 100;
rect.width = Math.round(rect.width * 100) / 100;
rect.height = Math.round(rect.height * 100) / 100;
} else {
bgItem['rect'] = {
x: 0,
......@@ -870,19 +1164,43 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
for (let i = 0; i < hotZoneArr.length; i++) {
const hotZoneItem = {
id: hotZoneArr[i].id,
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
mapScale: this.mapScale,
skeJsonData: hotZoneArr[i].skeJsonData,
texJsonData: hotZoneArr[i].texJsonData,
texPngData: hotZoneArr[i].texPngData,
gIdx: hotZoneArr[i].gIdx
};
hotZoneItem['rect'] = hotZoneArr[i].getBoundingBox();
hotZoneItem['actionData_' + hotZoneItem.gIdx] = hotZoneArr[i]['actionData_' + hotZoneArr[i].gIdx]
if (this.hotZoneFontObj) {
hotZoneItem['fontSize'] = this.hotZoneFontObj.size;
hotZoneItem['fontName'] = this.hotZoneFontObj.name;
hotZoneItem['ontColor'] = this.hotZoneFontObj.color;
}
if (hotZoneArr[i].itemType == 'pic') {
hotZoneItem['rect'] = hotZoneArr[i].pic.getBoundingBox();
} else if (hotZoneArr[i].itemType == 'text') {
hotZoneArr[i].textLabel.refreshSize();
hotZoneItem['rect'] = hotZoneArr[i].textLabel.getLabelRect();
// hotZoneItem['rect'].width = hotZoneItem['rect'].width / hotZoneArr[i].textLabel.scaleX;
// hotZoneItem['rect'].height = hotZoneArr[i].textLabel.height * hotZoneArr[i].textLabel.scaleY;
} else {
hotZoneItem['rect'] = hotZoneArr[i].getBoundingBox();
}
// 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;
......@@ -894,7 +1212,275 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
console.log('hotZoneItemArr: ', hotZoneItemArr);
this.save.emit({bgItem, hotZoneItemArr});
return {bgItem, hotZoneItemArr};
}
saveText(item) {
if (item.itemType == 'text') {
item.textLabel.text = item.text;
}
}
onSaveCustomAction(e, item) {
const data = e;
item['actionData_' + item.gIdx] = data;
if (data.type == 'pic') {
let picUrl = data.pic_url;
if (picUrl) {
this.loadHotZonePic(item.pic, picUrl);
}
}
if (data.type == 'text') {
this.setActionFont(item.textLabel, data);
item.textLabel.refreshSize();
}
// if (data.type == 'anima') {
// this.setActionAnima(item.anima, data);
// }
// this.loadHotZonePic(item.pic, e.url);
this.refresh()
}
setActionAnima() {
}
setAnimaBtnClick(index) {
console.log('aaaa')
this.isAnimaSmall = false;
this.setCurDragonBone(index);
// this.curDragonBoneIndex = index;
// this.curDragonBoneGIdx = Number(this.hotZoneArr[index].gIdx);
// const {skeJsonData, texJsonData, texPngData} = this.hotZoneArr[index];
// this.skeJsonData = skeJsonData || {};
// this.texJsonData = texJsonData || {};
// this.texPngData = texPngData || {};
// this.animaPanelVisible = true;
// this.refresh();
}
setAnimaSmallBtnClick(index) {
console.log('bbb')
this.isAnimaSmall = true;
this.setCurDragonBone(index);
}
setCurDragonBone(index) {
this.curDragonBoneIndex = index;
this.curDragonBoneGIdx = Number(this.hotZoneArr[index].gIdx);
const {skeJsonData, texJsonData, texPngData} = this.hotZoneArr[index];
this.skeJsonData = skeJsonData || {};
this.texJsonData = texJsonData || {};
this.texPngData = texPngData || {};
this.animaPanelVisible = true;
this.refresh();
}
setItemSizeByAnima(jsonData, item) {
console.log('json: ', jsonData);
const request = new XMLHttpRequest();
//通过url获取文件,第二个选项是文件所在的具体地址
request.open('GET', jsonData.url, true);
request.send(null);
request.onreadystatechange = ()=> {
if (request.readyState === 4 && request.status === 200) {
var type = request.getResponseHeader('Content-Type');
if (type.indexOf("text") !== 1) {
//返回一个文件内容的对象
const data = JSON.parse(request.responseText);
console.log('request.responseText;', data)
const animaSize = data.armature[0].canvas;
item.width = animaSize.width;
item.height = animaSize.height;
// return request.responseText;
}
}
}
}
animaPanelCancel() {
this.animaPanelVisible = false;
this.refresh();
}
animaPanelOk() {
this.setItemDragonBoneData(this.hotZoneArr[this.curDragonBoneIndex]);
console.log('this.hotZoneArr: ', this.hotZoneArr);
this.animaPanelVisible = false;
if (this.isAnimaSmall) {
this.setItemSizeByAnima(this.skeJsonData, this.hotZoneArr[this.curDragonBoneIndex]);
}
this.refresh();
}
setItemDragonBoneData(item) {
item['skeJsonData'] = this.skeJsonData;
item['texJsonData'] = this.texJsonData;
item['texPngData'] = this.texPngData;
}
skeJsonHandleChange(e) {
console.log('e: ', e);
switch (e.type) {
case 'start':
this.isSkeJsonLoading = true;
break;
case 'success':
this.skeJsonData['url'] = e.file.response.url;
this.skeJsonData['name'] = e.file.name;
this.nzMessageService.success('上传成功');
this.isSkeJsonLoading = false;
break;
case 'progress':
break;
}
}
texJsonHandleChange(e) {
console.log('e: ', e);
switch (e.type) {
case 'start':
this.isTexJsonLoading = true;
break;
case 'success':
this.texJsonData['url'] = e.file.response.url;
this.texJsonData['name'] = e.file.name;
this.nzMessageService.success('上传成功');
this.isTexJsonLoading = false;
break;
case 'progress':
break;
}
}
texPngHandleChange(e) {
console.log('e: ', e);
switch (e.type) {
case 'start':
this.isTexPngLoading = true;
break;
case 'success':
this.texPngData['url'] = e.file.response.url;
this.texPngData['name'] = e.file.name;
this.nzMessageService.success('上传成功');
this.isTexPngLoading = false;
break;
case 'progress':
break;
}
}
copyHotZoneData() {
const {bgItem, hotZoneItemArr} = this.getSendData();
// const hotZoneItemArrNew = [];
// const tmpArr = JSON.parse(JSON.stringify(hotZoneItemArr));
// tmpArr.forEach((item) => {
// if (item.gIdx === '0') {
// hotZoneItemArr.push(item);
// }
// })
const jsonData = {
bgItem,
hotZoneItemArr,
isHasRect: this.isHasRect,
isHasPic: this.isHasPic,
isHasText: this.isHasText,
isHasAudio: this.isHasAudio,
isHasAnima: this.isHasAnima,
hotZoneFontObj: this.hotZoneFontObj,
defaultItemType: this.defaultItemType,
hotZoneImgSize: this.hotZoneImgSize,
};
const oInput = document.createElement('input');
oInput.value = JSON.stringify(jsonData);
document.body.appendChild(oInput);
oInput.select(); // 选择对象
document.execCommand('Copy'); // 执行浏览器复制命令
document.body.removeChild(oInput);
this.nzMessageService.success('复制成功');
// alert('复制成功');
}
importData() {
if (!this.pasteData) {
return;
}
try {
const data = JSON.parse(this.pasteData);
console.log('data:', data);
const {
bgItem,
hotZoneItemArr,
isHasRect,
isHasPic,
isHasText,
isHasAudio,
isHasAnima,
hotZoneFontObj,
defaultItemType,
hotZoneImgSize,
} = data;
this.hotZoneItemArr = hotZoneItemArr;
this.isHasRect = isHasRect;
this.isHasPic = isHasPic;
this.isHasText = isHasText;
this.isHasAudio = isHasAudio;
this.isHasAnima = isHasAnima;
this.hotZoneFontObj = hotZoneFontObj;
this.defaultItemType = defaultItemType;
this.hotZoneImgSize = hotZoneImgSize;
this.bgItem = bgItem;
this.pasteData = '';
} catch (e) {
console.log('err: ', e);
this.nzMessageService.error('导入失败');
}
}
private updatePos() {
......@@ -915,33 +1501,59 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
x = item.textLabel.x;
y = item.textLabel.y;
break;
case 'point':
x = item.point.x;
y = item.point.y;
break;
}
if (x != undefined && y != undefined) {
item.x = x;
item.y = y;
item.pic.x = x;
item.pic.y = y;
item.textLabel.x = x;
item.textLabel.y = y;
}
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;
item.textLabel.visible = false;
item.point.visible = false;
}
private setRectState(item: any) {
item.visible = true;
item.textLabel.visible = false;
item.pic.visible = false;
item.textLabel.visible = false;
item.point.visible = false;
}
private setTextState(item: any) {
item.visible = false;
item.pic.visible = false;
item.textLabel.visible = true;
item.point.visible = false;
}
private setNoneState(item: any) {
item.visible = false;
item.pic.visible = false;
item.textLabel.visible = false;
item.point.visible = false;
}
private setPointState(item) {
item.visible = false;
item.pic.visible = false;
item.textLabel.visible = false;
item.point.visible = true;
}
private clickedHotZoneRect(item: any) {
......@@ -962,6 +1574,17 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
private clickedHotZonePic(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);
}
this.curItem = item;
}
}
......@@ -972,15 +1595,51 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
}
}
saveText(item) {
item.textLabel.text = item.text;
private clickedHotZonePoint(item) {
if (this.checkClickTarget(item)) {
this.curItem = item;
}
}
private loadHotZonePic(pic: HotZoneImg, url) {
const baseLen = this.hotZoneImgSize * this.mapScale;
private loadHotZonePic(pic: HotZoneImg, url, saveData = null) {
let baseLen;
if (this.hotZoneImgSize) {
baseLen = this.hotZoneImgSize * this.mapScale;
}
console.log('saveData: ', saveData);
pic.load(url).then(() => {
const s = getMinScale(pic, baseLen);
pic.setScaleXY(s);
if (!saveData) {
let scale = this.bg.scaleX;
if (baseLen) {
scale = getMinScale(pic, baseLen);
}
pic.setScaleXY(scale);
} else {
const targetW = saveData.rect.width /// saveData.imgScale;
const targetH = saveData.rect.height /// saveData.imgScale;
pic.scaleX = targetW / pic.width;
pic.scaleY = targetH / pic.height;
}
});
}
closeAfterPanel() {
this.refresh();
}
/**
* 刷新 渲染页面
*/
refresh() {
setTimeout(() => {
this.appRef.tick();
}, 1);
}
}
<div class="position-relative">
<button nz-button (click)="setAnimaBtnClick()" style=" border-radius: 0.5rem; border: 1px solid #ddd;">
<i nz-icon nzType="tool" nzTheme="outline"></i>
{{btnName}}
</button>
<!--配置龙骨面板-->
<nz-modal [(nzVisible)]="animaPanelVisible" (nzAfterClose)="closePanel()" nzTitle="配置资源文件"
(nzOnCancel)="animaPanelCancel()" (nzOnOk)="animaPanelOk()" nzOkText="保存">
<div class="anima-upload-btn">
<span style="margin-right: 10px">上传 ske_json 文件: </span>
<nz-upload [nzShowUploadList]="false" nzAccept="application/json" [nzAction]="uploadUrl" [nzData]="uploadData"
(nzChange)="skeJsonHandleChange($event)">
<button nz-button><i nz-icon nzType="upload"></i><span>Upload</span></button>
</nz-upload>
<i *ngIf="isSkeJsonLoading" style="margin-left: 10px;" nz-icon [nzType]="'loading'"></i>
<span *ngIf="skeJsonData && skeJsonData['name']" style="margin-left: 10px"><u> {{skeJsonData['name']}} </u></span>
</div>
<div class="anima-upload-btn">
<span style="margin-right: 10px">上传 tex_json 文件: </span>
<nz-upload [nzShowUploadList]="false" nzAccept="application/json" [nzAction]="uploadUrl" [nzData]="uploadData"
(nzChange)="texJsonHandleChange($event)">
<button nz-button><i nz-icon nzType="upload"></i><span>Upload</span></button>
</nz-upload>
<i *ngIf="isTexJsonLoading" style="margin-left: 10px;" nz-icon [nzType]="'loading'"></i>
<span *ngIf="texJsonData && texJsonData['name']" style="margin-left: 10px"><u> {{texJsonData['name']}} </u></span>
</div>
<div class="anima-upload-btn">
<span style="margin-right: 10px">上传 tex_png 文件: </span>
<nz-upload [nzShowUploadList]="false" nzAccept="image/*" [nzAction]="uploadUrl" [nzData]="uploadData"
(nzChange)="texPngHandleChange($event)">
<button nz-button><i nz-icon nzType="upload"></i><span>Upload</span></button>
</nz-upload>
<i *ngIf="isTexPngLoading" style="margin-left: 10px;" nz-icon [nzType]="'loading'"></i>
<span *ngIf="texPngData && texPngData['name']" style="margin-left: 10px"><u> {{texPngData['name']}} </u></span>
</div>
<div class="anima-upload-btn" *ngIf="animaNames && animaNames.length > 0">
提示:需包含动画: {{animaNames.toString()}}.
</div>
</nz-modal>
</div>
\ No newline at end of file
@import '../../style/common_mixin.css';
.p-image-uploader {
position: relative;
display: block;
width: 100%;
height: 0;
padding-bottom: 56.25%;
.p-box {
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
border: 2px dashed #ddd;
border-radius: 0.5rem;
background-color: #fafafa;
text-align: center;
color: #aaa;
.p-upload-icon {
text-align: center;
margin: auto;
.anticon-upload {
color: #888;
font-size: 5rem;
}
.p-progress-bar {
position: relative;
width: 20rem;
height: 1.5rem;
border: 1px solid #ccc;
border-radius: 1rem;
.p-progress-bg {
background-color: #1890ff;
border-radius: 1rem;
height: 100%;
}
.p-progress-value {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
text-shadow: 0 0 4px #000;
color: white;
text-align: center;
font-size: 0.9rem;
line-height: 1.5rem;
}
}
}
.p-preview {
width: 100%;
height: 100%;
background-size: contain;
background-repeat: no-repeat;
background-position: 50% 50%;
//background-image: url("https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png");
}
}
.d-flex{
display: flex;
}
}
.p-btn-delete {
position: absolute;
right: -0.5rem;
top: -0.5rem;
width: 2rem;
height: 2rem;
border: 0.2rem solid white;
border-radius: 50%;
font-size: 1.2rem;
background-color: #fb781a;
color: white;
text-align: center;
}
.p-upload-progress-bg {
position: absolute;
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
& .i-text {
position: absolute;
text-align: center;
color: white;
text-shadow: 0 0 2px rgba(0, 0, 0, .85);
}
& .i-bg {
position: absolute;
left: 0;
top: 0;
height: 100%;
background-color: #27b43f;
border-radius: 0.5rem;
}
}
.anima-upload-btn {
padding: 10px;
}
:host ::ng-deep .ant-upload {
display: block;
}
import {ApplicationRef, Component, EventEmitter, Input, OnChanges, OnDestroy, Output} from '@angular/core';
import { NzMessageService, UploadXHRArgs, UploadFile } from 'ng-zorro-antd';
@Component({
selector: 'app-upload-dragon-bone',
templateUrl: './upload-dragon-bone.component.html',
styleUrls: ['./upload-dragon-bone.component.scss']
})
export class UploadDragonBoneComponent implements OnDestroy, OnChanges {
uploading = false;
progress = 0;
@Input()
btnName = '配置龙骨动画';
@Input()
animaNames = [];
@Input()
skeJsonData = {};
@Input()
texJsonData = {};
@Input()
texPngData = {};
@Output()
save = new EventEmitter();
@Output()
refreshEmitter = new EventEmitter();
// @Input()
// picUrl;
// @Input()
// canDelete = false;
// @Output()
// imageUploaded = new EventEmitter();
// @Output()
// imageUploadFailure = new EventEmitter();
// @Output()
// delete = new EventEmitter();
// @Input()
// picItem = null;
// @Input()
// iconSize = 2;
// @Input()
// TIP = 'Click here to upload image';
// @Input()
// disableUpload = false;
uploadUrl;
uploadData;
animaPanelVisible = false;
isSkeJsonLoading = false;
isTexJsonLoading = false;
isTexPngLoading = false;
constructor(private appRef: ApplicationRef, 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() {
}
setAnimaBtnClick() {
this.animaPanelVisible = true;
this.refresh();
}
animaPanelCancel() {
this.animaPanelVisible = false;
this.refresh();
}
animaPanelOk() {
this.sendItemDragonBoneData();
this.animaPanelVisible = false;
this.refresh();
}
sendItemDragonBoneData() {
const data = {};
data['skeJsonData'] = this.skeJsonData;
data['texJsonData'] = this.texJsonData;
data['texPngData'] = this.texPngData;
this.save.emit(data);
}
skeJsonHandleChange(e) {
console.log('e: ', e);
switch (e.type) {
case 'start':
this.isSkeJsonLoading = true;
break;
case 'success':
this.skeJsonData['url'] = e.file.response.url;
this.skeJsonData['name'] = e.file.name;
this.nzMessageService.success('上传成功');
this.isSkeJsonLoading = false;
break;
case 'progress':
break;
}
}
texJsonHandleChange(e) {
console.log('e: ', e);
switch (e.type) {
case 'start':
this.isTexJsonLoading = true;
break;
case 'success':
this.texJsonData['url'] = e.file.response.url;
this.texJsonData['name'] = e.file.name;
this.nzMessageService.success('上传成功');
this.isTexJsonLoading = false;
break;
case 'progress':
break;
}
}
texPngHandleChange(e) {
console.log('e: ', e);
switch (e.type) {
case 'start':
this.isTexPngLoading = true;
break;
case 'success':
this.texPngData['url'] = e.file.response.url;
this.texPngData['name'] = e.file.name;
this.nzMessageService.success('上传成功');
this.isTexPngLoading = false;
break;
case 'progress':
break;
}
}
/**
* 刷新 渲染页面
*/
refresh() {
// this.refreshEmitter.emit();
setTimeout(() => {
this.appRef.tick();
}, 1);
}
closePanel() {
console.log(' in closePanel ');
this.refresh();
}
ngOnDestroy() {
}
}
......@@ -42,7 +42,24 @@ export class UploadImageWithPreviewComponent implements OnDestroy, OnChanges {
this.uploadData = data;
};
this.setUploadUrl();
}
setUploadUrl() {
if (!this.uploadUrl) {
this.uploadUrl = (<any> window).courseware.uploadUrl();
this.uploadData = (<any> window).courseware.uploadData();
setTimeout(() => {
this.setUploadUrl();
}, 500);
}
}
ngOnChanges() {
if (!this.picItem) {
return;
......
......@@ -6,3 +6,30 @@
height: 100%;
}
.radioPaire {
float: left;
margin: 3px;
border-style: dashed;
border-color: #000;
border-width: 1px;
}
.border {
border-radius: 20px;
border-style: dashed;
padding: 20px;
margin: 20px;
/*width: 500px; */
/*//border-radius: 20px;*/
/*//border-width: 2px;*/
/*//border-color: #000000;*/
}
.border-lite {
border: 2px dashed #ddd;
border-radius: 0.5rem;
padding: 10px;
margin: 10px;
}
<div class="model-content">
<div style="padding: 10px;">
<div style="width: 100%; margin-top: 15px; margin-bottom: 50px;" align="center">
<h2>气泡文本</h2>
<div style="width: 80%; display: flex; justify-content: center; align-items: center;">
<input type="text" nz-input [(ngModel)]="item.title" (blur)="save()" style="margin-top: 5px">
<!-- <app-audio-recorder
style="margin-top: 5px; margin-left: 5px;"
[audioUrl]="item.title_audio_url"
(audioUploaded)="onAudioUploadSuccess($event, 'title_audio_url')"
></app-audio-recorder> -->
</div>
</div>
<app-custom-hot-zone
[bgItem]="item.bgItem"
[hotZoneItemArr]="item.hotZoneItemArr"
[customTypeGroupArr]="customTypeGroupArr"
(save)="saveHotZone(item, $event)"
>
<div style="position: absolute; left: 200px; top: 100px; width: 800px;">
</app-custom-hot-zone>
<!-- <div style="width: 300px;" align='center'>
<span>图1: </span>
<app-upload-image-with-preview
[picUrl]="item.pic_url"
(imageUploaded)="onImageUploadSuccess($event, 'pic_url')">
</app-upload-image-with-preview>
</div>
<div style="width: 300px; margin-top: 5px;" align='center'>
<span>图2: </span>
<app-upload-image-with-preview
[picUrl]="item.pic_url_2"
(imageUploaded)="onImageUploadSuccess($event, 'pic_url_2')">
</app-upload-image-with-preview>
</div>
<input type="text" nz-input [(ngModel)]="item.text" (blur)="save()">
<div style="width: 300px; margin-top: 15px;">
<span>文本: </span>
<input type="text" nz-input [(ngModel)]="item.text" (blur)="save()">
</div>
<app-upload-image-with-preview
[picUrl]="item.pic_url"
(imageUploaded)="onImageUploadSuccess($event, 'pic_url')"
></app-upload-image-with-preview>
<div style="margin-top: 5px">
<span>音频: </span>
<app-audio-recorder
[audioUrl]="item.audio_url"
(audioUploaded)="onAudioUploadSuccess($event, 'audio_url')"
></app-audio-recorder>
</div> -->
<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>
</div>
</div>
\ No newline at end of file
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';
import { JsonPipe } from '@angular/common';
@Component({
......@@ -10,22 +10,96 @@ import {Component, EventEmitter, Input, OnDestroy, OnChanges, OnInit, Output, Ap
export class FormComponent implements OnInit, OnChanges, OnDestroy {
// 储存数据用
saveKey = "test_0011";
saveKey = "pu_16";
// 储存对象
item;
customTypeGroupArr = [
{
name: '遮照图片',
pic: true,
isShowArrowAll: true,
// rect: true,
// animaSmall: true,
// audio: true,
},
{
name: 'Open按钮',
point: true,
// animaSmall: true,
// audio: true,
},
// {
// name: '发音图片',
// pic: true,
// audio: true,
// },
// {
// name: '发音区块',
// rect: true,
// audio: true,
// },
// {
// name: '变化文本',
// action: {
// type: 'text',
// option: [
// ['fontColor', '#000000'],
// ['fontSize', '100'],
// ['opacity', '0', '100']
// ]
// },
// },
// {
// name: '变化图片',
// action: {
// type: 'pic',
// option: [
// // ['scale', '1'],
// ['opacity', '0', '100']
// ]
// },
// },
// {
// name: '变化动画',
// action: {
// type: 'anima',
// option: [
// // ['scale', '1'],
// ['opacity', '0', '100']
// ]
// },
// },
]
constructor(private appRef: ApplicationRef, private changeDetectorRef: ChangeDetectorRef) {
constructor(private appRef: ApplicationRef,private changeDetectorRef: ChangeDetectorRef) {
}
createShell() {
this.item.wordList.push({
word: '',
audio: '',
backWord: '',
backWordAudio: '',
});
this.save();
}
removeShell(idx) {
this.item.wordList.splice(idx, 1);
this.save();
}
ngOnInit() {
this.item = {};
// 获取存储的数据
(<any> window).courseware.getData((data) => {
(<any>window).courseware.getData((data) => {
if (data) {
this.item = data;
......@@ -37,20 +111,34 @@ export class FormComponent implements OnInit, OnChanges, OnDestroy {
this.refresh();
}, this.saveKey);
}
ngOnChanges() {
}
ngOnDestroy() {
}
init() {
}
init() {
onSaveCustomAction(e) {
console.log('e:', e);
this.item.customAction = e;
this.save();
}
saveHotZone(group, e) {
console.log('e: ', e);
const {bgItem, hotZoneItemArr} = e;
group.bgItem = bgItem;
group.hotZoneItemArr = hotZoneItemArr;
this.save();
}
......@@ -60,8 +148,8 @@ export class FormComponent implements OnInit, OnChanges, OnDestroy {
*/
onImageUploadSuccess(e, key) {
this.item[key] = e.url;
this.save();
this.item[key] = e.url;
this.save();
}
/**
......@@ -69,19 +157,28 @@ export class FormComponent implements OnInit, OnChanges, OnDestroy {
* @param e
*/
onAudioUploadSuccess(e, key) {
this.item[key] = e.url;
this.save();
}
onWordAudioUploadSuccess(e, idx) {
this.item.wordList[idx].audio = e.url;
this.save();
}
onBackWordAudioUploadSuccess(e, idx) {
this.item.wordList[idx].backWordAudio = e.url;
this.save();
}
/**
* 储存数据
*/
save() {
(<any> window).courseware.setData(this.item, null, this.saveKey);
(<any>window).courseware.setData(this.item, null, this.saveKey);
this.refresh();
console.log('this.item = ' + JSON.stringify(this.item));
}
/**
......@@ -93,5 +190,4 @@ export class FormComponent implements OnInit, OnChanges, OnDestroy {
}, 1);
}
}
}
\ No newline at end of file
......@@ -77,7 +77,9 @@ export class MySprite extends Sprite {
_offCtx;
isCircleStyle = false; // 切成圆形
parent;
_maskSpr;
_maskSprArr = [];
_maskType = "destination-in" // destination-out
init(imgObj = null, anchorX: number = 0.5, anchorY: number = 0.5) {
......@@ -114,16 +116,20 @@ export class MySprite extends Sprite {
this._radius = r;
}
setMaskSpr(spr) {
this._maskSpr = spr;
addMaskSpr(spr) {
this._maskSprArr.push(spr);
this._createOffCtx();
}
setMaskType(t) {
this._maskType = t;
}
_createOffCtx() {
if (!this._offCtx) {
this._offCanvas = document.createElement('canvas'); // 创建一个新的canvas
this.width = this._offCanvas.width = this.width; // 创建一个正好包裹住一个粒子canvas
this.height = this._offCanvas.height = this.height;
this._offCanvas.width = this.width; // 创建一个正好包裹住一个粒子canvas
this._offCanvas.height = this.height;
this._offCtx = this._offCanvas.getContext('2d');
}
}
......@@ -220,12 +226,22 @@ export class MySprite extends Sprite {
this._offCtx.clearRect(0, 0, this.width, this.height);
this._offCtx.drawImage(this.img, 0, 0);
if (this._maskSpr) {
this._offCtx.globalCompositeOperation = 'destination-in';
this._offCtx.drawImage(this._maskSpr.img, this._maskSpr.x + this._maskSpr._offX - this._offX , this._maskSpr.y + this._maskSpr._offY - this._offY);
this._offCtx.globalCompositeOperation = this._maskType;
if (this._maskSprArr && this._maskSprArr.length > 0) {
for (let i=0; i<this._maskSprArr.length; i++) {
this._maskSprArr[i].ctx = this._offCtx;
this._maskSprArr[i].update();
}
}
this.ctx.drawImage(this._offCanvas, this._offX, this._offY);
this._offCtx.restore();
......@@ -822,8 +838,10 @@ export class RichTextOld extends Label {
export class RichText extends Label {
disH = 30;
disH = 10;
offW = 10;
row = 1;
textBaseline = "middle";
constructor(ctx?: any) {
super(ctx);
......@@ -831,7 +849,17 @@ export class RichText extends Label {
// this.dataArr = dataArr;
}
getLineNum() {
this.drawSelf();
return this.row;
}
getAreaHeight() {
this.drawSelf();
const tmpTextH = this.row * this.fontSize;
const tmpDisH = (this.row - 1) * this.disH
return tmpTextH + tmpDisH;
}
drawText() {
......@@ -842,7 +870,7 @@ export class RichText extends Label {
this.ctx.font = `${this.fontSize}px ${this.fontName}`;
this.ctx.textAlign = this.textAlign;
this.ctx.textBaseline = 'middle';
this.ctx.textBaseline = this.textBaseline;
this.ctx.fontWeight = this.fontWeight;
this.ctx.fillStyle = this.fontColor;
......@@ -868,9 +896,11 @@ export class RichText extends Label {
}
}
row.push(temp);
this.row = row.length;
const x = 0;
const y = -row.length * disH / 2;
const y = 0//-row.length * disH / 2;
// for (let b = 0 ; b < row.length; b++) {
// this.ctx.strokeText(row[b], x, y + ( b + 1 ) * disH ); // 每行字体y坐标间隔20
// }
......@@ -954,9 +984,31 @@ export class ShapeRect extends MySprite {
drawShape() {
this.ctx.fillStyle = this.fillColor;
this.ctx.fillRect(this._offX, this._offY, this.width, this.height);
if (this._offCtx) {
this._offCtx.save();
this._offCtx.clearRect(0, 0, this.width, this.height);
this._offCtx.fillStyle = this.fillColor;
this._offCtx.fillRect(this._offX, this._offY, this.width, this.height);
this._offCtx.globalCompositeOperation = this._maskType;
if (this._maskSprArr && this._maskSprArr.length > 0) {
for (let i=0; i<this._maskSprArr.length; i++) {
this._maskSprArr[i].ctx = this._offCtx;
this._maskSprArr[i].update();
}
}
this.ctx.drawImage(this._offCanvas, this._offX, this._offY);
this._offCtx.restore();
} else {
this.ctx.fillStyle = this.fillColor;
this.ctx.fillRect(this._offX, this._offY, this.width, this.height);
}
}
......
......@@ -14,6 +14,5 @@
@font-face
{
font-family: 'BRLNSDB';
src: url("../../assets/font/BRLNSDB.TTF") ;
src: url("../../assets/play/font/BRLNSDB_1.TTF")
}
<span style="font-family:'BRLNSDB'" ></span>
<div class="game-container" #wrap>
<canvas id="canvas" #canvas></canvas>
</div>
import {Component, ElementRef, ViewChild, OnInit, Input, OnDestroy, HostListener} from '@angular/core';
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, RichText,
} from './Unit';
import {res, resAudio} from './resources';
import { res, resAudio } from './resources';
import {Subject} from 'rxjs';
import {debounceTime} from 'rxjs/operators';
import { Subject } from 'rxjs';
import { debounceTime } from 'rxjs/operators';
import * as _ from 'lodash';
import TWEEN from '@tweenjs/tween.js';
......@@ -21,23 +26,38 @@ import TWEEN from '@tweenjs/tween.js';
styleUrls: ['./play.component.css']
})
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', { static: true }) canvas: ElementRef;
@ViewChild('wrap', { static: true }) 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,137 +69,1322 @@ export class PlayComponent implements OnInit, OnDestroy {
animationId: any;
winResizeEventStream = new Subject();
audioObj = {};
audioObj = {};
renderArr;
mapScale = 1;
canvasLeft;
canvasTop;
canvasLeft;
canvasTop;
canTouch = true;
KEY = 'pu_16';
// -----
picArr;
titleLabel;
light;
particleLayer;
shadowArr;
answerTarget;
answerCurrent;
bgRect;
starBgArr;
clickedSuccessArr;
pageLabel;
leftBtn;
rightBtn;
bgLayer;
curPageIndex;
hotZoneArr;
picIndex = 0;
bgArr;
endPageArr;
gameEndFlag;
showPetalFlag;
bg;
@HostListener('window:resize', ['$event'])
onResize(event) {
this.winResizeEventStream.next();
}
ngOnInit() {
const getData = (<any>window).courseware.getData;
getData((data) => {
if (data && typeof data == 'object') {
this.data = { contentObj: data };
} else {
this.initDefaultData();
}
console.log('data:', data);
if (!this.data) {
this.data.contentObj = {};
}
this.initAudio();
this.initImg();
this.initListener();
}, this.KEY);
//
// // this.initAudio();
// this.initImg();
// this.initListener();
}
initDefaultData() {
const data = { "bgItem": { "url": "http://staging-teach.cdn.ireadabc.com/92494971d4791dc82ea2e6a2608a2499.jpeg", "rect": { "x": 279.14, "y": 0, "width": 964.72, "height": 572 } }, "hotZoneItemArr": [{ "id": "1618278861641", "index": 0, "itemType": "rect", "fontScale": 1.18984375, "imgScale": 1, "mapScale": 1.18984375, "gIdx": "0", "rect": { "x": 171.86, "y": 421, "width": 341, "height": 122 } }, { "id": "1618278871717", "index": 1, "itemType": "rect", "fontScale": 1.18984375, "imgScale": 1, "mapScale": 1.18984375, "gIdx": "0", "rect": { "x": 559.86, "y": 225, "width": 293, "height": 156 } }], "title": "qipao qipao qipao qipao qipao qipao ." };
this.data = { contentObj: data };
return;
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);
}
//
// const picArr = [];
// for (let i = 0; i < 2; i++) {
// picArr.push({
// 'pic_url': 'assets/play/default/pic.jpg',
// 'audio_url': 'assets/play/default/audio.mp3'
// });
// }
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 addAudio = (key) => {
// const audioUrl = contentObj[key];
// if (audioUrl) {
// const audio = new Audio();
// audio.src = audioUrl;
// audio.load();
// this.audioObj[key] = audio;
// }
// }
//
// for (let i = 0; i < 4; i ++) {
// const key = i + '_audio_url';
// addAudio(key);
// }
//
// addAudio('audio_url');
//
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('open', this.rawAudios.get('open'), 0.5);
// addOneAudio('cow_start', this.rawAudios.get('cow_start'), 1);
// addOneAudio('eat', this.rawAudios.get('eat'), 1);
// addOneAudio('grass', this.rawAudios.get('grass'), 1);
// addOneAudio('happy', this.rawAudios.get('happy'), 1);
// addOneAudio('right', this.rawAudios.get('right'), 1);
// addOneAudio('wrong', this.rawAudios.get('wrong'), 1);
//
// const titleUrl = this.data.contentObj.title_audio_url;
// if (titleUrl) {
//
// this.titleAudio.src = titleUrl;
// this.titleAudio.load();
// }
// this.bgAudio.src = 'assets/bat-mail/music/bg.mp3';
// this.bgAudio.load();
// this.bgAudio.loop = true;
// this.bgAudio.volume = 0.5;
//
// this.wrongAudio.src = 'assets/common/music/wrong.mp3';
// this.wrongAudio.load();
//
// this.rightAudio.src = 'assets/common/music/right.mp3';
// this.rightAudio.load();
//
// this.successAudio.src = 'assets/magic-hat/music/finish.mp3';
// this.successAudio.load();
//
// this.successAudio.onended = () => {
// // this.showSuccessAudio();
// };
}
initImg() {
const contentObj = this.data.contentObj;
if (contentObj) {
const addPicUrl = (url) => {
if (url) {
this.rawImages.set(url, url);
}
};
let arr = this.data.contentObj.hotZoneItemArr;
if (arr) {
for (let i = 0; i < arr.length; i++) {
console.log('arr[i].pic_url: ', arr[i].pic_url);
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.update();
});
}
initFontImg() {
// const fontbaseUrlW = 'assets/mechanical/letter/';
// const fontDataW = {};
//
// let num = 97;
// for (let i = 0; i < 26; i++) {
//
// const key = String.fromCharCode(num + i); // 'a'
// const url = fontbaseUrlW + key + '.png';
//
// this.rawImages.set(url, url);
// fontDataW[key] = url;
// }
//
//
// this.fontDataW = fontDataW;
}
setfontData() {
// for (let key in this.fontDataW) {
// this.fontDataW[key] = this.images.get(this.fontDataW[key]);
// }
}
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.initTitle();
// this.initPic();
// this.initTitle();
// this.initLight();
// this.refreshAnswerNum();
this.test();
}
test() {
}
curDialog;
initTitle() {
const dialogSmall = new MySprite();
dialogSmall.init(this.images.get("dialog_small"))
dialogSmall.x = this.canvasWidth / 2;
dialogSmall.y = ( dialogSmall.height / 2 + 20 ) * dialogSmall.scaleY;
this.renderArr.push(dialogSmall);
const dialogBig = new MySprite();
dialogBig.init(this.images.get("dialog_big"))
dialogBig.x = this.canvasWidth / 2;
dialogBig.y = ( dialogBig.height / 2 + 20 ) * dialogBig.scaleY;
this.renderArr.push(dialogBig);
dialogSmall.setScaleXY(this.mapScale);
dialogBig.setScaleXY(this.mapScale);
const label = new Label();
label.fontSize = 35;
label.fontName = 'BRLNSDB';
label.textAlign = 'center';
// label.setMaxSize(this.canvasWidth * 0.9);
// label.x = this.canvasWidth / 2;
// label.y = this.canvasHeight / 2;
label.fontColor = '#000000';
label.text = this.data.contentObj.title || "";
dialogSmall.addChild(label);
dialogSmall['label'] = label;
label.refreshSize();
const richText = new RichText();
richText.fontSize = 40;
richText.setMaxSize(dialogBig.width * 0.92);
richText.text = label.text;
richText.fontColor = '#000000'
richText.fontName = 'BRLNSDB';
richText.width = dialogBig.width * 0.92;
richText.disH = 10;
richText.x = -richText.width / 2 + 15;
// richText.textAlign = "center";
richText.textBaseline = "top";
const h = richText.getAreaHeight();
richText.y = -h / 2 - dialogBig.height / 2 + richText.fontSize / 2 + 3;
dialogBig.addChild(richText);
dialogBig['label'] = richText;
if (label.width > dialogSmall.width * 0.92) {
dialogSmall.visible = false;
this.curDialog = dialogBig;
} else {
dialogBig.visible = false;
this.curDialog = dialogSmall;
}
// this.renderArr.push(label);
}
_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) / 2;
label.fontColor = '#fff143';
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;
// const textBg = new MySprite();
// textBg.init(this.images.get('text_bg'));
// textBg.setScaleXY(this.mapScale);
// textBg.x = label.x;
// textBg.y = label.y - textBg.height / 2 * textBg.scaleY - disH / 2;
// this.renderArr.push(textBg);
//
// label.y += label.height / 2 * label.scaleY + disH / 2;
//
//
// const pageLabel = new Label();
// pageLabel.text = '0 / 0';
// pageLabel.fontName = 'BRLNSDB';
// pageLabel.fontColor = '#ffffff';
// pageLabel.textAlign = 'center';
// pageLabel.fontSize = 24;
// 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);
}
}
}
}
showAudio() {
const data = this.picArr[this.curPageIndex];
const audio = this.audioObj[data.audio_url];
if (audio) {
audio.play();
}
}
initPic() {
}
initLight() {
// const light = new MySprite();
// light.init(this.images.get('light'));
// light.visible = false;
// this.light = light;
// this.renderArr.push(light);
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 ShapeRect();
bg.setSize(this.canvasWidth, this.canvasHeight);
bg.fillColor = '#8b6a48'
// bg.x = this.canvasWidth / 2;
// bg.y = this.canvasHeight / 2;
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 / 2;
const maxW = this.canvasWidth;
const maxH = this.canvasHeight;
let sx = maxW / bgItem.width;
let sy = maxH / bgItem.height;
let 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;
}
mapDown(event) {
if (!this.canTouch) {
return;
}
if (this.checkClickTarget(this.openBtn)) {
this.openBtnClicked();
this.canTouch = false;
}
// for (let i = 0; i < this.hotZoneArr.length; i ++) {
// if (this.checkClickTarget(this.hotZoneArr[i])) {
// this.clickHotZone(i);
// return;
// }
// }
// this.clickWrong();
}
mapMove(event) {
}
mapUp(event) {
}
openBtnClicked() {
console.log(' cliced open btn');
this.showBgPic();
}
showBgPic() {
const time = 0.7;
tweenChange(this.maskBg, { alpha: 0 }, time, () => {
this.maskBg.visible = false;
}, TWEEN.Easing.Cubic.Out)
tweenChange(this.openBtn, { alpha: 0 }, time, () => {
this.openBtn.visible = false;
}, TWEEN.Easing.Cubic.Out)
this.curDialog.label.visible = false;
tweenChange(this.curDialog, { alpha: 0 }, time / 3, () => {
this.curDialog.visible = false;
}, TWEEN.Easing.Cubic.Out)
this.playAudio('open')
}
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(() => {
// if (this.curPageIndex >= this.picArr.length) {
// this.gameEnd();
// return;
// }
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);
}
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);
}
}
maskBg;
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;
console.log('arr: ', arr);
const maskBg = new ShapeRect();
maskBg.setSize(this.canvasWidth, this.canvasHeight);
// maskBg.x = curBgRect.x;
// maskBg.y = curBgRect.y;
maskBg.fillColor = "#000000"
this.maskBg = maskBg;
this.renderArr.push(maskBg);
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;
const hotZone = this.getHotZoneItem(data);
// hotZone.alpha = 0.5;
// this.hotZoneArr.push(hotZone);
}
}
saveKey = 'test_0011';
openBtn;
getHotZoneItem(data) {
console.log(' item data: ', data);
const saveRect = data.rect;
btnLeft;
btnRight;
pic1;
pic2;
if (data.gIdx == '0') {
canTouch = true;
//遮照
const pic = new MySprite();
pic.init(this.images.get(data.pic_url));
pic.scaleX = saveRect.width / pic.width;
pic.scaleY = saveRect.height / pic.height;
pic.x = saveRect.x + saveRect.width / 2;
pic.y = saveRect.y + saveRect.height / 2;
pic['data'] = data;
curPic;
this.maskBg.setMaskType("destination-out");
this.maskBg.addMaskSpr(pic);
@HostListener('window:resize', ['$event'])
onResize(event) {
this.winResizeEventStream.next();
}
return pic;
} else {
ngOnInit() {
//open按钮
this.data = {};
const openBtn = new MySprite();
openBtn.init(this.images.get("open"))
// 获取数据
const getData = (<any> window).courseware.getData;
getData((data) => {
openBtn.x = saveRect.x + saveRect.width / 2;
openBtn.y = saveRect.y + saveRect.height / 2;
openBtn['data'] = data;
if (data && typeof data == 'object') {
this.data = data;
}
// console.log('data:' , data);
openBtn.setScaleXY(this.mapScale);
this.openBtn = openBtn;
this.renderArr.push(openBtn);
}
// 初始化 各事件监听
this.initListener();
// 若无数据 则为预览模式 需要填充一些默认数据用来显示
this.initDefaultData();
// 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.fillColor = '#ff0000';
// item['data'] = data;
// 初始化 音频资源
this.initAudio();
// 初始化 图片资源
this.initImg();
// 开始预加载资源
this.load();
// this.renderArr.push(item);
// return item;
}
}, this.saveKey);
showEndPetal() {
this.endPageArr = [];
this.showPetalFlag = true;
this.addPetal();
}
ngOnDestroy() {
window['curCtx'] = null;
window.cancelAnimationFrame(this.animationId);
this.cleanAudio();
stopEndPetal() {
this.endPageArr = [];
this.showPetalFlag = false;
}
addPetal() {
cleanAudio() {
if (this.audioObj) {
for (const key in this.audioObj) {
this.audioObj[key].pause();
}
if (!this.showPetalFlag) {
return;
}
}
load() {
const petal = this.getPetal();
this.endPageArr.push(petal);
// 预加载资源
this.loadResources().then(() => {
window["air"].hideAirClassLoading(this.saveKey, this.data);
this.init();
this.update();
moveItem(petal, petal.x, this.canvasHeight + petal.height * petal.scaleY, petal['time'], () => {
removeItemFromArr(this.endPageArr, petal);
});
}
rotateItem(petal, petal['tr'], petal['time']);
init() {
setTimeout(() => {
this.addPetal();
}, 100);
this.initCtx();
this.initData();
this.initView();
}
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;
this.ctx = this.canvas.nativeElement.getContext('2d');
this.canvas.nativeElement.width = this.canvasWidth;
this.canvas.nativeElement.height = this.canvasHeight;
getPetal() {
window['curCtx'] = this.ctx;
window['curImages'] = this.images;
}
const petal = new MySprite(this.ctx);
const id = Math.ceil(Math.random() * 3);
petal.init(this.images.get('petal_' + id));
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;
updateItem(item) {
if (item) {
item.update();
}
}
let randomTR = 360 * Math.random(); // - 180;
if (Math.random() < 0.5) { randomTR *= -1; }
petal['tr'] = randomTR;
updateArr(arr) {
if (!arr) {
return;
}
for (let i = 0; i < arr.length; i++) {
arr[i].update(this);
}
return petal;
}
initListener() {
this.winResizeEventStream
......@@ -220,6 +1425,7 @@ export class PlayComponent implements OnInit, OnDestroy {
firstTouch = false;
removeMouseListener();
}
console.log('touch down');
setMxMyByTouch(e);
this.mapDown(e);
};
......@@ -237,6 +1443,7 @@ export class PlayComponent implements OnInit, OnDestroy {
firstTouch = false;
removeTouchListener();
}
console.log('mouse down');
setMxMyByMouse(e);
this.mapDown(e);
};
......@@ -301,6 +1508,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) => {// 预加载图片
......@@ -314,7 +1558,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(() => {
......@@ -340,8 +1584,9 @@ export class PlayComponent implements OnInit, OnDestroy {
preloadAudio(url) {
return new Promise((resolve, reject) => {
const audio = new Audio();
resolve({})
audio.oncanplay = (a) => {
resolve();
//resolve();
};
audio.onerror = () => {
reject();
......@@ -360,8 +1605,6 @@ export class PlayComponent implements OnInit, OnDestroy {
checkClickTarget(target) {
const rect = target.getBoundingBox();
......@@ -394,297 +1637,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"],
['bg_left', "assets/play/bg_left.png"],
['bg_right', "assets/play/bg_right.png"],
['bg', "assets/play/bg.png"],
['open', "assets/play/open.png"],
['dialog_big', "assets/play/dialog_big.png"],
['dialog_small', "assets/play/dialog_small.png"],
// ['text_bg', "assets/play/text_bg.png"],
];
......@@ -11,7 +15,7 @@ const res = [
const resAudio = [
['click', "assets/play/music/click.mp3"],
['open', "assets/play/music/open.mp3"],
];
......
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