Commit 829edc41 authored by limingzhe's avatar limingzhe

feat: 首次提交

parent 9f3a2900
......@@ -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
import { FontAwesomeModule, FaIconLibrary } from '@fortawesome/angular-fontawesome';
import { fas } from '@fortawesome/free-solid-svg-icons';
import { far } from '@fortawesome/free-regular-svg-icons';
import { CustomActionComponent } from './common/custom-action/custom-action.component';
import { UploadDragonBoneComponent } from './common/upload-dragon-bone/upload-dragon-bone.component';
import { SubTemplateComponent } from './common/sub-template/sub-template.component';
registerLocaleData(zh);
......@@ -40,8 +43,11 @@ registerLocaleData(zh);
TimePipe,
UploadVideoComponent,
CustomHotZoneComponent,
SubTemplateComponent,
PlayerContentWrapperComponent
PlayerContentWrapperComponent,
CustomActionComponent,
UploadDragonBoneComponent
],
imports: [
......
......@@ -35,7 +35,8 @@
<ng-template #truthyTemplate >
<div class="btn-delete" (click)="onBtnDeleteAudio()">
<fa-icon icon="close"></fa-icon>
<!-- <fa-icon icon="close"></fa-icon> -->
<i nz-icon nzType="close" nzTheme="outline"></i>
</div>
</ng-template>
......
......@@ -26,7 +26,7 @@ export class AudioRecorderComponent implements OnInit, OnChanges, OnDestroy {
uploadData;
@Input()
needRemove = false;
needRemove = true;
@Input()
audioItem: any = null;
......@@ -62,8 +62,25 @@ export class AudioRecorderComponent implements OnInit, OnChanges, OnDestroy {
this.uploadUrl = url;
this.uploadData = data;
};
this.setUploadUrl();
}
setUploadUrl() {
if (!this.uploadUrl) {
this.uploadUrl = (<any> window).courseware.uploadUrl();
this.uploadData = (<any> window).courseware.uploadData();
setTimeout(() => {
this.setUploadUrl();
}, 500);
}
}
init() {
this.playIcon = 'play';
this.isPlaying = false;
......@@ -157,6 +174,7 @@ export class AudioRecorderComponent implements OnInit, OnChanges, OnDestroy {
onBtnDeleteAudio() {
this.audioUrl = null;
this.audioUploaded.emit({});
this.audioRemoved.emit();
}
......
<div class="position-relative">
<button nz-button (click)="setAnimaBtnClick()" style=" border-radius: 0.5rem; border: 1px solid #ddd;" >
<i nz-icon nzType="tool" nzTheme="outline"></i>
{{btnName}}
</button>
<!--配置龙骨面板-->
<nz-modal [(nzVisible)]="panelVisible" (nzAfterClose)="closePanel()" [nzTitle]="btnName" (nzOnCancel)="panelCancel()" (nzOnOk)="panelOk()" nzOkText="保存">
<div>
<h4>基础内容:</h4>
<div style="margin-bottom: 10px; width: 80%; margin: auto;">
<!-- <nz-radio-group [ngModel]="item.type" (ngModelChange)="radioChange($event)">
<label nz-radio nzValue="pic">图片</label>
<label nz-radio nzValue="text">文本</label>
</nz-radio-group> -->
<div *ngIf="item.type == 'pic'">
<app-upload-image-with-preview
[picUrl]="item?.pic_url"
(imageUploaded)="onItemImgUploadSuccess($event, item)">
</app-upload-image-with-preview>
</div>
<div *ngIf="item.type == 'text'">
<input type="text" nz-input [(ngModel)]="item.text" (blur)="saveText(item)">
</div>
<div *ngIf="item.type == 'anima'" style="margin-left: 100px;">
<app-upload-dragon-bone
[skeJsonData]=item.skeJsonData
[texJsonData]=item.texJsonData
[texPngData]=item.texPngData
(save)="saveAnima($event)"
>
</app-upload-dragon-bone>
</div>
</div>
<nz-divider style="margin-top: 10px;"></nz-divider>
<h4>状态设置:</h4>
<div style="display: flex; justify-content: space-around;">
<div style="width: 30%; display: flex; align-items: center; flex-direction: column;">
<h5> 开始状态 </h5>
<div *ngFor="let op of item.changeOption; let i = index" style="margin-bottom: 5px; ">
<div style="display: flex; align-items: center; justify-content: center;">
<span>{{op[0]}}: </span> <input type="text" nz-input [(ngModel)]="op[1]" (blur)="saveText(op)" style="margin-left: 5px;">
</div>
</div>
</div>
<div style="width: 30%; display: flex; align-items: center; flex-direction: column; ">
<h5> 切换时间 </h5>
<div style="display: flex; width: 100%; align-items: center; justify-content: center;">
<span>time: </span> <input type="text" nz-input [(ngModel)]="item.changeTime" (blur)="saveText(item.changeTime)" style="width: 80px; margin-left: 5px;">
</div>
</div>
<div style="width: 30%; display: flex; align-items: center; flex-direction: column;">
<h5> 结束状态 </h5>
<div *ngFor="let op of item.changeOption; let i = index" style="margin-bottom: 5px; ">
<div style="display: flex; align-items: center; justify-content: center;">
<span>{{op[0]}}: </span> <input [disabled]="op[2] == null" type="text" nz-input [(ngModel)]="op[2]" (blur)="saveText(op)" style="margin-left: 5px;">
</div>
</div>
</div>
</div>
<div style="display: flex; align-items: center; justify-content: center; margin-top: 10px;">
<button style="margin-left: 20px; margin-top: -5px" nz-button (click)="copyChangeData()"> 复制数据 </button>
<div style="margin-left: 20px; margin-top: -5px" >
<span>粘贴数据: </span>
<input style="width: 100px;" type="text" nz-input [(ngModel)]="pasteData" >
<button style="margin-left: 5px;" nz-button [disabled]="pasteData==''" nzType="primary" (click)="importData()">导入</button>
</div>
</div>
<nz-divider style="margin-top: 10px;"></nz-divider>
<h4> 音频设置 </h4>
<app-audio-recorder
style="margin: auto"
[audioUrl]="item?.audio_url"
(audioUploaded)="onItemAudioUploadSuccess($event, item)"
></app-audio-recorder>
</div>
<!--
<div class="anima-upload-btn">
<span style="margin-right: 10px">上传 ske_json 文件: </span>
<nz-upload [nzShowUploadList]="false"
nzAccept="application/json"
[nzAction]="uploadUrl"
[nzData]="uploadData"
(nzChange)="skeJsonHandleChange($event)">
<button nz-button><i nz-icon nzType="upload"></i><span>Upload</span></button>
</nz-upload>
<i *ngIf="isSkeJsonLoading" style="margin-left: 10px;" nz-icon [nzType]="'loading'"></i>
<span *ngIf="skeJsonData && skeJsonData['name']" style="margin-left: 10px"><u> {{skeJsonData['name']}} </u></span>
</div>
<div class="anima-upload-btn">
<span style="margin-right: 10px">上传 tex_json 文件: </span>
<nz-upload [nzShowUploadList]="false"
nzAccept="application/json"
[nzAction]="uploadUrl"
[nzData]="uploadData"
(nzChange)="texJsonHandleChange($event)">
<button nz-button><i nz-icon nzType="upload"></i><span>Upload</span></button>
</nz-upload>
<i *ngIf="isTexJsonLoading" style="margin-left: 10px;" nz-icon [nzType]="'loading'"></i>
<span *ngIf="texJsonData && texJsonData['name']" style="margin-left: 10px"><u> {{texJsonData['name']}} </u></span>
</div>
<div class="anima-upload-btn">
<span style="margin-right: 10px">上传 tex_png 文件: </span>
<nz-upload [nzShowUploadList]="false"
nzAccept = "image/*"
[nzAction]="uploadUrl"
[nzData]="uploadData"
(nzChange)="texPngHandleChange($event)">
<button nz-button><i nz-icon nzType="upload"></i><span>Upload</span></button>
</nz-upload>
<i *ngIf="isTexPngLoading" style="margin-left: 10px;" nz-icon [nzType]="'loading'"></i>
<span *ngIf="texPngData && texPngData['name']" style="margin-left: 10px"><u> {{texPngData['name']}} </u></span>
</div>
<div class="anima-upload-btn" *ngIf="animaNames && animaNames.length > 0">
提示:需包含动画: {{animaNames.toString()}}.
</div> -->
</nz-modal>
</div>
@import '../../style/common_mixin.css';
.p-image-uploader {
position: relative;
display: block;
width: 100%;
height: 0;
padding-bottom: 56.25%;
.p-box {
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
border: 2px dashed #ddd;
border-radius: 0.5rem;
background-color: #fafafa;
text-align: center;
color: #aaa;
.p-upload-icon {
text-align: center;
margin: auto;
.anticon-upload {
color: #888;
font-size: 5rem;
}
.p-progress-bar {
position: relative;
width: 20rem;
height: 1.5rem;
border: 1px solid #ccc;
border-radius: 1rem;
.p-progress-bg {
background-color: #1890ff;
border-radius: 1rem;
height: 100%;
}
.p-progress-value {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
text-shadow: 0 0 4px #000;
color: white;
text-align: center;
font-size: 0.9rem;
line-height: 1.5rem;
}
}
}
.p-preview {
width: 100%;
height: 100%;
background-size: contain;
background-repeat: no-repeat;
background-position: 50% 50%;
//background-image: url("https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png");
}
}
.d-flex{
display: flex;
}
}
.p-btn-delete {
position: absolute;
right: -0.5rem;
top: -0.5rem;
width: 2rem;
height: 2rem;
border: 0.2rem solid white;
border-radius: 50%;
font-size: 1.2rem;
background-color: #fb781a;
color: white;
text-align: center;
}
.p-upload-progress-bg {
position: absolute;
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
& .i-text {
position: absolute;
text-align: center;
color: white;
text-shadow: 0 0 2px rgba(0, 0, 0, .85);
}
& .i-bg {
position: absolute;
left: 0;
top: 0;
height: 100%;
background-color: #27b43f;
border-radius: 0.5rem;
}
}
.anima-upload-btn {
padding: 10px;
}
:host ::ng-deep .ant-upload {
display: block;
}
import {ApplicationRef, Component, EventEmitter, Input, OnChanges, OnDestroy, Output} from '@angular/core';
import { NzMessageService, UploadXHRArgs, UploadFile } from 'ng-zorro-antd';
@Component({
selector: 'app-custom-action',
templateUrl: './custom-action.component.html',
styleUrls: ['./custom-action.component.scss']
})
export class CustomActionComponent implements OnDestroy, OnChanges {
uploading = false;
progress = 0;
@Input()
btnName = '配置变化状态';
@Input()
option = []
@Input()
item;
@Input()
type = 'text'
@Output()
save = new EventEmitter();
@Output()
refreshEmitter = new EventEmitter();
uploadUrl;
uploadData;
panelVisible = false;
pasteData = '';
constructor(private appRef: ApplicationRef, private nzMessageService: NzMessageService) {
window['air'].getUploadCallback = (url, data) => {
this.uploadUrl = url;
this.uploadData = data;
};
const tmpId = setInterval(() => {
console.log(' in setInterval')
this.uploadUrl = (<any> window).courseware.uploadUrl();
this.uploadData = (<any> window).courseware.uploadData();
if (this.uploadUrl) {
clearInterval(tmpId);
}
}, 500)
}
ngOnInit() {
this.initItem();
}
ngOnChanges() {
}
initItem() {
console.log('```this.item: ', this.item);
if (!this.item) {
this.item = {
type: this.type,
skeJsonData: {},
texJsonData: {},
texPngData: {},
changeStart: [
],
changeEnd: [
],
changeTime: 0.3
};
if (this.option) {
this.item.changeOption = JSON.parse(JSON.stringify(this.option));
}
}
console.log('initItem', this.item);
}
setAnimaBtnClick() {
this.panelVisible = true;
this.refresh();
}
panelCancel() {
this.panelVisible = false;
this.refresh();
}
panelOk() {
// this.sendItemDragonBoneData();
this.panelVisible = false;
this.refresh();
this.save.emit(this.item);
}
saveText(t) {
}
radioChange(e) {
this.item.type = e;
console.log('e: ', e);
}
onItemImgUploadSuccess(e, item) {
item.pic_url = e.url;
this.refresh();
}
onItemAudioUploadSuccess(e, item) {
item.audio_url = e.url;
this.refresh();
}
saveAnima(e) {
console.log("~ e: ", e);
}
copyChangeData() {
console.log('this.item: ', this.item);
const jsonData = {
changeOption: this.item.changeOption,
changeTime : this.item.changeTime
// bgItem,
// hotZoneItemArr,
// isHasRect: this.isHasRect,
// isHasPic: this.isHasPic,
// isHasText: this.isHasText,
// isHasAudio: this.isHasAudio,
// isHasAnima: this.isHasAnima,
// hotZoneFontObj: this.hotZoneFontObj,
// defaultItemType: this.defaultItemType,
// hotZoneImgSize: this.hotZoneImgSize,
};
const oInput = document.createElement('input');
oInput.value = JSON.stringify(jsonData);
document.body.appendChild(oInput);
oInput.select(); // 选择对象
document.execCommand('Copy'); // 执行浏览器复制命令
document.body.removeChild(oInput);
this.nzMessageService.success('复制成功');
}
importData() {
if (!this.pasteData) {
return;
}
try {
const data = JSON.parse(this.pasteData);
console.log('data:', data);
const {
changeOption,
changeTime
} = data;
this.item.changeOption = changeOption;
this.item.changeTime = changeTime;
this.pasteData = '';
} catch (e) {
console.log('err: ', e);
this.nzMessageService.error('导入失败');
}
}
/**
* 刷新 渲染页面
*/
refresh() {
// this.refreshEmitter.emit();
setTimeout(() => {
this.appRef.tick();
}, 1);
}
closePanel() {
console.log(' in closePanel ');
this.refresh();
}
ngOnDestroy() {
}
}
......@@ -329,6 +329,7 @@ export class MySprite extends Sprite {
this.scaleX = this.scaleY = value;
}
getBoundingBox() {
const getParentData = (item) => {
......@@ -1956,6 +1957,10 @@ export class HotZoneItem extends MySprite {
audio_url;
pic_url;
text;
gIdx;
isAnimaStyle = false;
private _itemType;
private shapeRect: ShapeRect;
......@@ -2056,7 +2061,10 @@ export class HotZoneItem extends MySprite {
this.hideLabel();
}
setAnimaStyle(isAnimaStyle) {
this.isAnimaStyle = isAnimaStyle;
console.log('in setAnimaStyle ')
}
drawArrow() {
if (!this.arrow) { return; }
......@@ -2068,13 +2076,16 @@ export class HotZoneItem extends MySprite {
this.arrow.update();
this.arrowTop.x = rect.x + rect.width / 2;
this.arrowTop.y = rect.y;
this.arrowTop.update();
this.arrowRight.x = rect.x + rect.width;
this.arrowRight.y = rect.y + rect.height / 2;
this.arrowRight.update();
if (!this.isAnimaStyle) {
this.arrowTop.x = rect.x + rect.width / 2;
this.arrowTop.y = rect.y;
this.arrowTop.update();
this.arrowRight.x = rect.x + rect.width;
this.arrowRight.y = rect.y + rect.height / 2;
this.arrowRight.update();
}
}
drawFrame() {
......@@ -2197,8 +2208,26 @@ export class HotZoneLabel extends Label {
this.drawFrame();
}
getLabelRect() {
const rect = this.getBoundingBox();
const width = rect.width / this.scaleX;
const height = this.height * this.scaleY;
const x = this.x - width / 2;
const y = this.y - height / 2;
return {width, height, x, y};
}
}
export class HotZoneAction extends MySprite {
}
......@@ -2208,6 +2237,8 @@ export class EditorItem extends MySprite {
arrow: MySprite;
label: Label;
text;
arrowTop;
arrowRight;
showLabel(text = null) {
......@@ -2246,6 +2277,13 @@ export class EditorItem extends MySprite {
this.arrow.load('assets/common/arrow.png', 1, 0);
this.arrow.setScaleXY(0.06);
this.arrowTop = new MySprite(this.ctx);
this.arrowTop.load('assets/common/arrow_top.png', 0.5, 0);
this.arrowTop.setScaleXY(0.06);
this.arrowRight = new MySprite(this.ctx);
this.arrowRight.load('assets/common/arrow_right.png', 1, 0.5);
this.arrowRight.setScaleXY(0.06);
}
this.showLabel();
......@@ -2262,16 +2300,25 @@ export class EditorItem extends MySprite {
this.hideLabel();
}
refreshLabelScale() {}
drawArrow() {
if (!this.arrow) { return; }
const rect = this.getBoundingBox();
this.arrow.x = rect.x + rect.width;
this.arrow.y = rect.y;
this.arrow.update();
this.arrowTop.x = rect.x + rect.width / 2;
this.arrowTop.y = rect.y;
this.arrowTop.update();
this.arrowRight.x = rect.x + rect.width;
this.arrowRight.y = rect.y + rect.height / 2;
this.arrowRight.update();
}
drawFrame() {
......@@ -2326,783 +2373,73 @@ export class EditorItem extends MySprite {
//
//
// import TWEEN from '@tweenjs/tween.js';
//
//
// class Sprite {
// x = 0;
// y = 0;
// color = '';
// radius = 0;
// alive = false;
// margin = 0;
// angle = 0;
// ctx;
//
// constructor(ctx) {
// this.ctx = ctx;
// }
// update($event) {
// this.draw();
// }
// draw() {
//
// }
//
// }
//
//
//
//
//
// export class MySprite extends Sprite {
//
// width = 0;
// height = 0;
// _anchorX = 0;
// _anchorY = 0;
// _offX = 0;
// _offY = 0;
// scaleX = 1;
// scaleY = 1;
// alpha = 1;
// rotation = 0;
// visible = true;
//
// children = [this];
//
// img;
// _z = 0;
//
//
// init(imgObj = null, anchorX:number = 0.5, anchorY:number = 0.5) {
//
// if (imgObj) {
//
// this.img = imgObj;
//
// this.width = this.img.width;
// this.height = this.img.height;
// }
//
// this.anchorX = anchorX;
// this.anchorY = anchorY;
// }
//
//
//
// update($event = null) {
// if (this.visible) {
// this.draw();
// }
// }
// draw() {
//
// this.ctx.save();
//
// this.drawInit();
//
// this.updateChildren();
//
// this.ctx.restore();
// }
//
// drawInit() {
//
// this.ctx.translate(this.x, this.y);
//
// this.ctx.rotate(this.rotation * Math.PI / 180);
//
// this.ctx.scale(this.scaleX, this.scaleY);
//
// this.ctx.globalAlpha = this.alpha;
//
// }
//
// drawSelf() {
// if (this.img) {
// this.ctx.drawImage(this.img, this._offX, this._offY);
// }
// }
//
// updateChildren() {
//
// if (this.children.length <= 0) { return; }
//
// for (let i = 0; i < this.children.length; i++) {
//
// if (this.children[i] === this) {
//
// this.drawSelf();
// } else {
//
// this.children[i].update();
// }
// }
// }
//
//
// load(url, anchorX = 0.5, anchorY = 0.5) {
//
// return new Promise((resolve, reject) => {
// const img = new Image();
// img.onload = () => resolve(img);
// img.onerror = reject;
// img.src = url;
// }).then(img => {
//
// this.init(img, anchorX, anchorY);
// return img;
// });
// }
//
// addChild(child, z = 1) {
// if (this.children.indexOf(child) === -1) {
// this.children.push(child);
// child._z = z;
// child.parent = this;
// }
//
// this.children.sort((a, b) => {
// return a._z - b._z;
// });
//
// }
// removeChild(child) {
// const index = this.children.indexOf(child);
// if (index !== -1) {
// this.children.splice(index, 1);
// }
// }
//
// set anchorX(value) {
// this._anchorX = value;
// this.refreshAnchorOff();
// }
// get anchorX() {
// return this._anchorX;
// }
// set anchorY(value) {
// this._anchorY = value;
// this.refreshAnchorOff();
// }
// get anchorY() {
// return this._anchorY;
// }
// refreshAnchorOff() {
// this._offX = -this.width * this.anchorX;
// this._offY = -this.height * this.anchorY;
// }
//
// setScaleXY(value) {
// this.scaleX = this.scaleY = value;
// }
//
// getBoundingBox() {
//
// const x = this.x + this._offX * this.scaleX;
// const y = this.y + this._offY * this.scaleY;
// const width = this.width * this.scaleX;
// const height = this.height * this.scaleY;
//
// return {x, y, width, height};
// }
//
// }
//
//
//
//
//
// export class Item extends MySprite {
//
// baseX;
//
// move(targetY, callBack) {
//
// const self = this;
//
// const tween = new TWEEN.Tween(this)
// .to({ y: targetY }, 2500)
// .easing(TWEEN.Easing.Quintic.Out)
// .onComplete(function() {
//
// self.hide(callBack);
// // if (callBack) {
// // callBack();
// // }
// })
// .start();
//
// }
//
// show(callBack = null) {
//
// const tween = new TWEEN.Tween(this)
// .to({ alpha: 1 }, 800)
// // .easing(TWEEN.Easing.Quadratic.Out) // Use an easing function to make the animation smooth.
// .onComplete(function() {
// if (callBack) {
// callBack();
// }
// })
// .start(); // Start the tween immediately.
//
// }
//
// hide(callBack = null) {
//
// const tween = new TWEEN.Tween(this)
// .to({ alpha: 0 }, 800)
// // .easing(TWEEN.Easing.Quadratic.Out) // Use an easing function to make the animation smooth.
// .onComplete(function() {
// if (callBack) {
// callBack();
// }
// })
// .start(); // Start the tween immediately.
// }
//
//
// shake(id) {
//
//
// if (!this.baseX) {
// this.baseX = this.x;
// }
//
// const baseX = this.baseX;
// const baseTime = 50;
// const sequence = [
// {target: {x: baseX + 40 * id}, time: baseTime - 25},
// {target: {x: baseX - 20 * id}, time: baseTime},
// {target: {x: baseX + 10 * id}, time: baseTime},
// {target: {x: baseX - 5 * id}, time: baseTime},
// {target: {x: baseX + 2 * id}, time: baseTime},
// {target: {x: baseX - 1 * id}, time: baseTime},
// {target: {x: baseX}, time: baseTime},
//
// ];
//
//
// const self = this;
//
// function runSequence() {
//
// if (self['shakeTween']) {
// self['shakeTween'].stop();
// }
//
// const tween = new TWEEN.Tween(self);
//
// if (sequence.length > 0) {
// // console.log('sequence.length: ', sequence.length);
// const action = sequence.shift();
// tween.to(action['target'], action['time']);
// tween.onComplete( () => {
// runSequence();
// });
// tween.start();
//
// self['shakeTween'] = tween;
// }
// }
//
// runSequence();
//
// }
//
//
//
// drop(targetY, callBack = null) {
//
// const self = this;
//
// const time = Math.abs(targetY - this.y) * 2.4;
//
// this.alpha = 1;
//
// const tween = new TWEEN.Tween(this)
// .to({ y: targetY }, time)
// .easing(TWEEN.Easing.Cubic.In)
// .onComplete(function() {
//
// // self.hideItem(callBack);
// if (callBack) {
// callBack();
// }
// })
// .start();
//
//
// }
//
//
// }
//
//
// export class EndSpr extends MySprite {
//
// show(s) {
//
// this.scaleX = this.scaleY = 0;
// this.alpha = 0;
//
// const tween = new TWEEN.Tween(this)
// .to({ alpha: 1, scaleX: s, scaleY: s }, 800)
// .easing(TWEEN.Easing.Elastic.Out) // Use an easing function to make the animation smooth.
// .onComplete(function() {
//
// })
// .start(); // Start the tween immediately.
//
// }
// }
//
//
//
// export class ShapeRect extends MySprite {
//
// fillColor = '#FF0000';
//
// setSize(w, h) {
// this.width = w;
// this.height = h;
//
// console.log('w:', w);
// console.log('h:', h);
// }
//
// drawShape() {
//
// this.ctx.fillStyle = this.fillColor;
// this.ctx.fillRect(this._offX, this._offY, this.width, this.height);
//
// }
//
//
// drawSelf() {
// super.drawSelf();
// this.drawShape();
// }
// }
//
//
// export class HotZoneItem extends MySprite {
//
//
// lineDashFlag = false;
// arrow: MySprite;
// label: Label;
// title;
//
// arrowTop;
// arrowRight;
//
// audio_url;
// pic_url;
// text;
// private _itemType;
// private shapeRect: ShapeRect;
//
// get itemType() {
// return this._itemType;
// }
// set itemType(value) {
// this._itemType = value;
// }
//
// setSize(w, h) {
// this.width = w;
// this.height = h;
//
//
// const rect = new ShapeRect(this.ctx);
// rect.x = -w / 2;
// rect.y = -h / 2;
// rect.setSize(w, h);
// rect.fillColor = '#ffffff';
// rect.alpha = 0.2;
// this.addChild(rect);
// }
//
// showLabel(text = null) {
//
//
// if (!this.label) {
// this.label = new Label(this.ctx);
// this.label.anchorY = 0;
// this.label.fontSize = '40px';
// this.label.textAlign = 'center';
// this.addChild(this.label);
// // this.label.scaleX = 1 / this.scaleX;
// // this.label.scaleY = 1 / this.scaleY;
//
// this.refreshLabelScale();
//
// }
//
// if (text) {
// this.label.text = text;
// } else if (this.title) {
// this.label.text = this.title;
// }
// this.label.visible = true;
//
// }
//
// hideLabel() {
// if (!this.label) { return; }
//
// this.label.visible = false;
// }
//
// refreshLabelScale() {
// if (this.scaleX == this.scaleY) {
// this.label.setScaleXY(1);
// }
//
// if (this.scaleX > this.scaleY) {
// this.label.scaleX = this.scaleY / this.scaleX;
// } else {
// this.label.scaleY = this.scaleX / this.scaleY;
// }
// }
//
// showLineDash() {
// this.lineDashFlag = true;
//
// if (this.arrow) {
// this.arrow.visible = true;
// } else {
// this.arrow = new MySprite(this.ctx);
// this.arrow.load('assets/common/arrow.png', 1, 0);
// this.arrow.setScaleXY(0.06);
//
// this.arrowTop = new MySprite(this.ctx);
// this.arrowTop.load('assets/common/arrow_top.png', 0.5, 0);
// this.arrowTop.setScaleXY(0.06);
//
// this.arrowRight = new MySprite(this.ctx);
// this.arrowRight.load('assets/common/arrow_right.png', 1, 0.5);
// this.arrowRight.setScaleXY(0.06);
// }
//
// this.showLabel();
// }
//
// hideLineDash() {
//
// this.lineDashFlag = false;
//
// if (this.arrow) {
// this.arrow.visible = false;
// }
//
// this.hideLabel();
// }
//
//
//
// drawArrow() {
// if (!this.arrow) { return; }
//
// const rect = this.getBoundingBox();
// this.arrow.x = rect.x + rect.width;
// this.arrow.y = rect.y;
//
// this.arrow.update();
//
//
// this.arrowTop.x = rect.x + rect.width / 2;
// this.arrowTop.y = rect.y;
// this.arrowTop.update();
//
// this.arrowRight.x = rect.x + rect.width;
// this.arrowRight.y = rect.y + rect.height / 2;
// this.arrowRight.update();
// }
//
// drawFrame() {
//
//
// this.ctx.save();
//
//
// const rect = this.getBoundingBox();
//
// const w = rect.width;
// const h = rect.height;
// const x = rect.x + w / 2;
// const y = rect.y + h / 2;
//
// this.ctx.setLineDash([5, 5]);
// this.ctx.lineWidth = 2;
// this.ctx.strokeStyle = '#1bfff7';
// // this.ctx.fillStyle = '#ffffff';
//
// this.ctx.beginPath();
//
// this.ctx.moveTo( x - w / 2, y - h / 2);
//
// this.ctx.lineTo(x + w / 2, y - h / 2);
//
// this.ctx.lineTo(x + w / 2, y + h / 2);
//
// this.ctx.lineTo(x - w / 2, y + h / 2);
//
// this.ctx.lineTo(x - w / 2, y - h / 2);
//
// // this.ctx.fill();
// this.ctx.stroke();
//
//
//
//
// this.ctx.restore();
//
// }
//
// draw() {
// super.draw();
//
// if (this.lineDashFlag) {
// this.drawFrame();
// this.drawArrow();
// }
// }
// }
//
//
// export class EditorItem extends MySprite {
//
// lineDashFlag = false;
// arrow: MySprite;
// label:Label;
// text;
//
// showLabel(text = null) {
//
//
// if (!this.label) {
// this.label = new Label(this.ctx);
// this.label.anchorY = 0;
// this.label.fontSize = '50px';
// this.label.textAlign = 'center';
// this.addChild(this.label);
// this.label.setScaleXY(1 / this.scaleX);
// }
//
// if (text) {
// this.label.text = text;
// } else if (this.text) {
// this.label.text = this.text;
// }
// this.label.visible = true;
//
// }
//
// hideLabel() {
// if (!this.label) { return; }
//
// this.label.visible = false;
// }
//
// showLineDash() {
// this.lineDashFlag = true;
//
// if (this.arrow) {
// this.arrow.visible = true;
// } else {
// this.arrow = new MySprite(this.ctx);
// this.arrow.load('assets/common/arrow.png', 1, 0);
// this.arrow.setScaleXY(0.06);
//
// }
//
// this.showLabel();
// }
//
// hideLineDash() {
//
// this.lineDashFlag = false;
//
// if (this.arrow) {
// this.arrow.visible = false;
// }
//
// this.hideLabel();
// }
//
//
//
// drawArrow() {
// if (!this.arrow) { return; }
//
// const rect = this.getBoundingBox();
// this.arrow.x = rect.x + rect.width;
// this.arrow.y = rect.y;
//
// this.arrow.update();
// }
//
// drawFrame() {
//
//
// this.ctx.save();
//
//
// const rect = this.getBoundingBox();
//
// const w = rect.width;
// const h = rect.height;
// const x = rect.x + w / 2;
// const y = rect.y + h / 2;
//
// this.ctx.setLineDash([5, 5]);
// this.ctx.lineWidth = 2;
// this.ctx.strokeStyle = '#1bfff7';
// // this.ctx.fillStyle = '#ffffff';
//
// this.ctx.beginPath();
//
// this.ctx.moveTo( x - w / 2, y - h / 2);
//
// this.ctx.lineTo(x + w / 2, y - h / 2);
//
// this.ctx.lineTo(x + w / 2, y + h / 2);
//
// this.ctx.lineTo(x - w / 2, y + h / 2);
//
// this.ctx.lineTo(x - w / 2, y - h / 2);
//
// // this.ctx.fill();
// this.ctx.stroke();
//
//
//
//
// this.ctx.restore();
//
// }
//
// draw() {
// super.draw();
//
// if (this.lineDashFlag) {
// this.drawFrame();
// this.drawArrow();
// }
// }
// }
//
//
//
// export class Label extends MySprite {
//
// text:String;
// fontSize:String = '40px';
// fontName:String = 'Verdana';
// textAlign:String = 'left';
//
//
// constructor(ctx) {
// super(ctx);
// this.init();
// }
//
// drawText() {
//
// // console.log('in drawText', this.text);
//
// if (!this.text) { return; }
//
// this.ctx.font = `${this.fontSize} ${this.fontName}`;
// this.ctx.textAlign = this.textAlign;
// this.ctx.textBaseline = 'middle';
// this.ctx.fontWeight = 900;
//
// this.ctx.lineWidth = 5;
// this.ctx.strokeStyle = '#ffffff';
// this.ctx.strokeText(this.text, 0, 0);
//
// this.ctx.fillStyle = '#000000';
// this.ctx.fillText(this.text, 0, 0);
//
//
// }
//
//
// drawSelf() {
// super.drawSelf();
// this.drawText();
// }
//
// }
//
//
//
// export function getPosByAngle(angle, len) {
//
// const radian = angle * Math.PI / 180;
// const x = Math.sin(radian) * len;
// const y = Math.cos(radian) * len;
//
// return {x, y};
//
// }
//
// export function getAngleByPos(px, py, mx, my) {
//
// // const _x = p2x - p1x;
// // const _y = p2y - p1y;
// // const tan = _y / _x;
// //
// // const radina = Math.atan(tan); // 用反三角函数求弧度
// // const angle = Math.floor(180 / (Math.PI / radina)); //
// //
// // console.log('r: ' , angle);
// // return angle;
// //
//
//
//
// const x = Math.abs(px - mx);
// const y = Math.abs(py - my);
// // const x = Math.abs(mx - px);
// // const y = Math.abs(my - py);
// const z = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
// const cos = y / z;
// const radina = Math.acos(cos); // 用反三角函数求弧度
// let angle = Math.floor(180 / (Math.PI / radina) * 100) / 100; // 将弧度转换成角度
//
// if(mx > px && my > py) {// 鼠标在第四象限
// angle = 180 - angle;
// }
//
// if(mx === px && my > py) {// 鼠标在y轴负方向上
// angle = 180;
// }
//
// if(mx > px && my === py) {// 鼠标在x轴正方向上
// angle = 90;
// }
//
// if(mx < px && my > py) {// 鼠标在第三象限
// angle = 180 + angle;
// }
//
// if(mx < px && my === py) {// 鼠标在x轴负方向
// angle = 270;
// }
//
// if(mx < px && my < py) {// 鼠标在第二象限
// angle = 360 - angle;
// }
//
// // console.log('angle: ', angle);
// return angle;
//
// }
export class HotZonePoint extends HotZoneItem {
strokeColor = "#000000"
fillColor = "#00ff00"
constructor(ctx = null) {
super(ctx);
this.radius = 15;
this.width = this.radius * 2;
this.height = this.radius * 2;
this.anchorX = this.anchorY = 0.5;
}
drawFrame() {
this.ctx.save();
// const rect = this.getBoundingBox();
// const w = rect.width / this.scaleX;
// const h = this.height * this.scaleY;
// const x = this.x;
// const y = this.y;
// this.ctx.setLineDash([5, 5]);
this.ctx.lineWidth = 2 * this.scaleX;
this.ctx.strokeStyle = this.strokeColor;
// this.ctx.beginPath();
// this.ctx.moveTo( x - w / 2, y - h / 2);
// this.ctx.lineTo(x + w / 2, y - h / 2);
// this.ctx.lineTo(x + w / 2, y + h / 2);
// this.ctx.lineTo(x - w / 2, y + h / 2);
// this.ctx.lineTo(x - w / 2, y - h / 2);
this.ctx.setLineDash([3, 3]);
this.ctx.beginPath();
this.ctx.fillStyle = this.fillColor;
this.ctx.arc(this.x, this.y, this.radius * this.scaleX, 0, angleToRadian(360));
this.ctx.fill();
// this.ctx.fill();
this.ctx.stroke();
this.ctx.restore();
}
draw() {
super.draw();
this.drawFrame();
}
getLabelRect() {
const rect = this.getBoundingBox();
const width = rect.width / this.scaleX;
const height = this.height * this.scaleY;
const x = this.x - width / 2;
const y = this.y - height / 2;
return {width, height, x, y};
}
}
......@@ -32,33 +32,111 @@
<nz-divider style="margin-top: 10px;"></nz-divider>
<div style="margin-top: -20px; margin-bottom: 5px; width: 100%;">
<div style="margin-top: -20px; margin-bottom: 5px">
<nz-radio-group [ngModel]="it.itemType" (ngModelChange)="radioChange($event, it)">
<label *ngIf="isHasRect" nz-radio nzValue="rect">矩形</label>
<label *ngIf="isHasPic" nz-radio nzValue="pic">图片</label>
<label *ngIf="isHasText" nz-radio nzValue="text">文本</label>
</nz-radio-group>
</div>
<div *ngIf="customTypeGroupArr">
<nz-radio-group [ngModel]="it.gIdx" (ngModelChange)="customRadioChange($event, it)" style="display: flex; align-items: center; justify-content: center; flex-wrap: wrap;">
<div *ngFor="let group of customTypeGroupArr; let gIdx = index" style="display: flex; ">
<label nz-radio nzValue="{{gIdx}}">{{group.name}}</label>
</div>
</nz-radio-group>
<div *ngIf="it.itemType == 'pic'">
<app-upload-image-with-preview
[picUrl]="it?.pic_url"
(imageUploaded)="onItemImgUploadSuccess($event, it)">
</app-upload-image-with-preview>
</div>
</div>
<!-- <div *ngIf="!customTypeGroupArr">
<nz-radio-group [ngModel]="it.itemType" (ngModelChange)="radioChange($event, it)" style="display: flex; align-items: center; justify-content: center">
<label *ngIf="isHasRect" nz-radio nzValue="rect">矩形</label>
<label *ngIf="isHasPic" nz-radio nzValue="pic">图片</label>
<label *ngIf="isHasText" nz-radio nzValue="text">文本</label>
</nz-radio-group>
</div> -->
<div *ngIf="it.itemType == 'text'">
<input type="text" nz-input [(ngModel)]="it.text" (blur)="saveText(it)">
</div>
<div style="width: 100%; margin-top: 5px;">
<app-audio-recorder
[audioUrl]="it.audio_url"
(audioUploaded)="onItemAudioUploadSuccess($event, it)"
></app-audio-recorder>
<div *ngIf="customTypeGroupArr && customTypeGroupArr[it.gIdx]">
<div *ngIf="customTypeGroupArr[it.gIdx].pic">
<app-upload-image-with-preview
[picUrl]="it?.pic_url"
(imageUploaded)="onItemImgUploadSuccess($event, it)">
</app-upload-image-with-preview>
</div>
<div *ngIf="customTypeGroupArr[it.gIdx].text" style="margin-top: 5px">
<input type="text" nz-input [(ngModel)]="it.text" (blur)="saveText(it)">
</div>
<div *ngIf="customTypeGroupArr[it.gIdx].anima" align="center" style="margin-top: 5px">
<button nz-button (click)="setAnimaBtnClick(i)" >
<i nz-icon nzType="tool" nzTheme="outline"></i>
配置龙骨动画
</button>
</div>
<div *ngIf="customTypeGroupArr[it.gIdx].animaSmall" align="center" style="margin-top: 5px">
<button nz-button (click)="setAnimaSmallBtnClick(i)" >
<i nz-icon nzType="tool" nzTheme="outline"></i>
配置龙骨动画(小)
</button>
</div>
<div *ngIf="customTypeGroupArr[it.gIdx].audio" style="display: flex;align-items: center; margin-top: 5px">
<app-audio-recorder
style="margin: auto"
[audioUrl]="it.audio_url"
(audioUploaded)="onItemAudioUploadSuccess($event, it)"
></app-audio-recorder>
</div>
<div *ngIf="customTypeGroupArr[it.gIdx]?.action" style="display: flex;align-items: center; margin-top: 5px">
<app-custom-action
style="margin: auto"
[item]="it ? it['actionData_' + it.gIdx] : {}"
[type]="customTypeGroupArr[it.gIdx].action.type"
[option]="customTypeGroupArr[it.gIdx].action.option"
(save)="onSaveCustomAction($event, it)">
></app-custom-action>
</div>
</div>
<!-- <div *ngIf="!customTypeGroupArr">
<div *ngIf="it.itemType == 'pic'">
<app-upload-image-with-preview
[picUrl]="it?.pic_url"
(imageUploaded)="onItemImgUploadSuccess($event, it)">
</app-upload-image-with-preview>
</div>
<div *ngIf="it.itemType == 'text'">
<input type="text" nz-input [(ngModel)]="it.text" (blur)="saveText(it)">
</div>
<div *ngIf="isHasAudio"
style="width: 100%; margin-top: 5px; display: flex; align-items: center; justify-items: center;">
<app-audio-recorder
style="margin: auto"
[audioUrl]="it.audio_url"
(audioUploaded)="onItemAudioUploadSuccess($event, it)"
></app-audio-recorder>
</div>
<div *ngIf="it.itemType == 'rect' && isHasAnima" align="center" style="margin-bottom: 5px">
<button nz-button (click)="setAnimaBtnClick(i)" >
<i nz-icon nzType="tool" nzTheme="outline"></i>
配置龙骨动画
</button>
</div>
</div> -->
</div>
</div>
......@@ -83,12 +161,29 @@
<div class="save-box">
<button class="save-btn" nz-button nzType="primary" [nzSize]="'large'" nzShape="round"
<button style="margin-left: 200px" class="save-btn" nz-button nzType="primary" [nzSize]="'large'" nzShape="round"
(click)="saveClick()" >
<i nz-icon nzType="save"></i>
Save
</button>
<div *ngIf="isCopyData" style="height: 40px; display: flex; justify-items: center;" >
<label style="margin-left: 40px" nz-checkbox [(ngModel)]="bgItem.isShowDebugLine">显示辅助框</label>
<button style="margin-left: 20px; margin-top: -5px" nz-button (click)="copyHotZoneData()"> 复制基础数据 </button>
<div style="margin-left: 10px; margin-top: -5px" >
<span>粘贴数据: </span>
<input style="width: 100px;" type="text" nz-input [(ngModel)]="pasteData" >
<button style="margin-left: 5px;" nz-button [disabled]="pasteData==''" nzType="primary" (click)="importData()">导入</button>
</div>
</div>
</div>
......@@ -98,3 +193,52 @@
<label style="opacity: 0; position: absolute; top: 0px; font-family: 'BRLNSR_1'">1</label>
<!--龙骨面板-->
<nz-modal [(nzVisible)]="animaPanelVisible" nzTitle="配置资源文件" (nzAfterClose)="closeAfterPanel()" (nzOnCancel)="animaPanelCancel()" (nzOnOk)="animaPanelOk()" nzOkText="保存">
<div class="anima-upload-btn">
<span style="margin-right: 10px">上传 ske_json 文件: </span>
<nz-upload [nzShowUploadList]="false"
nzAccept="application/json"
[nzAction]="uploadUrl"
[nzData]="uploadData"
(nzChange)="skeJsonHandleChange($event)">
<button nz-button><i nz-icon nzType="upload"></i><span>Upload</span></button>
</nz-upload>
<i *ngIf="isSkeJsonLoading" style="margin-left: 10px;" nz-icon [nzType]="'loading'"></i>
<span *ngIf="skeJsonData['name']" style="margin-left: 10px"><u> {{skeJsonData['name']}} </u></span>
</div>
<div class="anima-upload-btn">
<span style="margin-right: 10px">上传 tex_json 文件: </span>
<nz-upload [nzShowUploadList]="false"
nzAccept="application/json"
[nzAction]="uploadUrl"
[nzData]="uploadData"
(nzChange)="texJsonHandleChange($event)">
<button nz-button><i nz-icon nzType="upload"></i><span>Upload</span></button>
</nz-upload>
<i *ngIf="isTexJsonLoading" style="margin-left: 10px;" nz-icon [nzType]="'loading'"></i>
<span *ngIf="texJsonData['name']" style="margin-left: 10px"><u> {{texJsonData['name']}} </u></span>
</div>
<div class="anima-upload-btn">
<span style="margin-right: 10px">上传 tex_png 文件: </span>
<nz-upload [nzShowUploadList]="false"
nzAccept = "image/*"
[nzAction]="uploadUrl"
[nzData]="uploadData"
(nzChange)="texPngHandleChange($event)">
<button nz-button><i nz-icon nzType="upload"></i><span>Upload</span></button>
</nz-upload>
<i *ngIf="isTexPngLoading" style="margin-left: 10px;" nz-icon [nzType]="'loading'"></i>
<span *ngIf="texPngData['name']" style="margin-left: 10px"><u> {{texPngData['name']}} </u></span>
</div>
<div class="anima-upload-btn" *ngIf="customTypeGroupArr && customTypeGroupArr[curDragonBoneGIdx] && customTypeGroupArr[curDragonBoneGIdx].animaNames">
提示:需包含以下动画: {{customTypeGroupArr[curDragonBoneGIdx].animaNames.toString()}}
</div>
</nz-modal>
......@@ -81,19 +81,21 @@
}
}
h5 {
margin-top: 1rem;
.anima-upload-btn {
padding: 10px;
}
@font-face
{
font-family: 'BRLNSR_1';
src: url("/assets/font/BRLNSR_1.TTF") ;
h5 {
margin-top: 1rem;
}
//
//@font-face
//{
// font-family: 'BRLNSR_1';
// src: url("/assets/font/BRLNSR_1.TTF") ;
//}
......@@ -107,104 +109,3 @@ h5 {
//@import '../../../style/common_mixin';
//
//.p-image-uploader {
// position: relative;
// display: block;
// width: 100%;
// height: 0;
// padding-bottom: 56.25%;
// .p-box {
// position: absolute;
// left: 0;
// top: 0;
// right: 0;
// bottom: 0;
// border: 2px dashed #ddd;
// border-radius: 0.5rem;
// background-color: #fafafa;
// text-align: center;
// color: #aaa;
// .p-upload-icon {
// text-align: center;
// margin: auto;
// .anticon-upload {
// color: #888;
// font-size: 5rem;
// }
// .p-progress-bar {
// position: relative;
// width: 20rem;
// height: 1.5rem;
// border: 1px solid #ccc;
// border-radius: 1rem;
// .p-progress-bg {
// background-color: #1890ff;
// border-radius: 1rem;
// height: 100%;
// }
// .p-progress-value {
// position: absolute;
// top: 0;
// left: 0;
// width: 100%;
// height: 100%;
// text-shadow: 0 0 4px #000;
// color: white;
// text-align: center;
// font-size: 0.9rem;
// line-height: 1.5rem;
// }
// }
// }
// .p-preview {
// width: 100%;
// height: 100%;
// //background-image: url("https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png");
// @include k-img-bg();
// }
// }
//}
//
//.p-btn-delete {
// position: absolute;
// right: -0.5rem;
// top: -0.5rem;
// width: 2rem;
// height: 2rem;
// border: 0.2rem solid white;
// border-radius: 50%;
// font-size: 1.2rem;
// background-color: #fb781a;
// color: white;
// text-align: center;
//}
//
//.p-upload-progress-bg {
// position: absolute;
// width: 100%;
// height: 100%;
// display: flex;
// align-items: center;
// justify-content: center;
// & .i-text {
// position: absolute;
// text-align: center;
// color: white;
// text-shadow: 0 0 2px rgba(0, 0, 0, .85);
// }
// & .i-bg {
// position: absolute;
// left: 0;
// top: 0;
// height: 100%;
// background-color: #27b43f;
// border-radius: 0.5rem;
// }
//}
//
//
//:host ::ng-deep .ant-upload {
// display: block;
//}
import {
ApplicationRef,
ChangeDetectorRef,
Component,
ElementRef,
EventEmitter,
......@@ -12,10 +14,11 @@ import {
} from '@angular/core';
import {Subject} from 'rxjs';
import {debounceTime} from 'rxjs/operators';
import {EditorItem, HotZoneImg, HotZoneItem, HotZoneLabel, Label, MySprite, removeItemFromArr} from './Unit';
import {EditorItem, HotZoneImg, HotZoneItem, HotZoneLabel, HotZonePoint, Label, MySprite, removeItemFromArr, ShapeRect, ShapeRectNew} from './Unit';
import TWEEN from '@tweenjs/tween.js';
import {getMinScale} from "../../play/Unit";
import {tar} from "compressing";
import {getMinScale} from '../../play/Unit';
import {tar} from 'compressing';
import {NzMessageService} from 'ng-zorro-antd';
@Component({
......@@ -25,18 +28,14 @@ import {tar} from "compressing";
})
export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
@ViewChild('canvas', {static: true}) canvas: ElementRef;
@ViewChild('wrap', {static: true}) wrap: ElementRef;
@Input()
imgItemArr = null;
@Input()
hotZoneItemArr = null;
@Input()
hotZoneArr = null;
@Output()
save = new EventEmitter();
@ViewChild('canvas', {static: true}) canvas: ElementRef;
@ViewChild('wrap', {static: true}) wrap: ElementRef;
@Input()
isHasRect = true;
@Input()
......@@ -44,16 +43,30 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
@Input()
isHasText = true;
@Input()
hotZoneFontObj = {
size: 50,
name: 'BRLNSR_1',
color: '#8f3758'
}
isHasAudio = true;
@Input()
defaultItemType = 'text';
isHasAnima = false;
@Input()
customTypeGroupArr; // [{name:string, rect:boolean, pic:boolean, text:boolean, audio:boolean, anima:boolean, animaNames:['name1', ..]}, ...]
@Input()
hotZoneFontObj;
@Input()
isCopyData = false;
// hotZoneFontObj = {
// size: 50,
// name: 'BRLNSR_1',
// color: '#8f3758'
// }
@Input()
hotZoneImgSize = 190;
defaultItemType = 'text';
@Input()
hotZoneImgSize = 0;
@Output()
save = new EventEmitter();
saveDisabled = true;
......@@ -86,8 +99,33 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
changeSizeFlag = false;
changeTopSizeFlag = false;
changeRightSizeFlag = false;
animaPanelVisible = false;
uploadUrl;
uploadData;
skeJsonData = {};
texJsonData = {};
texPngData = {};
animaName = '';
curDragonBoneIndex;
curDragonBoneGIdx;
pasteData = '';
constructor() {
isSkeJsonLoading = false;
isTexJsonLoading = false;
isTexPngLoading = false;
isAnimaSmall = false;
constructor(private nzMessageService: NzMessageService, private appRef: ApplicationRef, private changeDetectorRef: ChangeDetectorRef) {
this.uploadUrl = (<any> window).courseware.uploadUrl();
this.uploadData = (<any> window).courseware.uploadData();
window['air'].getUploadCallback = (url, data) => {
this.uploadUrl = url;
this.uploadData = data;
};
}
_bgItem = null;
......@@ -110,11 +148,14 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
ngOnInit() {
this.initListener();
// this.init();
this.update();
this.refresh();
}
ngOnDestroy() {
......@@ -136,10 +177,12 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
onItemImgUploadSuccess(e, item) {
item.pic_url = e.url;
this.loadHotZonePic(item.pic, e.url);
this.refresh();
}
onItemAudioUploadSuccess(e, item) {
item.audio_url = e.url;
this.refresh();
}
......@@ -150,25 +193,32 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
this.renderArr.push(this.bg);
}
if (!this.bgItem.url) {
this.bgItem.url = 'http://teach.cdn.ireadabc.com/8ebb1858564340ea0936b83e3280ad7d.jpg';
}
const bg = this.bg;
if (this.bgItem.url) {
// if (this.bgItem.url) {
bg.load(this.bgItem.url).then(() => {
const rate1 = this.canvasWidth / bg.width;
const rate2 = this.canvasHeight / bg.height;
bg.load(this.bgItem.url).then(() => {
const rate1 = this.canvasWidth / bg.width;
const rate2 = this.canvasHeight / bg.height;
const rate = Math.min(rate1, rate2);
bg.setScaleXY(rate);
const rate = Math.min(rate1, rate2);
bg.setScaleXY(rate);
bg.x = this.canvasWidth / 2;
bg.y = this.canvasHeight / 2;
bg.x = this.canvasWidth / 2;
bg.y = this.canvasHeight / 2;
if (callBack) {
callBack();
}
});
}
if (callBack) {
callBack();
}
this.refresh();
});
// }
}
......@@ -191,6 +241,7 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
const item = this.hotZoneArr.splice(index, 1)[0];
removeItemFromArr(this.renderArr, item.pic);
removeItemFromArr(this.renderArr, item.textLabel);
removeItemFromArr(this.renderArr, item.point);
this.refreshHotZoneId();
......@@ -199,6 +250,7 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
onImgUploadSuccessByImg(e, img) {
img.pic_url = e.url;
this.refreshImage(img);
this.refresh();
}
refreshImage(img) {
......@@ -221,6 +273,7 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
}
}
this.refresh();
}
......@@ -245,10 +298,17 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
item.anchorX = 0.5;
item.anchorY = 0.5;
item.x = this.canvasWidth / 2;
item.y = this.canvasHeight / 2;
item.itemType = this.defaultItemType;
item.itemType = this.getDefaultItemType();
item.gIdx = '0';
item['id'] = new Date().getTime().toString();
item['data'] = saveData;
console.log('item.x: ', item.x);
if (saveData) {
......@@ -257,41 +317,183 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
item.scaleY = saveRect.height / item.height;
item.x = saveRect.x + saveRect.width / 2;
item.y = saveRect.y + saveRect.height / 2;
item.gIdx = saveData.gIdx;
item['id'] = saveData.id;
item['skeJsonData'] = saveData.skeJsonData;
item['texJsonData'] = saveData.texJsonData;
item['texPngData'] = saveData.texPngData;
item['actionData_' + item.gIdx] = saveData['actionData_' + item.gIdx];
}
console.log('item.x:~~ ', item.x);
item.showLineDash();
const pic = new HotZoneImg(this.ctx);
// const pic = new HotZoneImg(this.ctx);
this.setItemPic(item, saveData);
this.setItemLabel(item, saveData);
this.setItemAnima(item, saveData);
this.setItemPoint(item, saveData);
return item;
}
setItemPic(item, saveData) {
console.log('in setItemPic ', saveData);
const pic = new EditorItem(this.ctx);
pic.visible = false;
item['pic'] = pic;
if (saveData && saveData.pic_url) {
this.loadHotZonePic(pic, saveData.pic_url);
if (saveData) {
let picUrl = saveData.pic_url;
const actionData = saveData['actionData_' + item.gIdx];
if (actionData && actionData.type == 'pic') {
picUrl = actionData.pic_url;
}
console.log('saveData: ', saveData);
console.log('picUrl: ', picUrl);
if (picUrl) {
this.loadHotZonePic(pic, picUrl, saveData);
}
}
pic.x = item.x;
pic.y = item.y;
this.renderArr.push(pic);
}
setItemAnima(item, saveData) {
console.log('in setItemAnima ', saveData);
// const pic = new EditorItem(this.ctx);
// pic.visible = false;
// item['pic'] = pic;
// if (saveData) {
// let picUrl = saveData.pic_url;
// const actionData = saveData['actionData_' + item.gIdx];
// if (actionData && actionData.type == 'pic') {
// picUrl = actionData.pic_url;
// }
// console.log('saveData: ', saveData);
// console.log('picUrl: ', picUrl);
// if (picUrl) {
// this.loadHotZonePic(pic, picUrl, saveData.imgScale);
// }
// }
// pic.x = item.x;
// pic.y = item.y;
// this.renderArr.push(pic);
}
setItemPoint(item, saveData) {
console.log('in setItemPoint ', saveData);
const point = new HotZonePoint(this.ctx);
point.visible = false;
item['point'] = point;
item.width = point.width;
item.height = point.height;
// const pic = new EditorItem(this.ctx);
// pic.visible = false;
// item['pic'] = pic;
// if (saveData) {
// let picUrl = saveData.pic_url;
// const actionData = saveData['actionData_' + item.gIdx];
// if (actionData && actionData.type == 'pic') {
// picUrl = actionData.pic_url;
// }
// console.log('saveData: ', saveData);
// console.log('picUrl: ', picUrl);
// if (picUrl) {
// this.loadHotZonePic(pic, picUrl, saveData);
// }
// }
console.log('item.x: ', item.x);
point.setScaleXY(this.mapScale);
console.log('point.scaleX: ', point.scaleX)
point.x = item.x;
point.y = item.y;
this.renderArr.push(point);
}
setItemLabel(item, saveData) {
const textLabel = new HotZoneLabel(this.ctx);
textLabel.fontSize = this.hotZoneFontObj.size;
textLabel.fontName = this.hotZoneFontObj.name;
textLabel.fontColor = this.hotZoneFontObj.color;
if (this.hotZoneFontObj) {
textLabel.fontSize = this.hotZoneFontObj.size;
textLabel.fontName = this.hotZoneFontObj.name;
textLabel.fontColor = this.hotZoneFontObj.color;
}
textLabel.textAlign = 'center';
// textLabel.setOutline();
// console.log('saveData:', saveData);
item['textLabel'] = textLabel;
textLabel.setScaleXY(this.mapScale);
if (saveData && saveData.text) {
textLabel.text = saveData.text;
if (saveData) {
if (saveData.text && this.hotZoneFontObj) {
textLabel.text = saveData.text
}
this.setActionFont(textLabel, saveData['actionData_' + item.gIdx]);
textLabel.refreshSize();
}
textLabel.x = item.x;
textLabel.y = item.y;
this.renderArr.push(textLabel);
}
return item;
setActionFont(textLabel, actionData) {
if (actionData && actionData.type == 'text') {
textLabel.text = actionData.text;
for (let i=0; i<actionData.changeOption.length; i++) {
const op = actionData.changeOption[i];
textLabel[op[0]] = op[1];
}
}
}
getDefaultItemType() {
if (this.customTypeGroupArr) {
const group = this.customTypeGroupArr[0];
if (group.rect) {
return 'rect';
}
if (group.pic) {
return 'pic';
}
if (group.text) {
return 'text';
}
if (group.point) {
return 'point';
}
} else {
return this.defaultItemType;
}
}
getPicItem(img, saveData = null) {
......@@ -327,9 +529,11 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
item.y = saveRect.y + saveRect.height / 2;
} else {
item.showLineDash();
// item.showLineDash();
}
item.showLineDash();
console.log('aaa');
});
return item;
}
......@@ -337,6 +541,7 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
onAudioUploadSuccessByImg(e, img) {
img.audio_url = e.url;
this.refresh();
}
deleteItem(e, i) {
......@@ -345,15 +550,118 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
this.hotZoneArr.splice(i, 1);
this.refreshHotZoneId();
this.refresh();
}
radioChange(e, item) {
item.itemType = e;
// radioChange(e, item) {
// item.itemType = e;
this.refreshItem(item);
// this.refreshItem(item);
// this.refresh();
// // console.log(' in radioChange e: ', e);
// }
customRadioChange(e, item) {
console.log('in customRadioChange', e);
item.gIdx = -1;
setTimeout(() => {
item.gIdx = e;
this.refreshCustomItem(item);
this.refresh();
}, 1);
// const curGroup = this.customTypeGroupArr[e];
}
refreshCustomItem(item) {
this.hideHotZoneItem(item);
const group = this.customTypeGroupArr[item.gIdx];
if (!group) {
return;
}
if (group.text) {
this.showItemLabel(item);
}
if (group.rect) {
this.showItemRect(item);
}
if (group.pic && !group.anima) {
this.showItemPic(item);
}
if (group.point) {
this.showItemPoint(item);
}
if (group.action) {
if (group.action.type == 'pic') {
this.showItemPic(item);
}
if (group.action.type == 'text') {
this.showItemLabel(item);
}
if (group.action.type == 'anima') {
this.showItemRect(item);
}
}
item.setAnimaStyle(group.animaSmall)
}
setItemIsAnimaStyle(item, isAnimal) {
}
// console.log(' in radioChange e: ', e);
showItemPic(item) {
item.pic.visible = true;
item.itemType = 'pic';
this.showArrowTop(item, item.data.isShowArrowAll)
}
showItemLabel(item) {
item.textLabel.visible = true;
item.itemType = 'text';
this.showArrowTop(item, item.data.isShowArrowAll)
}
showItemRect(item) {
item.visible = true;
item.itemType = 'rect';
const isShowArrowAll = item.data.isShowArrowAll == false ? false : true;
this.showArrowTop(item, isShowArrowAll)
}
showItemPoint(item) {
item.point.visible = true;
item.itemType = 'point';
this.showArrowTop(item, false)
}
showArrowTop(item, isShowArrowTop = false) {
if (isShowArrowTop) {
item.arrowTop.visible = true;
item.arrowRight.visible = true;
} else {
item.arrowTop.visible = false;
item.arrowRight.visible = false;
}
}
hideHotZoneItem(item) {
item.visible = false;
item.pic.visible = false;
item.textLabel.visible = false;
}
refreshItem(item) {
......@@ -367,14 +675,18 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
case 'text':
this.setTextState(item);
break;
case 'point':
this.setPointState(item);
break;
default:
this.setNoneState(item);
}
}
init() {
console.log('init');
this.initData();
this.initCtx();
......@@ -382,18 +694,15 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
}
initItem() {
this.changeDetectorRef.markForCheck();
this.changeDetectorRef.detectChanges();
if (!this.bgItem) {
this.bgItem = {};
} else {
this.refreshBackground(() => {
// if (!this.imgItemArr) {
// this.imgItemArr = [];
// } else {
// this.initImgArr();
// }
// console.log('aaaaa');
if (!this.hotZoneItemArr) {
this.hotZoneItemArr = [];
......@@ -404,6 +713,7 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
});
}
this.refresh();
}
initHotZoneArr() {
......@@ -427,6 +737,7 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
this.hotZoneArr = [];
const arr = this.hotZoneItemArr.concat();
console.log('this.hotZoneItemArr: ', this.hotZoneItemArr);
for (let i = 0; i < arr.length; i++) {
const data = JSON.parse(JSON.stringify(arr[i]));
......@@ -449,9 +760,15 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
item.pic_url = data.pic_url;
item.text = data.text;
item.itemType = data.itemType;
this.refreshItem(item);
console.log('item: ', item);
if (this.customTypeGroupArr) {
this.refreshCustomItem(item);
} else {
this.refreshItem(item);
}
console.log('1 item: ', item);
this.hotZoneArr.push(item);
}
......@@ -463,48 +780,6 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
}
initImgArr() {
console.log('this.imgItemArr: ', this.imgItemArr);
let curBgRect;
if (this.bg) {
curBgRect = this.bg.getBoundingBox();
} else {
curBgRect = {x: 0, y: 0, width: this.canvasWidth, height: this.canvasHeight};
}
let oldBgRect = this.bgItem.rect;
if (!oldBgRect) {
oldBgRect = curBgRect;
}
const rate = curBgRect.width / oldBgRect.width;
console.log('rate: ', rate);
this.imgArr = [];
const arr = this.imgItemArr.concat();
for (let i = 0; i < arr.length; i++) {
const data = JSON.parse(JSON.stringify(arr[i]));
const img = {pic_url: data.pic_url};
data.rect.x *= rate;
data.rect.y *= rate;
data.rect.width *= rate;
data.rect.height *= rate;
data.rect.x += curBgRect.x;
data.rect.y += curBgRect.y;
img['picItem'] = this.getPicItem(img, data);
img['audio_url'] = arr[i].audio_url;
this.imgArr.push(img);
}
this.refreshImageId();
}
initData() {
this.canvasWidth = this.wrap.nativeElement.clientWidth;
......@@ -528,9 +803,10 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
this.oldPos = {x: this.mx, y: this.my};
for (let i = 0; i < this.hotZoneArr.length; i++) {
for (let i = this.hotZoneArr.length - 1; i >= 0; i--) {
const item = this.hotZoneArr[i];
console.log('mapDown item: ', item);
let callback;
let target;
switch (item.itemType) {
......@@ -546,9 +822,13 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
target = item.textLabel;
callback = this.clickedHotZoneText.bind(this);
break;
case 'point':
target = item.point;
callback = this.clickedHotZonePoint.bind(this);
break;
}
if (this.checkClickTarget(target)) {
if (target && this.checkClickTarget(target)) {
callback(target);
return;
}
......@@ -582,7 +862,7 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
this.oldPos = {x: this.mx, y: this.my};
this.saveDisabled = true;
// this.saveDisabled = false;
}
......@@ -723,7 +1003,7 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
// }
this.updateArr(this.hotZoneArr);
this.updatePos()
this.updatePos();
TWEEN.update();
......@@ -833,7 +1113,9 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
checkClickTarget(target) {
if (!target || !target.visible) {
return;
}
const rect = target.getBoundingBox();
if (this.checkPointInRect(this.mx, this.my, rect)) {
return true;
......@@ -852,9 +1134,21 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
saveClick() {
const sendData = this.getSendData();
this.save.emit(sendData);
}
getSendData() {
const bgItem = this.bgItem;
if (this.bg) {
bgItem['rect'] = this.bg.getBoundingBox();
const rect = this.bg.getBoundingBox();
bgItem['rect'] = rect;
rect.x = Math.round(rect.x * 100) / 100;
rect.y = Math.round(rect.y * 100) / 100;
rect.width = Math.round(rect.width * 100) / 100;
rect.height = Math.round(rect.height * 100) / 100;
} else {
bgItem['rect'] = {
x: 0,
......@@ -870,19 +1164,43 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
for (let i = 0; i < hotZoneArr.length; i++) {
const hotZoneItem = {
id: hotZoneArr[i].id,
index: hotZoneArr[i].index,
pic_url: hotZoneArr[i].pic_url,
text: hotZoneArr[i].text,
audio_url: hotZoneArr[i].audio_url,
itemType: hotZoneArr[i].itemType,
fontSize: this.hotZoneFontObj.size,
fontName: this.hotZoneFontObj.name,
fontColor: this.hotZoneFontObj.color,
fontScale: hotZoneArr[i].textLabel ? hotZoneArr[i].textLabel.scaleX : 1,
imgScale: hotZoneArr[i].pic ? hotZoneArr[i].pic.scaleX : 1,
mapScale: this.mapScale
mapScale: this.mapScale,
skeJsonData: hotZoneArr[i].skeJsonData,
texJsonData: hotZoneArr[i].texJsonData,
texPngData: hotZoneArr[i].texPngData,
gIdx: hotZoneArr[i].gIdx
};
hotZoneItem['rect'] = hotZoneArr[i].getBoundingBox();
hotZoneItem['actionData_' + hotZoneItem.gIdx] = hotZoneArr[i]['actionData_' + hotZoneArr[i].gIdx]
if (this.hotZoneFontObj) {
hotZoneItem['fontSize'] = this.hotZoneFontObj.size;
hotZoneItem['fontName'] = this.hotZoneFontObj.name;
hotZoneItem['ontColor'] = this.hotZoneFontObj.color;
}
if (hotZoneArr[i].itemType == 'pic') {
hotZoneItem['rect'] = hotZoneArr[i].pic.getBoundingBox();
} else if (hotZoneArr[i].itemType == 'text') {
hotZoneArr[i].textLabel.refreshSize();
hotZoneItem['rect'] = hotZoneArr[i].textLabel.getLabelRect();
// hotZoneItem['rect'].width = hotZoneItem['rect'].width / hotZoneArr[i].textLabel.scaleX;
// hotZoneItem['rect'].height = hotZoneArr[i].textLabel.height * hotZoneArr[i].textLabel.scaleY;
} else {
hotZoneItem['rect'] = hotZoneArr[i].getBoundingBox();
}
// hotZoneItem['rect'] = hotZoneArr[i].getBoundingBox();
hotZoneItem['rect'].x = Math.round((hotZoneItem['rect'].x - bgItem['rect'].x) * 100) / 100;
hotZoneItem['rect'].y = Math.round((hotZoneItem['rect'].y - bgItem['rect'].y) * 100) / 100;
hotZoneItem['rect'].width = Math.round((hotZoneItem['rect'].width) * 100) / 100;
......@@ -894,7 +1212,275 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
console.log('hotZoneItemArr: ', hotZoneItemArr);
this.save.emit({bgItem, hotZoneItemArr});
return {bgItem, hotZoneItemArr};
}
saveText(item) {
if (item.itemType == 'text') {
item.textLabel.text = item.text;
}
}
onSaveCustomAction(e, item) {
const data = e;
item['actionData_' + item.gIdx] = data;
if (data.type == 'pic') {
let picUrl = data.pic_url;
if (picUrl) {
this.loadHotZonePic(item.pic, picUrl);
}
}
if (data.type == 'text') {
this.setActionFont(item.textLabel, data);
item.textLabel.refreshSize();
}
// if (data.type == 'anima') {
// this.setActionAnima(item.anima, data);
// }
// this.loadHotZonePic(item.pic, e.url);
this.refresh()
}
setActionAnima() {
}
setAnimaBtnClick(index) {
console.log('aaaa')
this.isAnimaSmall = false;
this.setCurDragonBone(index);
// this.curDragonBoneIndex = index;
// this.curDragonBoneGIdx = Number(this.hotZoneArr[index].gIdx);
// const {skeJsonData, texJsonData, texPngData} = this.hotZoneArr[index];
// this.skeJsonData = skeJsonData || {};
// this.texJsonData = texJsonData || {};
// this.texPngData = texPngData || {};
// this.animaPanelVisible = true;
// this.refresh();
}
setAnimaSmallBtnClick(index) {
console.log('bbb')
this.isAnimaSmall = true;
this.setCurDragonBone(index);
}
setCurDragonBone(index) {
this.curDragonBoneIndex = index;
this.curDragonBoneGIdx = Number(this.hotZoneArr[index].gIdx);
const {skeJsonData, texJsonData, texPngData} = this.hotZoneArr[index];
this.skeJsonData = skeJsonData || {};
this.texJsonData = texJsonData || {};
this.texPngData = texPngData || {};
this.animaPanelVisible = true;
this.refresh();
}
setItemSizeByAnima(jsonData, item) {
console.log('json: ', jsonData);
const request = new XMLHttpRequest();
//通过url获取文件,第二个选项是文件所在的具体地址
request.open('GET', jsonData.url, true);
request.send(null);
request.onreadystatechange = ()=> {
if (request.readyState === 4 && request.status === 200) {
var type = request.getResponseHeader('Content-Type');
if (type.indexOf("text") !== 1) {
//返回一个文件内容的对象
const data = JSON.parse(request.responseText);
console.log('request.responseText;', data)
const animaSize = data.armature[0].canvas;
item.width = animaSize.width;
item.height = animaSize.height;
// return request.responseText;
}
}
}
}
animaPanelCancel() {
this.animaPanelVisible = false;
this.refresh();
}
animaPanelOk() {
this.setItemDragonBoneData(this.hotZoneArr[this.curDragonBoneIndex]);
console.log('this.hotZoneArr: ', this.hotZoneArr);
this.animaPanelVisible = false;
if (this.isAnimaSmall) {
this.setItemSizeByAnima(this.skeJsonData, this.hotZoneArr[this.curDragonBoneIndex]);
}
this.refresh();
}
setItemDragonBoneData(item) {
item['skeJsonData'] = this.skeJsonData;
item['texJsonData'] = this.texJsonData;
item['texPngData'] = this.texPngData;
}
skeJsonHandleChange(e) {
console.log('e: ', e);
switch (e.type) {
case 'start':
this.isSkeJsonLoading = true;
break;
case 'success':
this.skeJsonData['url'] = e.file.response.url;
this.skeJsonData['name'] = e.file.name;
this.nzMessageService.success('上传成功');
this.isSkeJsonLoading = false;
break;
case 'progress':
break;
}
}
texJsonHandleChange(e) {
console.log('e: ', e);
switch (e.type) {
case 'start':
this.isTexJsonLoading = true;
break;
case 'success':
this.texJsonData['url'] = e.file.response.url;
this.texJsonData['name'] = e.file.name;
this.nzMessageService.success('上传成功');
this.isTexJsonLoading = false;
break;
case 'progress':
break;
}
}
texPngHandleChange(e) {
console.log('e: ', e);
switch (e.type) {
case 'start':
this.isTexPngLoading = true;
break;
case 'success':
this.texPngData['url'] = e.file.response.url;
this.texPngData['name'] = e.file.name;
this.nzMessageService.success('上传成功');
this.isTexPngLoading = false;
break;
case 'progress':
break;
}
}
copyHotZoneData() {
const {bgItem, hotZoneItemArr} = this.getSendData();
// const hotZoneItemArrNew = [];
// const tmpArr = JSON.parse(JSON.stringify(hotZoneItemArr));
// tmpArr.forEach((item) => {
// if (item.gIdx === '0') {
// hotZoneItemArr.push(item);
// }
// })
const jsonData = {
bgItem,
hotZoneItemArr,
isHasRect: this.isHasRect,
isHasPic: this.isHasPic,
isHasText: this.isHasText,
isHasAudio: this.isHasAudio,
isHasAnima: this.isHasAnima,
hotZoneFontObj: this.hotZoneFontObj,
defaultItemType: this.defaultItemType,
hotZoneImgSize: this.hotZoneImgSize,
};
const oInput = document.createElement('input');
oInput.value = JSON.stringify(jsonData);
document.body.appendChild(oInput);
oInput.select(); // 选择对象
document.execCommand('Copy'); // 执行浏览器复制命令
document.body.removeChild(oInput);
this.nzMessageService.success('复制成功');
// alert('复制成功');
}
importData() {
if (!this.pasteData) {
return;
}
try {
const data = JSON.parse(this.pasteData);
console.log('data:', data);
const {
bgItem,
hotZoneItemArr,
isHasRect,
isHasPic,
isHasText,
isHasAudio,
isHasAnima,
hotZoneFontObj,
defaultItemType,
hotZoneImgSize,
} = data;
this.hotZoneItemArr = hotZoneItemArr;
this.isHasRect = isHasRect;
this.isHasPic = isHasPic;
this.isHasText = isHasText;
this.isHasAudio = isHasAudio;
this.isHasAnima = isHasAnima;
this.hotZoneFontObj = hotZoneFontObj;
this.defaultItemType = defaultItemType;
this.hotZoneImgSize = hotZoneImgSize;
this.bgItem = bgItem;
this.pasteData = '';
} catch (e) {
console.log('err: ', e);
this.nzMessageService.error('导入失败');
}
}
private updatePos() {
......@@ -915,33 +1501,59 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
x = item.textLabel.x;
y = item.textLabel.y;
break;
case 'point':
x = item.point.x;
y = item.point.y;
break;
}
if (x != undefined && y != undefined) {
item.x = x;
item.y = y;
item.pic.x = x;
item.pic.y = y;
item.textLabel.x = x;
item.textLabel.y = y;
}
item.x = x;
item.y = y;
item.pic.x = x;
item.pic.y = y;
item.textLabel.x = x;
item.textLabel.y = y;
});
}
private setPicState(item: any) {
item.visible = false;
item.textLabel.visible = false;
item.pic.visible = true;
item.textLabel.visible = false;
item.point.visible = false;
}
private setRectState(item: any) {
item.visible = true;
item.textLabel.visible = false;
item.pic.visible = false;
item.textLabel.visible = false;
item.point.visible = false;
}
private setTextState(item: any) {
item.visible = false;
item.pic.visible = false;
item.textLabel.visible = true;
item.point.visible = false;
}
private setNoneState(item: any) {
item.visible = false;
item.pic.visible = false;
item.textLabel.visible = false;
item.point.visible = false;
}
private setPointState(item) {
item.visible = false;
item.pic.visible = false;
item.textLabel.visible = false;
item.point.visible = true;
}
private clickedHotZoneRect(item: any) {
......@@ -962,6 +1574,17 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
private clickedHotZonePic(item: any) {
if (this.checkClickTarget(item)) {
if (item.lineDashFlag && this.checkClickTarget(item.arrow)) {
this.changeItemSize(item);
} else if (item.lineDashFlag && this.checkClickTarget(item.arrowTop)) {
this.changeItemTopSize(item);
} else if (item.lineDashFlag && this.checkClickTarget(item.arrowRight)) {
this.changeItemRightSize(item);
} else {
this.changeCurItem(item);
}
this.curItem = item;
}
}
......@@ -972,15 +1595,51 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
}
}
saveText(item) {
item.textLabel.text = item.text;
private clickedHotZonePoint(item) {
if (this.checkClickTarget(item)) {
this.curItem = item;
}
}
private loadHotZonePic(pic: HotZoneImg, url) {
const baseLen = this.hotZoneImgSize * this.mapScale;
private loadHotZonePic(pic: HotZoneImg, url, saveData = null) {
let baseLen;
if (this.hotZoneImgSize) {
baseLen = this.hotZoneImgSize * this.mapScale;
}
console.log('saveData: ', saveData);
pic.load(url).then(() => {
const s = getMinScale(pic, baseLen);
pic.setScaleXY(s);
if (!saveData) {
let scale = this.bg.scaleX;
if (baseLen) {
scale = getMinScale(pic, baseLen);
}
pic.setScaleXY(scale);
} else {
const targetW = saveData.rect.width /// saveData.imgScale;
const targetH = saveData.rect.height /// saveData.imgScale;
pic.scaleX = targetW / pic.width;
pic.scaleY = targetH / pic.height;
}
});
}
closeAfterPanel() {
this.refresh();
}
/**
* 刷新 渲染页面
*/
refresh() {
setTimeout(() => {
this.appRef.tick();
}, 1);
}
}
<div class="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 {
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() {
if (!this.picItem) {
return;
......
......@@ -6,3 +6,30 @@
height: 100%;
}
.radioPaire {
float: left;
margin: 3px;
border-style: dashed;
border-color: #000;
border-width: 1px;
}
.border {
border-radius: 20px;
border-style: dashed;
padding: 20px;
margin: 20px;
/*width: 500px; */
/*//border-radius: 20px;*/
/*//border-width: 2px;*/
/*//border-color: #000000;*/
}
.border-lite {
border: 2px dashed #ddd;
border-radius: 0.5rem;
padding: 10px;
margin: 10px;
}
<div class="model-content">
<div style="padding: 20px;">
<h2 style="margin-top: 20px;">
封面图
</h2>
<div style="width: 300px; margin-bottom: 50px;">
<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;">
<h2 style="width: 60px;">标题:</h2>
<input type="text" nz-input [(ngModel)]="item.title" (blur)="save()" style="margin-left: 15px">
</div>
<div *ngFor="let s of item.sentenceArr; let i = index" style=" margin-bottom: 10px; display: flex;">
<input type="text" nz-input [(ngModel)]="s.text" (blur)="save()" style="width: 500px;">
<input type="text" nz-input [(ngModel)]="s.answer" (blur)="save()" style="margin-left: 15px; width: 120px;">
<button nz-button nzType="danger" (click)="deleteBtnClick(i)" style="margin-left: 15px">
<i nz-icon nzType="delete" nzTheme="outline"></i>
删除
</button>
</div>
<div style="position: absolute; left: 200px; top: 100px; width: 800px;">
<div>
<button nz-button nzType="dashed" (click)="addBtnClick()" style="width: 200px; height: 50px;">
<i nz-icon nzType="plus-circle" nzTheme="outline"></i>
添加句子
</button>
</div>
<input type="text" nz-input [(ngModel)]="item.text" (blur)="save()">
<app-upload-image-with-preview
[picUrl]="item.pic_url"
(imageUploaded)="onImageUploadSuccess($event, 'pic_url')"
></app-upload-image-with-preview>
<div *ngIf="item.templateArr" >
<div *ngFor="let template of item.templateArr; let i = index" style="margin-bottom: 10px;">
<app-sub-template
[item]="template"
[key]="i+1"
(save)="onSaveTemplate($event, i)"
(deleteFunc)="onDeleteTemplate($event, i)"
>
</app-sub-template>
</div>
</div>
<button *ngIf=" item.templateArr.length < 2 " nz-button nzType="primary" (click)="addSubTemplate()" style="border-radius: 0.5rem; border: 1px solid #ddd; margin-top: 15px;">
<i nz-icon nzType="plus" nzTheme="outline"></i>
添加子模板
</button>
<!--
<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> -->
<span>音频: </span>
<app-audio-recorder
[audioUrl]="item.audio_url"
(audioUploaded)="onAudioUploadSuccess($event, 'audio_url')"
></app-audio-recorder>
<app-custom-hot-zone></app-custom-hot-zone>
<app-upload-video></app-upload-video>
<app-lesson-title-config></app-lesson-title-config>
</div>
</div>
\ No newline at end of file
import {Component, EventEmitter, Input, OnDestroy, OnChanges, OnInit, Output, ApplicationRef, ChangeDetectorRef} from '@angular/core';
import { Component, EventEmitter, Input, OnDestroy, OnChanges, OnInit, Output, ApplicationRef, ChangeDetectorRef } from '@angular/core';
import { JsonPipe } from '@angular/common';
@Component({
......@@ -10,22 +10,56 @@ import {Component, EventEmitter, Input, OnDestroy, OnChanges, OnInit, Output, Ap
export class FormComponent implements OnInit, OnChanges, OnDestroy {
// 储存数据用
saveKey = "test_0011";
saveKey = "JM_4-1";
// 储存对象
item;
customTypeGroupArr = [
{
name: '遮照图片',
pic: true,
isShowArrowAll: true,
// rect: true,
// animaSmall: true,
// audio: true,
},
{
name: 'Open按钮',
point: true,
// animaSmall: true,
// audio: 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() {
this.item = {};
// 获取存储的数据
(<any> window).courseware.getData((data) => {
(<any>window).courseware.getData((data) => {
if (data) {
this.item = data;
......@@ -37,20 +71,72 @@ export class FormComponent implements OnInit, OnChanges, OnDestroy {
this.refresh();
}, this.saveKey);
}
ngOnChanges() {
}
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 +146,8 @@ export class FormComponent implements OnInit, OnChanges, OnDestroy {
*/
onImageUploadSuccess(e, key) {
this.item[key] = e.url;
this.save();
this.item[key] = e.url;
this.save();
}
/**
......@@ -69,19 +155,28 @@ export class FormComponent implements OnInit, OnChanges, OnDestroy {
* @param e
*/
onAudioUploadSuccess(e, key) {
this.item[key] = e.url;
this.save();
}
onWordAudioUploadSuccess(e, idx) {
this.item.wordList[idx].audio = e.url;
this.save();
}
onBackWordAudioUploadSuccess(e, idx) {
this.item.wordList[idx].backWordAudio = e.url;
this.save();
}
/**
* 储存数据
*/
save() {
(<any> window).courseware.setData(this.item, null, this.saveKey);
(<any>window).courseware.setData(this.item, null, this.saveKey);
this.refresh();
console.log('this.item = ' + JSON.stringify(this.item));
}
/**
......@@ -93,5 +188,4 @@ export class FormComponent implements OnInit, OnChanges, OnDestroy {
}, 1);
}
}
}
\ No newline at end of file
import TWEEN from '@tweenjs/tween.js';
import { randomInt } from 'crypto';
interface AirWindow extends Window {
air: any;
......@@ -77,7 +78,9 @@ export class MySprite extends Sprite {
_offCtx;
isCircleStyle = false; // 切成圆形
parent;
_maskSpr;
_maskSprArr = [];
_maskType = "destination-in" // destination-out
init(imgObj = null, anchorX: number = 0.5, anchorY: number = 0.5) {
......@@ -114,16 +117,20 @@ export class MySprite extends Sprite {
this._radius = r;
}
setMaskSpr(spr) {
this._maskSpr = spr;
addMaskSpr(spr) {
this._maskSprArr.push(spr);
this._createOffCtx();
}
setMaskType(t) {
this._maskType = t;
}
_createOffCtx() {
if (!this._offCtx) {
this._offCanvas = document.createElement('canvas'); // 创建一个新的canvas
this.width = this._offCanvas.width = this.width; // 创建一个正好包裹住一个粒子canvas
this.height = this._offCanvas.height = this.height;
this._offCanvas.width = this.width; // 创建一个正好包裹住一个粒子canvas
this._offCanvas.height = this.height;
this._offCtx = this._offCanvas.getContext('2d');
}
}
......@@ -220,12 +227,22 @@ export class MySprite extends Sprite {
this._offCtx.clearRect(0, 0, this.width, this.height);
this._offCtx.drawImage(this.img, 0, 0);
if (this._maskSpr) {
this._offCtx.globalCompositeOperation = 'destination-in';
this._offCtx.drawImage(this._maskSpr.img, this._maskSpr.x + this._maskSpr._offX - this._offX , this._maskSpr.y + this._maskSpr._offY - this._offY);
this._offCtx.globalCompositeOperation = this._maskType;
if (this._maskSprArr && this._maskSprArr.length > 0) {
for (let i=0; i<this._maskSprArr.length; i++) {
this._maskSprArr[i].ctx = this._offCtx;
this._maskSprArr[i].update();
}
}
this.ctx.drawImage(this._offCanvas, this._offX, this._offY);
this._offCtx.restore();
......@@ -293,6 +310,8 @@ export class MySprite extends Sprite {
child.alpha = this.alpha;
}
child.ctx = this.ctx;
}
removeChild(child) {
const index = this.children.indexOf(child);
......@@ -819,11 +838,17 @@ export class RichTextOld extends Label {
export class RichText extends Label {
disH = 30;
disH = 10;
offW = 10;
row = 1;
textBaseline = "middle";
isShowWordBg = false;
wordBgData;
constructor(ctx?: any) {
super(ctx);
......@@ -831,7 +856,60 @@ export class RichText extends Label {
// this.dataArr = dataArr;
}
getLineNum() {
this.drawSelf();
return this.row;
}
getAreaHeight() {
this.drawSelf();
const tmpTextH = this.row * this.fontSize;
const tmpDisH = (this.row - 1) * this.disH
return tmpTextH + tmpDisH;
}
getSubTextRect(subText, targetIndex=0) {
this.isShowWordBg = true;
this.update();
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;
console.log('subText: ', subText);
console.log('this.text: ', this.text);
// const indexArr = searchSubStr(this.text, subText);
// console.log('indexArr: ', indexArr);
// const index = indexArr[targetIndex];
const index = this.text.indexOf(subText, targetIndex);
console.log('index: ', index);
if (index == -1) {
return;
}
console.log('this.wordBgData: ', this.wordBgData);
// const index = this.text.indexOf(subText);
// console.log('!!!index: ', index);
const data = this.wordBgData[index.toString()];
// console.log('!!!wordBgData: ', this.wordBgData);
// console.log('!!!data: ', data);
return data;
}
drawText() {
......@@ -842,7 +920,7 @@ export class RichText extends Label {
this.ctx.font = `${this.fontSize}px ${this.fontName}`;
this.ctx.textAlign = this.textAlign;
this.ctx.textBaseline = 'middle';
this.ctx.textBaseline = this.textBaseline;
this.ctx.fontWeight = this.fontWeight;
this.ctx.fillStyle = this.fontColor;
......@@ -856,21 +934,46 @@ export class RichText extends Label {
const w = selfW - this.offW * 2;
const disH = (this.fontSize + this.disH) * this.scaleY;
let isPushWordData = false;
if (this.isShowWordBg && !this.wordBgData) {
this.wordBgData = {};
isPushWordData = true;
}
let wordIndex = -1;
for (const c of chr) {
if (isPushWordData) {
}
for (const c of chr) {
if (this.ctx.measureText(temp).width < w && this.ctx.measureText(temp + (c)).width <= w) {
if (c == '\n') {
row.push(temp);
temp = '';
} else if (this.ctx.measureText(temp).width < w && this.ctx.measureText(temp + (c)).width <= w) {
temp += ' ' + c;
} else {
row.push(temp);
temp = ' ' + c;
}
if (isPushWordData) {
wordIndex = this.text.indexOf(c, wordIndex+1);
const key = wordIndex.toString();
const rectX = this.ctx.measureText(temp).width
const rectY = ( row.length ) * disH / this.scaleY
const rectW = this.ctx.measureText(c).width;
const rectH = this.fontSize;
this.wordBgData[key] = {rect: {x: rectX, y: rectY, width: rectW, height: rectH}, text: c, index: wordIndex}
}
}
row.push(temp);
this.row = row.length;
const x = 0;
const y = -row.length * disH / 2;
const y = 0//-row.length * disH / 2;
// for (let b = 0 ; b < row.length; b++) {
// this.ctx.strokeText(row[b], x, y + ( b + 1 ) * disH ); // 每行字体y坐标间隔20
// }
......@@ -880,7 +983,7 @@ export class RichText extends Label {
this.ctx.lineWidth = this._outLineWidth;
this.ctx.strokeStyle = this._outLineColor;
for (let b = 0 ; b < row.length; b++) {
this.ctx.strokeText(row[b], x, y + ( b + 1 ) * disH ); // 每行字体y坐标间隔20
this.ctx.strokeText(row[b], x, y + ( b + 0 ) * disH / this.scaleY ); // 每行字体y坐标间隔20
}
// this.ctx.strokeText(this.text, 0, 0);
}
......@@ -888,7 +991,7 @@ export class RichText extends Label {
// this.ctx.fillStyle = '#ff7600';
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
}
}
......@@ -903,7 +1006,6 @@ export class RichText extends Label {
export class LineRect extends MySprite {
lineColor = '#ffffff';
......@@ -954,9 +1056,31 @@ export class ShapeRect extends MySprite {
drawShape() {
this.ctx.fillStyle = this.fillColor;
this.ctx.fillRect(this._offX, this._offY, this.width, this.height);
if (this._offCtx) {
this._offCtx.save();
this._offCtx.clearRect(0, 0, this.width, this.height);
this._offCtx.fillStyle = this.fillColor;
this._offCtx.fillRect(this._offX, this._offY, this.width, this.height);
this._offCtx.globalCompositeOperation = this._maskType;
if (this._maskSprArr && this._maskSprArr.length > 0) {
for (let i=0; i<this._maskSprArr.length; i++) {
this._maskSprArr[i].ctx = this._offCtx;
this._maskSprArr[i].update();
}
}
this.ctx.drawImage(this._offCanvas, this._offX, this._offY);
this._offCtx.restore();
} else {
this.ctx.fillStyle = this.fillColor;
this.ctx.fillRect(this._offX, this._offY, this.width, this.height);
}
}
......@@ -1765,6 +1889,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) {
......@@ -1847,5 +2043,330 @@ export class MyVideo extends MySprite {
}
export class ScrollView extends MySprite {
static ScrollSideType = {
VERTICAL : 'VERTICAL',
HORIZONTAL : 'HORIZONTAL',
}
_offCtx;
_offCanvas;
_scrollBar;
content;
bgColor;
barColor = '#fbe9b7'
scrollSide = ScrollView.ScrollSideType.VERTICAL;
scorllBarWidth;
scrollBarHeight;
itemArr = [];
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.itemArr.push(sprite);
this.content.addChild(sprite);
sprite.ctx = this._offCtx;
this.refreshContentSize();
}
refreshContentSize() {
const children = this.itemArr;
// console.log('children: ', children);
let maxW = 0;
let maxH = 0;
for (let i=0; i<children.length; i++) {
const box = children[i].getBoundingBox();
const curChild = children[i];
// console.log('box: ', box);
const boxEdgeX = curChild.x + (1 - curChild.anchorX) * curChild.width * curChild.scaleX;
const boxEdgeY = curChild.y + (1 - curChild.anchorY) * curChild.height * curChild.scaleY;
if (!children[i].colorRect) {
//测试
// const rect = new ShapeRectNew();
// rect.fillColor = '#ff0000';
// rect.setSize(curChild.width * curChild.scaleX, curChild.height * curChild.scaleY, 0);
// rect.alpha = 0.3;
// rect.x = boxEdgeX - curChild.width * curChild.scaleX;
// rect.y = boxEdgeY - curChild.height * curChild.scaleY;
// this.content.addChild(rect);
// children[i].colorRect = rect;
}
// console.log('boxEdgeY: ', boxEdgeY);
if (boxEdgeX > maxW) {
maxW = boxEdgeX;
}
if (boxEdgeY > maxH) {
maxH = boxEdgeY;
}
}
// console.log('maxW: ', maxW);s
// console.log('maxH: ', maxH);
// console.log('this.y: ', this.y);
// console.log(this.getBoundingBox().height);
// const box = this.getBoundingBox();
this.content.width = maxW;
this.content.height = maxH + 10 //+ 500;
this.refreshScrollBar();
}
setScrollBarSize(w, h) {
this.scorllBarWidth = w;
this.scrollBarHeight = h;
}
refreshScrollBar() {
let w = this.scorllBarWidth;
if (!w) {
w = this.width / 50;
}
const rect1 = this.getBoundingBox();
const rect2 = this.content.getBoundingBox();
const sRate = rect1.height / this.height;
let rate = rect1.height / rect2.height;
// let rate = this.height / this.content.height;
// 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 / sRate;
const r = w / 2;
this._scrollBar.setSize(w, h, r);
this._scrollBar.x = this.width;
}
refreshScrollBarPos() {
const rect1 = this.getBoundingBox();
const rect2 = this.content.getBoundingBox();
let rate = this.height / this.content.height;
this._scrollBar.y = -this.content.y * (rate );
}
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;
const rect = this.getBoundingBox();
const rect2 = this.content.getBoundingBox();
if (this.scrollSide == ScrollView.ScrollSideType.VERTICAL) {
this.content.y = between(this.touchStartContentPos.y + offsetY, 0, this.height - this.content.height);
} else {
this.content.x = between(this.touchStartContentPos.x + offsetX, 0, this.width - this.content.width);
}
this.refreshScrollBarPos();
}
onTouchEnd(x, y) {
this.touchStartPos = null;
this.touchStartContentPos = null;
}
onWheelUp(offsetY) {
if (!this._scrollBar.visible) {
return;
}
const rect = this.getBoundingBox();
if (this.scrollSide == ScrollView.ScrollSideType.VERTICAL) {
this.content.y = between(this.content.y + 40, 0, this.height - this.content.height);
} else {
this.content.x = between(this.content.x + 40, 0, this.width - this.content.width);
}
this.refreshScrollBarPos();
}
onWheelDown(offsetY) {
if (!this._scrollBar.visible) {
return;
}
const rect = this.getBoundingBox();
if (this.scrollSide == ScrollView.ScrollSideType.VERTICAL) {
this.content.y = between(this.content.y - 40, 0, this.height - this.content.height);
} else {
this.content.x = between(this.content.x - 40, 0, this.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 --------------------
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 @@
height: 100%;
background: #ffffff;
background-size: cover;
}
#canvas {
......@@ -10,10 +12,28 @@
}
@font-face
{
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>
<canvas id="canvas" #canvas></canvas>
<span style="font-family:'DroidSansFallback'" ></span>
<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 #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>
<input type="file" value="请选择文件" />
<form method="POST" [action]="uploadUrl"></form>
<!-- <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 {
MySprite,
Label,
MySprite, tweenChange,
moveItem,
rotateItem,
removeItemFromArr,
ShapeRect, scaleItem, tweenChange, showPopParticle, hideItem, showItem, LineRect, shake, RichText, ShapeRectNew, showShapeParticle, delayCall, randomSortByArr, ScrollView,
} from './Unit';
import {res, resAudio} from './resources';
import { res, resAudio } from './resources';
import {Subject} from 'rxjs';
import {debounceTime} from 'rxjs/operators';
import { Subject } from 'rxjs';
import { debounceTime } from 'rxjs/operators';
import * as _ from 'lodash';
import TWEEN from '@tweenjs/tween.js';
import { loadFonts } from './Util'
import { faTshirt } from '@fortawesome/free-solid-svg-icons';
import { DomSanitizer } from '@angular/platform-browser';
import { NzMessageService } from 'ng-zorro-antd';
import { HttpClient, HttpHeaders } from '@angular/common/http';
......@@ -21,23 +32,42 @@ import TWEEN from '@tweenjs/tween.js';
styleUrls: ['./play.component.css']
})
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;
@ViewChild('wrap', {static: true }) wrap: ElementRef;
@Input()
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;
fps = 0;
frametime = 0; // 上一帧动画的时间, 两帧时间差
canvasWidth = 1280; // canvas实际宽度
canvasHeight = 720; // canvas实际高度
canvasBaseW = 1280; // canvas 资源预设宽度
canvasBaseH = 720; // canvas 资源预设高度
mx;
my; // 点击坐标
mx; // 点击x坐标
my; // 点击y坐标
// 资源
......@@ -49,132 +79,2686 @@ export class PlayComponent implements OnInit, OnDestroy {
animationId: any;
winResizeEventStream = new Subject();
audioObj = {};
audioObj = {};
renderArr;
mapScale = 1;
mapScaleMax = 1;
canvasLeft;
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'])
onResize(event) {
this.winResizeEventStream.next();
}
constructor(private message: NzMessageService, private http: HttpClient, private sanitizer: DomSanitizer, private appRef: ApplicationRef) {
}
isTeacher = false;
async ngOnInit() {
ngOnInit() {
this.data = {};
// 获取数据
const getData = (<any> window).courseware.getData;
getData((data) => {
await loadFonts('DroidSansFallback', 'DroidSansFallback.ttf');
await loadFonts('Aileron-Black', 'Aileron-Black.ttf');
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);
this.initStoreData(aspect);
}
if (data && typeof data == 'object') {
this.data = data;
this.data = { contentObj: data };
} else {
this.initDefaultData();
}
// console.log('data:' , data);
// 初始化 各事件监听
this.initListener();
console.log('data:', data);
console.log('data Json:', JSON.stringify( data ));
// if (!this.data) {
// this.data.contentObj = {};
// }
// 若无数据 则为预览模式 需要填充一些默认数据用来显示
this.initDefaultData();
// 初始化 音频资源
this.initAudio();
// 初始化 图片资源
this.initImg();
// 开始预加载资源
this.load();
this.initListener();
}, 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) {
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);
}
}
}
// 用于存储私有数据 当翻页时清空
storeData;
initStoreData(aspect) {
const storeDataStr = aspect?.user_aspect;
if (!storeDataStr) {
this.storeData = {};
} else {
this.storeData = JSON.parse(storeDataStr);
}
console.log('initStoreData this.storeData: ', this.storeData);
}
setStoreData(key, value, isSend=true) {
if (this.storeData) {
console.log('this.storeData: ', this.storeData);
this.storeData[key] = value;
if (isSend) {
this.sendStoreData();
}
}
}
getStoreData(key) {
return this.storeData && this.storeData[key];
}
sendStoreData() {
const data = this.storeData;
if (window && window['courseware']) {
let storeAspect = window['courseware'].storeAspect;
if (storeAspect) {
storeAspect(data);
}
}
}
initDefaultData() {
}, this.saveKey);
const data = {"sentenceArr":[{"text":"1.There can be mentally and physically _ for a person to use.","answer":"exhausting"},{"text":"2.To travel through beautiful scenery at a speed of four horsepower is just _ .","answer":"marvellous"},{"text":"3.The Park is known as a place for _ and hiking, as well as events.","answer":"recreation"},{"text":"4.She looked at him in _ distress that he had to look away.","answer":"such"},{"text":"5.He enjoys the finer things in life, like _ with his wife.","answer":"ballroom dancing"},{"text":"6.Rappers always dress in their own _.","answer":"style"},{"text":"7.They suggest _ reasons for the difference in the federal government's attitudes toward the two lawsuits.","answer":"a couple of"},{"text":"8.Mr. Smith bought a new house near _ by the beach.","answer":"waterfront"},{"text":"9.One has to be knowledgeable in low to do international _ .","answer":"trade"},{"text":"10.Planes must _ from one ground beacon (信标) to the next to flight through the Mount Everest.","answer":"zigzag"},{"text":"11.Baltimore in its heyday(鼎盛时期) was a major centre of industrial and _ activity.","answer":"commercial"},{"text":"12.Despite persistent rain showers, the music festival’s _ were packed with fans.","answer":"pavilion"},{"text":"13.If something _ you, it surprises you very much. ","answer":"amazes"}],"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":"zigzag","text":"1. They staggered (蹒跚)in a _ across the road.","audio_url":"https://staging-teach.cdn.ireadabc.com/2ee1851630ae13b645f41acba1500109.mp3"},{"answer":"pavilion","text":"2. Despite persistent rain showers, the lawn and _ were packed with fans.","audio_url":"https://staging-teach.cdn.ireadabc.com/d051865834696ed4a161660ea9bd5e67.mp3"},{"answer":"amazed","text":"3. We just moved house and are _ with the amount of junk we have.","audio_url":"https://staging-teach.cdn.ireadabc.com/7c0432dc51915132f139dce7a75f1808.mp3"},{"answer":"Trade","text":"4. _between the two countries has increased.","audio_url":"https://staging-teach.cdn.ireadabc.com/30ad4162816dd0fc9747d0f38236fdba.mp3"},{"text":"5. They went for a walk along the_ .","answer":"waterfront","audio_url":"https://staging-teach.cdn.ireadabc.com/4736dddf059affd06cccc2bed72b2608.mp3"},{"text":"6. Yunnan has indeed become more _ over the past decade.","answer":"commercial","audio_url":"https://staging-teach.cdn.ireadabc.com/b68d81e3e216e80a5d14aef66a11b0c7.mp3"},{"text":"7. What’s the _ of haircut do you like?","answer":"style","audio_url":"https://staging-teach.cdn.ireadabc.com/0206e3bfd21c45d89e12612230742b19.mp3"},{"text":"8. Saturday afternoon is for _ and outings.","answer":"recreation","audio_url":"https://staging-teach.cdn.ireadabc.com/3298442f14bf32f3dbdaa32929cfe8f6.mp3"},{"text":"9. It's the most _ piece of music.","answer":"marvellous","audio_url":"https://staging-teach.cdn.ireadabc.com/4b6005977408e74acdcddc9a936cc423.mp3"},{"text":"10. She was too _ and distressed(痛苦的)to talk about the tragedy.","answer":"exhausted","audio_url":"https://staging-teach.cdn.ireadabc.com/96c2a53cfc64ea56e0ae24c24fe1731d.mp3"},{"text":"11. He is _ a fool to cheat on an exam.","answer":"such","audio_url":"https://staging-teach.cdn.ireadabc.com/a5f60ce1e9e13c1905636ac9ba170f0d.mp3"},{"text":"12. I also enjoy dancing like_ .","answer":" ballroom dancing","audio_url":"https://staging-teach.cdn.ireadabc.com/079c1935a169043acc524c8c19449c88.mp3"},{"text":"13. We went to the US _ years ago.","answer":"a couple of","audio_url":"https://staging-teach.cdn.ireadabc.com/1af6c6dae99270fe36eaae56588dae46.mp3"}],"templateArr":[],"title":"Spell the words according to what you heard"}},{"formUrl":"https://staging-teach.cdn.ireadabc.com/h5template/JM04-3/v16/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":16,"pub_date":null,"is_public":0,"created_date":"2021-07-20T06:18:52.000Z","updated_date":"2021-08-17T03:18:58.000Z"},"data":{"contentObj":{"version":"1.0","dataKey":"DataKey_JM04_3","title":{"NO":"C","mainText":"connected with the buying and selling of goods and services","mainTextAudio_url":""},"size":{"wh":"17*17"},"dataArray":[{"image_url":"","audio_url":"","text":"used to emphasize the great degree of something","uuid":"9803c50c-3638-4a6a-a4f8-719bdeaacede","direction":"Across"},{"image_url":"","audio_url":"","direction":"Down","text":"","uuid":"64635d65-972a-42d1-95c5-148efc9bd866"},{"image_url":"","audio_url":"","direction":"Down","text":"the particular way in which something is done","uuid":"1e27124a-49f2-44e6-8478-fcbc461e420f"},{"image_url":"","audio_url":"","direction":"Across","text":"emely good; wonderful","uuid":"6c6dce11-9a9d-484d-90b2-39a8ffe827f5"},{"image_url":"","audio_url":"","direction":"Down","text":"very surprised","uuid":"97ffbe71-6304-43e1-9688-a0002b45fadf"},{"image_url":"","audio_url":"","direction":"Down","text":"a part of a town or an area that is next to water","uuid":"8532c243-0036-432e-92d4-5cfdfa67a958"},{"image_url":"","audio_url":"","direction":"Down","text":"a line that has a series of angles in it like a continuous series","uuid":"8f1d8024-ebdc-4094-89ae-8238c5a9b47b"},{"image_url":"","audio_url":"","direction":"Across","text":"making you feel very tired","uuid":"8d4742d0-ee35-4c27-8da1-ff649c477222"},{"image_url":"","audio_url":"","direction":"Down","text":"the activity of buying and selling or of exchanging goods or services between people or countries","uuid":"2bd8882e-b637-4652-8c0e-da232e698223"},{"image_url":"","audio_url":"","direction":"Across","text":"a building next to a sports ground, used by players and people watching the game","uuid":"5ab70f33-0523-46aa-ac52-e0b1b191a4d7"},{"image_url":"","audio_url":"","direction":"Across","text":"(a way of) enjoying yourself when you are not working","uuid":"c2a844a2-fd57-4cc7-bec0-3930e4423c5f"}],"grid":[[{"index":[],"text":""},{"index":[],"text":""},{"index":[0],"text":"s"},{"index":[0],"text":"u"},{"index":[0,1],"text":"c"},{"index":[0],"text":"h"},{"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":[1],"text":"o"},{"index":[],"text":""},{"index":[2],"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":[1],"text":"m"},{"index":[],"text":""},{"index":[2],"text":"t"},{"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":[1],"text":"m"},{"index":[],"text":""},{"index":[2],"text":"y"},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""}],[{"index":[3],"text":"m"},{"index":[3,4],"text":"a"},{"index":[3],"text":"r"},{"index":[3],"text":"v"},{"index":[1,3],"text":"e"},{"index":[3],"text":"l"},{"index":[2,3],"text":"l"},{"index":[3],"text":"o"},{"index":[3],"text":"u"},{"index":[3],"text":"s"},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""}],[{"index":[],"text":""},{"index":[4],"text":"m"},{"index":[],"text":""},{"index":[],"text":""},{"index":[1],"text":"r"},{"index":[],"text":""},{"index":[2],"text":"e"},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""}],[{"index":[],"text":""},{"index":[4],"text":"a"},{"index":[],"text":""},{"index":[],"text":""},{"index":[1],"text":"c"},{"index":[],"text":""},{"index":[],"text":""},{"index":[5],"text":"w"},{"index":[],"text":""},{"index":[],"text":""},{"index":[6],"text":"z"},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""}],[{"index":[],"text":""},{"index":[4],"text":"z"},{"index":[],"text":""},{"index":[],"text":""},{"index":[1],"text":"i"},{"index":[],"text":""},{"index":[],"text":""},{"index":[5],"text":"a"},{"index":[],"text":""},{"index":[],"text":""},{"index":[6],"text":"i"},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""}],[{"index":[],"text":""},{"index":[4,7],"text":"e"},{"index":[7],"text":"x"},{"index":[7],"text":"h"},{"index":[1,7],"text":"a"},{"index":[7],"text":"u"},{"index":[7],"text":"s"},{"index":[5,7],"text":"t"},{"index":[7],"text":"i"},{"index":[7],"text":"n"},{"index":[7,6],"text":"g"},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""}],[{"index":[],"text":""},{"index":[4],"text":"d"},{"index":[],"text":""},{"index":[],"text":""},{"index":[1],"text":"l"},{"index":[],"text":""},{"index":[],"text":""},{"index":[5],"text":"e"},{"index":[],"text":""},{"index":[],"text":""},{"index":[6],"text":"z"},{"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":[5],"text":"r"},{"index":[],"text":""},{"index":[],"text":""},{"index":[6],"text":"a"},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""}],[{"index":[],"text":""},{"index":[],"text":""},{"index":[8],"text":"t"},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[5],"text":"f"},{"index":[],"text":""},{"index":[],"text":""},{"index":[6],"text":"g"},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""}],[{"index":[],"text":""},{"index":[],"text":""},{"index":[8],"text":"r"},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[5],"text":"r"},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""}],[{"index":[],"text":""},{"index":[9],"text":"p"},{"index":[9,8],"text":"a"},{"index":[9],"text":"v"},{"index":[9],"text":"i"},{"index":[9],"text":"l"},{"index":[9],"text":"i"},{"index":[5,9],"text":"o"},{"index":[9],"text":"n"},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""}],[{"index":[],"text":""},{"index":[],"text":""},{"index":[8],"text":"d"},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[5],"text":"n"},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""},{"index":[],"text":""}],[{"index":[],"text":""},{"index":[10],"text":"r"},{"index":[8,10],"text":"e"},{"index":[10],"text":"c"},{"index":[10],"text":"r"},{"index":[10],"text":"e"},{"index":[10],"text":"a"},{"index":[5,10],"text":"t"},{"index":[10],"text":"i"},{"index":[10],"text":"o"},{"index":[10],"text":"n"},{"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/1aaccbaa8f3a32df099f3308feac49e7.png"}
// 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/JM04-3/v14/index.html?type=form&key=1","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":14,"pub_date":null,"is_public":0,"created_date":"2021-07-20T06:18:52.000Z","updated_date":"2021-08-11T13:46:52.000Z"}},{"formUrl":"https://staging-teach.cdn.ireadabc.com/h5template/JM04-3/v14/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":14,"pub_date":null,"is_public":0,"created_date":"2021-07-20T06:18:52.000Z","updated_date":"2021-08-11T13:46:52.000Z"}}],"title":"Vocabulary box","bg_url":"https://staging-teach.cdn.ireadabc.com/892d0db2075efa3fa7aea6911bf36a83.png"}
this.data = { contentObj: data };
}
ngOnDestroy() {
window['curCtx'] = null;
window.cancelAnimationFrame(this.animationId);
this.cleanAudio();
this.gameEndFlag = true;
}
sentenceArr = [];
submitCount = 0;
safeDefaultUrl;
resultAnswerArr;
cleanAudio() {
if (this.audioObj) {
for (const key in this.audioObj) {
this.audioObj[key].pause();
}
scrollView;
resultSv;
uploadUrl;
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.uploadUrl = (<any> window).courseware.uploadUrl();
window['air'].getUploadCallback = (url, data) => {
this.uploadUrl = url;
};
this.topArr = [];
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.bg_url);
}
// this.initFontImg();
// 预加载资源
this.loadResources().then(() => {
window["air"].hideAirClassLoading(this.saveKey, this.data);
this.init();
this.update();
// this.setfontData();
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();
}
});
if (this.isTeacher) {
return;
}
c.onEvent('sendBtnClick', (data, next) => {
let infoText = '发题接收'// `sendBtnClick: data: ${JSON.stringify(data)}\n`
const durTime = new Date().getTime() - data.time
infoText += ' 用时: ' + ( Math.round( durTime / 1000 * 1000) / 1000) + ''
this.infoLabel.text = infoText;
next();
});
c.onEvent('uploadAudioBtn1Click', (data, next) => {
this.infoLabel.text = `uploadAudioBtn1Click: data: ${JSON.stringify(data)}`;
//30秒
const audioUrl = 'http://staging-teach.cdn.ireadabc.com/107582309ca6d5de35404bcf56af69bf.mp3'
this.uploadTestAudio('30秒', audioUrl);
next();
});
c.onEvent('uploadAudioBtn2Click', (data, next) => {
this.infoLabel.text = `uploadAudioBtn2Click: data: ${JSON.stringify(data)}`;
const audioUrl = 'http://staging-teach.cdn.ireadabc.com/7c1f608da28f4a42646724c4011bfd46.mp3'
this.uploadTestAudio('1分钟', audioUrl);
next();
});
c.onEvent('uploadAudioBtn3Click', (data, next) => {
this.infoLabel.text = `uploadAudioBtn3Click: data: ${JSON.stringify(data)}`;
const audioUrl = 'http://staging-teach.cdn.ireadabc.com/b1c832ecdd7e58632af6c48f37245b88.mp3'
this.uploadTestAudio('1分半', audioUrl);
next();
});
c.onEvent('uploadAudioBtn4Click', (data, next) => {
this.infoLabel.text = `uploadAudioBtn4Click: data: ${JSON.stringify(data)}`;
const audioUrl = 'http://staging-teach.cdn.ireadabc.com/3b6ea60055587e6d6fce27d179bf36eb.mp3'
this.uploadTestAudio('2分半', audioUrl);
next();
});
c.onEvent('uploadAudioBtn5Click', (data, next) => {
this.infoLabel.text = `uploadAudioBtn5Click: data: ${JSON.stringify(data)}`;
const audioUrl = 'http://staging-teach.cdn.ireadabc.com/82b7cd5a8ac70b12d2b70229bae990ea.mp3'
this.uploadTestAudio('3分钟', audioUrl);
next();
});
c.onEvent('uploadAudioBtn6Click', (data, next) => {
this.infoLabel.text = `uploadAudioBtn6Click: data: ${JSON.stringify(data)}`;
const audioUrl = 'http://staging-teach.cdn.ireadabc.com/811fad370642b71d21ed7f47f95a9d04.mp3'
this.uploadTestAudio('5分钟', audioUrl);
next();
});
c.onEvent('greadPapersForTextBtnClick', (data, next) => {
this.infoLabel.text = `greadPapersForTextBtnClick: data: ${JSON.stringify(data)}`;
//文本纠错
this.showGreadPapersForText()
next();
});
c.onEvent('greadPapersForCheckBtnClick', (data, next) => {
this.infoLabel.text = `greadPapersForCheckBtnClick: data: ${JSON.stringify(data)}`;
//词性检查
this.showGreadPapersForCheck();
next();
});
c.onEvent('lansiEvaluationBtnClick', (data, next) => {
this.infoLabel.text = `lansiEvaluationBtnClick: data: ${JSON.stringify(data)}`;
//蓝思值
this.showLansiEvaluation();
next();
});
c.onEvent('sendAnswerBtnClick', (data, next) => {
this.infoLabel.text = `sendAnswerBtnClick: data: ${JSON.stringify(data)}`;
//蓝思值
this.showSendAnswer();
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;
}
}
showSendAnswer() {
const sendAnswer = window['courseware'].sendAnswer;
if (!sendAnswer) {
this.infoLabel.text = '接口异常: sendAnswer';
return;
}
const startTime = new Date().getTime();
sendAnswer({callback: () => {
const endTime = new Date().getTime();
const durTime = endTime - startTime;
this.infoLabel.text = '上报成绩 用时' + (Math.round(durTime / 1000 * 1000) / 1000 ) + ''
console.log('res: ', res);
}})
}
showLansiEvaluation() {
const lansiEvaluation = window['courseware'].lansiEvaluation;
if (!lansiEvaluation) {
this.infoLabel.text = '接口异常: lansiEvaluation';
return;
}
const startTime = new Date().getTime();
lansiEvaluation({text: this.checkText}, () => {
// res 需要toJSON
const endTime = new Date().getTime();
const durTime = endTime - startTime;
this.infoLabel.text = '蓝思值 用时' + (Math.round(durTime / 1000 * 1000) / 1000 ) + ''
console.log('res: ', res);
})
}
showGreadPapersForCheck() {
const greadPapersForCheck = window['courseware'].greadPapersForCheck;
if (!greadPapersForCheck) {
this.infoLabel.text = '接口异常: greadPapersForCheck';
return;
}
const startTime = new Date().getTime();
greadPapersForCheck({type: 'pos', blankWord: 'NN', word: 'apple'}, res => {
// res 需要toJSON
const endTime = new Date().getTime();
const durTime = endTime - startTime;
this.infoLabel.text = '词性检查 用时' + (Math.round(durTime / 1000 * 1000) / 1000 ) + ''
console.log('res: ', res);
})
}
checkText = `
Hello boys and girls, my name is Alex. Today I will give you a speech about our beautiful country.
Before I start my speech, I want you to guess where I am talking about.
There is a very famous poem saying: The sky is blue, the wild is boundless. When the winds blow, the grass is low, and you can see the sheep and cattle.天苍苍野茫茫,风吹草低见牛羊。
Now do you know where I am talking about? Yes, it is Inner Mongolia, the second largest province in China.
My mother took me there in the summer holiday.
Inner Mongolia is very large. It has many cities, such as Ulanhot, Hohhot,Ordos and Baotou. The native Inner Mongolia people live on the grassland and enjoy their lives all the time.
I have been to Xilamuren Grassland. It has many cows and horses. When I was there, I rode horses, hugged the lamb, and played with my new friend Wangqi. How big Inner Mongolia is!
The most brilliant place I’ve visited is Mongolian yurts. It is so plain outside, but once you go inside the yurts, you will find how big it is, and how good the people they are! I love the people there.
The most famous person in Inner Mongolia is Genghis Khan. He had built the biggest China in the history. Can you guess how big it was when Genghis Khan ruled China? It is almost three times as big as today’s China! I admire him very much. I wish I can be a man as brave as him when I grow up.
Camels are amazing animals in Inner Mongolia. A camel has two humps. It stores fat inside the humps. A camel can live a week without water, and can live a month without food, which benefits from its body-its humps and stomach can provide energy and water as necessary. Camels can endure extremely cold and extremely hot temperatures. Camels are important transportation tools in dessert, they help to deliver passengers and goods. However, they have been killed a lot these years. We should protect them!
Our country is great and Inner Mongolia is great. I wish I have chance to travel around China.
`
showGreadPapersForText() {
const greadPapersForText = window['courseware'].greadPapersForText;
if (!greadPapersForText) {
this.infoLabel.text = '接口异常:greadPapersForText';
return;
}
const startTime = new Date().getTime();
greadPapersForText({text: this.checkText}, (res) => {
const endTime = new Date().getTime();
const durTime = endTime - startTime;
this.infoLabel.text = '文本纠错 用时' + (Math.round(durTime / 1000 * 1000) / 1000 ) + ''
console.log('res: ', res);
})
}
url2Blob (url) {
return new Promise(resolve => {
var xhr = new XMLHttpRequest();
xhr.open('get', url, true);
xhr.responseType = 'blob';
xhr.onload = () => {
if (xhr.status == 200) {
// console.log(xhr.response);
resolve(xhr.response);
}
};
xhr.send();
});
}
uploadTestAudio(text, url) {
this.url2Blob(url).then((res) => {
console.log('res: ', res);
const startTime = new Date().getTime();
const blob = res //new Blob([u8arr], {type: mime});
const fd = new FormData();
fd.append("file", <Blob>blob, 'test_audio.mp3');
this.http.post(this.uploadUrl, fd).subscribe((res) => {
// 存储服务器的截图url
if (res['url']) {
console.log('res url: ', res['url']);
const endTime = new Date().getTime();
const durTime = endTime - startTime;
this.infoLabel.text = '音频'+text+'上传 用时' + (Math.round(durTime / 1000 * 1000) / 1000 ) + ''
}
});
});
}
init() {
this.initCtx();
this.initData();
this.initCtx();
this.initView();
}
initCtx() {
this.canvasWidth = this.wrap.nativeElement.clientWidth;
this.canvasHeight = this.wrap.nativeElement.clientHeight;
this.canvas.nativeElement.width = this.wrap.nativeElement.clientWidth;
this.canvas.nativeElement.height = this.wrap.nativeElement.clientHeight;
this.ctx = this.canvas.nativeElement.getContext('2d');
this.canvas.nativeElement.width = this.canvasWidth;
this.canvas.nativeElement.height = this.canvasHeight;
window['curCtx'] = this.ctx;
}
initView() {
this.initBg();
if (this.isTeacher) {
this.initBtn();
} else {
this.initLabel();
}
// this.initSentence();
// this.changeBtnOff();
// this.initIframe();
// this.initWindowListener();
// this.initMaskPic();
// this.relink();
// this.gameStart();
// this.initResultView();
}
infoLabel;
infoLabel2;
initLabel() {
const richText = new RichText();
richText.fontColor = '#ffffff';
richText.x = this.canvasWidth / 2;
richText.y = this.canvasHeight / 2; //100 * this.mapScale;
richText.text = '...'
richText.width = this.canvasWidth * 0.9;
richText.textAlign = 'center';
const richText2 = new RichText();
richText2.fontColor = '#ffffff';
richText2.x = this.canvasWidth / 2;
richText2.y = 100 * this.mapScale;
richText2.text = '...'
richText2.width = this.canvasWidth * 0.9;
richText2.textAlign = 'center';
this.topArr.push(richText);
// this.topArr.push(richText2);
this.infoLabel = richText;
this.infoLabel2 = richText2;
}
relink() {
const progress = this.getPageData('progress');
if (this.isTeacher) {
if (progress != null) {
this.gameStart();
return;
}
return;
}
if (progress == '1') {
const progressStore = this.getStoreData('progress')
if (progressStore == '2' || progressStore == '3') {
this.gameStart();
const submitCount = this.getStoreData('submitCount')
this.submitCount = submitCount;
this.checkShowSubTemplateOne();
return;
}
if (progressStore == '4') {
return;
}
// const resultData = this.getStoreData('resultData')
// if (resultData) {
// this.initResultView(resultData);
// return;
// }
this.gameStart();
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.setStoreData('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);
richText.isShowWordBg = true;
richText.update();
const rectData = richText.getSubTextRect('____________________');
// if (!rectData) {
// continue;
// }
const {rect} = rectData;
rect.width += 8;
rect.height += 16;
const colorRect = new ShapeRectNew();
colorRect.setSize(rect.width, rect.height, 10);
colorRect.fillColor = '#007b3e'
const offX = 4;
colorRect.x = rect.x + offX - rect.width;
colorRect.y = rect.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
}
}
resultSv.content.height = baseY;
resultSv.refreshScrollBar();
}
submitBtn;
btnArr = [];
btnDisH = 120;
sendBtn;
uploadAudioBtn1;
uploadAudioBtn2;
uploadAudioBtn3;
uploadAudioBtn4;
uploadAudioBtn5;
uploadAudioBtn6;
startRecordBtn;
stopRecordBtn;
greadPapersForTextBtn;
greadPapersForCheckBtn;
lansiEvaluationBtn;
sendAnswerBtn;
startTestBtn;
stopTestBtn;
initBtn() {
const sendBtn = this.getBtnWithLabel('发题');
sendBtn.x = this.canvasWidth / 2 //- 300 * this.mapScale;
sendBtn.y = this.canvasHeight / 2 - 600 * this.mapScale;
sendBtn.setScaleXY(this.mapScale);
this.sendBtn = sendBtn;
this.topArr.push(sendBtn);
const uploadAudioBtn1 = this.getBtnWithLabel('音频 上传 半分钟');
uploadAudioBtn1.x = this.canvasWidth / 2 - 800 * this.mapScale;
uploadAudioBtn1.y = this.canvasHeight / 2 - 400 * this.mapScale;
uploadAudioBtn1.setScaleXY(this.mapScale * 0.8);
this.uploadAudioBtn1 = uploadAudioBtn1;
this.topArr.push(uploadAudioBtn1);
const uploadAudioBtn2 = this.getBtnWithLabel('音频 上传 一分钟');
uploadAudioBtn2.x = this.canvasWidth / 2 - 800 * this.mapScale;
uploadAudioBtn2.y = this.canvasHeight / 2 - 200 * this.mapScale;
uploadAudioBtn2.setScaleXY(this.mapScale * 0.8);
this.uploadAudioBtn2 = uploadAudioBtn2;
this.topArr.push(uploadAudioBtn2);
const uploadAudioBtn3 = this.getBtnWithLabel('音频 上传 一分半');
uploadAudioBtn3.x = this.canvasWidth / 2 - 800 * this.mapScale;
uploadAudioBtn3.y = this.canvasHeight / 2 - 0 * this.mapScale;
uploadAudioBtn3.setScaleXY(this.mapScale * 0.8);
this.uploadAudioBtn3 = uploadAudioBtn3;
this.topArr.push(uploadAudioBtn3);
const uploadAudioBtn4 = this.getBtnWithLabel('音频 上传 两分半');
uploadAudioBtn4.x = this.canvasWidth / 2 //- 300 * this.mapScale;
uploadAudioBtn4.y = this.canvasHeight / 2 - 400 * this.mapScale;
uploadAudioBtn4.setScaleXY(this.mapScale * 0.8);
this.uploadAudioBtn4 = uploadAudioBtn4;
this.topArr.push(uploadAudioBtn4);
const uploadAudioBtn5 = this.getBtnWithLabel('音频 上传 三分钟');
uploadAudioBtn5.x = this.canvasWidth / 2 //- 300 * this.mapScale;
uploadAudioBtn5.y = this.canvasHeight / 2 - 200 * this.mapScale;
uploadAudioBtn5.setScaleXY(this.mapScale * 0.8);
this.uploadAudioBtn5 = uploadAudioBtn5;
this.topArr.push(uploadAudioBtn5);
const uploadAudioBtn6 = this.getBtnWithLabel('音频 上传 五分钟');
uploadAudioBtn6.x = this.canvasWidth / 2 //- 300 * this.mapScale;
uploadAudioBtn6.y = this.canvasHeight / 2 - 0 * this.mapScale;
uploadAudioBtn6.setScaleXY(this.mapScale * 0.8);
this.uploadAudioBtn6 = uploadAudioBtn6;
this.topArr.push(uploadAudioBtn6);
// startRecord 录音开始 转文本
// stopRecord 录音结束 转文本
// greadPapersForText 文本纠错
// greadPapersForCheck 词性检查
// lansiEvaluation 蓝思值
// startTest 开始口语评分
// stopTest 结束口语评分
// sendAnswer
// const startRecordBtn = this.getBtnWithLabel('开始 录音转文本');
// startRecordBtn.x = this.canvasWidth / 2 //- 300 * this.mapScale;
// startRecordBtn.y = this.canvasHeight / 2 - 400 * this.mapScale;
// startRecordBtn.setScaleXY(this.mapScale * 0.8);
// this.startRecordBtn = startRecordBtn;
// this.topArr.push(startRecordBtn);
// const stopRecordBtn = this.getBtnWithLabel('结束 录音转文本');
// stopRecordBtn.x = this.canvasWidth / 2 //- 300 * this.mapScale;
// stopRecordBtn.y = this.canvasHeight / 2 - 200 * this.mapScale;
// stopRecordBtn.setScaleXY(this.mapScale * 0.8);
// this.stopRecordBtn = stopRecordBtn;
// this.topArr.push(stopRecordBtn);
// const greadPapersForTextBtn = this.getBtnWithLabel('文本纠错');
// greadPapersForTextBtn.x = this.canvasWidth / 2 //- 300 * this.mapScale;
// greadPapersForTextBtn.y = this.canvasHeight / 2 - 0 * this.mapScale;
// greadPapersForTextBtn.setScaleXY(this.mapScale * 0.8);
// this.greadPapersForTextBtn = greadPapersForTextBtn;
// this.topArr.push(greadPapersForTextBtn);
// startTest 开始口语评分
// stopTest 结束口语评分
const greadPapersForTextBtn = this.getBtnWithLabel('文本纠错');
greadPapersForTextBtn.x = this.canvasWidth / 2 + 800 * this.mapScale;
greadPapersForTextBtn.y = this.canvasHeight / 2 - 400 * this.mapScale;
greadPapersForTextBtn.setScaleXY(this.mapScale * 0.8);
this.greadPapersForTextBtn = greadPapersForTextBtn;
this.topArr.push(greadPapersForTextBtn);
// const startTestBtn = this.getBtnWithLabel('开始 口语评分');
// startTestBtn.x = this.canvasWidth / 2 + 800 * this.mapScale;
// startTestBtn.y = this.canvasHeight / 2 - 400 * this.mapScale;
// startTestBtn.setScaleXY(this.mapScale * 0.8);
// this.startTestBtn = startTestBtn;
// this.topArr.push(startTestBtn);
// const stopTestBtn = this.getBtnWithLabel('结束 口语评分');
// stopTestBtn.x = this.canvasWidth / 2 + 800 * this.mapScale;
// stopTestBtn.y = this.canvasHeight / 2 - 200 * this.mapScale;
// stopTestBtn.setScaleXY(this.mapScale * 0.8);
// this.stopTestBtn = stopTestBtn;
// this.topArr.push(stopTestBtn);
const greadPapersForCheckBtn = this.getBtnWithLabel('词性检查');
greadPapersForCheckBtn.x = this.canvasWidth / 2 + 800 * this.mapScale;
greadPapersForCheckBtn.y = this.canvasHeight / 2 - 200 * this.mapScale;
greadPapersForCheckBtn.setScaleXY(this.mapScale * 0.8);
this.greadPapersForCheckBtn = greadPapersForCheckBtn;
this.topArr.push(greadPapersForCheckBtn);
const lansiEvaluationBtn = this.getBtnWithLabel('蓝思值');
lansiEvaluationBtn.x = this.canvasWidth / 2 + 800 * this.mapScale;
lansiEvaluationBtn.y = this.canvasHeight / 2 - 0 * this.mapScale;
lansiEvaluationBtn.setScaleXY(this.mapScale * 0.8);
this.lansiEvaluationBtn = lansiEvaluationBtn;
this.topArr.push(lansiEvaluationBtn);
const sendAnswerBtn = this.getBtnWithLabel('上报数据');
sendAnswerBtn.x = this.canvasWidth / 2 ;
sendAnswerBtn.y = this.canvasHeight / 2 + 200 * this.mapScale;
sendAnswerBtn.setScaleXY(this.mapScale * 0.8);
this.sendAnswerBtn = sendAnswerBtn;
this.topArr.push(sendAnswerBtn);
// c.sendAnswer(this.serverResultObj);
}
getBtnWithLabel(text) {
const btn = this.getMySprite('btn_normal');
const label = this.getFillLabel()
label.textAlign = 'center';
label.text = text;
btn.addChild(label);
return btn;
}
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';
label.setMaxSize(btn.width * 0.95);
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;
richText.setScaleXY(1);
richText.width = sv.width;
richText.isShowWordBg = true;
richText.update();
const rectData = richText.getSubTextRect('____________________');
// if (!rectData) {
// continue
// }
const rect = rectData.rect;
// index = rectData.index + 1;
const edgeW = 5 * this.mapScale;
const edgeH = 10 * this.mapScale;
const colorRect = new ShapeRectNew();
colorRect.setSize(rect.width + edgeW * 2, rect.height + edgeH * 2, 10 * this.mapScale);
colorRect.x = rect.x - rect.width - edgeW;
colorRect.y = rect.y - rect.height / 2 - edgeH * 0.7;
colorRect.alpha = 0;
richText.addChild(colorRect);
this.sentenceEmptyArr.push(colorRect);
// 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.5;
// richText.addChild(colorRect);
// this.sentenceEmptyArr.push(colorRect);
curY += richText.getAreaHeight() + disH;
richText['data'] = arr[i];
richText.height = richText.getAreaHeight();
sv.addItem(richText);
// this.renderArr.push(richText);
colorRect.ctx = colorRect.parent.ctx;
}
}
getFillLabel() {
const label = new Label();
label.fontSize = 56;
label.fontColor = '#ffffff'
label.fontName = 'Aileron-Black';
// 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() {
console.log('this.data: ', this.data);
const bg = new MySprite();
bg.init(this.images.get("bg"));
bg.x = this.canvasWidth / 2;
bg.y = this.canvasHeight / 2;
bg.scaleX = this.canvasWidth / bg.width;
bg.scaleY = this.canvasHeight / bg.height;
this.renderArr.push(bg);
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);
}
// sendBtn;
// uploadAudioBtn1;
// uploadAudioBtn2;
// uploadAudioBtn3;
// startRecordBtn;
// stopRecordBtn;
// greadPapersForTextBtn;
// greadPapersForCheckBtn;
// lansiEvaluationBtn;
// startTestBtn;
// stopTestBtn;
sendBtnClick() {
console.log(' in sendBtnClick')
const time = new Date().getTime();
this.sendServerEvent('sendBtnClick', {time});
}
uploadAudioBtn1Click() {
console.log(' in uploadAudioBtn1Click')
this.sendServerEvent('uploadAudioBtn1Click', {});
}
uploadAudioBtn2Click() {
console.log(' in uploadAudioBtn2Click')
this.sendServerEvent('uploadAudioBtn2Click', {});
}
uploadAudioBtn3Click() {
console.log(' in uploadAudioBtn3Click')
this.sendServerEvent('uploadAudioBtn3Click', {});
}
uploadAudioBtn4Click() {
console.log(' in uploadAudioBtn4Click')
this.sendServerEvent('uploadAudioBtn4Click', {});
}
uploadAudioBtn5Click() {
console.log(' in uploadAudioBtn5Click')
this.sendServerEvent('uploadAudioBtn5Click', {});
}
uploadAudioBtn6Click() {
console.log(' in uploadAudioBtn6Click')
this.sendServerEvent('uploadAudioBtn6Click', {});
}
greadPapersForTextBtnClick() {
console.log(' in greadPapersForTextBtnClick')
this.sendServerEvent('greadPapersForTextBtnClick', {});
}
greadPapersForCheckBtnClick() {
console.log(' in greadPapersForCheckBtnClick')
this.sendServerEvent('greadPapersForCheckBtnClick', {});
}
lansiEvaluationBtnClick() {
console.log(' in lansiEvaluationBtnClick')
this.sendServerEvent('lansiEvaluationBtnClick', {});
}
sendAnswerBtnClick() {
console.log(' in sendAnswerBtnClick')
this.sendServerEvent('sendAnswerBtnClick', {});
}
checkBtnClick(btn, btnFunc) {
if (this.checkClickTarget(btn)) {
btnFunc();
}
}
curMoveItem = null;
downFlag = false;
mapDown(event) {
if (!this.canTouch) {
return;
}
this.downFlag = true;
if (this.isTeacher) {
this.checkBtnClick(this.sendBtn, this.sendBtnClick.bind(this));
this.checkBtnClick(this.uploadAudioBtn1, this.uploadAudioBtn1Click.bind(this));
this.checkBtnClick(this.uploadAudioBtn2, this.uploadAudioBtn2Click.bind(this));
this.checkBtnClick(this.uploadAudioBtn3, this.uploadAudioBtn3Click.bind(this));
this.checkBtnClick(this.uploadAudioBtn4, this.uploadAudioBtn4Click.bind(this));
this.checkBtnClick(this.uploadAudioBtn5, this.uploadAudioBtn5Click.bind(this));
this.checkBtnClick(this.uploadAudioBtn6, this.uploadAudioBtn6Click.bind(this));
this.checkBtnClick(this.greadPapersForTextBtn, this.greadPapersForTextBtnClick.bind(this));
this.checkBtnClick(this.greadPapersForCheckBtn, this.greadPapersForCheckBtnClick.bind(this));
this.checkBtnClick(this.lansiEvaluationBtn, this.lansiEvaluationBtnClick.bind(this));
this.checkBtnClick(this.sendAnswerBtn, this.sendAnswerBtnClick.bind(this));
return;
}
this.downFlag = false;
}
mapMove(event) {
if (event) {
event.preventDefault()
}
if (!this.downFlag) {
return;
}
}
mapUp(event) {
this.downFlag = false;
}
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.getStoreData('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;
}
emptyRectDown(emptyRect) {
if (emptyRect.label) {
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.setStoreData('progress', '2', false);
this.setStoreData('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) }, '*');
}
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.getStoreData('progress');
if (progress == '2') {
this.setStoreData('progress', '3');
} else {
this.setStoreData('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);
const maskBg = new ShapeRect();
maskBg.setSize(this.canvasWidth, this.canvasHeight);
// maskBg.x = curBgRect.x;
// maskBg.y = curBgRect.y;
maskBg.fillColor = "#000000"
this.maskBg = maskBg;
this.renderArr.push(maskBg);
for (let i = 0; i < arr.length; i++) {
const data = JSON.parse(JSON.stringify(arr[i]));
// const img = {pic_url: data.pic_url};
data.rect.x *= rate;
data.rect.y *= rate;
data.rect.width *= rate;
data.rect.height *= rate;
data.rect.x += curBgRect.x;
data.rect.y += curBgRect.y;
const hotZone = this.getHotZoneItem(data);
// hotZone.alpha = 0.5;
// this.hotZoneArr.push(hotZone);
}
}
openBtn;
getHotZoneItem(data) {
console.log(' item data: ', data);
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;
}
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);
});
this.ctx = this.canvas.nativeElement.getContext('2d');
this.canvas.nativeElement.width = this.canvasWidth;
this.canvas.nativeElement.height = this.canvasHeight;
rotateItem(petal, petal['tr'], petal['time']);
setTimeout(() => {
this.addPetal();
}, 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) {
if (item) {
item.update();
}
}
const randomR = Math.random() * 360;
petal.rotation = randomR;
updateArr(arr) {
if (!arr) {
return;
}
for (let i = 0; i < arr.length; i++) {
arr[i].update(this);
}
}
const randomX = Math.random() * this.canvasWidth;
petal.x = randomX;
petal.y = -petal.height / 2 * petal.scaleY;
const randomT = 0.5 + Math.random() * 2.5;
petal['time'] = randomT;
let randomTR = 360 * Math.random(); // - 180;
if (Math.random() < 0.5) { randomTR *= -1; }
petal['tr'] = randomTR;
return petal;
}
......@@ -202,13 +2786,13 @@ export class PlayComponent implements OnInit, OnDestroy {
if (this.canvasLeft == null) {
setParentOffset();
}
this.mx = event.touches[0].pageX - this.canvasLeft;
this.my = event.touches[0].pageY - this.canvasTop;
this.mx = event.touches[0].pageX * this.canvasScale - this.canvasLeft;
this.my = event.touches[0].pageY * this.canvasScale - this.canvasTop;
};
const setMxMyByMouse = (event) => {
this.mx = event.offsetX;
this.my = event.offsetY;
this.mx = event.offsetX * this.canvasScale;
this.my = event.offsetY * this.canvasScale;
};
// ---------------------------------------------
......@@ -220,6 +2804,7 @@ export class PlayComponent implements OnInit, OnDestroy {
firstTouch = false;
removeMouseListener();
}
console.log('touch down');
setMxMyByTouch(e);
this.mapDown(e);
};
......@@ -237,6 +2822,7 @@ export class PlayComponent implements OnInit, OnDestroy {
firstTouch = false;
removeTouchListener();
}
console.log('mouse down');
setMxMyByMouse(e);
this.mapDown(e);
};
......@@ -278,29 +2864,109 @@ export class PlayComponent implements OnInit, OnDestroy {
addMouseListener();
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) {
const audio = this.audioObj[key];
if (audio) {
if (now) {
audio.pause();
audio.currentTime = 0;
}
if (callback) {
audio.onended = () => {
callback();
};
}
audio.play();
const audioNew = new Audio();
audioNew.src = audio.src;
audioNew.load();
audioNew.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() {
const pr = [];
this.rawImages.forEach((value, key) => {// 预加载图片
......@@ -314,7 +2980,7 @@ export class PlayComponent implements OnInit, OnDestroy {
pr.push(p);
});
this.rawAudios.forEach((value, key) => {// 预加载音频
this.rawAudios.forEach((value, key) => {// 预加载图片
const a = this.preloadAudio(value)
.then(() => {
......@@ -340,8 +3006,9 @@ export class PlayComponent implements OnInit, OnDestroy {
preloadAudio(url) {
return new Promise((resolve, reject) => {
const audio = new Audio();
resolve({})
audio.oncanplay = (a) => {
resolve();
//resolve();
};
audio.onerror = () => {
reject();
......@@ -358,14 +3025,61 @@ export class PlayComponent implements OnInit, OnDestroy {
this.init();
}
checkClickTargetSv(target) {
let tmpRect = target.getBoundingBox();
// rect.x /= 2;
// rect.y /= 2;
// rect.width /= 2;
// rect.height /= 2;
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};
// 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) {
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)) {
return true;
}
......@@ -386,6 +3100,7 @@ export class PlayComponent implements OnInit, OnDestroy {
}
checkPointInRect(x, y, rect) {
if (x >= rect.x && x <= rect.x + rect.width) {
if (y >= rect.y && y <= rect.y + rect.height) {
return true;
......@@ -394,297 +3109,22 @@ export class PlayComponent implements OnInit, OnDestroy {
return false;
}
getPosByAngle(angle, len) {
const radian = angle * Math.PI / 180;
const x = Math.sin(radian) * len;
const y = Math.cos(radian) * len;
addUrlToAudioObj(key, url = null, vlomue = 1, loop = false, callback = null) {
const audioObj = this.audioObj;
if (url == null) {
url = key;
}
this.rawAudios.set(key, url);
const audio = new Audio();
audio.src = url;
audio.load();
audio.loop = loop;
audio.volume = vlomue;
audioObj[key] = audio;
if (callback) {
audio.onended = () => {
callback();
};
}
}
addUrlToImages(url) {
this.rawImages.set(url, url);
}
// ======================================================编写区域==========================================================================
/**
* 添加默认数据 便于无数据时的展示
*/
initDefaultData() {
if (!this.data.pic_url) {
this.data.pic_url = 'assets/play/default/pic.jpg';
this.data.pic_url_2 = 'assets/play/default/pic.jpg';
}
}
/**
* 添加预加载图片
*/
initImg() {
this.addUrlToImages(this.data.pic_url);
this.addUrlToImages(this.data.pic_url_2);
}
/**
* 添加预加载音频
*/
initAudio() {
// 音频资源
this.addUrlToAudioObj(this.data.audio_url);
this.addUrlToAudioObj(this.data.audio_url_2);
// 音效
this.addUrlToAudioObj('click', this.rawAudios.get('click'), 0.3);
}
/**
* 初始化数据
*/
initData() {
const sx = this.canvasWidth / this.canvasBaseW;
const sy = this.canvasHeight / this.canvasBaseH;
const s = Math.min(sx, sy);
this.mapScale = s;
// this.mapScale = sx;
// this.mapScale = sy;
this.renderArr = [];
}
/**
* 初始化试图
*/
initView() {
this.initPic();
this.initBottomPart();
}
initBottomPart() {
const btnLeft = new MySprite();
btnLeft.init(this.images.get('btn_left'));
btnLeft.x = this.canvasWidth - 150 * this.mapScale;
btnLeft.y = this.canvasHeight - 100 * this.mapScale;
btnLeft.setScaleXY(this.mapScale);
this.renderArr.push(btnLeft);
this.btnLeft = btnLeft;
const btnRight = new MySprite();
btnRight.init(this.images.get('btn_right'));
btnRight.x = this.canvasWidth - 50 * this.mapScale;
btnRight.y = this.canvasHeight - 100 * this.mapScale;
btnRight.setScaleXY(this.mapScale);
this.renderArr.push(btnRight);
this.btnRight = btnRight;
}
initPic() {
const maxW = this.canvasWidth * 0.7;
const pic1 = new MySprite();
pic1.init(this.images.get(this.data.pic_url));
pic1.x = this.canvasWidth / 2;
pic1.y = this.canvasHeight / 2;
pic1.setScaleXY(maxW / pic1.width);
this.renderArr.push(pic1);
this.pic1 = pic1;
const label1 = new Label();
label1.text = this.data.text;
label1.textAlign = 'center';
label1.fontSize = 50;
label1.fontName = 'BRLNSDB';
label1.fontColor = '#ffffff';
pic1.addChild(label1);
const pic2 = new MySprite();
pic2.init(this.images.get(this.data.pic_url_2));
pic2.x = this.canvasWidth / 2 + this.canvasWidth;
pic2.y = this.canvasHeight / 2;
pic2.setScaleXY(maxW / pic2.width);
this.renderArr.push(pic2);
this.pic2 = pic2;
this.curPic = pic1;
}
btnLeftClicked() {
this.lastPage();
}
btnRightClicked() {
this.nextPage();
}
lastPage() {
if (this.curPic == this.pic1) {
return;
}
this.canTouch = false;
const moveLen = this.canvasWidth;
tweenChange(this.pic1, {x: this.pic1.x + moveLen}, 1);
tweenChange(this.pic2, {x: this.pic2.x + moveLen}, 1, () => {
this.canTouch = true;
this.curPic = this.pic1;
});
}
nextPage() {
if (this.curPic == this.pic2) {
return;
}
this.canTouch = false;
const moveLen = this.canvasWidth;
tweenChange(this.pic1, {x: this.pic1.x - moveLen}, 1);
tweenChange(this.pic2, {x: this.pic2.x - moveLen}, 1, () => {
this.canTouch = true;
this.curPic = this.pic2;
});
}
pic1Clicked() {
this.playAudio(this.data.audio_url);
}
pic2Clicked() {
this.playAudio(this.data.audio_url_2);
}
mapDown(event) {
if (!this.canTouch) {
return;
}
if ( this.checkClickTarget(this.btnLeft) ) {
this.btnLeftClicked();
return;
}
if ( this.checkClickTarget(this.btnRight) ) {
this.btnRightClicked();
return;
}
if ( this.checkClickTarget(this.pic1) ) {
this.pic1Clicked();
return;
}
if ( this.checkClickTarget(this.pic2) ) {
this.pic2Clicked();
return;
}
}
mapMove(event) {
}
mapUp(event) {
return { x, y };
}
getPosDistance(sx, sy, ex, ey) {
update() {
// ----------------------------------------------------------
this.animationId = window.requestAnimationFrame(this.update.bind(this));
// 清除画布内容
this.ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight);
// tween 更新动画
TWEEN.update();
// ----------------------------------------------------------
this.updateArr(this.renderArr);
const _x = ex - sx;
const _y = ey - sy;
const len = Math.sqrt(Math.pow(_x, 2) + Math.pow(_y, 2));
return len;
}
}
const res = [
// ['bg', "assets/play/bg.jpg"],
['btn_left', "assets/play/btn_left.png"],
['btn_right', "assets/play/btn_right.png"],
// ['text_bg', "assets/play/text_bg.png"],
['bg', "assets/play/bg.png"],
['bg_item', "assets/play/bg_item.png"],
['btn', "assets/play/btn.png"],
['btn_off', "assets/play/btn_off.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"],
['btn_normal', "assets/play/btn_normal.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 +30,19 @@ const res = [
const resAudio = [
['click', "assets/play/music/click.mp3"],
['submit', "assets/play/music/submit.mp3"],
['more', "assets/play/music/more.mp3"],
['0-30', "assets/play/music/0-30.mp3"],
['1-00', "assets/play/music/1-00.mp3"],
['1-30', "assets/play/music/1-30.mp3"],
['2-30', "assets/play/music/2-30.mp3"],
['3-00', "assets/play/music/3-00.mp3"],
['5-00', "assets/play/music/5-00.mp3"],
];
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 @@
<!-- <meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">-->
<meta name="viewport" content="width=device-width, initial-scale=1">
<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>
<body>
<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