Commit a351942f authored by limingzhe's avatar limingzhe

表单完成 play展示输入页面

parent 9f3a2900
...@@ -128,5 +128,8 @@ ...@@ -128,5 +128,8 @@
} }
} }
}, },
"defaultProject": "ng-template-generator" "defaultProject": "ng-template-generator",
} "cli": {
"analytics": false
}
}
\ No newline at end of file
...@@ -24,6 +24,9 @@ import {AudioRecorderComponent} from './common/audio-recorder/audio-recorder.com ...@@ -24,6 +24,9 @@ import {AudioRecorderComponent} from './common/audio-recorder/audio-recorder.com
import { FontAwesomeModule, FaIconLibrary } from '@fortawesome/angular-fontawesome'; import { FontAwesomeModule, FaIconLibrary } from '@fortawesome/angular-fontawesome';
import { fas } from '@fortawesome/free-solid-svg-icons'; import { fas } from '@fortawesome/free-solid-svg-icons';
import { far } from '@fortawesome/free-regular-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';
import { SubTemplateComponent } from './common/sub-template/sub-template.component';
registerLocaleData(zh); registerLocaleData(zh);
...@@ -40,8 +43,11 @@ registerLocaleData(zh); ...@@ -40,8 +43,11 @@ registerLocaleData(zh);
TimePipe, TimePipe,
UploadVideoComponent, UploadVideoComponent,
CustomHotZoneComponent, CustomHotZoneComponent,
SubTemplateComponent,
PlayerContentWrapperComponent PlayerContentWrapperComponent,
CustomActionComponent,
UploadDragonBoneComponent
], ],
imports: [ imports: [
......
...@@ -35,7 +35,8 @@ ...@@ -35,7 +35,8 @@
<ng-template #truthyTemplate > <ng-template #truthyTemplate >
<div class="btn-delete" (click)="onBtnDeleteAudio()"> <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> </div>
</ng-template> </ng-template>
......
...@@ -26,7 +26,7 @@ export class AudioRecorderComponent implements OnInit, OnChanges, OnDestroy { ...@@ -26,7 +26,7 @@ export class AudioRecorderComponent implements OnInit, OnChanges, OnDestroy {
uploadData; uploadData;
@Input() @Input()
needRemove = false; needRemove = true;
@Input() @Input()
audioItem: any = null; audioItem: any = null;
...@@ -62,8 +62,25 @@ export class AudioRecorderComponent implements OnInit, OnChanges, OnDestroy { ...@@ -62,8 +62,25 @@ export class AudioRecorderComponent implements OnInit, OnChanges, OnDestroy {
this.uploadUrl = url; this.uploadUrl = url;
this.uploadData = data; 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() { init() {
this.playIcon = 'play'; this.playIcon = 'play';
this.isPlaying = false; this.isPlaying = false;
...@@ -157,6 +174,7 @@ export class AudioRecorderComponent implements OnInit, OnChanges, OnDestroy { ...@@ -157,6 +174,7 @@ export class AudioRecorderComponent implements OnInit, OnChanges, OnDestroy {
onBtnDeleteAudio() { onBtnDeleteAudio() {
this.audioUrl = null; this.audioUrl = null;
this.audioUploaded.emit({});
this.audioRemoved.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 { ...@@ -329,6 +329,7 @@ export class MySprite extends Sprite {
this.scaleX = this.scaleY = value; this.scaleX = this.scaleY = value;
} }
getBoundingBox() { getBoundingBox() {
const getParentData = (item) => { const getParentData = (item) => {
...@@ -1956,6 +1957,10 @@ export class HotZoneItem extends MySprite { ...@@ -1956,6 +1957,10 @@ export class HotZoneItem extends MySprite {
audio_url; audio_url;
pic_url; pic_url;
text; text;
gIdx;
isAnimaStyle = false;
private _itemType; private _itemType;
private shapeRect: ShapeRect; private shapeRect: ShapeRect;
...@@ -2056,7 +2061,10 @@ export class HotZoneItem extends MySprite { ...@@ -2056,7 +2061,10 @@ export class HotZoneItem extends MySprite {
this.hideLabel(); this.hideLabel();
} }
setAnimaStyle(isAnimaStyle) {
this.isAnimaStyle = isAnimaStyle;
console.log('in setAnimaStyle ')
}
drawArrow() { drawArrow() {
if (!this.arrow) { return; } if (!this.arrow) { return; }
...@@ -2068,13 +2076,16 @@ export class HotZoneItem extends MySprite { ...@@ -2068,13 +2076,16 @@ export class HotZoneItem extends MySprite {
this.arrow.update(); this.arrow.update();
this.arrowTop.x = rect.x + rect.width / 2; if (!this.isAnimaStyle) {
this.arrowTop.y = rect.y; this.arrowTop.x = rect.x + rect.width / 2;
this.arrowTop.update(); 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.x = rect.x + rect.width;
this.arrowRight.update(); this.arrowRight.y = rect.y + rect.height / 2;
this.arrowRight.update();
}
} }
drawFrame() { drawFrame() {
...@@ -2197,10 +2208,155 @@ export class HotZoneLabel extends Label { ...@@ -2197,10 +2208,155 @@ export class HotZoneLabel extends Label {
this.drawFrame(); 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 {
}
export class DragItem extends MySprite {
lineDashFlag = true;
item;
init() {
this.anchorX = 0.5;
this.anchorY = 0.5;
this.initCenterCircle();
}
setSize(w, h) {
this.anchorX = 0.5;
this.anchorY = 0.5;
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 = '#000000';
// rect.alpha = 0.1;
// this.addChild(rect);
}
initCenterCircle() {
const circle = new ShapeCircle(this.ctx);
circle.setRadius(10);
circle.fillColor = '#ffa568'
this.addChild(circle);
this.width = circle.width;
this.height = circle.height;
}
getPosition() {
return {x: this.x, y: this.y};
}
drawLine() {
if (!this.item) {
return;
}
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([4, 4]);
this.ctx.lineWidth = 1;
this.ctx.strokeStyle = '#ffa568';
this.ctx.beginPath();
this.ctx.moveTo( x + w / 2 , y + h / 2 );
this.ctx.lineTo(this.item.x, this.item.y);
// this.ctx.fill();
this.ctx.stroke();
this.ctx.restore();
}
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([4, 4]);
this.ctx.lineWidth = 2;
this.ctx.strokeStyle = '#ffa568';
// 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.drawLine();
// this.drawFrame();
// this.drawArrow();
}
}
}
export class EditorItem extends MySprite { export class EditorItem extends MySprite {
...@@ -2208,6 +2364,8 @@ export class EditorItem extends MySprite { ...@@ -2208,6 +2364,8 @@ export class EditorItem extends MySprite {
arrow: MySprite; arrow: MySprite;
label: Label; label: Label;
text; text;
arrowTop;
arrowRight;
showLabel(text = null) { showLabel(text = null) {
...@@ -2246,6 +2404,13 @@ export class EditorItem extends MySprite { ...@@ -2246,6 +2404,13 @@ export class EditorItem extends MySprite {
this.arrow.load('assets/common/arrow.png', 1, 0); this.arrow.load('assets/common/arrow.png', 1, 0);
this.arrow.setScaleXY(0.06); 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(); this.showLabel();
...@@ -2262,16 +2427,25 @@ export class EditorItem extends MySprite { ...@@ -2262,16 +2427,25 @@ export class EditorItem extends MySprite {
this.hideLabel(); this.hideLabel();
} }
refreshLabelScale() {}
drawArrow() { drawArrow() {
if (!this.arrow) { return; } if (!this.arrow) { return; }
const rect = this.getBoundingBox(); const rect = this.getBoundingBox();
this.arrow.x = rect.x + rect.width; this.arrow.x = rect.x + rect.width;
this.arrow.y = rect.y; this.arrow.y = rect.y;
this.arrow.update(); 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() { drawFrame() {
...@@ -2325,784 +2499,3 @@ export class EditorItem extends MySprite { ...@@ -2325,784 +2499,3 @@ 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;
//
// }
...@@ -32,33 +32,137 @@ ...@@ -32,33 +32,137 @@
<nz-divider style="margin-top: 10px;"></nz-divider> <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"> <div *ngIf="customTypeGroupArr">
<nz-radio-group [ngModel]="it.itemType" (ngModelChange)="radioChange($event, it)"> <nz-radio-group [ngModel]="it.gIdx" (ngModelChange)="customRadioChange($event, it)" style="display: flex; align-items: center; justify-content: center; flex-wrap: wrap;">
<label *ngIf="isHasRect" nz-radio nzValue="rect">矩形</label> <div *ngFor="let group of customTypeGroupArr; let gIdx = index" style="display: flex; ">
<label *ngIf="isHasPic" nz-radio nzValue="pic">图片</label> <label nz-radio nzValue="{{gIdx}}">{{group.name}}</label>
<label *ngIf="isHasText" nz-radio nzValue="text">文本</label> </div>
</nz-radio-group> </nz-radio-group>
</div>
<div *ngIf="it.itemType == 'pic'"> </div>
<app-upload-image-with-preview
[picUrl]="it?.pic_url" <!-- <div *ngIf="!customTypeGroupArr">
(imageUploaded)="onItemImgUploadSuccess($event, it)"> <nz-radio-group [ngModel]="it.itemType" (ngModelChange)="radioChange($event, it)" style="display: flex; align-items: center; justify-content: center">
</app-upload-image-with-preview>
</div> <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>
<div style="width: 100%; margin-top: 5px;"> <div *ngIf="customTypeGroupArr && customTypeGroupArr[it.gIdx]">
<app-audio-recorder
[audioUrl]="it.audio_url" <div *ngIf="customTypeGroupArr[it.gIdx].pic">
(audioUploaded)="onItemAudioUploadSuccess($event, it)" <app-upload-image-with-preview
></app-audio-recorder> [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 *ngIf="customTypeGroupArr[it.gIdx]?.isShowPos" style="display: flex; align-items: center; justify-content: center; margin-top: 5px;">
x: <input type="text" nz-input [(ngModel)]="it.posX" style="width: 50px; margin-right: 15px;" (blur)="saveItemPos(it)">
y: <input type="text" nz-input [(ngModel)]="it.posY" style="width: 50px" (blur)="saveItemPos(it)">
</div>
<div *ngIf="customTypeGroupArr[it.gIdx]?.select" align="center" >
<nz-select [(ngModel)]="it.selectType" nzAllowClear nzPlaceHolder="Choose" style="width: 70%; margin-top: 5px;">
<nz-option *ngFor="let s of customTypeGroupArr[it.gIdx]?.select" [nzValue]="s.value" [nzLabel]="s.label">
</nz-option>
</nz-select>
</div>
<div *ngIf="customTypeGroupArr[it.gIdx]?.label" align="center" style="margin-top: 5px; display: flex; align-items: center; justify-content: center;">
<span style="width: 30%;">{{customTypeGroupArr[it.gIdx].label + ':'}}</span>
<input type="text" nz-input [(ngModel)]="it.labelText" (blur)="saveText(it)">
</div>
<div *ngIf="customTypeGroupArr[it.gIdx]?.isCopy" align="center" style="margin-top: 5px; display: flex; align-items: center; justify-content: center;">
<button nz-button (click)="copyItem(it)" >
<i nz-icon nzType="copy" nzTheme="outline"></i>
复制粘贴
</button>
</div>
</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>
</div> </div>
...@@ -83,12 +187,29 @@ ...@@ -83,12 +187,29 @@
<div class="save-box"> <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()" > (click)="saveClick()" >
<i nz-icon nzType="save"></i> <i nz-icon nzType="save"></i>
Save Save
</button> </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> </div>
...@@ -98,3 +219,52 @@ ...@@ -98,3 +219,52 @@
<label style="opacity: 0; position: absolute; top: 0px; font-family: 'BRLNSR_1'">1</label> <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,6 +81,10 @@ ...@@ -81,6 +81,10 @@
} }
} }
.anima-upload-btn {
padding: 10px;
}
h5 { h5 {
margin-top: 1rem; margin-top: 1rem;
} }
...@@ -89,8 +93,8 @@ h5 { ...@@ -89,8 +93,8 @@ h5 {
@font-face @font-face
{ {
font-family: 'BRLNSR_1'; font-family: 'ahronbd-1';
src: url("/assets/font/BRLNSR_1.TTF") ; src: url("/assets/font/ahronbd-1.ttf") ;
} }
...@@ -105,106 +109,3 @@ h5 { ...@@ -105,106 +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 { import {
ApplicationRef,
ChangeDetectorRef,
Component, Component,
ElementRef, ElementRef,
EventEmitter, EventEmitter,
...@@ -12,10 +14,11 @@ import { ...@@ -12,10 +14,11 @@ import {
} from '@angular/core'; } from '@angular/core';
import {Subject} from 'rxjs'; import {Subject} from 'rxjs';
import {debounceTime} from 'rxjs/operators'; import {debounceTime} from 'rxjs/operators';
import {EditorItem, HotZoneImg, HotZoneItem, HotZoneLabel, Label, MySprite, removeItemFromArr} from './Unit'; import {DragItem, EditorItem, HotZoneImg, HotZoneItem, HotZoneLabel, Label, MySprite, removeItemFromArr, ShapeRect, ShapeRectNew} from './Unit';
import TWEEN from '@tweenjs/tween.js'; import TWEEN from '@tweenjs/tween.js';
import {getMinScale} from "../../play/Unit"; import {getMinScale} from '../../play/Unit';
import {tar} from "compressing"; import {tar} from 'compressing';
import {NzMessageService} from 'ng-zorro-antd';
@Component({ @Component({
...@@ -25,18 +28,14 @@ import {tar} from "compressing"; ...@@ -25,18 +28,14 @@ import {tar} from "compressing";
}) })
export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
@ViewChild('canvas', {static: true}) canvas: ElementRef;
@ViewChild('wrap', {static: true}) wrap: ElementRef;
@Input()
imgItemArr = null;
@Input() @Input()
hotZoneItemArr = null; hotZoneItemArr = null;
@Input() @Input()
hotZoneArr = null; hotZoneArr = null;
@Output()
save = new EventEmitter();
@ViewChild('canvas', {static: true}) canvas: ElementRef;
@ViewChild('wrap', {static: true}) wrap: ElementRef;
@Input() @Input()
isHasRect = true; isHasRect = true;
@Input() @Input()
...@@ -44,16 +43,31 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { ...@@ -44,16 +43,31 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
@Input() @Input()
isHasText = true; isHasText = true;
@Input() @Input()
hotZoneFontObj = { isHasAudio = true;
size: 50, @Input()
name: 'BRLNSR_1', isHasAnima = false;
color: '#8f3758' @Input()
} customTypeGroupArr; // [{name:string, rect:boolean, pic:boolean, text:boolean, audio:boolean, anima:boolean, animaNames:['name1', ..]}, ...]
@Input()
// hotZoneFontObj;
@Input()
isCopyData = false;
hotZoneFontObj;
// hotZoneFontObj = {
// size: 50,
// name: 'ahronbd-1',
// color: '#8f3758'
// }
@Input() @Input()
defaultItemType = 'text'; defaultItemType = 'text';
@Input() @Input()
hotZoneImgSize = 190; hotZoneImgSize = 0;
@Output()
save = new EventEmitter();
saveDisabled = true; saveDisabled = true;
...@@ -86,8 +100,42 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { ...@@ -86,8 +100,42 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
changeSizeFlag = false; changeSizeFlag = false;
changeTopSizeFlag = false; changeTopSizeFlag = false;
changeRightSizeFlag = false; changeRightSizeFlag = false;
animaPanelVisible = false;
constructor() {
uploadUrl;
uploadData;
skeJsonData = {};
texJsonData = {};
texPngData = {};
animaName = '';
curDragonBoneIndex;
curDragonBoneGIdx;
pasteData = '';
isSkeJsonLoading = false;
isTexJsonLoading = false;
isTexPngLoading = false;
isAnimaSmall = false;
savePropertyArr = [
'id',
'gIdx',
'selectType',
'labelText',
'posX',
'posY'
]
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; _bgItem = null;
...@@ -110,11 +158,14 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { ...@@ -110,11 +158,14 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
ngOnInit() { ngOnInit() {
this.initListener(); this.initListener();
// this.init(); // this.init();
this.update(); this.update();
this.refresh();
} }
ngOnDestroy() { ngOnDestroy() {
...@@ -136,10 +187,12 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { ...@@ -136,10 +187,12 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
onItemImgUploadSuccess(e, item) { onItemImgUploadSuccess(e, item) {
item.pic_url = e.url; item.pic_url = e.url;
this.loadHotZonePic(item.pic, e.url); this.loadHotZonePic(item.pic, e.url);
this.refresh();
} }
onItemAudioUploadSuccess(e, item) { onItemAudioUploadSuccess(e, item) {
item.audio_url = e.url; item.audio_url = e.url;
this.refresh();
} }
...@@ -150,37 +203,49 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { ...@@ -150,37 +203,49 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
this.renderArr.push(this.bg); this.renderArr.push(this.bg);
} }
if (!this.bgItem.url) {
this.bgItem.url = 'http://teach.cdn.ireadabc.com/8ebb1858564340ea0936b83e3280ad7d.jpg';
}
const bg = this.bg; const bg = this.bg;
if (this.bgItem.url) { // if (this.bgItem.url) {
bg.load(this.bgItem.url).then(() => { bg.load(this.bgItem.url).then(() => {
const rate1 = this.canvasWidth / bg.width; const rate1 = this.canvasWidth / bg.width;
const rate2 = this.canvasHeight / bg.height; const rate2 = this.canvasHeight / bg.height;
const rate = Math.min(rate1, rate2); const rate = Math.min(rate1, rate2);
bg.setScaleXY(rate); bg.setScaleXY(rate);
bg.x = this.canvasWidth / 2; bg.x = this.canvasWidth / 2;
bg.y = this.canvasHeight / 2; bg.y = this.canvasHeight / 2;
if (callBack) { if (callBack) {
callBack(); callBack();
} }
});
} this.refresh();
});
// }
} }
addBtnClick() { addBtnClick(data=null) {
// this.imgArr.push({}); // this.imgArr.push({});
// this.hotZoneArr.push({}); // this.hotZoneArr.push({});
const item = this.getHotZoneItem(); const item = this.getHotZoneItem(data);
this.hotZoneArr.push(item); this.hotZoneArr.push(item);
this.refreshItem(item);
if (this.customTypeGroupArr) {
this.refreshCustomItem(item);
} else {
this.refreshItem(item);
}
this.refreshHotZoneId(); this.refreshHotZoneId();
...@@ -191,6 +256,7 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { ...@@ -191,6 +256,7 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
const item = this.hotZoneArr.splice(index, 1)[0]; const item = this.hotZoneArr.splice(index, 1)[0];
removeItemFromArr(this.renderArr, item.pic); removeItemFromArr(this.renderArr, item.pic);
removeItemFromArr(this.renderArr, item.textLabel); removeItemFromArr(this.renderArr, item.textLabel);
removeItemFromArr(this.renderArr, item.drag);
this.refreshHotZoneId(); this.refreshHotZoneId();
...@@ -199,6 +265,7 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { ...@@ -199,6 +265,7 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
onImgUploadSuccessByImg(e, img) { onImgUploadSuccessByImg(e, img) {
img.pic_url = e.url; img.pic_url = e.url;
this.refreshImage(img); this.refreshImage(img);
this.refresh();
} }
refreshImage(img) { refreshImage(img) {
...@@ -221,6 +288,7 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { ...@@ -221,6 +288,7 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
} }
} }
this.refresh();
} }
...@@ -245,10 +313,18 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { ...@@ -245,10 +313,18 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
item.anchorX = 0.5; item.anchorX = 0.5;
item.anchorY = 0.5; item.anchorY = 0.5;
item.x = this.canvasWidth / 2; item.x = this.canvasWidth / 2;
item.y = this.canvasHeight / 2; item.y = this.canvasHeight / 2;
item.itemType = this.defaultItemType; item.itemType = this.getDefaultItemType();
item.gIdx = '0';
item['id'] = this.createItemId() // new Date().getTime().toString();
item['data'] = saveData;
console.log('item.x: ', item.x);
if (saveData) { if (saveData) {
...@@ -257,41 +333,203 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { ...@@ -257,41 +333,203 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
item.scaleY = saveRect.height / item.height; item.scaleY = saveRect.height / item.height;
item.x = saveRect.x + saveRect.width / 2; item.x = saveRect.x + saveRect.width / 2;
item.y = saveRect.y + saveRect.height / 2; item.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];
this.savePropertyArr.forEach((key) => {
if (saveData[key]) {
item[key] = saveData[key];
}
})
} }
console.log('item.x:~~ ', item.x);
item.showLineDash(); 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.setItemDrag(item, saveData);
return item;
}
setItemPic(item, saveData) {
console.log('in setItemPic ', saveData);
const pic = new EditorItem(this.ctx);
pic.visible = false; pic.visible = false;
item['pic'] = pic; item['pic'] = pic;
if (saveData && saveData.pic_url) { if (saveData) {
this.loadHotZonePic(pic, saveData.pic_url);
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.x = item.x;
pic.y = item.y; pic.y = item.y;
this.renderArr.push(pic); this.renderArr.push(pic);
}
setItemDrag(item, saveData) {
console.log('in setItemDrag ', saveData);
const dragItem = new DragItem(this.ctx);
dragItem.init();
dragItem.item = item;
item['drag'] = dragItem;
dragItem.visible = false;
dragItem.x = item.x;
dragItem.y = item.y;
this.renderArr.push(dragItem);
if (saveData) {
if (saveData.dragDot) {
dragItem.x = saveData.dragDot.x / saveData.mapScale * this.mapScale;
dragItem.y = saveData.dragDot.y / saveData.mapScale * this.mapScale;
}
}
// console.log('item.itemType: ', item.itemType);
// let w = item.width;
// let h = item.height;
// if (saveData) {
// switch (saveData.itemType) {
// case 'rect':
// w = saveData.rect.width;
// h = saveData.rect.height;
// break;
// case 'pic':
// w = saveData.imgSizeW * saveData.imgScale;
// h = saveData.imgSizeH * saveData.imgScale;;
// break;
// case 'text':
// w = saveData.rect.width;
// h = saveData.rect.height;
// break;
// }
// }
// dragItem.setSize(w, h);
}
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);
}
setItemLabel(item, saveData) {
const textLabel = new HotZoneLabel(this.ctx); const textLabel = new HotZoneLabel(this.ctx);
textLabel.fontSize = this.hotZoneFontObj.size; if (this.hotZoneFontObj) {
textLabel.fontName = this.hotZoneFontObj.name; textLabel.fontSize = this.hotZoneFontObj.size;
textLabel.fontColor = this.hotZoneFontObj.color; textLabel.fontName = this.hotZoneFontObj.name;
textLabel.fontColor = this.hotZoneFontObj.color;
}
textLabel.textAlign = 'center'; textLabel.textAlign = 'center';
// textLabel.setOutline(); // textLabel.setOutline();
// console.log('saveData:', saveData);
item['textLabel'] = textLabel; item['textLabel'] = textLabel;
textLabel.setScaleXY(this.mapScale); textLabel.setScaleXY(this.mapScale);
if (saveData && saveData.text) { if (saveData) {
textLabel.text = saveData.text;
if (saveData.text && this.hotZoneFontObj) {
textLabel.text = saveData.text
}
this.setActionFont(textLabel, saveData['actionData_' + item.gIdx]);
textLabel.refreshSize(); textLabel.refreshSize();
} }
textLabel.x = item.x; textLabel.x = item.x;
textLabel.y = item.y; textLabel.y = item.y;
this.renderArr.push(textLabel); 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';
}
} else {
return this.defaultItemType;
}
}
getPicItem(img, saveData = null) { getPicItem(img, saveData = null) {
...@@ -327,9 +565,11 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { ...@@ -327,9 +565,11 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
item.y = saveRect.y + saveRect.height / 2; item.y = saveRect.y + saveRect.height / 2;
} else { } else {
item.showLineDash(); // item.showLineDash();
} }
item.showLineDash();
console.log('aaa');
}); });
return item; return item;
} }
...@@ -337,6 +577,7 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { ...@@ -337,6 +577,7 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
onAudioUploadSuccessByImg(e, img) { onAudioUploadSuccessByImg(e, img) {
img.audio_url = e.url; img.audio_url = e.url;
this.refresh();
} }
deleteItem(e, i) { deleteItem(e, i) {
...@@ -345,15 +586,111 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { ...@@ -345,15 +586,111 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
this.hotZoneArr.splice(i, 1); this.hotZoneArr.splice(i, 1);
this.refreshHotZoneId(); this.refreshHotZoneId();
this.refresh();
}
// radioChange(e, item) {
// item.itemType = e;
// 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, !group.isFixed);
}
if (group.pic && !group.anima) {
this.showItemPic(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.drag.visible = group.drag;
item.setAnimaStyle(group.animaSmall)
} }
showItemDrag(item) {
item.drag.visible = true;
// item.dragBody.visible = true;
// item.itemType = 'pic';
// this.showArrowTop(item)
}
radioChange(e, item) {
item.itemType = e;
this.refreshItem(item); showItemPic(item) {
item.pic.visible = true;
item.itemType = 'pic';
this.showArrowTop(item)
}
showItemLabel(item) {
item.textLabel.visible = true;
item.itemType = 'text';
this.showArrowTop(item)
}
showItemRect(item, isShowArrowTop = true) {
item.visible = true;
item.itemType = 'rect';
this.showArrowTop(item, isShowArrowTop)
}
// console.log(' in radioChange e: ', e); 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) { refreshItem(item) {
...@@ -368,32 +705,29 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { ...@@ -368,32 +705,29 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
this.setTextState(item); this.setTextState(item);
break; break;
default: default:
this.setNoneState(item);
} }
} }
init() { init() {
console.log('init');
this.initData(); this.initData();
this.initCtx(); this.initCtx();
this.initItem(); this.initItem();
} }
initItem() { initItem() {
this.changeDetectorRef.markForCheck();
this.changeDetectorRef.detectChanges();
if (!this.bgItem) { if (!this.bgItem) {
this.bgItem = {}; this.bgItem = {};
} else { } else {
this.refreshBackground(() => { this.refreshBackground(() => {
// if (!this.imgItemArr) {
// this.imgItemArr = [];
// } else {
// this.initImgArr();
// }
// console.log('aaaaa');
if (!this.hotZoneItemArr) { if (!this.hotZoneItemArr) {
this.hotZoneItemArr = []; this.hotZoneItemArr = [];
...@@ -404,6 +738,7 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { ...@@ -404,6 +738,7 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
}); });
} }
this.refresh();
} }
initHotZoneArr() { initHotZoneArr() {
...@@ -427,6 +762,7 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { ...@@ -427,6 +762,7 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
this.hotZoneArr = []; this.hotZoneArr = [];
const arr = this.hotZoneItemArr.concat(); const arr = this.hotZoneItemArr.concat();
console.log('this.hotZoneItemArr: ', this.hotZoneItemArr);
for (let i = 0; i < arr.length; i++) { for (let i = 0; i < arr.length; i++) {
const data = JSON.parse(JSON.stringify(arr[i])); const data = JSON.parse(JSON.stringify(arr[i]));
...@@ -449,9 +785,15 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { ...@@ -449,9 +785,15 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
item.pic_url = data.pic_url; item.pic_url = data.pic_url;
item.text = data.text; item.text = data.text;
item.itemType = data.itemType; 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); this.hotZoneArr.push(item);
} }
...@@ -463,48 +805,6 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { ...@@ -463,48 +805,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() { initData() {
this.canvasWidth = this.wrap.nativeElement.clientWidth; this.canvasWidth = this.wrap.nativeElement.clientWidth;
...@@ -528,9 +828,28 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { ...@@ -528,9 +828,28 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
this.oldPos = {x: this.mx, y: this.my}; 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];
if (item && item.drag && item.drag.visible) {
if (this.checkClickTarget(item.drag)) {
this.clickedDragPoint(item.drag);
return;
}
}
}
for (let i = this.hotZoneArr.length - 1; i >= 0; i--) {
const item = this.hotZoneArr[i]; const item = this.hotZoneArr[i];
console.log('mapDown item: ', item);
let callback; let callback;
let target; let target;
switch (item.itemType) { switch (item.itemType) {
...@@ -548,7 +867,7 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { ...@@ -548,7 +867,7 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
break; break;
} }
if (this.checkClickTarget(target)) { if (target && this.checkClickTarget(target)) {
callback(target); callback(target);
return; return;
} }
...@@ -578,15 +897,18 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { ...@@ -578,15 +897,18 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
const addY = this.my - this.oldPos.y; const addY = this.my - this.oldPos.y;
this.curItem.x += addX; this.curItem.x += addX;
this.curItem.y += addY; this.curItem.y += addY;
this.curItem.posX = this.curItem.x;
this.curItem.posY = this.curItem.y;
} }
this.oldPos = {x: this.mx, y: this.my}; this.oldPos = {x: this.mx, y: this.my};
this.saveDisabled = true; // this.saveDisabled = false;
} }
mapUp(event) { mapUp(event=null) {
this.curItem = null; this.curItem = null;
this.changeSizeFlag = false; this.changeSizeFlag = false;
this.changeTopSizeFlag = false; this.changeTopSizeFlag = false;
...@@ -685,10 +1007,13 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { ...@@ -685,10 +1007,13 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
changeCurItem(item) { changeCurItem(item) {
console.log(' in changeCurItem', item)
this.hideAllLineDash(); this.hideAllLineDash();
this.curItem = item; this.curItem = item;
this.curItem.showLineDash(); this.curItem.showLineDash();
} }
hideAllLineDash() { hideAllLineDash() {
...@@ -723,7 +1048,7 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { ...@@ -723,7 +1048,7 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
// } // }
this.updateArr(this.hotZoneArr); this.updateArr(this.hotZoneArr);
this.updatePos() this.updatePos();
TWEEN.update(); TWEEN.update();
...@@ -833,7 +1158,9 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { ...@@ -833,7 +1158,9 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
checkClickTarget(target) { checkClickTarget(target) {
if (!target || !target.visible) {
return;
}
const rect = target.getBoundingBox(); const rect = target.getBoundingBox();
if (this.checkPointInRect(this.mx, this.my, rect)) { if (this.checkPointInRect(this.mx, this.my, rect)) {
return true; return true;
...@@ -852,9 +1179,21 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { ...@@ -852,9 +1179,21 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
saveClick() { saveClick() {
const sendData = this.getSendData();
this.save.emit(sendData);
}
getSendData() {
const bgItem = this.bgItem; const bgItem = this.bgItem;
if (this.bg) { 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 { } else {
bgItem['rect'] = { bgItem['rect'] = {
x: 0, x: 0,
...@@ -870,19 +1209,52 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { ...@@ -870,19 +1209,52 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
for (let i = 0; i < hotZoneArr.length; i++) { for (let i = 0; i < hotZoneArr.length; i++) {
const hotZoneItem = { const hotZoneItem = {
id: hotZoneArr[i].id,
index: hotZoneArr[i].index, index: hotZoneArr[i].index,
pic_url: hotZoneArr[i].pic_url, pic_url: hotZoneArr[i].pic_url,
text: hotZoneArr[i].text, text: hotZoneArr[i].text,
audio_url: hotZoneArr[i].audio_url, audio_url: hotZoneArr[i].audio_url,
itemType: hotZoneArr[i].itemType, 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, fontScale: hotZoneArr[i].textLabel ? hotZoneArr[i].textLabel.scaleX : 1,
imgScale: hotZoneArr[i].pic ? hotZoneArr[i].pic.scaleX : 1, imgScale: hotZoneArr[i].pic ? hotZoneArr[i].pic.scaleX : 1,
mapScale: this.mapScale imgSizeW: hotZoneArr[i].pic ? hotZoneArr[i].pic.width : 0,
imgSizeH: hotZoneArr[i].pic ? hotZoneArr[i].pic.height : 0,
mapScale: this.mapScale,
skeJsonData: hotZoneArr[i].skeJsonData,
texJsonData: hotZoneArr[i].texJsonData,
texPngData: hotZoneArr[i].texPngData,
dragDot: hotZoneArr[i].drag.getPosition(),
gIdx: hotZoneArr[i].gIdx,
}; };
hotZoneItem['rect'] = hotZoneArr[i].getBoundingBox();
this.savePropertyArr.forEach((key) => {
if (hotZoneArr[i][key]) {
hotZoneItem[key] = hotZoneArr[i][key];
}
})
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'].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'].y = Math.round((hotZoneItem['rect'].y - bgItem['rect'].y) * 100) / 100;
hotZoneItem['rect'].width = Math.round((hotZoneItem['rect'].width) * 100) / 100; hotZoneItem['rect'].width = Math.round((hotZoneItem['rect'].width) * 100) / 100;
...@@ -894,7 +1266,360 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { ...@@ -894,7 +1266,360 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
console.log('hotZoneItemArr: ', hotZoneItemArr); console.log('hotZoneItemArr: ', hotZoneItemArr);
this.save.emit({bgItem, hotZoneItemArr}); return {bgItem, hotZoneItemArr};
}
saveText(item) {
if (item.itemType == 'text') {
item.textLabel.text = item.text;
}
}
saveItemPos(item) {
console.log('item.posX: ', item.posX)
console.log('item.posY: ', item.posY)
item.x = Number(item.posX || 0)
item.y = Number(item.posY || 0)
// this.changeCurItem(item);
// this.curItem.x = item.posX || 0;
// this.curItem.y = item.posY || 0;
// this.mapUp();
}
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;
}
}
copyItem(it) {
const {hotZoneItemArr} = this.getSendData();
let itemData;
hotZoneItemArr.forEach((data) => {
if (data.id == it.id) {
itemData = data;
}
})
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);
const data = itemData
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 item = this.getHotZoneItem(data);
item.audio_url = data.audio_url;
item.pic_url = data.pic_url;
item.text = data.text;
item.itemType = data.itemType;
this.hotZoneArr.push(item);
if (this.customTypeGroupArr) {
this.refreshCustomItem(item);
} else {
this.refreshItem(item);
}
this.refreshHotZoneId();
item['id'] = this.createItemId();
}
createItemId() {
return new Date().getTime().toString();
}
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() { private updatePos() {
...@@ -917,12 +1642,15 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { ...@@ -917,12 +1642,15 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
break; break;
} }
item.x = x; if (x != undefined && y != undefined) {
item.y = y; item.x = x;
item.pic.x = x; item.y = y;
item.pic.y = y; item.pic.x = x;
item.textLabel.x = x; item.pic.y = y;
item.textLabel.y = y; item.textLabel.x = x;
item.textLabel.y = y;
}
}); });
} }
...@@ -944,6 +1672,12 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { ...@@ -944,6 +1672,12 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
item.textLabel.visible = true; item.textLabel.visible = true;
} }
private setNoneState(item: any) {
item.visible = false;
item.pic.visible = false;
item.textLabel.visible = false;
}
private clickedHotZoneRect(item: any) { private clickedHotZoneRect(item: any) {
if (this.checkClickTarget(item)) { if (this.checkClickTarget(item)) {
...@@ -962,6 +1696,17 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { ...@@ -962,6 +1696,17 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
private clickedHotZonePic(item: any) { private clickedHotZonePic(item: any) {
if (this.checkClickTarget(item)) { 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; this.curItem = item;
} }
} }
...@@ -972,15 +1717,42 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { ...@@ -972,15 +1717,42 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
} }
} }
saveText(item) { clickedDragPoint(item) {
item.textLabel.text = item.text; this.curItem = item;
} }
private loadHotZonePic(pic: HotZoneImg, url) { private loadHotZonePic(pic: HotZoneImg, url, scale = null) {
const baseLen = this.hotZoneImgSize * this.mapScale;
let baseLen;
if (this.hotZoneImgSize) {
baseLen = this.hotZoneImgSize * this.mapScale;
}
pic.load(url).then(() => { pic.load(url).then(() => {
const s = getMinScale(pic, baseLen); if (!scale) {
pic.setScaleXY(s); if (baseLen) {
scale = getMinScale(pic, baseLen);
} else {
scale = this.bg.scaleX;
}
}
pic.setScaleXY(scale);
}); });
} }
closeAfterPanel() {
this.refresh();
}
/**
* 刷新 渲染页面
*/
refresh() {
setTimeout(() => {
this.appRef.tick();
}, 1);
}
} }
<div class="content">
<div style="display: flex; margin-bottom: 5px;">
<button nz-button nzType="dashed" (click)="selectSubTemplate()" style=" border-radius: 0.5rem; border: 1px solid #ddd;">
<i nz-icon nzType="appstore" nzTheme="outline"></i>
选择子模板类型
</button>
<h2 *ngIf="_item.template" style="margin-left: 10px; margin-top: 1px;">
{{_item.template.description}}
</h2>
<button nz-button nzType="danger" (click)="deleteSubTemplate()" style="position: absolute; right: 30px; border-radius: 0.5rem; border: 1px solid #ddd;">
<i nz-icon nzType="delete" nzTheme="outline"></i>
删除
</button>
</div>
<iframe #iframe id="iframe" [src]="safeUrl" style="width: 98%; height: 70vh; border: 1px solid #ccc; padding: 5px;" frameborder="0">
</iframe>
<nz-modal [(nzVisible)]="isShowTemplate" (nzAfterClose)="closePanel()" nzTitle="选择子模板" [nzFooter]="null"
(nzOnCancel)="panelCancelClicked()" nzWidth="80%" nzHeight="80%">
<div class="template-container">
<div *ngFor="let template of templateArr" >
<div (click)="templateClick(template)" style="width: 150px; height: 100px; border: 1px solid #ccc; margin: 5px; cursor:pointer; user-select: none;">
<div style="width: 100%; height: 70%; border-bottom: 1px solid #ccc; overflow: hidden;">
<img [src]="template.cover" style="width: 100%; height: auto;">
</div>
<div style="width: 100%; height: 30%; display: flex; align-items: center; justify-content: center; ">
<label style="width: 90%; text-align: center; text-overflow: ellipsis; white-space:nowrap; overflow: hidden; ">{{template.description}}</label>
</div>
</div>
</div>
</div>
</nz-modal>
</div>
\ No newline at end of file
@import '../../style/common_mixin.css';
.content {
// width: 100%;
height: 100%;
border: 2px solid #ccc;
padding: 10px;
border-radius: 5px;
}
.template-container{
width: 100%;
display: flex;
// align-items: center;
// justify-content: space-around;
flex-wrap: wrap;
}
\ No newline at end of file
import {ApplicationRef, Component, ElementRef, EventEmitter, Input, OnChanges, OnDestroy, Output, ViewChild} from '@angular/core';
import { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser';
import { NzMessageService, UploadXHRArgs, UploadFile } from 'ng-zorro-antd';
@Component({
selector: 'app-sub-template',
templateUrl: './sub-template.component.html',
styleUrls: ['./sub-template.component.scss']
})
export class SubTemplateComponent implements OnDestroy, OnChanges {
uploading = false;
progress = 0;
@Output()
save = new EventEmitter();
@Output()
deleteFunc = new EventEmitter();
@Output()
refreshEmitter = new EventEmitter();
@Input()
set item(v) {
console.log('set item: ', v);
if (this.uploadUrl) {
this._item = v;
console.log(' __ refreshSafeUrl 3')
this.refreshSafeUrl();
}
this._data = v;
}
get item() {
return this._data;
}
_item;
_data;
@Input()
key = '';
uploadUrl;
uploadData;
@ViewChild('iframe', {static: true }) iframe: ElementRef;
isShowTemplate = false;
constructor(private el:ElementRef, private appRef: ApplicationRef, private nzMessageService: NzMessageService, private sanitizer: DomSanitizer) {
console.log(' in constructor 1111:', window['air']);
this.uploadUrl = (<any> window).courseware.uploadUrl();
this.uploadData = (<any> window).courseware.uploadData();
window['air'].getUploadCallback = (url, data) => {
this.uploadUrl = url;
this.uploadData = data;
};
this.setUploadUrl();
}
setUploadUrl() {
if (!this.uploadUrl) {
setTimeout(() => {
this.setUploadUrl();
}, 500);
} else {
if (this._data) {
this._item = this._data;
this.refreshSafeUrl()
}
}
}
safeUrl;
refreshSafeUrl(formUrl=null) {
if (!formUrl) {
formUrl = this._item.formUrl || '';
}
this.safeUrl = this.sanitizer.bypassSecurityTrustResourceUrl(formUrl);
}
ngOnChanges() {
}
isInit = false;
ngOnInit(): void {
console.log(' in ngOnInit ')
if (!this._item) {
this._item = {};
}
this.initListener();
}
templateArr = [];
async selectSubTemplate() {
if (this.templateArr.length == 0) {
await this.getAllTemplateData().then((data : []) => {
this.templateArr = data;
});
}
this.isShowTemplate = true;
}
deleteSubTemplate() {
console.log('in deleteFunc');
this.refreshSafeUrl('');
this.deleteFunc.emit({});
}
templateClick(template) {
console.log("template: ", template);
this._item = {};
const {name, last_version, form_url} = template;
const formUrl = `http://staging-teach.cdn.ireadabc.com/h5template/${name}/v${last_version}/${form_url}&key=${this.key}`
this._item.formUrl = formUrl;
this._item.template = template;
console.log('formUrl: ', formUrl)
this.refreshSafeUrl();
this.closePanel();
this.sendData();
console.log('this.safeUrl 2 : ', this.safeUrl)
// const key = this.getQueryVariable(formUrl, 'key');
// console.log("key: ", key);
// console.log("url: ", this._item['safeUrl']);
}
sendData() {
this.save.emit(this._item)
}
getQueryVariable(url, variable) {
var query = url.substring(1);
var vars = query.split("&");
for (var i=0;i<vars.length;i++) {
var pair = vars[i].split("=");
if(pair[0] == variable){return pair[1];}
}
return(false);
}
saveSubTemplate() {
}
initListener() {
const msgFunc = (e) => {
if (!this.iframe || !this.iframe.nativeElement || !this.iframe.nativeElement.contentWindow) {
console.log('this.iframe not exist');
window.removeEventListener('message', msgFunc);
return;
}
let msgData = e.data;
if (msgData.action === "getData") {
console.log("getData e: ", e);
if (this.iframe) {
console.log('ifram exist: ', this.iframe);
}
if (!msgData.urlParams) {
console.log(' !msgData.urlParams: ' , msgData)
return;
}
const key = this.getQueryVariable(msgData.urlParams, 'key');
if (key != this.key) {
console.log(' key != this.key ')
return;
}
const data = { msg: 'success', data: JSON.stringify(this._item.data)};
// iframeContent.postMessage( { action: 'getData', data: JSON.stringify(data) }, '*');
this.iframe.nativeElement.contentWindow.postMessage( { action: 'getData', data: JSON.stringify(data) }, '*');
}
if (msgData.action === "setData") {
if (!msgData.urlParams) {
console.log(' !msgData.urlParams: ' , msgData)
return;
}
const key = this.getQueryVariable(msgData.urlParams, 'key');
if (key != this.key) {
console.log(' key != this.key ')
return;
}
console.log("setData e: ", e);
if (typeof(msgData.data) === "string") {
console.log('msgData is string');
msgData.data = JSON.parse(msgData.data);
console.log('msgData.data: ', msgData.data);
}
this._item.data = msgData.data;
this.sendData();
}
if (msgData.action === "getUpload") {
console.log( ' in getUpload')
// const iframeContent = this.el.nativeElement.querySelector('#iframe').contentWindow;
this.iframe.nativeElement.contentWindow.postMessage({
action: 'getUpload',
uploadUrl: this.uploadUrl,
uploadData: this.uploadData
}, '*');
}
}
if (this.iframe?.nativeElement?.contentWindow) {
console.log(' init Listener !');
window.addEventListener('message', msgFunc);
}
}
async getAllTemplateData() {
return new Promise((resolve, reject) => {
const c = window['courseware']
try {
if (c && c.getTemplates) {
c.getTemplates((data) => {
// data =
// [
// {"id": 26, "uuid":"c94fb1b0-3395-42ca-9ae3-03ca7c242d3f", "name": "hw_001", "description": "音频课件", "cover": "http://iplayabc-teach-yun.oss-cn-beijing.aliyuncs.com/3feddb01-4350-42ad-909f-236ad052fbb2.jpg", "type": 1, "t_type": 2, "form_url": "index.html?type=form", "play_url": "index.html", "last_version": 16},
// {"id": 27, "uuid":"b8bedc68-9ef6-42a6-ba99-513daa244a6d", "name": "hw_002", "description": "视频课件", "cover": "http://iplayabc-teach-yun.oss-cn-beijing.aliyuncs.com/1b11d370-9d8b-4358-98d3-4757f825d2a4.jpg", "type": 1, "t_type": 2, "form_url": "index.html?type=form", "play_url": "index.html", "last_version": 16},
// {"id": 28, "uuid":"068fcffb-4e99-4148-bc8e-2a89ee9bfe7c", "name": "hw_003", "description": "转盘课件", "cover": "http://iplayabc-teach-yun.oss-cn-beijing.aliyuncs.com/de3d8498-7523-4601-934e-932ac219a408.jpg", "type": 1, "t_type": 2, "form_url": "index.html?type=form", "play_url": "index.html", "last_version": 17},
// {"id": 29, "uuid":"b2bfd8df-e0e4-41c9-b65f-12160628e1a3", "name": "hw_004", "description": "连线课件", "cover": "http://iplayabc-teach-yun.oss-cn-beijing.aliyuncs.com/824989ac-78fb-4db7-848a-790cba00effe.jpg", "type": 1, "t_type": 2, "form_url": "index.html?type=form", "play_url": "index.html", "last_version": 9 },
// {"id": 30, "uuid":"d7be3c21-fc25-482d-a4a6-1a371970457a", "name": "hw_005", "description": "分类课件", "cover": "http://iplayabc-teach-yun.oss-cn-beijing.aliyuncs.com/aa69d85a-3430-48b2-91bf-a804dee1826d.jpg", "type": 1, "t_type": 2, "form_url": "index.html?type=form", "play_url": "index.html", "last_version": 19},
// {"id": 31, "uuid":"34e98c65-f3f0-46e4-a7b8-5caf72954847", "name": "hw_006", "description": "翻卡游戏", "cover": "http://iplayabc-teach-yun.oss-cn-beijing.aliyuncs.com/fe54031b-7879-4c65-8de7-102fa5e5e9f5.png", "type": 1, "t_type": 2, "form_url": "index.html?type=form", "play_url": "index.html", "last_version": 5 }
// ]
// resolve(data);
// return
if (data) {
console.log('data~~~:', data);
resolve(JSON.parse(data));
} else {
console.log('data none');
resolve([]);
}
})
}
} catch (error) {
reject(error);
}
})
// const data =
// [
// {"id": 26, "uuid":"c94fb1b0-3395-42ca-9ae3-03ca7c242d3f", "name": "hw_001", "description": "音频课件", "cover": "http://iplayabc-teach-yun.oss-cn-beijing.aliyuncs.com/3feddb01-4350-42ad-909f-236ad052fbb2.jpg", "type": 1, "t_type": 2, "form_url": "index.html?type=form", "play_url": "index.html", "last_version": 16},
// {"id": 27, "uuid":"b8bedc68-9ef6-42a6-ba99-513daa244a6d", "name": "hw_002", "description": "视频课件", "cover": "http://iplayabc-teach-yun.oss-cn-beijing.aliyuncs.com/1b11d370-9d8b-4358-98d3-4757f825d2a4.jpg", "type": 1, "t_type": 2, "form_url": "index.html?type=form", "play_url": "index.html", "last_version": 16},
// {"id": 28, "uuid":"068fcffb-4e99-4148-bc8e-2a89ee9bfe7c", "name": "hw_003", "description": "转盘课件", "cover": "http://iplayabc-teach-yun.oss-cn-beijing.aliyuncs.com/de3d8498-7523-4601-934e-932ac219a408.jpg", "type": 1, "t_type": 2, "form_url": "index.html?type=form", "play_url": "index.html", "last_version": 17},
// {"id": 29, "uuid":"b2bfd8df-e0e4-41c9-b65f-12160628e1a3", "name": "hw_004", "description": "连线课件", "cover": "http://iplayabc-teach-yun.oss-cn-beijing.aliyuncs.com/824989ac-78fb-4db7-848a-790cba00effe.jpg", "type": 1, "t_type": 2, "form_url": "index.html?type=form", "play_url": "index.html", "last_version": 9 },
// {"id": 30, "uuid":"d7be3c21-fc25-482d-a4a6-1a371970457a", "name": "hw_005", "description": "分类课件", "cover": "http://iplayabc-teach-yun.oss-cn-beijing.aliyuncs.com/aa69d85a-3430-48b2-91bf-a804dee1826d.jpg", "type": 1, "t_type": 2, "form_url": "index.html?type=form", "play_url": "index.html", "last_version": 19},
// {"id": 31, "uuid":"34e98c65-f3f0-46e4-a7b8-5caf72954847", "name": "hw_006", "description": "翻卡游戏", "cover": "http://iplayabc-teach-yun.oss-cn-beijing.aliyuncs.com/fe54031b-7879-4c65-8de7-102fa5e5e9f5.png", "type": 1, "t_type": 2, "form_url": "index.html?type=form", "play_url": "index.html", "last_version": 5 }
// ]
// return data;
}
/**
* 刷新 渲染页面
*/
refresh() {
// this.refreshEmitter.emit();
setTimeout(() => {
this.appRef.tick();
}, 1);
}
closePanel() {
console.log(' in closePanel ');
// this.refresh();
this.isShowTemplate = false;
}
panelCancelClicked() {
this.isShowTemplate = false;
}
panelOkClicked() {
this.isShowTemplate = false;
}
ngOnDestroy() {
}
}
<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,28 @@ export class UploadImageWithPreviewComponent implements OnDestroy, OnChanges { ...@@ -42,7 +42,28 @@ export class UploadImageWithPreviewComponent implements OnDestroy, OnChanges {
this.uploadData = data; this.uploadData = data;
}; };
this.setUploadUrl();
} }
setUploadUrl() {
if (!this.uploadUrl) {
console.log('this.uploadUrl -=- 1 : ', this.uploadUrl)
this.uploadUrl = (<any> window).courseware.uploadUrl();
this.uploadData = (<any> window).courseware.uploadData();
console.log('this.uploadUrl -=- 2 : ', this.uploadUrl)
setTimeout(() => {
this.setUploadUrl();
}, 500);
}
console.log('this.uploadUrl -=- 3 : ', this.uploadUrl)
}
ngOnChanges() { ngOnChanges() {
if (!this.picItem) { if (!this.picItem) {
return; return;
......
...@@ -6,3 +6,30 @@ ...@@ -6,3 +6,30 @@
height: 100%; 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 class="model-content">
<div style="padding: 20px;">
<div style="position: absolute; left: 200px; top: 100px; width: 800px;">
<input type="text" nz-input [(ngModel)]="item.text" (blur)="save()"> <h2 style="margin-top: 20px;">
封面图
</h2>
<div style="width: 300px; margin-bottom: 30px;">
<app-upload-image-with-preview
[picUrl]="item.bg_url"
(imageUploaded)="onImageUploadSuccess($event, 'bg_url')">
</app-upload-image-with-preview>
</div>
<div style="width: 400px; display: flex; justify-content: center; margin-bottom: 50px;">
<app-upload-image-with-preview <h2 style="width: 60px;">标题:</h2>
[picUrl]="item.pic_url" <input type="text" nz-input [(ngModel)]="item.title" (blur)="save()" style="margin-left: 15px">
(imageUploaded)="onImageUploadSuccess($event, 'pic_url')" </div>
></app-upload-image-with-preview>
<app-audio-recorder
[audioUrl]="item.audio_url" <h2>热区配置:</h2>
(audioUploaded)="onAudioUploadSuccess($event, 'audio_url')" <app-custom-hot-zone
></app-audio-recorder> [bgItem]="item.bgItem"
<app-custom-hot-zone></app-custom-hot-zone> [hotZoneItemArr]="item.hotZoneItemArr"
<app-upload-video></app-upload-video> [customTypeGroupArr]="customTypeGroupArr"
<app-lesson-title-config></app-lesson-title-config> (save)="saveHotZone(item, $event)"
</div> >
</app-custom-hot-zone>
<!--
<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">
</div>
</div>
<app-custom-hot-zone
[bgItem]="item.bgItem"
[hotZoneItemArr]="item.hotZoneItemArr"
[customTypeGroupArr]="customTypeGroupArr"
(save)="saveHotZone(item, $event)"
>
</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>
<div style="width: 300px; margin-top: 15px;">
<span>文本: </span>
<input type="text" nz-input [(ngModel)]="item.text" (blur)="save()">
</div>
<div style="margin-top: 5px">
<span>音频: </span>
<app-audio-recorder
[audioUrl]="item.audio_url"
(audioUploaded)="onAudioUploadSuccess($event, 'audio_url')"
></app-audio-recorder>
</div> -->
</div>
</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({ @Component({
...@@ -10,22 +10,57 @@ import {Component, EventEmitter, Input, OnDestroy, OnChanges, OnInit, Output, Ap ...@@ -10,22 +10,57 @@ import {Component, EventEmitter, Input, OnDestroy, OnChanges, OnInit, Output, Ap
export class FormComponent implements OnInit, OnChanges, OnDestroy { export class FormComponent implements OnInit, OnChanges, OnDestroy {
// 储存数据用 // 储存数据用
saveKey = "test_0011"; saveKey = "JM_4-1";
// 储存对象 // 储存对象
item; item;
customTypeGroupArr = [
{
name: '输入框区域',
rect: true,
isShowPos: true,
isCopy: true,
select: [
{label: '日期', value: 'date'},
{label: '时间', value: 'time'},
{label: '人名', value: 'name'}
],
label: '比对',
},
{
name: '提交按钮',
rect: true,
isFixed: true
}
]
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() { ngOnInit() {
this.item = {}; this.item = {};
// 获取存储的数据 // 获取存储的数据
(<any> window).courseware.getData((data) => { (<any>window).courseware.getData((data) => {
if (data) { if (data) {
this.item = data; this.item = data;
...@@ -37,20 +72,72 @@ export class FormComponent implements OnInit, OnChanges, OnDestroy { ...@@ -37,20 +72,72 @@ export class FormComponent implements OnInit, OnChanges, OnDestroy {
this.refresh(); this.refresh();
}, this.saveKey); }, this.saveKey);
} }
ngOnChanges() { ngOnChanges() {
} }
ngOnDestroy() { ngOnDestroy() {
} }
init() {
if (!this.item.sentenceArr) {
this.item.sentenceArr = [];
}
if (!this.item.templateArr) {
this.item.templateArr = [];
}
}
addSubTemplate() {
this.item.templateArr.push({
})
this.save();
}
onDeleteTemplate(e, index) {
this.item.templateArr[index] = {};
this.item.templateArr.splice(index, 1);
this.save();
}
onSaveTemplate(e, index) {
this.item.templateArr[index] = e;
this.save();
}
init() {
addBtnClick() {
this.item.sentenceArr.push({});
this.save();
}
deleteBtnClick(index) {
this.item.sentenceArr.splice(index, 1);
this.save();
}
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 +147,8 @@ export class FormComponent implements OnInit, OnChanges, OnDestroy { ...@@ -60,8 +147,8 @@ export class FormComponent implements OnInit, OnChanges, OnDestroy {
*/ */
onImageUploadSuccess(e, key) { onImageUploadSuccess(e, key) {
this.item[key] = e.url; this.item[key] = e.url;
this.save(); this.save();
} }
/** /**
...@@ -69,19 +156,28 @@ export class FormComponent implements OnInit, OnChanges, OnDestroy { ...@@ -69,19 +156,28 @@ export class FormComponent implements OnInit, OnChanges, OnDestroy {
* @param e * @param e
*/ */
onAudioUploadSuccess(e, key) { onAudioUploadSuccess(e, key) {
this.item[key] = e.url; this.item[key] = e.url;
this.save(); 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() { save() {
(<any> window).courseware.setData(this.item, null, this.saveKey); (<any>window).courseware.setData(this.item, null, this.saveKey);
this.refresh(); this.refresh();
console.log('this.item = ' + JSON.stringify(this.item));
} }
/** /**
...@@ -93,5 +189,4 @@ export class FormComponent implements OnInit, OnChanges, OnDestroy { ...@@ -93,5 +189,4 @@ export class FormComponent implements OnInit, OnChanges, OnDestroy {
}, 1); }, 1);
} }
} }
\ No newline at end of file
import TWEEN from '@tweenjs/tween.js'; import TWEEN from '@tweenjs/tween.js';
import { randomInt } from 'crypto';
interface AirWindow extends Window { interface AirWindow extends Window {
air: any; air: any;
...@@ -77,7 +78,9 @@ export class MySprite extends Sprite { ...@@ -77,7 +78,9 @@ export class MySprite extends Sprite {
_offCtx; _offCtx;
isCircleStyle = false; // 切成圆形 isCircleStyle = false; // 切成圆形
parent; parent;
_maskSpr;
_maskSprArr = [];
_maskType = "destination-in" // destination-out
init(imgObj = null, anchorX: number = 0.5, anchorY: number = 0.5) { init(imgObj = null, anchorX: number = 0.5, anchorY: number = 0.5) {
...@@ -114,16 +117,20 @@ export class MySprite extends Sprite { ...@@ -114,16 +117,20 @@ export class MySprite extends Sprite {
this._radius = r; this._radius = r;
} }
setMaskSpr(spr) { addMaskSpr(spr) {
this._maskSpr = spr; this._maskSprArr.push(spr);
this._createOffCtx(); this._createOffCtx();
} }
setMaskType(t) {
this._maskType = t;
}
_createOffCtx() { _createOffCtx() {
if (!this._offCtx) { if (!this._offCtx) {
this._offCanvas = document.createElement('canvas'); // 创建一个新的canvas this._offCanvas = document.createElement('canvas'); // 创建一个新的canvas
this.width = this._offCanvas.width = this.width; // 创建一个正好包裹住一个粒子canvas this._offCanvas.width = this.width; // 创建一个正好包裹住一个粒子canvas
this.height = this._offCanvas.height = this.height; this._offCanvas.height = this.height;
this._offCtx = this._offCanvas.getContext('2d'); this._offCtx = this._offCanvas.getContext('2d');
} }
} }
...@@ -220,12 +227,22 @@ export class MySprite extends Sprite { ...@@ -220,12 +227,22 @@ export class MySprite extends Sprite {
this._offCtx.clearRect(0, 0, this.width, this.height); this._offCtx.clearRect(0, 0, this.width, this.height);
this._offCtx.drawImage(this.img, 0, 0); this._offCtx.drawImage(this.img, 0, 0);
if (this._maskSpr) { this._offCtx.globalCompositeOperation = this._maskType;
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); 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.ctx.drawImage(this._offCanvas, this._offX, this._offY);
this._offCtx.restore(); this._offCtx.restore();
...@@ -293,6 +310,8 @@ export class MySprite extends Sprite { ...@@ -293,6 +310,8 @@ export class MySprite extends Sprite {
child.alpha = this.alpha; child.alpha = this.alpha;
} }
child.ctx = this.ctx;
} }
removeChild(child) { removeChild(child) {
const index = this.children.indexOf(child); const index = this.children.indexOf(child);
...@@ -822,8 +841,10 @@ export class RichTextOld extends Label { ...@@ -822,8 +841,10 @@ export class RichTextOld extends Label {
export class RichText extends Label { export class RichText extends Label {
disH = 30; disH = 10;
offW = 10; offW = 10;
row = 1;
textBaseline = "middle";
constructor(ctx?: any) { constructor(ctx?: any) {
super(ctx); super(ctx);
...@@ -831,7 +852,46 @@ export class RichText extends Label { ...@@ -831,7 +852,46 @@ export class RichText extends Label {
// this.dataArr = dataArr; // 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;
}
getSubTextRect(subText) {
const tmpLabel = new RichText();
tmpLabel.fontSize = this.fontSize;
tmpLabel.fontName = this.fontName;
tmpLabel.textAlign = this.textAlign;
tmpLabel.textBaseline = this.textBaseline;
tmpLabel.fontWeight = this.fontWeight;
tmpLabel.width = this.width;
tmpLabel.height = this.height;
const index = this.text.indexOf(subText);
tmpLabel.text = this.text.substring(0, index);
tmpLabel.refreshSize();
const x = tmpLabel.width;
tmpLabel.text = subText;
tmpLabel.refreshSize();
const width = tmpLabel.width;
const y = this.fontSize / 2;
const height = this.fontSize;
return {x, y, width, height}
}
drawText() { drawText() {
...@@ -842,7 +902,7 @@ export class RichText extends Label { ...@@ -842,7 +902,7 @@ export class RichText extends Label {
this.ctx.font = `${this.fontSize}px ${this.fontName}`; this.ctx.font = `${this.fontSize}px ${this.fontName}`;
this.ctx.textAlign = this.textAlign; this.ctx.textAlign = this.textAlign;
this.ctx.textBaseline = 'middle'; this.ctx.textBaseline = this.textBaseline;
this.ctx.fontWeight = this.fontWeight; this.ctx.fontWeight = this.fontWeight;
this.ctx.fillStyle = this.fontColor; this.ctx.fillStyle = this.fontColor;
...@@ -868,9 +928,11 @@ export class RichText extends Label { ...@@ -868,9 +928,11 @@ export class RichText extends Label {
} }
} }
row.push(temp); row.push(temp);
this.row = row.length;
const x = 0; const x = 0;
const y = -row.length * disH / 2; const y = 0//-row.length * disH / 2;
// for (let b = 0 ; b < row.length; b++) { // for (let b = 0 ; b < row.length; b++) {
// this.ctx.strokeText(row[b], x, y + ( b + 1 ) * disH ); // 每行字体y坐标间隔20 // this.ctx.strokeText(row[b], x, y + ( b + 1 ) * disH ); // 每行字体y坐标间隔20
// } // }
...@@ -880,7 +942,7 @@ export class RichText extends Label { ...@@ -880,7 +942,7 @@ export class RichText extends Label {
this.ctx.lineWidth = this._outLineWidth; this.ctx.lineWidth = this._outLineWidth;
this.ctx.strokeStyle = this._outLineColor; this.ctx.strokeStyle = this._outLineColor;
for (let b = 0 ; b < row.length; b++) { for (let b = 0 ; b < row.length; b++) {
this.ctx.strokeText(row[b], x, y + ( b + 1 ) * disH ); // 每行字体y坐标间隔20 this.ctx.strokeText(row[b], x, y + ( b + 0 ) * disH / this.scaleY ); // 每行字体y坐标间隔20
} }
// this.ctx.strokeText(this.text, 0, 0); // this.ctx.strokeText(this.text, 0, 0);
} }
...@@ -888,7 +950,7 @@ export class RichText extends Label { ...@@ -888,7 +950,7 @@ export class RichText extends Label {
// this.ctx.fillStyle = '#ff7600'; // this.ctx.fillStyle = '#ff7600';
for (let b = 0 ; b < row.length; b++) { for (let b = 0 ; b < row.length; b++) {
this.ctx.fillText(row[b], x, y + ( b + 1 ) * disH ); // 每行字体y坐标间隔20 this.ctx.fillText(row[b], x, y + ( b + 0 ) * disH / this.scaleY ); // 每行字体y坐标间隔20
} }
} }
...@@ -954,9 +1016,31 @@ export class ShapeRect extends MySprite { ...@@ -954,9 +1016,31 @@ export class ShapeRect extends MySprite {
drawShape() { drawShape() {
this.ctx.fillStyle = this.fillColor; if (this._offCtx) {
this.ctx.fillRect(this._offX, this._offY, this.width, this.height); 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);
}
} }
...@@ -1765,6 +1849,78 @@ export function showPopParticle(img, pos, parent, num = 20, minLen = 40, maxLen ...@@ -1765,6 +1849,78 @@ export function showPopParticle(img, pos, parent, num = 20, minLen = 40, maxLen
} }
export function RandomInt(a, b = 0) {
let max = Math.max(a, b);
let min = Math.min(a, b);
return Math.floor(Math.random() * (max - min) + min);
}
export function showShapeParticle(shapeType, shapeW, shapeH, pos, parent, num = 20, minLen = 40, maxLen = 80, showTime = 0.4) {
const randomColorArr = [
'#6996af',
'#4da940',
'#911b40',
]
for (let i = 0; i < num; i ++) {
let particle;
switch(shapeType) {
case 'rect':
particle = new ShapeRectNew();
particle.setSize(shapeW, shapeH, 0);
particle.fillColor = randomColorArr[RandomInt(0, randomColorArr.length)];
break;
}
particle.x = pos.x;
particle.y = pos.y;
parent.addChild(particle);
const randomR = 360 * Math.random();
// particle.rotation = randomR;
const randomS = 0.3 + Math.random() * 0.7;
particle.setScaleXY(randomS * 0.3);
const randomX = Math.random() * 20 - 10;
particle.x += randomX;
const randomY = Math.random() * 20 - 10;
particle.y += randomY;
const randomL = minLen + Math.random() * (maxLen - minLen);
const randomA = 360 * Math.random();
const randomT = getPosByAngle(randomA, randomL);
moveItem(particle, particle.x + randomT.x, particle.y + randomT.y, showTime, () => {
}, TWEEN.Easing.Exponential.Out);
// scaleItem(particle, 0, 0.6, () => {
//
// });
scaleItem(particle, randomS, 0.6, () => {
}, TWEEN.Easing.Exponential.Out);
setTimeout(() => {
hideItem(particle, 0.4, () => {
}, TWEEN.Easing.Cubic.In);
}, showTime * 0.5 * 1000);
}
}
export function shake(item, time = 0.5, callback = null, rate = 1) { export function shake(item, time = 0.5, callback = null, rate = 1) {
...@@ -1846,6 +2002,360 @@ export class MyVideo extends MySprite { ...@@ -1846,6 +2002,360 @@ export class MyVideo extends MySprite {
} }
} }
export class InputView extends MySprite {
element;
callback;
_isShowScroll = false;
constructor(ctx=null) {
super(ctx);
this._createInput()
}
set isShowScroll(v) {
this._isShowScroll = v;
if (!v) {
this.element.style.overflow = 'hidden';
}
}
get isShowScroll() {
return this._isShowScroll;
}
_createInput() {
const input = document.createElement('textarea');
input.style.resize = 'none';
input.style.border = 'none';
input.style.position = 'absolute';
input.onblur = this.onblur.bind(this);
const div = document.getElementById('div_input');
div.appendChild(input);
this.element = input;
}
onblur() {
if (this.callback) {
this.callback(this.element.value);
}
this.callback = null;
this.hide();
}
set text(v) {
this.element.value = v;
}
show() {
this.element.hidden = false;
setTimeout(() => {
this.element.focus();
}, 1);
}
hide() {
this.element.hidden = true;
}
setStyle(style) {
for ( let key in style ) {
console.log('key: ', key)
console.log('value: ', style[key])
this.element.style[key] = style[key];
}
console.log('this.element: ``````', this.element)
}
refreshInputStyle() {
this.element.style.left = this.x + 'px';
this.element.style.top = this.y + 'px';
this.element.style.width = this.width + 'px';
this.element.style.height = this.height + 'px';
}
}
export class ScrollView extends MySprite {
static ScrollSideType = {
VERTICAL : 'VERTICAL',
HORIZONTAL : 'HORIZONTAL',
}
_offCtx;
_offCanvas;
_scrollBar;
content;
bgColor;
barColor = '#fbe9b7'
scrollSide = ScrollView.ScrollSideType.VERTICAL;
scorllBarWidth;
scrollBarHeight;
constructor(ctx = null) {
super(ctx);
this._createOffCtx();
this._createScrollBar();
}
_createOffCtx() {
if (!this._offCtx) {
this._offCanvas = document.createElement('canvas'); // 创建一个新的canvas
this._offCanvas.width = this.width; // 创建一个正好包裹住一个粒子canvas
this._offCanvas.height = this.height;
this._offCtx = this._offCanvas.getContext('2d');
this.content = new MySprite(this._offCtx);
}
}
_createScrollBar() {
this._scrollBar = new ShapeRectNew();
this._scrollBar.anchorY = 0;
this._scrollBar.anchorX = 1;
this._scrollBar.setSize(10, 100, 5);
this._scrollBar.fillColor = this.barColor;
this.addChild(this._scrollBar);
}
setBgColor(color) {
this.bgColor = color;
}
setShowSize(w, h) {
this.width = w;
this.height = h;
if (this.content.width < this.width) {
this.content.width = this._offCanvas.width = this.width;
}
if (this.content.height < this.height) {
this.content.height = this._offCanvas.height = this.height;
}
this.refreshScrollBar();
}
setContentSize(w, h) {
this.content.width = w;
this.content.height = h;
this._offCanvas.width = w;
this._offCanvas.height = h;
}
addItem(sprite) {
this.content.addChild(sprite);
sprite.ctx = this._offCtx;
this.refreshContentSize();
}
refreshContentSize() {
const children = this.content.children;
console.log('children: ', children);
let maxW = 0;
let maxH = 0;
for (let i=0; i<children.length; i++) {
if (children[i] == this.content) {
continue;
}
const box = children[i].getBoundingBox();
console.log('box: ', box);
const boxEdgeX = box.x + box.width;
const boxEdgeY = box.y + box.height;
console.log('boxEdgeY: ', boxEdgeY);
if (boxEdgeX > maxW) {
maxW = boxEdgeX;
}
if (boxEdgeY > maxH) {
maxH = boxEdgeY;
}
}
console.log('maxW: ', maxW);
console.log('maxH: ', maxH);
this.content.width = maxW;
this.content.height = maxH ;
this.refreshScrollBar();
}
setScrollBarSize(w, h) {
this.scorllBarWidth = w;
this.scrollBarHeight = h;
}
setContentScale(s) {
this.content.setScaleXY( 1 / s);
this.refreshScrollBar();
}
refreshScrollBar() {
let w = this.scorllBarWidth;
if (!w) {
w = this.width / 50;
}
let rate = this.height * this.scaleY / this.content.height / this.content.scaleY;
if (rate >= 1) {
this._scrollBar.visible = false;
rate = 1;
} else {
this._scrollBar.visible = true;
}
const h = rate * this.height
const r = w / 2;
this._scrollBar.setSize(w, h, r);
this._scrollBar.x = this.width;
}
refreshScrollBarPos() {
this._scrollBar.y = -this.content.y * ( this.height / this.content.height );
}
drawSelf() {
super.drawSelf();
this._offScreenRender();
}
touchStartPos;
touchStartContentPos;
onTouchStart(x, y) {
if (!this._scrollBar.visible) {
return;
}
this.touchStartPos = { x, y };
this.touchStartContentPos = { x: this.content.x, y: this.content.y };
}
onTouchMove(x, y) {
if (!this.touchStartPos) {
return;
}
if (!this.touchStartContentPos) {
return;
}
const offsetX = x - this.touchStartPos.x;
const offsetY = y - this.touchStartPos.y;
if (this.scrollSide == ScrollView.ScrollSideType.VERTICAL) {
this.content.y = between(this.touchStartContentPos.y + offsetY, 0, this.getBoundingBox().height - this.content.height);
} else {
this.content.x = between(this.touchStartContentPos.x + offsetX, 0, this.getBoundingBox().width - this.content.width);
}
this.refreshScrollBarPos();
}
onTouchEnd(x, y) {
this.touchStartPos = null;
this.touchStartContentPos = null;
}
onWheelUp(offsetY) {
if (!this._scrollBar.visible) {
return;
}
if (this.scrollSide == ScrollView.ScrollSideType.VERTICAL) {
this.content.y = between(this.content.y + 40, 0, this.getBoundingBox().height - this.content.height);
} else {
this.content.x = between(this.content.x + 40, 0, this.getBoundingBox().width - this.content.width);
}
this.refreshScrollBarPos();
}
onWheelDown(offsetY) {
if (!this._scrollBar.visible) {
return;
}
if (this.scrollSide == ScrollView.ScrollSideType.VERTICAL) {
this.content.y = between(this.content.y - 40, 0, this.getBoundingBox().height - this.content.height);
} else {
this.content.x = between(this.content.x - 40, 0, this.getBoundingBox().width - this.content.width);
}
this.refreshScrollBarPos();
}
setContentSpr() {
}
_offScreenRender() {
this._offCtx.save();
this._offCtx.clearRect(0, 0, this._offCanvas.width, this._offCanvas.height);
if (this.bgColor) {
this._offCtx.fillStyle = this.bgColor;
this._offCtx.fillRect(this._offX, this._offY, this.width, this.height);
this._offCtx.globalCompositeOperation = "source-atop";
} else {
this._offCtx.fillStyle = '#ffffff'
this._offCtx.fillRect(this._offX, this._offY, this.width, this.height);
this._offCtx.globalCompositeOperation = "xor";
}
this.content.update();
this.ctx.drawImage(this._offCanvas, this._offX, this._offY);
// this.ctx.drawImage(this._offCanvas, this._offX, this._offY);
// this.ctx.drawImage(this._offCanvas, this._offX, this._offY, this.content.width, this.content.height, this._offX + this.content.x, this._offY + this.content.y, this.width, this.height);
this._offCtx.restore();
}
}
export function between(a, b, c) {
return [a, b, c].sort((x, y) => x - y)[1];
}
// --------------- custom class -------------------- // --------------- custom class --------------------
export async function loadFonts (fontName, fontFile) {
// const font = new FontFace(
// "DroidSansFallback",
// "url(" + "../../assets/play/font/DroidSansFallback.ttf" + ")"
// );
try {
console.log(location.href.split("#")[0] + "assets/play/font/" + fontFile);
const font = new FontFace(
fontName,
"url(" + location.href.split("#")[0] + "../../assets/play/font/" + fontFile + ")"
);
console.log('start: ', new Date().getTime())
await font.load();
console.log('end: ', new Date().getTime())
document.fonts.add(font);
document.body.classList.add("fonts-loaded");
} catch (error) {
console.log(error);
}
}
// --------------- custom class --------------------
...@@ -3,6 +3,8 @@ ...@@ -3,6 +3,8 @@
height: 100%; height: 100%;
background: #ffffff; background: #ffffff;
background-size: cover; background-size: cover;
} }
#canvas { #canvas {
...@@ -10,10 +12,28 @@ ...@@ -10,10 +12,28 @@
} }
@font-face @font-face
{ {
font-family: 'BRLNSDB'; font-family: 'BRLNSDB';
src: url("../../assets/font/BRLNSDB.TTF") ; src: url("../../assets/play/font/BRLNSDB_1.TTF")
}
@font-face
{
font-family: 'Aileron-Black';
src: url("../../assets/play/font/Aileron-Black.ttf")
}
@font-face
{
font-family: 'Aileron-Bold';
src: url("../../assets/play/font/Aileron-Bold.ttf")
} }
@font-face
{
font-family: 'DroidSansFallback';
src: url("../../assets/play/font/DroidSansFallback.ttf");
}
\ No newline at end of file
<div class="game-container" #wrap> <span style="font-family:'DroidSansFallback'" ></span>
<canvas id="canvas" #canvas></canvas> <span style="font-family:'Aileron-Black'" ></span>
<span style="font-family:'Aileron-Bold'" ></span>
<div class="game-container" #wrap >
<canvas id="canvas" style="width: 100%; height: 100%;" #canvas></canvas>
</div> </div>
<div id='div_input'>
</div>
<div #iframeContent style="position: absolute; top: 0; overflow: hidden; ">
<div *ngFor="let t of templateArr; let i = index" >
<iframe *ngIf="!t.isHide" [style.width]="t?.leftOff || '0vw'" [src]="t?.playUrl || safeDefaultUrl" style="position: fixed; width: 100vw; height: 100vh; border: 0px solid #ccc; " frameborder="0">
</iframe>
</div>
</div>
<!-- <div style="position: absolute; top: 0">
<label style="font-family: Aileron-Black;"></label>
<label style="font-family: DroidSansFallback;"></label>
</div> -->
import {Component, ElementRef, ViewChild, OnInit, Input, OnDestroy, HostListener} from '@angular/core'; import { Component, ElementRef, ViewChild, OnInit, Input, OnDestroy, HostListener, ApplicationRef } from '@angular/core';
import { import {
MySprite,
Label, Label,
MySprite, tweenChange, moveItem,
rotateItem,
removeItemFromArr,
ShapeRect, scaleItem, tweenChange, showPopParticle, hideItem, showItem, LineRect, shake, RichText, ShapeRectNew, showShapeParticle, delayCall, randomSortByArr, ScrollView, InputView,
} from './Unit'; } from './Unit';
import {res, resAudio} from './resources'; import { res, resAudio } from './resources';
import {Subject} from 'rxjs'; import { Subject } from 'rxjs';
import {debounceTime} from 'rxjs/operators'; import { debounceTime } from 'rxjs/operators';
import * as _ from 'lodash';
import TWEEN from '@tweenjs/tween.js'; import TWEEN from '@tweenjs/tween.js';
import { loadFonts } from './Util'
import { faTshirt } from '@fortawesome/free-solid-svg-icons';
import { DomSanitizer } from '@angular/platform-browser';
...@@ -21,23 +30,42 @@ import TWEEN from '@tweenjs/tween.js'; ...@@ -21,23 +30,42 @@ import TWEEN from '@tweenjs/tween.js';
styleUrls: ['./play.component.css'] styleUrls: ['./play.component.css']
}) })
export class PlayComponent implements OnInit, OnDestroy { export class PlayComponent implements OnInit, OnDestroy {
// 数据
_data;
@Input()
set data(data) {
this._data = data;
}
get data() {
return this._data;
}
@ViewChild('canvas', {static: true }) canvas: ElementRef; @Input()
@ViewChild('wrap', {static: true }) wrap: ElementRef; sid;
@ViewChild('canvas', { static: true }) canvas: ElementRef;
@ViewChild('wrap', { static: true }) wrap: ElementRef;
@ViewChild('iframeContent', {static: true }) iframeContent: ElementRef;
canvasScale = 2;
canvasWidth = 2388;
canvasHeight = 1688;
canvasBaseW = 2388;
canvasBaseH = 1688;
// 数据
data;
ctx; ctx;
fps = 0;
frametime = 0; // 上一帧动画的时间, 两帧时间差
canvasWidth = 1280; // canvas实际宽度
canvasHeight = 720; // canvas实际高度
canvasBaseW = 1280; // canvas 资源预设宽度 mx;
canvasBaseH = 720; // canvas 资源预设高度 my; // 点击坐标
mx; // 点击x坐标
my; // 点击y坐标
// 资源 // 资源
...@@ -49,132 +77,2482 @@ export class PlayComponent implements OnInit, OnDestroy { ...@@ -49,132 +77,2482 @@ export class PlayComponent implements OnInit, OnDestroy {
animationId: any; animationId: any;
winResizeEventStream = new Subject(); winResizeEventStream = new Subject();
audioObj = {};
audioObj = {};
renderArr; renderArr;
mapScale = 1; mapScale = 1;
mapScaleMax = 1;
canvasLeft; canvasLeft;
canvasTop; canvasTop;
saveKey = 'test_0011';
canTouch = true;
btnLeft;
btnRight;
pic1;
pic2;
canTouch = true; KEY = 'JM_4-1';
// -----
picArr;
titleLabel;
light;
particleLayer;
shadowArr;
answerTarget;
answerCurrent;
bgRect;
starBgArr;
clickedSuccessArr;
pageLabel;
leftBtn;
rightBtn;
bgLayer;
curPageIndex;
hotZoneArr;
picIndex = 0;
bgArr;
endPageArr;
gameEndFlag;
showPetalFlag;
bg;
topArr;
curPic;
@HostListener('window:resize', ['$event']) @HostListener('window:resize', ['$event'])
onResize(event) { onResize(event) {
this.winResizeEventStream.next(); this.winResizeEventStream.next();
}
constructor(private sanitizer: DomSanitizer, private appRef: ApplicationRef) {
} }
isTeacher = false;
async ngOnInit() {
ngOnInit() {
this.data = {};
// 获取数据 await loadFonts('DroidSansFallback', 'DroidSansFallback.ttf');
const getData = (<any> window).courseware.getData; await loadFonts('Aileron-Black', 'Aileron-Black.ttf');
getData((data) => { await loadFonts('Aileron-Bold', 'Aileron-Bold.ttf');
const getData = (<any>window).courseware.getData;
getData((data, aspect) => {
if (window['air']?.airClassInfo?.user?.classRole == 'tea') {
this.isTeacher = true;
}
if (aspect) {
console.log('aspect : ', aspect);
this.initPageData(aspect);
}
if (data && typeof data == 'object') { if (data && typeof data == 'object') {
this.data = data; this.data = { contentObj: data };
} else {
this.initDefaultData();
} }
// console.log('data:' , data);
// 初始化 各事件监听 console.log('data:', data);
this.initListener(); if (!this.data) {
this.data.contentObj = {};
}
// 若无数据 则为预览模式 需要填充一些默认数据用来显示
this.initDefaultData();
// 初始化 音频资源
this.initAudio(); this.initAudio();
// 初始化 图片资源
this.initImg(); this.initImg();
// 开始预加载资源 this.initListener();
this.load();
}, this.KEY);
}
// 用于存储公共数据 当翻页时清空
pageData;
initPageData(aspect) {
const pageDataStr = aspect?.page_aspect?.pagedata;
if (!pageDataStr) {
this.pageData = {};
} else {
this.pageData = JSON.parse(pageDataStr);
}
console.log('this.pageData: ', this.pageData);
}
setPageData(key, value, isSend=true) {
if (this.pageData) {
}, this.saveKey); console.log('this.pageData: ', this.pageData);
this.pageData[key] = value;
if (isSend) {
this.sendPageData();
}
}
}
getPageData(key) {
if (this.pageData && this.pageData[key] != null) {
return this.pageData[key];
}
}
sendPageData() {
const data = this.pageData;
if (window && window['courseware']) {
let storePageAspect = window['courseware'].storePageAspect;
if (storePageAspect) {
storePageAspect(data);
}
}
}
initDefaultData() {
const data = {"sentenceArr":[{"text":"1. She was not only _ but also very musical.","answer":"starfish"},{"text":"2. A _ is a flat sea creature in the shape of a star with five arms.","answer":"sea horse"},{"text":"3. A _ is a small sea fish with a horse-like head.","answer":"stream"},{"text":"4. There was a small _ at the end of the garden.","answer":"intelligent"}],"templateArr":[{"formUrl":"https://staging-teach.cdn.ireadabc.com/h5template/JM_4-2/v11/index.html?type=form&key=1","template":{"id":740,"uuid":"b4279bef-f779-4ab7-be76-f1af96713a86","name":"JM_4-2","description":"JM04-02拼句子","interaction_type":"","recommend_type":"","cover":"https://staging-teach.cdn.ireadabc.com/d5baf57d-0175-4640-93a5-6baaff117867.png","type":1,"t_type":2,"form_url":"index.html?type=form","play_url":"index.html","developer_id":12,"git":"{\"id\":791,\"ssh\":\"git@vcs.ireadabc.com:template/JM_4-2.git\",\"http\":\"https://vcs.ireadabc.com/template/JM_4-2.git\"}","del":0,"publish":1,"last_version":11,"pub_date":null,"is_public":0,"created_date":"2021-07-26T10:01:26.000Z","updated_date":"2021-08-02T03:24:44.000Z"},"data":{"sentenceArr":[{"answer":"Sea horse","text":"1. _ is a small sea fish that swims in a vertical position and has a head that looks like the head of a horse. ","audio_url":"https://staging-teach.cdn.ireadabc.com/a9f91947f324c79d0d640aa4995cbcd2.mp3"},{"answer":"intelligent","text":"2. The dolphin is an _ animal. ","audio_url":"https://staging-teach.cdn.ireadabc.com/291f7ad56dd0999112256172c4331829.mp3"},{"answer":"stream","text":"3. A _ flowed gently down into the valley. ","audio_url":"https://staging-teach.cdn.ireadabc.com/9520380ba7ebf7fedb69b4ced3d53502.mp3"},{"answer":"starfishes","text":"4. In the oceans, you can find _ and sea horses. They are interesting and beautiful sea animals. ","audio_url":"https://staging-teach.cdn.ireadabc.com/41def023ed829fb5faf197b5de29b7cb.mp3"}],"templateArr":[],"title":"请同学们根据图示的主题自己通过朗读创作一篇文章"}},{"formUrl":"https://staging-teach.cdn.ireadabc.com/h5template/JM04-3/v10/index.html?type=form&key=2","template":{"id":733,"uuid":"3900b0f7-d041-490e-9b42-da8d3855633b","name":"JM04-3","description":"JM04-03拼单词","interaction_type":"","recommend_type":"","cover":"https://staging-teach.cdn.ireadabc.com/0455da10-c452-4cec-9f01-530536b886b3.png","type":1,"t_type":2,"form_url":"index.html?type=form","play_url":"index.html","developer_id":119,"git":"{\"id\":784,\"ssh\":\"git@vcs.ireadabc.com:template/JM04-3.git\",\"http\":\"https://vcs.ireadabc.com/template/JM04-3.git\"}","del":0,"publish":1,"last_version":10,"pub_date":null,"is_public":0,"created_date":"2021-07-20T06:18:52.000Z","updated_date":"2021-08-01T13:16:43.000Z"},"data":{"contentObj":{"version":"1.0","dataKey":"DataKey_JM04_3","title":{"NO":"C","mainText":"Solve the puzzle using the given clue","mainTextAudio_url":""},"size":{"wh":"12*12"},"dataArray":[{"image_url":"","audio_url":"","text":"smart and possessing sound knowledge","uuid":"9803c50c-3638-4a6a-a4f8-719bdeaacede","direction":"Across"},{"image_url":"","audio_url":"","direction":"Across","text":"running water flowing on the earth","uuid":"239d1dde-4fea-40a7-bc02-4fe681e6f20c"},{"image_url":"","audio_url":"","direction":"Across","text":"a fish whose head look like those of a horse","uuid":"5ae09383-2c3f-4c35-9ed8-f3f7c463dc3c"},{"image_url":"","audio_url":"","direction":"Down","text":"a star-shaped sea animal","uuid":"c9d5aeeb-e37a-41a7-8473-df34d28f1779"}],"grid":[[{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[3],"text":"s"},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""}],[{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[1],"text":"s"},{"index":[3],"text":"t"},{"index":[1],"text":"r"},{"index":[1],"text":"e"},{"index":[1],"text":"a"},{"index":[1],"text":"m"},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""}],[{"index":[],"text":""},{"index":[],"text":""},{"index":[2],"text":"s"},{"index":[2],"text":"e"},{"index":[3],"text":"a"},{"index":[2],"text":"h"},{"index":[2],"text":"o"},{"index":[2],"text":"r"},{"index":[2],"text":"s"},{"index":[2],"text":"e"},{"index":[],"text":""},{"index":[],"text":""}],[{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[3],"text":"r"},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""}],[{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[3],"text":"f"},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""}],[{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[3],"text":"i"},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""}],[{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[3],"text":"s"},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""}],[{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[3],"text":"h"},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""}],[{"index":[],"text":""},{"index":[0],"text":"i"},{"index":[0],"text":"n"},{"index":[0],"text":"t"},{"index":[3],"text":"e"},{"index":[0],"text":"l"},{"index":[0],"text":"l"},{"index":[0],"text":"i"},{"index":[0],"text":"g"},{"index":[0],"text":"e"},{"index":[0],"text":"n"},{"index":[0],"text":"t"}],[{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[3],"text":"s"},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""}],[{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""}],[{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""}]]}}}],"title":"Vocabulary box","bg_url":"https://staging-teach.cdn.ireadabc.com/892d0db2075efa3fa7aea6911bf36a83.png"}
this.data = { contentObj: data };
} }
ngOnDestroy() { ngOnDestroy() {
window['curCtx'] = null; window['curCtx'] = null;
window.cancelAnimationFrame(this.animationId); window.cancelAnimationFrame(this.animationId);
this.cleanAudio(); this.gameEndFlag = true;
} }
sentenceArr = [];
submitCount = 0;
safeDefaultUrl;
resultAnswerArr;
cleanAudio() { scrollView;
if (this.audioObj) { resultSv;
for (const key in this.audioObj) {
this.audioObj[key].pause(); initData() {
}
this.canvasWidth = this.wrap.nativeElement.clientWidth * this.canvasScale;
this.canvasHeight = this.wrap.nativeElement.clientHeight * this.canvasScale;
this.canvas.nativeElement.width = this.wrap.nativeElement.clientWidth * this.canvasScale;
this.canvas.nativeElement.height = this.wrap.nativeElement.clientHeight * this.canvasScale;
const sx = this.canvasWidth / this.canvasBaseW;
const sy = this.canvasHeight / this.canvasBaseH;
const s = Math.min(sx, sy);
this.mapScale = s;
console.log('this.mapScale: ', this.mapScale);
this.mapScaleMax = Math.max(sx, sy);
// this.mapScale = this.canvasWidth / this.canvasBaseW;
// this.mapScale = this.canvasHeight / this.canvasBaseH;
this.renderArr = [];
console.log(' in initData', this.data);
this.canTouch = true;
this.submitCount = 0;
this.replaceSentenceText();
this.safeDefaultUrl = this.sanitizer.bypassSecurityTrustResourceUrl('');
this.resultAnswerArr = [];
this.resultSv = null;
}
replaceSentenceText() {
const arr = this.data.contentObj.sentenceArr;
if (!arr) {
console.error('没有数据')
return;
}
this.sentenceArr = JSON.parse(JSON.stringify(arr));
for (let i=0; i<this.sentenceArr.length; i++) {
const text = this.sentenceArr[i].text;
this.sentenceArr[i].text = text.replace(/_/, "____________________")
} }
} }
load() {
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('click', this.rawAudios.get('click'), 1);
addOneAudio('more', this.rawAudios.get('more'), 0.8);
addOneAudio('submit', this.rawAudios.get('submit'), 0.8);
// 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);
}
};
addPicUrl(contentObj.bgItem?.url || '');
}
// this.initFontImg();
// 预加载资源 // 预加载资源
this.loadResources().then(() => { this.loadResources().then(() => {
window["air"].hideAirClassLoading(this.saveKey, this.data); // this.setfontData();
this.init();
this.update();
this.addServerListener();
window['air'].hideAirClassLoading(this.KEY, this.data);
}); });
}
loadEnd(cb) {
this.init();
this.update();
cb()
}
addServerListener() {
console.log(' in addServerListener');
const c = window['courseware'];
if (!c) {
console.log(' window.courseware not exist !!!!!!!!')
return;
}
const air = window['air']
if (!air) {
console.log(' window air err !!!!!!!!')
return;
}
air.onCourseInScreen = (next) => {
//各种逻辑
// this.showTemplateStartAnima();
console.log('in onCourseInScreen')
this.loadEnd(() => {
next();
});
}
c.onEvent('game_start', (data, next) => {
this.gameStart();
if (next) {
next();
}
});
}
sendServerEvent(key, data) {
const c = window['courseware'];
if (c) {
c.sendEvent(key, data);
}
}
gameStart() {
console.log(' in gameStart ');
if (this.isTeacher) {
this.sentBtn.visible = false;
this.sentBtn.shadowSpr.visible = false;
this.maskPic.visible = true;
} else {
this.changeBtnOn();
this.maskPic.visible = false;
}
} }
init() { init() {
this.initCtx();
this.initData(); this.initData();
this.initCtx();
this.initView(); this.initView();
} }
initCtx() { 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;
window['curCtx'] = this.ctx;
}
_initView() {
// const spr = new MySprite()
// spr.init(this.images.get("result_panel_item"));
// this.renderArr.push(spr);
this.renderArr = [];
const scrollView = new ScrollView();
// scrollView.setContentSize(300, 300);
scrollView.setShowSize(200, 200);
scrollView.x = this.canvasWidth / 2;
scrollView.y = this.canvasHeight / 2;
this.scrollView = scrollView;
this.renderArr.push(scrollView);
for (let i=0; i<10; i++) {
const spr = new MySprite()
spr.init(this.images.get("info_icon"));
spr.anchorX = 0;
spr.y = i * 100;
scrollView.addItem(spr)
}
}
initView() {
this.initBg();
this.initHotZone();
// this.initBtn();
// this.initSentence();
// this.changeBtnOff();
// this.initIframe();
// this.initWindowListener();
// this.initMaskPic();
// this.relink();
// // this.gameStart();
// // this.testInput()
}
testInput() {
const tmpRect = this.sentenceEmptyArr[0].getBoundingBox();
const svBox = this.scrollView.getBoundingBox();
const x = svBox.x + tmpRect.x * this.mapScale;
const y = svBox.y + tmpRect.y * this.mapScale;
const width = tmpRect.width * this.mapScale;
const height = tmpRect.height * this.mapScale;
const rect = {x, y, width, height};
console.log('rect: ', rect);
// const shape = new ShapeRectNew();
// shape.setSize(200, 200, 1);
// shape.fillColor = '#0000ff'
// shape.x = 500;
// shape.y = 500;
// this.topArr.push(shape);
}
inputView;
showInputView(style, rect, value, cb) {
if (!this.inputView) {
this.inputView = new InputView();
this.inputView.isShowScroll = true;
}
const inputView = this.inputView;
inputView.show();
inputView.x = rect.x / this.canvasScale ; // this.canvasWidth / 2;
inputView.y = rect.y / this.canvasScale ; // this.canvasHeight / 2;
inputView.width = rect.width / this.canvasScale ;
inputView.height = rect.height / this.canvasScale ;
inputView.text = value;
inputView.callback = cb;
inputView.setStyle(style);
inputView.refreshInputStyle();
}
hideInputView() {
if (!this.inputView) {
return;
}
this.inputView.hide();
}
relink() {
const progress = this.getPageData('progress');
if (this.isTeacher) {
if (progress != null) {
this.gameStart();
return;
}
return;
}
if (progress == '1') {
const resultData = this.getPageData('resultData')
if (resultData) {
this.initResultView(resultData);
return;
}
this.gameStart();
return;
}
if (progress == '2' || progress == '3') {
const submitCount = this.getPageData('submitCount')
this.submitCount = submitCount;
this.checkShowSubTemplateOne();
return;
}
}
maskPic;
initMaskPic() {
const bgUrl = this.data.contentObj.bg_url;
console.log('bgUrl', bgUrl);
const maskPic = this.getMySprite(bgUrl);
const sx = this.canvasWidth / maskPic.width;
const sy = this.canvasHeight / maskPic.height;
const s = Math.max(sx, sy);
maskPic.setScaleXY(s);
maskPic.x = this.canvasWidth / 2;
maskPic.y = this.canvasHeight / 2;
if (this.isTeacher) {
maskPic.visible = false;
}
this.maskPic = maskPic;
}
getMySprite(resName, isSetScale = true) {
const spr = new MySprite();
spr.init(this.images.get(resName))
if (isSetScale) {
spr.setScaleXY(this.mapScale);
}
return spr;
}
setRectRight(data) {
for (let i=0; i<this.sentenceEmptyArr.length; i++) {
if (data[i]) {
this.sentenceEmptyArr[i].isRight = true;
}
}
}
resultLayer;
resultPanel;
moreBtn;
initResultView(data = null) {
if (data) {
this.setRectRight(data);
} else {
const resultData = this.getResultData();
this.sendResult(resultData);
this.setPageData('resultData', resultData);
}
const resultLayer = new MySprite()
resultLayer.x = this.canvasWidth / 2;
resultLayer.y = this.canvasHeight / 2;
const bg = new MySprite();
bg.init(this.images.get("result_bg"))
bg.x = 0
bg.y = 0;
bg.setScaleXY(this.mapScaleMax);
resultLayer.addChild(bg);
const bgItem = new MySprite();
bgItem.init(this.images.get("result_bg_item"));
bg.addChild(bgItem);
const panelOffY = -50 * this.mapScale;
const panel = new MySprite();
panel.init(this.images.get("result_panel"));
panel.setScaleXY(this.mapScale);
panel.y = panelOffY;
resultLayer.addChild(panel, 1);
const panelItem = new MySprite();
panelItem.init(this.images.get("result_panel_item"));
panelItem.y = -600;
panel.addChild(panelItem);
const itemLabel = new RichText();
itemLabel.fontSize = 52;
// itemLabel.y = 5;
itemLabel.width = panelItem.width;
itemLabel.fontColor = '#ffffff'
itemLabel.fontName = 'Aileron-Black';
itemLabel.text = 'Check'
itemLabel.y = 10;
itemLabel.textAlign = 'center';
panelItem.addChild(itemLabel, 5);
const panelShadow = new MySprite();
panelShadow.init(this.images.get("result_panel_shadow"));
// panelShadow.setScaleXY(this.mapScale);
panelShadow.y = ( panel.height / 2 - 20 );
panel.addChild(panelShadow);
const btn = new MySprite();
btn.init(this.images.get("big_btn"));
btn.setScaleXY(this.mapScale);
btn.y = panel.y + ( panel.height / 2 + 120 ) * panel.scaleY;
resultLayer.addChild(btn, 2);
this.moreBtn = btn;
const btnShadow = new MySprite();
btnShadow.init(this.images.get("big_btn_shadow"));
btnShadow.setScaleXY(this.mapScale);
btnShadow.y = btn.y + 30 * this.mapScale;
resultLayer.addChild(btnShadow);
const btnLabel = new Label();
btnLabel.fontSize = 64;
btnLabel.fontName = 'Aileron-Black';
btnLabel.textAlign = 'center';
btnLabel.text = '更多练习';
btnLabel.y = 5;
btnLabel.fontColor = '#ffffff';
btn.addChild(btnLabel, 3);
this.topArr.push(resultLayer);
this.resultPanel = panel;
this.resultLayer = resultLayer;
this.initResultSentence();
}
getResultData() {
const dataArr = [];
for (let i=0; i<this.sentenceEmptyArr.length; i++) {
dataArr.push(this.sentenceEmptyArr[i].isRight == true);
}
return dataArr;
}
initResultSentence() {
const resultSv = new ScrollView();
resultSv.setShowSize(this.resultPanel.width, this.resultPanel.height * 0.85);
resultSv.setBgColor("#3e9e33");
resultSv.x = -this.resultPanel.width / 2;
resultSv.y = -this.resultPanel.height / 2 + 120;
resultSv.setScrollBarSize(20 * this.mapScale, 5);
resultSv.setContentScale(this.mapScale);
this.resultPanel.addChild(resultSv);
this.resultSv = resultSv;
let baseY = 0 //-500;
for (let i=0; i<this.sentenceArr.length; i++) {
const richText = new RichText();
richText.disH = 5;
// richText.x = -this.panel.width / 2 * 0.9
richText.x = 0.05 * this.panel.width;
richText.y = baseY + 80;
richText.fontSize = 48;
richText.width = this.panel.width * 0.9;
richText.fontColor = '#ffffff'
richText.fontName = 'DroidSansFallback';
richText.text = this.sentenceArr[i].text;
// this.resultPanel.addChild(richText, 1)
resultSv.addItem(richText);
const rect = richText.getSubTextRect('____________________');
rect.width += 8;
rect.height += 16;
const colorRect = new ShapeRectNew();
colorRect.setSize(rect.width, rect.height, 10);
colorRect.fillColor = '#007b3e'
const offX = 9;
colorRect.x = rect.x + offX;
colorRect.y = -rect.height / 2;
// colorRect.alpha = 0.5;
richText.addChild(colorRect);
baseY = richText.y + richText.getAreaHeight();
if (!this.sentenceEmptyArr[i].isRight) {
colorRect.fillColor = '#d71818'
const infoBg = new MySprite();
infoBg.init(this.images.get("info_bg"));
infoBg.y = baseY + 50;
infoBg.x = this.resultPanel.width / 2 * this.mapScale;
resultSv.addItem(infoBg);
// this.resultPanel.addChild(infoBg);
baseY += 130;
const infoIcon = new MySprite();
infoIcon.init(this.images.get("info_icon"));
infoIcon.x = -infoBg.width / 2 + 100;
infoBg.addChild(infoIcon);
const infoLabel = new RichText();
infoLabel.x = infoIcon.x + 50;
infoLabel.fontSize = 48;
infoLabel.y = 5;
infoLabel.width = infoBg.width;
infoLabel.fontColor = '#ffe9b1'
infoLabel.fontName = 'Aileron-Black';
infoLabel.text = this.sentenceArr[i].answer;
infoBg.addChild(infoLabel);
} else {
const labelAnswer = this.getFillLabel();
labelAnswer.fontSize = 48;
labelAnswer.fontColor = '#ffffff'
labelAnswer.fontName = 'Aileron-Black';
labelAnswer.text = this.sentenceArr[i].answer;
labelAnswer.setScaleXY(1);
labelAnswer.textAlign = 'center';
labelAnswer.refreshSize();
labelAnswer.x = colorRect.width / 2;
labelAnswer.y = colorRect.height / 2;
colorRect.addChild(labelAnswer);
}
if (i != this.sentenceArr.length - 1) {
const line = new MySprite();
line.init(this.images.get("line"));
line.x = this.resultPanel.width / 2;
line.y = baseY + 30;
resultSv.addItem(line);
// this.resultPanel.addChild(line);
baseY = line.y
}
}
}
submitBtn;
btnArr = [];
btnDisH = 120;
initBtn() {
this.topArr = [];
const btnArr = [];
let arr = JSON.parse(JSON.stringify(this.sentenceArr)) ;
arr = randomSortByArr(arr);
if (!arr) {
return;
}
const disW = 400 * this.mapScale;
const disH = this.btnDisH * this.mapScale;
const tmpLen = arr.length > 5 ? 5 : arr.length;
let baseX = this.canvasWidth / 2 - (tmpLen - 1) * disW / 2
let baseY = this.canvasHeight / 2 - 380 * this.mapScale;
let col = 0;
for (let i=0; i<arr.length; i++) {
const btn = new MySprite();
btn.init(this.images.get("btn"))
btn.x = baseX + disW * col;
btn.y = baseY;
btn['baseX'] = btn.x;
btn['baseY'] = btn.y;
btn.setScaleXY(this.mapScale * 0.8);
const btnBg = new MySprite();
btnBg.init(this.images.get("btn_bg"))
btnBg.x = btn.x;
btnBg.y = btn.y;
btnBg.setScaleXY(this.mapScale * 0.8);
this.renderArr.push(btnBg);
this.topArr.push(btn);
this.addBtnLabel(btn, arr[i].answer);
btnArr.push(btn);
col ++ ;
if (col % 5 == 0) {
col = 0;
baseY += disH;
}
}
this.btnArr = btnArr;
if (this.isTeacher) {
this.initSentBtn();
return;
}
const submitBtn = new MySprite();
submitBtn.init(this.images.get("submit"));
submitBtn.setScaleXY(this.mapScale);
submitBtn.x = this.canvasWidth / 2 + 650 * this.mapScale;
submitBtn.y = this.canvasHeight / 2 + 650 * this.mapScale;
const submitShadow = new MySprite();
submitShadow.init(this.images.get("submit_shadow"));
submitShadow.setScaleXY(this.mapScale);
submitShadow.x = submitBtn.x;
submitShadow.y = submitBtn.y + 20 * this.mapScale;
const submitOff = new MySprite();
submitOff.init(this.images.get("submit_off"));
submitOff.setScaleXY(this.mapScale);
submitOff.x = submitBtn.x;
submitOff.y = submitBtn.y + 5 * this.mapScale;
submitBtn['baseY'] = submitBtn.y;
submitBtn['offBtn'] = submitOff;
submitBtn['shadowSpr'] = submitShadow;
submitShadow['baseY'] = submitShadow.y;
this.renderArr.push(submitShadow);
this.renderArr.push(submitBtn);
this.renderArr.push(submitOff);
this.submitBtn = submitBtn;
this.submitOff();
}
sentBtn;
initSentBtn() {
const panel = this.panel;
const btn = new MySprite();
btn.init(this.images.get("big_btn"));
btn.setScaleXY(this.mapScale);
btn.x = this.canvasWidth / 2;
btn.y = panel.y + ( panel.height / 2 - 120 ) * panel.scaleY;
this.sentBtn = btn;
const btnShadow = new MySprite();
btnShadow.init(this.images.get("big_btn_shadow"));
btnShadow.setScaleXY(this.mapScale);
btnShadow.x = btn.x;
btnShadow.y = btn.y + 20 * this.mapScale;
this.sentBtn.shadowSpr = btnShadow;
const btnLabel = new Label();
btnLabel.fontSize = 64;
btnLabel.fontName = 'Aileron-Black';
btnLabel.textAlign = 'center';
btnLabel.text = 'Send';
btnLabel.y = 5;
btnLabel.fontColor = '#ffffff';
btn.addChild(btnLabel, 3);
this.renderArr.push(btnShadow);
this.renderArr.push(btn);
}
submitOff() {
this.submitBtn.offBtn.visible = true;
this.submitBtn.visible = false;
this.submitBtn.shadowSpr.visible = false;
}
submitOn() {
// this.submitBtn.y = this.submitBtn.baseY;
// this.submitBtn.scale = this.mapScale;
// this.submitBtn.shadowSpr.alpha = 1;
// this.submitBtn.shadowSpr.y = this.submitBtn.shadowSpr.baseY;
this.submitBtn.visible = true;
this.submitBtn.shadowSpr.visible = true;
this.submitBtn.offBtn.visible = false;
}
addBtnLabel(btn, text) {
console.log('text: ', text);
const label = new Label();
label.fontSize = 64;
label.fontName = 'Aileron-Black';
label.textAlign = 'center';
label.text = text;
// label.x = this.canvasWidth / 2;
label.y = -2;
label.fontColor = '#f1e4c2';
btn.addChild(label);
btn.text = text;
return label;
}
sentenceEmptyArr;
initSentence() {
const row = Math.floor( (this.btnArr.length - 1) / 5 ) + 1;
const subH = row * this.btnDisH ;
const sv = new ScrollView();
sv.setShowSize(this.panel.width, 900 - subH);
sv.x = -this.panel.width / 2;
sv.y = -395 + subH;
sv.setBgColor('#faf7ee')
// sv.setMapScale(this.mapScale);
// sv.content.setScaleXY(1/this.mapScale);
sv.setScrollBarSize(20 * this.mapScale, 5)
// this.renderArr.push(sv);
// sv.setScaleXY(this.mapScale);
// sv.x = 0;
// sv.y = 200;
sv.setContentScale(this.mapScale);
this.panel.addChild(sv);
this.scrollView = sv;
this.sentenceEmptyArr = [];
const arr = this.sentenceArr;
// const arr = this.sentenceArr.concat(this.sentenceArr);
if (!arr) {
return;
}
const baseX = this.panel.width / 2 - 1000;
let curY = 70 // this.canvasHeight / 2 - 110 * this.mapScale;
const disH = 70 * this.mapScale;
for (let i=0; i<arr.length; i++) {
const richText = this.getSentenceLabel();
richText.x = baseX;
richText.y = curY;
richText.text = arr[i].text;
const rect = richText.getSubTextRect('____________________');
const colorRect = new ShapeRectNew();
rect.height += 30;
colorRect.setSize(rect.width, rect.height, 1);
colorRect.fillColor = '#ff0000'
const offX = 13;
colorRect.x = rect.x + offX;
colorRect.y = -rect.height / 2;
console.log('rect.height: ', rect.height);
colorRect.alpha = 0;
richText.addChild(colorRect);
this.sentenceEmptyArr.push(colorRect);
curY += richText.getAreaHeight() * this.mapScale + disH;
richText['data'] = arr[i];
sv.addItem(richText);
// this.renderArr.push(richText);
colorRect.ctx = colorRect.parent.ctx;
}
}
getFillLabel() {
const label = new RichText();
label.fontSize = 56;
label.fontColor = '#000000'
label.fontName = 'Aileron-Bold';
// label.setScaleXY(this.mapScale);
return label;
}
getSentenceLabel() {
const richText = new RichText();
richText.disH = 0;
richText.fontSize = 56;
richText.width = 2000 / this.mapScale
richText.fontColor = '#000000'
richText.fontName = 'DroidSansFallback';
richText.setScaleXY(this.mapScale);
return richText;
}
changeBtnOff() {
for (let i=0; i<this.btnArr.length; i++) {
if (this.btnArr[i].visible) {
this.btnArr[i].init(this.images.get('btn_off'));
this.btnArr[i].isOff = true;
}
}
}
changeBtnOn() {
for (let i=0; i<this.btnArr.length; i++) {
if (this.btnArr[i].visible) {
this.btnArr[i].init(this.images.get('btn'));
this.btnArr[i].isOff = false;
}
}
}
_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();
}
}
panel;
initBg() {
const bgW = new ShapeRect()
bgW.setSize(this.canvasWidth, this.canvasHeight);
bgW.fillColor = '#ffffff';
this.renderArr.push(bgW);
console.log('this.data: ', this.data);
const sv = new ScrollView();
sv.setShowSize(this.canvasWidth, this.canvasHeight);
// sv.x = -this.canvasWidth / 2;
// sv.y = 0;
sv.setBgColor('#faf7ee')
sv.setScrollBarSize(20 * this.mapScale, 5)
// sv.setContentScale(this.mapScale);
this.renderArr.push(sv);
this.scrollView = sv;
const url = this.data.contentObj.bgItem?.url;
if (url) {
const bg = new MySprite();
bg.init(this.images.get(url));
const sx = this.canvasWidth / bg.width;
bg.setScaleXY(sx);
bg.x = this.canvasWidth / 2;
bg.y = 10;
// bg.y = this.canvasHeight / 2 * sx;
bg.anchorY = 0;
// this.renderArr.push(bg);
this.scrollView.addItem(bg);
bg['data'] = this.data.contentObj.bgItem;
this.bg = bg;
}
// bg.x = this.canvasWidth / 2;
// bg.y = this.canvasHeight / 2;
// bg.scaleX = this.canvasWidth / bg.width;
// bg.scaleY = this.canvasHeight / bg.height;
return;
const bgItem = new MySprite();
bgItem.init(this.images.get("bg_item"));
bgItem.x = this.canvasWidth / 2;
bgItem.y = this.canvasHeight / 2;
bgItem.setScaleXY(this.mapScale);
this.renderArr.push(bgItem);
const panel = new MySprite();
panel.init(this.images.get("panel"));
panel.x = this.canvasWidth / 2;
panel.y = this.canvasHeight / 2;
panel.setScaleXY(this.mapScale);
this.renderArr.push(panel);
// const panelItem = new MySprite();
// panelItem.init(this.images.get("panel_item"));
// panelItem.anchorY = 1;
// // panelItem.x = this.canvasWidth / 2;
// panelItem.y = 550;
// panel.addChild(panelItem);
const title = new Label();
title.fontSize = 72;
title.fontName = 'Aileron-Bold';
title.textAlign = 'center';
// title.setMaxSize(this.canvasWidth * 0.9);
// title.x = this.canvasWidth / 2;
title.y = -panel.height / 2 + 130;
title.fontColor = '#3c9e32';
title.text = this.data.contentObj.title || "";
panel.addChild(title);
title.refreshSize();
this.panel = panel;
}
curMoveItem = null;
downFlag = false;
mapDown(event) {
if (!this.canTouch) {
return;
}
if (this.maskPic?.visible) {
return;
}
this.downFlag = true;
if (this.isTeacher) {
if (this.sentBtn && this.sentBtn.visible) {
if (this.checkClickTarget(this.sentBtn)) {
this.sendServerEvent('game_start', {});
this.setPageData('progress', '1');
this.playAudio('submit', true);
}
}
return;
}
for (let i = 0; i < this.hotZoneArr.length; i++) {
if (this.checkClickTargetSv(this.hotZoneArr[i])) {
this.emptyRectDown(this.hotZoneArr[i]);
return;
}
}
console.log('aaaa 6')
if (this.checkClickTarget(this.scrollView)) {
this.scrollView.onTouchStart(this.mx, this.my);
return;
}
this.downFlag = false;
}
mapMove(event) {
if (event) {
event.preventDefault()
}
this.scrollView.onTouchMove(this.mx, this.my);
return;
if (this.resultSv) {
this.resultSv.onTouchMove(this.mx, this.my);
} else {
this.scrollView.onTouchMove(this.mx, this.my);
}
if (!this.curMoveItem) {
return;
}
if (!this.downFlag) {
return;
}
this.curMoveItem.x = this.mx;
this.curMoveItem.y = this.my;
if (this.curMoveItem.moveOffX) {
this.curMoveItem.x += this.curMoveItem.moveOffX;
this.curMoveItem.y += this.curMoveItem.moveOffY;
}
// this.curMoveItem.ctx = this.ctx;
}
mapUp(event) {
this.scrollView.onTouchEnd(this.mx, this.my);
return;
this.downFlag = false;
if (this.curMoveItem) {
this.checkOnTarget();
}
this.curMoveItem = null;
if (this.resultSv) {
this.resultSv.onTouchEnd(this.mx, this.my);
} else {
this.scrollView.onTouchEnd(this.mx, this.my);
}
}
moreBtnClick() {
// this.setPageData('progress', '2', false);
// this.setPageData('submitCount', this.submitCount);
this.checkShowSubTemplateOne();
this.isUpdateStop = true;
// this.serverSendAnswer();
}
checkShowSubTemplateOne() {
// this.showSubTemplate(0);
console.log(' in checkShowSubTemplateOne')
const progress = this.getPageData('progress');
console.log(' progress: ', progress);
if (progress == '2') {
if (this.submitCount == 1) {
this.showSubTemplate(1);
this.sendSubTempIsShowMore(1, true);
} else {
this.showSubTemplate(0);
this.sendSubTempIsShowMore(0, true);
}
return;
}
if (progress == '3') {
let index;
if (this.submitCount == 1) {
index = 0;
this.hideSubTemplate(1);
} else {
index = 1;
this.hideSubTemplate(0);
}
this.showSubTemplate(index);
this.sendSubTempIsShowMore(index, false);
}
}
sendSubTempIsShowMore(index, isShowMore) {
setTimeout(() => {
const divArr = this.iframeContent.nativeElement.children;
const iframecont = divArr[index].children[0];
const data = { msg: 'success', isShowMore};
iframecont.contentWindow.postMessage({ action: 'is_show_more', data: JSON.stringify(data) }, '*');
console.log(' post msg is_show_more ')
}, 1000);
}
btnDown(btn) {
this.curMoveItem = btn;
}
addLabelMask(target, label) {
const rect = target.getBoundingBox();
const mask = new ShapeRect();
mask.x = rect.x;
mask.y = rect.y;
mask.setSize(rect.width, rect.height);
label.addMaskSpr(mask);;
}
emptyRectDown(targetRect) {
if (!targetRect.label) {
const label = this.getFillLabel();
label.disH = 0;
label.textBaseline = 'top'
label.width = targetRect.width;
// targetRect.label.x = ( targetRect.width / 2 )
targetRect.label = label;
targetRect.addChild(targetRect.label);
this.addLabelMask(targetRect, label);
}
if (true) {
const scale = 1 // this.mapScale;
let tmpRect = targetRect.getBoundingBox();
const svBox = this.scrollView.getBoundingBox();
const x = svBox.x + tmpRect.x * scale;
const y = svBox.y + tmpRect.y * scale;
const width = tmpRect.width * scale;
const height = tmpRect.height * scale;
const rect = {x, y, width, height};
const style = {
'font-size' : 56 / this.canvasScale * scale + 'px',
'color' : '#000000',
'font-family' : 'Aileron-Bold',
'line-height' : 56 / this.canvasScale * scale + 'px',
}
this.showInputView(style, rect, targetRect.label.text || '', (value) => {
targetRect.label.text = value;
})
return;
// emptyRect.label.visible = false;
// console.log('emptyRect.label: ', emptyRect.label);
// const label = this.getFillLabel();
// label.textAlign = 'center';
// label.text = emptyRect.label.text;
// this.renderArr.push(label);
// label['targetLabel'] = emptyRect.label;
// label['fillRect'] = emptyRect.label.fillRect;
// this.curMoveItem = label;
// this.mapMove(null)
// return;
}
}
submitBtnClick() {
this.submitCount ++;
const btnBaseY = this.submitBtn['baseY'];
const btnTargetY = this.submitBtn['baseY'] + 5 * this.mapScale;
const baseS = this.submitBtn.scaleX;
const targetS = baseS * 0.95;
const time = 0.07;
this.canTouch = false;
tweenChange(this.submitBtn, {y: btnTargetY, scaleX: targetS, scaleY: targetS}, time, ()=> {
// tweenChange(this.submitBtn, {y: btnBaseY, scaleX: baseS, scaleY: baseS}, time)
this.canTouch = true;
this.submitOff();
const isAllRight = this.checkAnswer();
if (isAllRight || this.submitCount >= 2) {
this.changeBtnOff();
this.btnArr = [];
delayCall(0.3, ()=> {
this.initResultView();
this.setPageData('progress', '2', false);
this.setPageData('submitCount', this.submitCount);
this.serverSendAnswer('4-1', this.resultAnswerArr);
})
}
})
const shadow = this.submitBtn.shadowSpr;
const shadowBaseY = shadow['baseY'];
const shadowTargetY = shadow['baseY'] - 15 * this.mapScale;
tweenChange(shadow, {y: shadowTargetY, alpha: 0}, time, ()=> {
// tweenChange(shadow, {y: shadowBaseY, alpha: 1}, time)
})
this.addResultAnswer();
}
addResultAnswer() {
console.log('this.data.contentObj.sentenceArr: ', this.data.contentObj.sentenceArr)
console.log('this.sentenceEmptyArr: ', this.sentenceEmptyArr);
const sentenceArr = this.data.contentObj.sentenceArr;
const resultAnswer = [];
for (let i=0; i<sentenceArr.length; i++) {
const label = this.sentenceEmptyArr[i].label;
const tmpData = {};
tmpData['question'] = sentenceArr[i];
tmpData['userAnswer'] = label.text;
resultAnswer.push(tmpData);
}
this.resultAnswerArr.push(resultAnswer);
}
sendResult(data) {
// const sendResult = (<any>window).courseware.sendResult;
// sendResult(data);
}
checkAnswer() {
let isAllRight = true;
for (let i=0; i<this.sentenceEmptyArr.length; i++) {
const rightData = this.sentenceArr[i];
console.log('rightData: ', rightData);
const answer = this.sentenceEmptyArr[i].label.text;
console.log('answer: ', answer)
if (rightData.answer != answer) {
this.removeRectText( this.sentenceEmptyArr[i] );
isAllRight = false;
} else {
this.showSentenceRight(this.sentenceEmptyArr[i]);
}
}
return isAllRight;
}
removeRectText(emptyRect) {
this.showBtnByText(emptyRect.label.text);
emptyRect.removeChild(emptyRect.label);
// removeItemFromArr(this.renderArr, emptyRect.label);
emptyRect.label = null;
}
showSentenceRight( emptyRect ) {
if (!emptyRect.isRight) {
emptyRect.isRight = true;
const pos = {x: emptyRect.width / 2, y: emptyRect.height / 2};
this.showRightParticle(emptyRect, pos)
}
}
showRightParticle(emptyRect, point ) {
const shapeW = 25 // * this.mapScale;
const shapeH = 25 // * this.mapScale;
showShapeParticle( 'rect', shapeW, shapeH, point, emptyRect, 20, 50, 180, 0.4);
}
showBtnByText(text) {
for (let i=0; i<this.btnArr.length; i++) {
if (this.btnArr[i].text == text) {
this.btnArr[i].visible = true;
return;
}
}
}
checkOnTarget() {
for (let i = 0; i < this.sentenceEmptyArr.length; i++) {
if (this.checkClickTargetSv(this.sentenceEmptyArr[i])) {
this.playAudio('click', true);
if (this.sentenceEmptyArr[i].isRight) {
this.moveItemBack();
return;
}
const tmpText = this.sentenceEmptyArr[i].label ? this.sentenceEmptyArr[i].label.text : '';
const btnIndex = this.btnArr.indexOf(this.curMoveItem);
const isBtn = btnIndex != -1;
console.log('isBtn: ', isBtn);
if (isBtn && tmpText != '') {
this.moveItemBack();
return;
}
this.fillText(this.sentenceEmptyArr[i], this.curMoveItem.text);
if (this.curMoveItem.fillRect) {
this.fillText(this.curMoveItem.fillRect, tmpText);
this.curMoveItem.text = tmpText;
this.moveItemBack();
}
if (isBtn) {
this.removeBtn(this.curMoveItem);
}
this.checkShowSubmit();
return;
}
}
this.moveItemBack();
}
removeBtn(btn) {
this.moveItemBack();
btn.visible = false;
// removeItemFromArr(this.btnArr, btn);
// removeItemFromArr(this.topArr, btn);
}
fillText(emptyRect, text) {
const data = emptyRect.parent.data;
if (!emptyRect.label) {
emptyRect.label = this.getFillLabel();
emptyRect.label.setScaleXY(1);
emptyRect.label.textAlign = 'center';
emptyRect.addChild(emptyRect.label);
// this.renderArr.push(emptyRect.label);
}
const label = emptyRect.label
label.text = text;
// label.width = emptyRect.width / this.mapScale;
// label.setScaleXY(1);
label.refreshSize();
label.anchorY = 0.5;
// label.y = emptyRect.parent.y //- label.height * label.scaleY ;
// label.x = emptyRect.parent.x + ( emptyRect.x + emptyRect.width / 2 - label.width / 2 ) * this.mapScale
label.y = emptyRect.height / 2;
label.x = ( emptyRect.width / 2 )
// const w1 = emptyRect.width / this.mapScale;
// const w2 = label.width;
// label.width = w1// w2 < w1 ? w1: w2;
label['moveOffX'] = -label.width / 2 * label.scaleX;
label['moveOffY'] = 0// -label.height / 2 * label.scaleY;
label['baseX'] = label.x;
label['baseY'] = label.y;
emptyRect.label = label;
label.fillRect = emptyRect;
console.log('label: ', label.width);
}
checkShowSubmit() {
for (let i=0; i<this.btnArr.length; i++) {
if (this.btnArr[i].visible) {
return;
}
}
this.submitBtn.visible = true;
this.submitBtn.shadowSpr.visible = true;
this.submitBtn.offBtn.visible = false;
}
moveItemBack() {
if (this.curMoveItem.targetLabel) {
this.curMoveItem.targetLabel.visible = true;
removeItemFromArr(this.renderArr, this.curMoveItem);
return;
}
this.curMoveItem.x = this.curMoveItem['baseX'];
this.curMoveItem.y = this.curMoveItem['baseY'];
}
templateArr = [];
initIframe() {
this.templateArr = this.data.contentObj.templateArr;
if (this.templateArr.length <= 0) {
return;
}
console.log('arr: ', this.templateArr);
const c = window['courseware'];
if (!c) {
console.error('not found window.courseware')
return;
}
const addPlayUrl = (name, index) => {
c.getTemplateUrl(name, (data) => {
console.log('name~: ', name)
const urlData = JSON.parse(data)
console.log('data~~:' , data)
console.log('urlData~~:' , urlData)
console.log('i~~:' , index)
this.templateArr[index].playUrl = this.sanitizer.bypassSecurityTrustResourceUrl(urlData.play_url + `?key=${index+1}`);
this.appRef.tick();
index ++;
if (index < this.templateArr.length) {
const {name, last_version, play_url} = this.templateArr[index].template;
addPlayUrl(name, index);
}
})
}
const {name, last_version, play_url} = this.templateArr[0].template;
addPlayUrl(name, 0);
// for (let i=0; i<this.templateArr.length; i++) {
// const {name, last_version, play_url} = this.templateArr[i].template;
// const index = i;
// c.getTemplateUrl(name, (data) => {
// console.log('name~: ', name)
// const urlData = JSON.parse(data)
// console.log('data~~:' , data)
// console.log('urlData~~:' , urlData)
// console.log('i~~:' , index)
// this.templateArr[index].playUrl = this.sanitizer.bypassSecurityTrustResourceUrl(urlData.play_url + `?key=${index+1}`);
// })
// const playUrl = `https://staging-teach.cdn.ireadabc.com/h5template/${name}/v${last_version}/${play_url}?key=${i+1}`
// this.templateArr[i].playUrl = this.sanitizer.bypassSecurityTrustResourceUrl(playUrl);
// console.log('playUrl: ', playUrl);
// }
// this.showSubTemplate(0);
// setTimeout(() => {
// this.showSubTemplate(1);
// }, 5000);
}
showSubTemplate(index) {
if (this.isTeacher) {
return;
}
console.log('showSubTemplate _ ', index);
const arr = this.templateArr;
console.log('arr: ', arr);
for (let i=0; i<arr.length; i++) {
arr[i].leftOff = '0vw';
}
arr[index].leftOff = '100vw';
this.appRef.tick();
if (this.readyObj[(index + 1).toString()]) {
this.sendCourseIn(index);
}
}
hideSubTemplate(index) {
this.templateArr[index].isHide = true;
this.appRef.tick();
}
iframeArr;
readyObj;
initWindowListener() {
// const iframeArr = this.iframeArr;
// // setTimeout(() => {
// console.log("iframeContent: ", this.iframeContent);
// let divArr = this.iframeContent.nativeElement.children;
// console.log('divArr: ', divArr);
// for (let i=0; i<divArr.length; i++) {
// const iframe = divArr[i].children[0];
// console.log('iframe: ', iframe);
// iframeArr.push(iframe)
// }
// console.log('iframeArr: ', iframeArr);
// // }, 1);
this.readyObj = {};
window.addEventListener('message', (e) => {
let msgData = e.data;
if (msgData.action === "getData") {
console.log('msgData.urlParams: ', msgData);
const key = this.getQueryVariable(msgData.urlParams, 'key');
if (!key) {
return;
}
console.log('key: ', key);
const index = key - 1;
const divArr = this.iframeContent.nativeElement.children;
const iframecont = divArr[index].children[0];
// const iframecont = iframeArr[key-1]
const saveData = this.templateArr[index].data;
console.log("getData e: ", e);
const data = { msg: 'success', data: JSON.stringify(saveData)};
iframecont.contentWindow.postMessage({ action: 'getData', data: JSON.stringify(data) }, '*');
// const data2 = { msg: 'success', data: JSON.stringify({'isShowMore': false})};
// iframecont.contentWindow.postMessage({ action: 'is_show_more', data: JSON.stringify(data2) }, '*');
// setTimeout(() => {
// _this.frameLoaded = true;
// }, 300);
}
if (msgData.action === "temp_send_result") {
console.log(' in temp_send_result');
console.log('msgData.urlParams: ', msgData);
let key = msgData.key;
if (!key) {
key = '4-3';
}
console.log("key: ", key);
this.serverSendAnswer(key, JSON.parse( msgData.data ));
const progress = this.getPageData('progress');
if (progress == '2') {
this.setPageData('progress', '3');
} else {
this.setPageData('progress', '4');
}
console.log('in temp_send_result __ msgData: ', msgData);
}
if (msgData.action === "temp_show_more") {
console.log(' in temp_show_more');
this.checkShowSubTemplateOne();
}
if (msgData.action == 'course-ready') {
console.log(' in course-ready msgData: ', msgData)
console.log('msgData.urlParams: ', msgData);
const key = this.getQueryVariable(msgData.urlParams, 'key');
if (!key) {
return;
}
this.readyObj[key] = true;
}
});
}
sendCourseIn(index) {
const divArr = this.iframeContent.nativeElement.children;
const iframecont = divArr[index].children[0];
const data = { msg: 'success', data: ''};
iframecont.contentWindow.postMessage({ action: 'airEvents', evt: 'course-in-screen', data: JSON.stringify(data) }, '*');
}
getQueryVariable(url, variable) {
var query = url.substring(1);
var vars = query.split("&");
for (var i=0;i<vars.length;i++) {
var pair = vars[i].split("=");
if(pair[0] == variable){return pair[1];}
}
return(false);
}
serverResultObj;
serverSendAnswer(key, data) {
const c = window['courseware'];
if (!c) {
return;
}
if (!this.serverResultObj) {
this.serverResultObj = {};
}
this.serverResultObj[key] = data;
c.sendAnswer(this.serverResultObj);
console.log(' sendAnswer : ', this.serverResultObj);
console.log(' sendAnswer : ' + JSON.stringify( this.serverResultObj ));
}
isUpdateStop = false;
update() {
if (this.isUpdateStop) {
return;
}
this.animationId = window.requestAnimationFrame(this.update.bind(this));
// 清除画布内容
this.ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight);
TWEEN.update();
this.updateArr(this.renderArr);
// this.updateArr(this.topArr);
// if (this.curMoveItem) {
// this.curMoveItem.update();
// }
// this.updateItem(this.maskPic);
// 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);
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;
if (hotZone) {
this.hotZoneArr.push(hotZone);
}
}
}
openBtn;
getHotZoneItem(data) {
console.log(' item data: ', data);
switch(data.gIdx) {
case "0":
return this.setOneRect(data);
case "1":
return;
}
return;
const saveRect = data.rect;
if (data.gIdx == '0') {
//遮照
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;
this.maskBg.setMaskType("destination-out");
this.maskBg.addMaskSpr(pic);
return pic;
} else {
//open按钮
const openBtn = new MySprite();
openBtn.init(this.images.get("open"))
openBtn.x = saveRect.x + saveRect.width / 2;
openBtn.y = saveRect.y + saveRect.height / 2;
openBtn['data'] = data;
openBtn.setScaleXY(this.mapScale);
this.openBtn = openBtn;
this.renderArr.push(openBtn);
}
// 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.renderArr.push(item);
// return item;
}
setOneRect(data) {
const saveRect = data.rect;
const item = new ShapeRect(this.ctx);
item.setSize(saveRect.width, saveRect.height);
item.x = saveRect.x
item.y = saveRect.y
// item.setScaleXY(this.bg.scaleX);
item.fillColor = '#ff0000';
item['data'] = data;
item.alpha = 0;
// const subX = data.rect.x - this.bg.data.rect.x;
// const subY = data.rect.y - this.bg.data.rect.y;
// item.x = subX * this.mapScale //- this.bg.width / 2;
// item.y = subY * this.mapScale //- this.bg.height / 2;
// // item.y -= this.bg.height / 2;
// this.bg.addChild(item);
this.scrollView.addItem(item);
// this.renderArr.push(item);
return item;
}
showEndPetal() {
this.endPageArr = [];
this.showPetalFlag = true;
this.addPetal();
}
stopEndPetal() {
this.endPageArr = [];
this.showPetalFlag = false;
}
addPetal() {
if (!this.showPetalFlag) {
return;
}
const petal = this.getPetal();
this.endPageArr.push(petal);
moveItem(petal, petal.x, this.canvasHeight + petal.height * petal.scaleY, petal['time'], () => {
removeItemFromArr(this.endPageArr, petal);
});
rotateItem(petal, petal['tr'], petal['time']);
this.ctx = this.canvas.nativeElement.getContext('2d'); setTimeout(() => {
this.canvas.nativeElement.width = this.canvasWidth; this.addPetal();
this.canvas.nativeElement.height = this.canvasHeight; }, 100);
window['curCtx'] = this.ctx;
window['curImages'] = this.images;
} }
getPetal() {
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);
updateItem(item) { const randomR = Math.random() * 360;
if (item) { petal.rotation = randomR;
item.update();
}
}
updateArr(arr) { const randomX = Math.random() * this.canvasWidth;
if (!arr) { petal.x = randomX;
return; petal.y = -petal.height / 2 * petal.scaleY;
}
for (let i = 0; i < arr.length; i++) {
arr[i].update(this);
}
}
const randomT = 0.5 + Math.random() * 2.5;
petal['time'] = randomT;
let randomTR = 360 * Math.random(); // - 180;
if (Math.random() < 0.5) { randomTR *= -1; }
petal['tr'] = randomTR;
return petal;
}
...@@ -202,13 +2580,13 @@ export class PlayComponent implements OnInit, OnDestroy { ...@@ -202,13 +2580,13 @@ export class PlayComponent implements OnInit, OnDestroy {
if (this.canvasLeft == null) { if (this.canvasLeft == null) {
setParentOffset(); setParentOffset();
} }
this.mx = event.touches[0].pageX - this.canvasLeft; this.mx = event.touches[0].pageX * this.canvasScale - this.canvasLeft;
this.my = event.touches[0].pageY - this.canvasTop; this.my = event.touches[0].pageY * this.canvasScale - this.canvasTop;
}; };
const setMxMyByMouse = (event) => { const setMxMyByMouse = (event) => {
this.mx = event.offsetX; this.mx = event.offsetX * this.canvasScale;
this.my = event.offsetY; this.my = event.offsetY * this.canvasScale;
}; };
// --------------------------------------------- // ---------------------------------------------
...@@ -220,6 +2598,7 @@ export class PlayComponent implements OnInit, OnDestroy { ...@@ -220,6 +2598,7 @@ export class PlayComponent implements OnInit, OnDestroy {
firstTouch = false; firstTouch = false;
removeMouseListener(); removeMouseListener();
} }
console.log('touch down');
setMxMyByTouch(e); setMxMyByTouch(e);
this.mapDown(e); this.mapDown(e);
}; };
...@@ -237,6 +2616,7 @@ export class PlayComponent implements OnInit, OnDestroy { ...@@ -237,6 +2616,7 @@ export class PlayComponent implements OnInit, OnDestroy {
firstTouch = false; firstTouch = false;
removeTouchListener(); removeTouchListener();
} }
console.log('mouse down');
setMxMyByMouse(e); setMxMyByMouse(e);
this.mapDown(e); this.mapDown(e);
}; };
...@@ -278,29 +2658,109 @@ export class PlayComponent implements OnInit, OnDestroy { ...@@ -278,29 +2658,109 @@ export class PlayComponent implements OnInit, OnDestroy {
addMouseListener(); addMouseListener();
addTouchListener(); addTouchListener();
element.addEventListener('mousewheel', (event) => {
setMxMyByMouse(event);
if (event.deltaY > 0) {
this.wheelDown(event);
} else {
this.wheelUp(event);
}
});
}
wheelUp(event: any) {
if (this.resultSv) {
if (this.checkClickTarget(this.resultSv)) {
this.resultSv.onWheelUp(event.deltaY);
}
} else {
if (this.checkClickTarget(this.scrollView)) {
this.scrollView.onWheelUp(event.deltaY);
}
}
} }
wheelDown(event: any) {
if (this.resultSv) {
if (this.checkClickTarget(this.resultSv)) {
this.resultSv.onWheelDown(event.deltaY);
}
} else {
if (this.checkClickTarget(this.scrollView)) {
this.scrollView.onWheelDown(event.deltaY);
}
}
}
playAudio(key, now = false, callback = null) { playAudio(key, now = false, callback = null) {
const audio = this.audioObj[key]; const audio = this.audioObj[key];
if (audio) { if (audio) {
if (now) {
audio.pause();
audio.currentTime = 0;
}
if (callback) { const audioNew = new Audio();
audio.onended = () => { audioNew.src = audio.src;
callback(); audioNew.load();
}; audioNew.play();
}
audio.play(); // if (now) {
// audio.pause();
// audio.currentTime = 0;
// }
// if (callback) {
// audio.onended = () => {
// callback();
// };
// }
// audio.play();
}
}
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() { loadResources() {
const pr = []; const pr = [];
this.rawImages.forEach((value, key) => {// 预加载图片 this.rawImages.forEach((value, key) => {// 预加载图片
...@@ -314,7 +2774,7 @@ export class PlayComponent implements OnInit, OnDestroy { ...@@ -314,7 +2774,7 @@ export class PlayComponent implements OnInit, OnDestroy {
pr.push(p); pr.push(p);
}); });
this.rawAudios.forEach((value, key) => {// 预加载音频 this.rawAudios.forEach((value, key) => {// 预加载图片
const a = this.preloadAudio(value) const a = this.preloadAudio(value)
.then(() => { .then(() => {
...@@ -340,8 +2800,9 @@ export class PlayComponent implements OnInit, OnDestroy { ...@@ -340,8 +2800,9 @@ export class PlayComponent implements OnInit, OnDestroy {
preloadAudio(url) { preloadAudio(url) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const audio = new Audio(); const audio = new Audio();
resolve({})
audio.oncanplay = (a) => { audio.oncanplay = (a) => {
resolve(); //resolve();
}; };
audio.onerror = () => { audio.onerror = () => {
reject(); reject();
...@@ -358,14 +2819,60 @@ export class PlayComponent implements OnInit, OnDestroy { ...@@ -358,14 +2819,60 @@ export class PlayComponent implements OnInit, OnDestroy {
this.init(); this.init();
} }
checkClickTargetSv(target) {
console.log('target: ', target);
const scale = 1 // this.mapScale;
let tmpRect = target.getBoundingBox();
const svBox = this.scrollView.getBoundingBox();
const x = svBox.x + tmpRect.x * scale;
const y = svBox.y + tmpRect.y * scale;
const width = tmpRect.width * scale;
const height = tmpRect.height * scale;
const rect = {x, y, width, height};
// const contentBox = this.scrollView.content.getBoundingBox();
// rect.x += contentBox.x + svBox.x;
// rect.y += contentBox.y + svBox.y;
// console.log('rect: ', rect);
// console.log('this.mx: ', this.mx);
// console.log('this.my: ', this.my);
// const shape = new ShapeRectNew();
// shape.x = rect.x;
// shape.y = rect.y;
// shape.fillColor = '#0000ff'
// shape.alpha = 0.5;
// shape.setSize(rect.width, rect.height, 1);
// this.renderArr.push(shape);
if (this.checkPointInRect(this.mx, this.my, rect)) {
return true;
}
return false;
}
checkClickTarget(target) { checkClickTarget(target) {
const rect = target.getBoundingBox(); const rect = target.getBoundingBox();
// rect.x /= 2;
// rect.y /= 2;
// rect.width /= 2;
// rect.height /= 2;
// console.log('rect: ', rect);
if (this.checkPointInRect(this.mx, this.my, rect)) { if (this.checkPointInRect(this.mx, this.my, rect)) {
return true; return true;
} }
...@@ -386,6 +2893,7 @@ export class PlayComponent implements OnInit, OnDestroy { ...@@ -386,6 +2893,7 @@ export class PlayComponent implements OnInit, OnDestroy {
} }
checkPointInRect(x, y, rect) { checkPointInRect(x, y, rect) {
if (x >= rect.x && x <= rect.x + rect.width) { if (x >= rect.x && x <= rect.x + rect.width) {
if (y >= rect.y && y <= rect.y + rect.height) { if (y >= rect.y && y <= rect.y + rect.height) {
return true; return true;
...@@ -394,297 +2902,22 @@ export class PlayComponent implements OnInit, OnDestroy { ...@@ -394,297 +2902,22 @@ export class PlayComponent implements OnInit, OnDestroy {
return false; return false;
} }
getPosByAngle(angle, len) {
const radian = angle * Math.PI / 180;
const x = Math.sin(radian) * len;
const y = Math.cos(radian) * len;
return { x, y };
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) {
} }
getPosDistance(sx, sy, ex, ey) {
const _x = ex - sx;
update() { const _y = ey - sy;
const len = Math.sqrt(Math.pow(_x, 2) + Math.pow(_y, 2));
// ---------------------------------------------------------- return len;
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 res = [ const res = [
['bg', "assets/play/bg.png"],
// ['bg', "assets/play/bg.jpg"], ['bg_item', "assets/play/bg_item.png"],
['btn_left', "assets/play/btn_left.png"], ['btn', "assets/play/btn.png"],
['btn_right', "assets/play/btn_right.png"], ['btn_off', "assets/play/btn_off.png"],
// ['text_bg', "assets/play/text_bg.png"], ['panel', "assets/play/panel.png"],
['panel_item', "assets/play/panel_item.png"],
['btn_bg', "assets/play/btn_bg.png"],
['submit', "assets/play/submit.png"],
['submit_off', "assets/play/submit_off.png"],
['submit_shadow', "assets/play/submit_shadow.png"],
['result_bg', "assets/play/result_bg.png"],
['result_bg_item', "assets/play/result_bg_item.png"],
['result_panel', "assets/play/result_panel.png"],
['result_panel_item', "assets/play/result_panel_item.png"],
['result_panel_shadow', "assets/play/result_panel_shadow.png"],
['big_btn', "assets/play/big_btn.png"],
['big_btn_shadow', "assets/play/big_btn_shadow.png"],
['line', "assets/play/line.png"],
['info_icon', "assets/play/info_icon.png"],
['info_bg', "assets/play/info_bg.png"],
]; ];
...@@ -12,7 +28,12 @@ const res = [ ...@@ -12,7 +28,12 @@ const res = [
const resAudio = [ const resAudio = [
['click', "assets/play/music/click.mp3"], ['click', "assets/play/music/click.mp3"],
['submit', "assets/play/music/submit.mp3"],
['more', "assets/play/music/more.mp3"],
]; ];
export {res, resAudio}; export {res, resAudio};
// 刷新CDN路径
// https://staging-teach.cdn.ireadabc.com/h5template/h5-static-lib/js/air.js
// https://teach.cdn.ireadabc.com/h5template/h5-static-lib/js/air.js
const commonPostMessage = function (messageObj) {
const obj = {...messageObj, urlParams: window.location.search}
window.parent.postMessage(obj, '*');
};
const commonPostMessageWithCallback = function (messageObj, callback) {
const onMessage = (e) => {
let msgData = e.data;
if(msgData && msgData.action === messageObj.action){
window.removeEventListener("message", onMessage);
callback && callback(msgData.data);
}
};
window.addEventListener("message", onMessage);
commonPostMessage(messageObj);
};
const realAir = {
uploadUrl: null,
uploadData: null,
getDataCallback: null,
setDataCallback: null,
getUploadCallback: null,
pageLoaded: false,
isCourseInScreen: false,
hideAirClassLoading: function(templateName,loadData){
// 隐藏页面加载时候的loading
if (deleteHistory && typeof (deleteHistory) == 'function') {
deleteHistory();
}
window.parent.postMessage({ action: "course-ready", data: {template:templateName,loadData:loadData,urlParams: window.location.search}, urlParams: window.location.search}, '*');
window.air.pageLoaded = true;
window.courseware.next();
var cc = window.cc;
if (cc && cc.director && cc.director._scene) {
try {
const canvas = cc.find("Canvas");
canvas.on("mousemove", function () {});
cc.director._scene.on("mousemove", function () {
window.parent.postMessage({ action: "mousemove" }, "*");
});
cc.director._scene.on("touchmove", function () {
window.parent.postMessage({ action: "mousemove" }, "*");
});
if (cc.systemEvent && cc.SystemEvent) {
cc.systemEvent.on(cc.SystemEvent.EventType.KEY_DOWN, (event) => {
switch (event.keyCode) {
case cc.KEY.left:
window.parent.postMessage({ action: "ArrowLeft" }, "*");
break;
case cc.KEY.right:
window.parent.postMessage({ action: "ArrowRight" }, "*");
break;
}
});
}
} catch (e) {
console.log("====cc.director._scene绑定事件====");
}
}
},
};
const uploadCallbackQueue = [];
try{
window.air = new Proxy(realAir, {
set: function (target, key, value, receiver) {
if (key=="getUploadCallback") {
uploadCallbackQueue.push(value);
}
return Reflect.set(target, key, value, receiver);
},
get: function (target, key, receiver) {
return Reflect.get(target, key, receiver);
},
deleteProperty: function(target, key){
return Reflect.deleteProperty(target, key);
}
});
}catch(e){
console.error("浏览器不支持ES6新特性Proxy/Reflect,请使用谷歌浏览器!");
}
function deleteHistory() {
const disableBack = () => {
window.history.pushState(null, "", document.URL);
window.addEventListener("popstate", () => {
window.history.pushState(null, "", document.URL);
});
}
disableBack();
window.addEventListener("load", disableBack);
}
deleteHistory();
if (window.self !== window.top) {
window.addEventListener("message", function (e) {
let msgData = e.data;
// console.log("子页面接收到了消息", msgData);
if(msgData.type === "webpackWarnings" || msgData.type === "webpackOk") {
return;
}
if(msgData.action==="airEvents"){
return;
}
if (msgData.action === "getUpload" && msgData.uploadUrl) {
window.air.uploadUrl = msgData.uploadUrl;
window.air.uploadData = msgData.uploadData;
for (let i = 0; i < uploadCallbackQueue.length; i++) {
uploadCallbackQueue[i](msgData.uploadUrl, msgData.uploadData);
}
return;
}
if (msgData.action === "pauseCocos") {
let cc = window.cc;
if (cc && cc.game) {
cc.game.pause();
console.log('pause了');
}
return;
}
if (msgData.action === "resumeCocos") {
let cc = window.cc;
if (cc && cc.game) {
cc.game.resume();
console.log('resume了');
}
return;
}
if (msgData.action === "restartCocos") {
let cc = window.cc;
if (cc && cc.game) {
cc.audioEngine.stopAll();
// cc.game.restart();
console.log('restart了');
}
return;
}
if (msgData.action === "setData") {
window.air.setDataCallback && window.air.setDataCallback();
return;
}
if (msgData.action === "getData") {
try {
const res = JSON.parse(msgData.data);
if (res.msg !== "success") {
console.log('数据加载失败!');
return;
}
if (res.data && res.data != 'null') {
window.air.callData = JSON.parse(res.data);
}
window.air.callDataFlag = true;
return;
} catch (e) {
console.log('数据加载失败!');
}
}
});
window.parent.postMessage({ action: "getUpload" }, '*');
document.onmousemove = function(){
window.parent.postMessage({ action: "mousemove" }, '*');
};
document.ontouchmove = function(){
window.parent.postMessage({ action: "mousemove" }, '*');
};
document.onkeydown = (event) => {
switch(event.key) {
case "ArrowLeft":
window.parent.postMessage({ action: "ArrowLeft" }, '*');
break;
case "ArrowRight":
window.parent.postMessage({ action: "ArrowRight" }, '*');
break;
}
}
document.oncontextmenu = function(){
return false;
}
}
window.courseware = (function () {
let obj = {
airEvents: {},
eventQueue: [],
eventLock: false,
next: () => {
let exe = obj.eventQueue.splice(0,1);
if(exe.length>0){
obj.eventLock = true;
let evtName = exe[0].evtName;
let data = exe[0].data;
if(obj.airEvents[evtName]){
if(evtName === "course-in-screen"){
if(window.air.isCourseInScreen){
return;
}
window.air.isCourseInScreen = true;
}
console.log(`evtName==${evtName}的方法被执行`);
obj.airEvents[evtName](data, obj.next);
} else {
console.warn(`airclass教室交互事件 ${evtName} 没有被捕获,请确认监听事件的先后顺序2`);
obj.next();
}
}else{
obj.eventLock = false;
}
}
};
if (window.self !== window.top) {
window.addEventListener("message", function (e) {
let msgData = e.data;
if(msgData.action!=="airEvents"){
return;
}
let evtName = msgData.evt;
let res = msgData.data;
if (evtName === "course-out-screen"){
console.log(`evtName==${evtName}的方法被执行`);
window.location.reload();
return;
}
if (res&&evtName!='userchange') {
//userchange事件传过来的值不需要转换
res = JSON.parse(res);
}
if(!window.air.pageLoaded){
//如果页面还没有加载完成
obj.eventQueue.push({"evtName": evtName, data: res});
}else{
if (obj.eventQueue.length === 0 && !obj.eventLock) {
//如果没有消息积压并且事件锁未锁定
obj.eventLock = true;
if(obj.airEvents[evtName]){
if(evtName === "course-in-screen"){
if(window.air.isCourseInScreen){
return;
}
window.air.isCourseInScreen = true;
}
console.log(`evtName==${evtName}的方法被执行`);
obj.airEvents[evtName](res, obj.next);
} else {
console.warn(`airclass教室交互事件 ${evtName} 没有被捕获,请确认监听事件的先后顺序1`);
obj.next();
}
} else {
obj.eventQueue.push({"evtName": evtName, data: res});
}
}
});
obj.getData = function (callback, key = '') {
window.parent.postMessage({ action: "getData", data: window.location.search, urlParams: window.location.search }, '*');
window.air.callDataFlag = false;
const liuintval = setInterval(()=>{
if(window.air.callDataFlag){
console.log("========我进来了=========");
clearInterval(liuintval);
setTimeout(() => {
console.log("执行回调,回调数据为:");
console.log(window.air.callData);
callback(window.air.callData);
}, 100);
}
}, 100);
};
obj.setData = function (data, callback, key = '') {
let str = JSON.stringify(data);
console.log("==setData==", str);
window.parent.postMessage({ action: "setData", data: str, urlParams: window.location.search }, '*');
window.air.setDataCallback = callback;
};
obj.uploadUrl = function () {
// return net.getUploadFileURL();
return window.air.uploadUrl;
};
obj.uploadData = function () {
// return net.getAjaxData("uploadFile","");
return window.air.uploadData;
};
obj.beganRecording = function(){
commonPostMessage({ action: "beganRecording" });
};
obj.endRecording = function(callback){
commonPostMessageWithCallback({ action: "endRecording" }, callback);
};
obj.speakPoints = function(audioUrl, evalText, callback){
const obj = {audioUrl, evalText};
commonPostMessageWithCallback({ action: "speakPoints", data: JSON.stringify(obj) }, callback);
};
obj.startRecord = function(testText){
commonPostMessage({ action: "startRecord", data: testText });
};
obj.stopRecord = function(callback){
commonPostMessageWithCallback({ action: "stopRecord" }, callback);
};
obj.startTest = function(testText){
commonPostMessage({ action: "startTest", data: testText });
};
obj.stopTest = function(callback){
commonPostMessageWithCallback({ action: "stopTest" }, callback);
};
obj.getTemplates = function(callback){
commonPostMessageWithCallback({ action: "getTemplates" }, callback);
};
obj.getTemplateUrl = function(templateName, callback){
commonPostMessageWithCallback({ action: "getTemplateUrl", data: templateName}, callback);
};
obj.sendEvent = function(evtName,data,key = ''){
if(evtName==="reconnect"){
console.error("reconnect是内置的断线重连事件名称,请勿使用此名称作为事件名");
return;
}
if(evtName==="userchange"){
console.error("userchange是内置的用户变更事件名称,请勿使用此名称作为事件名");
return;
}
let str = null;
if(data){
str = JSON.stringify(data);
}
window.parent.postMessage({ action: "airEvents",evt: evtName, data: str, urlParams: window.location.search }, '*');
};
obj.onEvent = function(evtName,callback){
obj.airEvents[evtName] = callback;
};
obj.removeEvent = function(evtName){
if(obj.airEvents[evtName]){
delete obj.airEvents[evtName];
}
};
obj.sendErrorLog = function (error) {
// todo 这块预留后面采集模板的报错信息
// window.parent.postMessage({ action: "errorlog", data: error.stack }, '*');
};
} else {
obj.getData = function (callback, key = '') {
let data = localStorage.getItem("courseware_data_" + key);
if (data) {
data = JSON.parse(data);
}
callback && callback(data);
};
obj.setData = function (data, callback, key = '') {
console.log("******local********");
localStorage.setItem("courseware_data_" + key, JSON.stringify(data));
callback && callback();
};
obj.uploadUrl = function () {
var protocolStr = document.location.protocol;
return `${protocolStr}//staging-teach.ireadabc.com/fileUpload`;
};
obj.uploadData = function () {
return {};
};
obj.beganRecording = function(){
console.log("******beganRecording********");
};
obj.endRecording = function(callback){
console.log("******endRecording********");
callback&&callback("");
};
obj.speakPoints = function(audioUrl, evalText, callback){
console.log("******speakPoints********");
callback&&callback("");
};
obj.startRecord = function(){
console.log("******startRecord********");
};
obj.stopRecord = function(callback){
console.log("******stopRecord********");
callback&&callback("");
};
obj.startTest = function(testText){
console.log("******startTest********");
};
obj.stopTest = function(callback){
console.log("******stopTest********");
callback&&callback("");
};
obj.getTemplates = function(callback){
callback&&callback("");
};
obj.getTemplateUrl = function(templateName, callback){
const obj = {
play_url: "",
form_url: "",
};
callback&&callback(JSON.stringify(obj));
};
obj.sendEvent = function(evtName, data, key = ''){
if(evtName==="reconnect"){
console.error("reconnect是内置的断线重连事件名称,请勿使用此名称作为事件名");
return;
}
if(evtName==="userchange"){
console.error("userchange是内置的用户变更事件名称,请勿使用此名称作为事件名");
return;
}
return;
};
obj.onEvent = function(evtName,callback){
console.warn("==本地测试用,onEvent的监听事件会直接触发==", "事件名:"+ evtName);
callback && callback("", function(){});
};
obj.removeEvent = function(evtName){
};
obj.sendErrorLog = function (error) {
};
}
return obj;
})();
...@@ -7,8 +7,14 @@ ...@@ -7,8 +7,14 @@
<!-- <meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">--> <!-- <meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">-->
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico"> <link rel="icon" type="image/x-icon" href="favicon.ico">
<script type="text/javascript" src="https://staging-teach.cdn.ireadabc.com/h5template/h5-static-lib/js/air.js"></script> <script type="text/javascript" src="https://staging-teach.cdn.ireadabc.com/h5template/h5-static-lib/js/air_online_open.js"></script>
<!-- <script src="https://cdn.bootcdn.net/ajax/libs/vConsole/3.9.0/vconsole.min.js"></script>
<script>
// init vConsole
var vConsole = new VConsole();
console.log('Hello world');
</script> -->
</head> </head>
<body> <body>
<app-root></app-root> <app-root></app-root>
......
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