diff --git a/angular.json b/angular.json index 5952480a9ced5a16dc48a17e46fb1669d4e89426..52fb36708fbe391cb5bd6b42c6ea244b60adbb02 100644 --- a/angular.json +++ b/angular.json @@ -128,5 +128,8 @@ } } }, - "defaultProject": "ng-template-generator" -} + "defaultProject": "ng-template-generator", + "cli": { + "analytics": false + } +} \ No newline at end of file diff --git a/src/app/app.module.ts b/src/app/app.module.ts index a0995a75739d55061953bdc16761ee2f6524aed1..1e65864e21f0d3dbfc95f1b4554f059478b36c0d 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -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: [ diff --git a/src/app/common/audio-recorder/audio-recorder.component.html b/src/app/common/audio-recorder/audio-recorder.component.html index e174c34da6591aeefc1a0d1f9fb3576e6499d645..3c8d2d215843514f4ebc6a139ffde3b3307be3d0 100644 --- a/src/app/common/audio-recorder/audio-recorder.component.html +++ b/src/app/common/audio-recorder/audio-recorder.component.html @@ -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> diff --git a/src/app/common/audio-recorder/audio-recorder.component.ts b/src/app/common/audio-recorder/audio-recorder.component.ts index 605db0ab773819d944f4b9932a82f5cfb6111f94..609ed49f10a526596589ea163bb6cb0696abe73f 100644 --- a/src/app/common/audio-recorder/audio-recorder.component.ts +++ b/src/app/common/audio-recorder/audio-recorder.component.ts @@ -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(); } diff --git a/src/app/common/custom-action/custom-action.component.html b/src/app/common/custom-action/custom-action.component.html new file mode 100644 index 0000000000000000000000000000000000000000..1b8b57f06b62712d0aecd432219d2674d5af13ac --- /dev/null +++ b/src/app/common/custom-action/custom-action.component.html @@ -0,0 +1,153 @@ +<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> + + diff --git a/src/app/common/custom-action/custom-action.component.scss b/src/app/common/custom-action/custom-action.component.scss new file mode 100644 index 0000000000000000000000000000000000000000..e9c56bfc8de8aec772d05405514870f9bb6c30f6 --- /dev/null +++ b/src/app/common/custom-action/custom-action.component.scss @@ -0,0 +1,110 @@ +@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; +} diff --git a/src/app/common/custom-action/custom-action.component.ts b/src/app/common/custom-action/custom-action.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..4fda2662506e0269759f77659f5597fb0f0fe671 --- /dev/null +++ b/src/app/common/custom-action/custom-action.component.ts @@ -0,0 +1,216 @@ +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() { + } + +} diff --git a/src/app/common/custom-hot-zone/Unit.ts b/src/app/common/custom-hot-zone/Unit.ts index 7b99189ae1e79f71bf621d6c98beff55cb7df827..3345e2404d2ab972fd91322dec9d33410cf69f50 100644 --- a/src/app/common/custom-hot-zone/Unit.ts +++ b/src/app/common/custom-hot-zone/Unit.ts @@ -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,10 +2208,155 @@ 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 { + + +} + +export class DragItem extends MySprite { + + lineDashFlag = true; + item; + + init() { + this.anchorX = 0.5; + this.anchorY = 0.5; + + this.initCenterCircle(); + + } + + setSize(w, h) { + + this.anchorX = 0.5; + this.anchorY = 0.5; + + this.width = w; + this.height = h; + + + // const rect = new ShapeRect(this.ctx); + // rect.x = -w / 2; + // rect.y = -h / 2; + // rect.setSize(w, h); + // rect.fillColor = '#000000'; + // rect.alpha = 0.1; + // this.addChild(rect); + + + } + + initCenterCircle() { + const circle = new ShapeCircle(this.ctx); + circle.setRadius(10); + circle.fillColor = '#ffa568' + this.addChild(circle); + + this.width = circle.width; + this.height = circle.height; + } + + getPosition() { + return {x: this.x, y: this.y}; + } + + drawLine() { + if (!this.item) { + return; + } + + + this.ctx.save(); + + const rect = this.getBoundingBox(); + + const w = rect.width; + const h = rect.height; + const x = rect.x //+ w / 2; + const y = rect.y //+ h / 2; + + this.ctx.setLineDash([4, 4]); + this.ctx.lineWidth = 1; + this.ctx.strokeStyle = '#ffa568'; + + this.ctx.beginPath(); + + this.ctx.moveTo( x + w / 2 , y + h / 2 ); + + this.ctx.lineTo(this.item.x, this.item.y); + + // this.ctx.fill(); + this.ctx.stroke(); + + + this.ctx.restore(); + } + + drawFrame() { + + + this.ctx.save(); + + const rect = this.getBoundingBox(); + + const w = rect.width; + const h = rect.height; + const x = rect.x //+ w / 2; + const y = rect.y //+ h / 2; + + this.ctx.setLineDash([4, 4]); + this.ctx.lineWidth = 2; + this.ctx.strokeStyle = '#ffa568'; + // this.ctx.fillStyle = '#ffffff'; + + this.ctx.beginPath(); + + this.ctx.moveTo( x - w / 2, y - h / 2); + + this.ctx.lineTo(x + w / 2, y - h / 2); + this.ctx.lineTo(x + w / 2, y + h / 2); + this.ctx.lineTo(x - w / 2, y + h / 2); + + this.ctx.lineTo(x - w / 2, y - h / 2); + + // this.ctx.fill(); + this.ctx.stroke(); + + + + + this.ctx.restore(); + + } + + draw() { + super.draw(); + + if (this.lineDashFlag) { + this.drawLine(); + // this.drawFrame(); + // this.drawArrow(); + } + } +} export class EditorItem extends MySprite { @@ -2208,6 +2364,8 @@ export class EditorItem extends MySprite { arrow: MySprite; label: Label; text; + arrowTop; + arrowRight; showLabel(text = null) { @@ -2246,6 +2404,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 +2427,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() { @@ -2325,784 +2499,3 @@ export class EditorItem extends MySprite { } - -// -// -// import TWEEN from '@tweenjs/tween.js'; -// -// -// class Sprite { -// x = 0; -// y = 0; -// color = ''; -// radius = 0; -// alive = false; -// margin = 0; -// angle = 0; -// ctx; -// -// constructor(ctx) { -// this.ctx = ctx; -// } -// update($event) { -// this.draw(); -// } -// draw() { -// -// } -// -// } -// -// -// -// -// -// export class MySprite extends Sprite { -// -// width = 0; -// height = 0; -// _anchorX = 0; -// _anchorY = 0; -// _offX = 0; -// _offY = 0; -// scaleX = 1; -// scaleY = 1; -// alpha = 1; -// rotation = 0; -// visible = true; -// -// children = [this]; -// -// img; -// _z = 0; -// -// -// init(imgObj = null, anchorX:number = 0.5, anchorY:number = 0.5) { -// -// if (imgObj) { -// -// this.img = imgObj; -// -// this.width = this.img.width; -// this.height = this.img.height; -// } -// -// this.anchorX = anchorX; -// this.anchorY = anchorY; -// } -// -// -// -// update($event = null) { -// if (this.visible) { -// this.draw(); -// } -// } -// draw() { -// -// this.ctx.save(); -// -// this.drawInit(); -// -// this.updateChildren(); -// -// this.ctx.restore(); -// } -// -// drawInit() { -// -// this.ctx.translate(this.x, this.y); -// -// this.ctx.rotate(this.rotation * Math.PI / 180); -// -// this.ctx.scale(this.scaleX, this.scaleY); -// -// this.ctx.globalAlpha = this.alpha; -// -// } -// -// drawSelf() { -// if (this.img) { -// this.ctx.drawImage(this.img, this._offX, this._offY); -// } -// } -// -// updateChildren() { -// -// if (this.children.length <= 0) { return; } -// -// for (let i = 0; i < this.children.length; i++) { -// -// if (this.children[i] === this) { -// -// this.drawSelf(); -// } else { -// -// this.children[i].update(); -// } -// } -// } -// -// -// load(url, anchorX = 0.5, anchorY = 0.5) { -// -// return new Promise((resolve, reject) => { -// const img = new Image(); -// img.onload = () => resolve(img); -// img.onerror = reject; -// img.src = url; -// }).then(img => { -// -// this.init(img, anchorX, anchorY); -// return img; -// }); -// } -// -// addChild(child, z = 1) { -// if (this.children.indexOf(child) === -1) { -// this.children.push(child); -// child._z = z; -// child.parent = this; -// } -// -// this.children.sort((a, b) => { -// return a._z - b._z; -// }); -// -// } -// removeChild(child) { -// const index = this.children.indexOf(child); -// if (index !== -1) { -// this.children.splice(index, 1); -// } -// } -// -// set anchorX(value) { -// this._anchorX = value; -// this.refreshAnchorOff(); -// } -// get anchorX() { -// return this._anchorX; -// } -// set anchorY(value) { -// this._anchorY = value; -// this.refreshAnchorOff(); -// } -// get anchorY() { -// return this._anchorY; -// } -// refreshAnchorOff() { -// this._offX = -this.width * this.anchorX; -// this._offY = -this.height * this.anchorY; -// } -// -// setScaleXY(value) { -// this.scaleX = this.scaleY = value; -// } -// -// getBoundingBox() { -// -// const x = this.x + this._offX * this.scaleX; -// const y = this.y + this._offY * this.scaleY; -// const width = this.width * this.scaleX; -// const height = this.height * this.scaleY; -// -// return {x, y, width, height}; -// } -// -// } -// -// -// -// -// -// export class Item extends MySprite { -// -// baseX; -// -// move(targetY, callBack) { -// -// const self = this; -// -// const tween = new TWEEN.Tween(this) -// .to({ y: targetY }, 2500) -// .easing(TWEEN.Easing.Quintic.Out) -// .onComplete(function() { -// -// self.hide(callBack); -// // if (callBack) { -// // callBack(); -// // } -// }) -// .start(); -// -// } -// -// show(callBack = null) { -// -// const tween = new TWEEN.Tween(this) -// .to({ alpha: 1 }, 800) -// // .easing(TWEEN.Easing.Quadratic.Out) // Use an easing function to make the animation smooth. -// .onComplete(function() { -// if (callBack) { -// callBack(); -// } -// }) -// .start(); // Start the tween immediately. -// -// } -// -// hide(callBack = null) { -// -// const tween = new TWEEN.Tween(this) -// .to({ alpha: 0 }, 800) -// // .easing(TWEEN.Easing.Quadratic.Out) // Use an easing function to make the animation smooth. -// .onComplete(function() { -// if (callBack) { -// callBack(); -// } -// }) -// .start(); // Start the tween immediately. -// } -// -// -// shake(id) { -// -// -// if (!this.baseX) { -// this.baseX = this.x; -// } -// -// const baseX = this.baseX; -// const baseTime = 50; -// const sequence = [ -// {target: {x: baseX + 40 * id}, time: baseTime - 25}, -// {target: {x: baseX - 20 * id}, time: baseTime}, -// {target: {x: baseX + 10 * id}, time: baseTime}, -// {target: {x: baseX - 5 * id}, time: baseTime}, -// {target: {x: baseX + 2 * id}, time: baseTime}, -// {target: {x: baseX - 1 * id}, time: baseTime}, -// {target: {x: baseX}, time: baseTime}, -// -// ]; -// -// -// const self = this; -// -// function runSequence() { -// -// if (self['shakeTween']) { -// self['shakeTween'].stop(); -// } -// -// const tween = new TWEEN.Tween(self); -// -// if (sequence.length > 0) { -// // console.log('sequence.length: ', sequence.length); -// const action = sequence.shift(); -// tween.to(action['target'], action['time']); -// tween.onComplete( () => { -// runSequence(); -// }); -// tween.start(); -// -// self['shakeTween'] = tween; -// } -// } -// -// runSequence(); -// -// } -// -// -// -// drop(targetY, callBack = null) { -// -// const self = this; -// -// const time = Math.abs(targetY - this.y) * 2.4; -// -// this.alpha = 1; -// -// const tween = new TWEEN.Tween(this) -// .to({ y: targetY }, time) -// .easing(TWEEN.Easing.Cubic.In) -// .onComplete(function() { -// -// // self.hideItem(callBack); -// if (callBack) { -// callBack(); -// } -// }) -// .start(); -// -// -// } -// -// -// } -// -// -// export class EndSpr extends MySprite { -// -// show(s) { -// -// this.scaleX = this.scaleY = 0; -// this.alpha = 0; -// -// const tween = new TWEEN.Tween(this) -// .to({ alpha: 1, scaleX: s, scaleY: s }, 800) -// .easing(TWEEN.Easing.Elastic.Out) // Use an easing function to make the animation smooth. -// .onComplete(function() { -// -// }) -// .start(); // Start the tween immediately. -// -// } -// } -// -// -// -// export class ShapeRect extends MySprite { -// -// fillColor = '#FF0000'; -// -// setSize(w, h) { -// this.width = w; -// this.height = h; -// -// console.log('w:', w); -// console.log('h:', h); -// } -// -// drawShape() { -// -// this.ctx.fillStyle = this.fillColor; -// this.ctx.fillRect(this._offX, this._offY, this.width, this.height); -// -// } -// -// -// drawSelf() { -// super.drawSelf(); -// this.drawShape(); -// } -// } -// -// -// export class HotZoneItem extends MySprite { -// -// -// lineDashFlag = false; -// arrow: MySprite; -// label: Label; -// title; -// -// arrowTop; -// arrowRight; -// -// audio_url; -// pic_url; -// text; -// private _itemType; -// private shapeRect: ShapeRect; -// -// get itemType() { -// return this._itemType; -// } -// set itemType(value) { -// this._itemType = value; -// } -// -// setSize(w, h) { -// this.width = w; -// this.height = h; -// -// -// const rect = new ShapeRect(this.ctx); -// rect.x = -w / 2; -// rect.y = -h / 2; -// rect.setSize(w, h); -// rect.fillColor = '#ffffff'; -// rect.alpha = 0.2; -// this.addChild(rect); -// } -// -// showLabel(text = null) { -// -// -// if (!this.label) { -// this.label = new Label(this.ctx); -// this.label.anchorY = 0; -// this.label.fontSize = '40px'; -// this.label.textAlign = 'center'; -// this.addChild(this.label); -// // this.label.scaleX = 1 / this.scaleX; -// // this.label.scaleY = 1 / this.scaleY; -// -// this.refreshLabelScale(); -// -// } -// -// if (text) { -// this.label.text = text; -// } else if (this.title) { -// this.label.text = this.title; -// } -// this.label.visible = true; -// -// } -// -// hideLabel() { -// if (!this.label) { return; } -// -// this.label.visible = false; -// } -// -// refreshLabelScale() { -// if (this.scaleX == this.scaleY) { -// this.label.setScaleXY(1); -// } -// -// if (this.scaleX > this.scaleY) { -// this.label.scaleX = this.scaleY / this.scaleX; -// } else { -// this.label.scaleY = this.scaleX / this.scaleY; -// } -// } -// -// showLineDash() { -// this.lineDashFlag = true; -// -// if (this.arrow) { -// this.arrow.visible = true; -// } else { -// this.arrow = new MySprite(this.ctx); -// this.arrow.load('assets/common/arrow.png', 1, 0); -// this.arrow.setScaleXY(0.06); -// -// this.arrowTop = new MySprite(this.ctx); -// this.arrowTop.load('assets/common/arrow_top.png', 0.5, 0); -// this.arrowTop.setScaleXY(0.06); -// -// this.arrowRight = new MySprite(this.ctx); -// this.arrowRight.load('assets/common/arrow_right.png', 1, 0.5); -// this.arrowRight.setScaleXY(0.06); -// } -// -// this.showLabel(); -// } -// -// hideLineDash() { -// -// this.lineDashFlag = false; -// -// if (this.arrow) { -// this.arrow.visible = false; -// } -// -// this.hideLabel(); -// } -// -// -// -// drawArrow() { -// if (!this.arrow) { return; } -// -// const rect = this.getBoundingBox(); -// this.arrow.x = rect.x + rect.width; -// this.arrow.y = rect.y; -// -// this.arrow.update(); -// -// -// this.arrowTop.x = rect.x + rect.width / 2; -// this.arrowTop.y = rect.y; -// this.arrowTop.update(); -// -// this.arrowRight.x = rect.x + rect.width; -// this.arrowRight.y = rect.y + rect.height / 2; -// this.arrowRight.update(); -// } -// -// drawFrame() { -// -// -// this.ctx.save(); -// -// -// const rect = this.getBoundingBox(); -// -// const w = rect.width; -// const h = rect.height; -// const x = rect.x + w / 2; -// const y = rect.y + h / 2; -// -// this.ctx.setLineDash([5, 5]); -// this.ctx.lineWidth = 2; -// this.ctx.strokeStyle = '#1bfff7'; -// // this.ctx.fillStyle = '#ffffff'; -// -// this.ctx.beginPath(); -// -// this.ctx.moveTo( x - w / 2, y - h / 2); -// -// this.ctx.lineTo(x + w / 2, y - h / 2); -// -// this.ctx.lineTo(x + w / 2, y + h / 2); -// -// this.ctx.lineTo(x - w / 2, y + h / 2); -// -// this.ctx.lineTo(x - w / 2, y - h / 2); -// -// // this.ctx.fill(); -// this.ctx.stroke(); -// -// -// -// -// this.ctx.restore(); -// -// } -// -// draw() { -// super.draw(); -// -// if (this.lineDashFlag) { -// this.drawFrame(); -// this.drawArrow(); -// } -// } -// } -// -// -// export class EditorItem extends MySprite { -// -// lineDashFlag = false; -// arrow: MySprite; -// label:Label; -// text; -// -// showLabel(text = null) { -// -// -// if (!this.label) { -// this.label = new Label(this.ctx); -// this.label.anchorY = 0; -// this.label.fontSize = '50px'; -// this.label.textAlign = 'center'; -// this.addChild(this.label); -// this.label.setScaleXY(1 / this.scaleX); -// } -// -// if (text) { -// this.label.text = text; -// } else if (this.text) { -// this.label.text = this.text; -// } -// this.label.visible = true; -// -// } -// -// hideLabel() { -// if (!this.label) { return; } -// -// this.label.visible = false; -// } -// -// showLineDash() { -// this.lineDashFlag = true; -// -// if (this.arrow) { -// this.arrow.visible = true; -// } else { -// this.arrow = new MySprite(this.ctx); -// this.arrow.load('assets/common/arrow.png', 1, 0); -// this.arrow.setScaleXY(0.06); -// -// } -// -// this.showLabel(); -// } -// -// hideLineDash() { -// -// this.lineDashFlag = false; -// -// if (this.arrow) { -// this.arrow.visible = false; -// } -// -// this.hideLabel(); -// } -// -// -// -// drawArrow() { -// if (!this.arrow) { return; } -// -// const rect = this.getBoundingBox(); -// this.arrow.x = rect.x + rect.width; -// this.arrow.y = rect.y; -// -// this.arrow.update(); -// } -// -// drawFrame() { -// -// -// this.ctx.save(); -// -// -// const rect = this.getBoundingBox(); -// -// const w = rect.width; -// const h = rect.height; -// const x = rect.x + w / 2; -// const y = rect.y + h / 2; -// -// this.ctx.setLineDash([5, 5]); -// this.ctx.lineWidth = 2; -// this.ctx.strokeStyle = '#1bfff7'; -// // this.ctx.fillStyle = '#ffffff'; -// -// this.ctx.beginPath(); -// -// this.ctx.moveTo( x - w / 2, y - h / 2); -// -// this.ctx.lineTo(x + w / 2, y - h / 2); -// -// this.ctx.lineTo(x + w / 2, y + h / 2); -// -// this.ctx.lineTo(x - w / 2, y + h / 2); -// -// this.ctx.lineTo(x - w / 2, y - h / 2); -// -// // this.ctx.fill(); -// this.ctx.stroke(); -// -// -// -// -// this.ctx.restore(); -// -// } -// -// draw() { -// super.draw(); -// -// if (this.lineDashFlag) { -// this.drawFrame(); -// this.drawArrow(); -// } -// } -// } -// -// -// -// export class Label extends MySprite { -// -// text:String; -// fontSize:String = '40px'; -// fontName:String = 'Verdana'; -// textAlign:String = 'left'; -// -// -// constructor(ctx) { -// super(ctx); -// this.init(); -// } -// -// drawText() { -// -// // console.log('in drawText', this.text); -// -// if (!this.text) { return; } -// -// this.ctx.font = `${this.fontSize} ${this.fontName}`; -// this.ctx.textAlign = this.textAlign; -// this.ctx.textBaseline = 'middle'; -// this.ctx.fontWeight = 900; -// -// this.ctx.lineWidth = 5; -// this.ctx.strokeStyle = '#ffffff'; -// this.ctx.strokeText(this.text, 0, 0); -// -// this.ctx.fillStyle = '#000000'; -// this.ctx.fillText(this.text, 0, 0); -// -// -// } -// -// -// drawSelf() { -// super.drawSelf(); -// this.drawText(); -// } -// -// } -// -// -// -// export function getPosByAngle(angle, len) { -// -// const radian = angle * Math.PI / 180; -// const x = Math.sin(radian) * len; -// const y = Math.cos(radian) * len; -// -// return {x, y}; -// -// } -// -// export function getAngleByPos(px, py, mx, my) { -// -// // const _x = p2x - p1x; -// // const _y = p2y - p1y; -// // const tan = _y / _x; -// // -// // const radina = Math.atan(tan); // 用å三角函数求弧度 -// // const angle = Math.floor(180 / (Math.PI / radina)); // -// // -// // console.log('r: ' , angle); -// // return angle; -// // -// -// -// -// const x = Math.abs(px - mx); -// const y = Math.abs(py - my); -// // const x = Math.abs(mx - px); -// // const y = Math.abs(my - py); -// const z = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)); -// const cos = y / z; -// const radina = Math.acos(cos); // 用å三角函数求弧度 -// let angle = Math.floor(180 / (Math.PI / radina) * 100) / 100; // å°†å¼§åº¦è½¬æ¢æˆè§’度 -// -// if(mx > px && my > py) {// é¼ æ ‡åœ¨ç¬¬å››è±¡é™ -// angle = 180 - angle; -// } -// -// if(mx === px && my > py) {// é¼ æ ‡åœ¨yè½´è´Ÿæ–¹å‘上 -// angle = 180; -// } -// -// if(mx > px && my === py) {// é¼ æ ‡åœ¨xè½´æ£æ–¹å‘上 -// angle = 90; -// } -// -// if(mx < px && my > py) {// é¼ æ ‡åœ¨ç¬¬ä¸‰è±¡é™ -// angle = 180 + angle; -// } -// -// if(mx < px && my === py) {// é¼ æ ‡åœ¨xè½´è´Ÿæ–¹å‘ -// angle = 270; -// } -// -// if(mx < px && my < py) {// é¼ æ ‡åœ¨ç¬¬äºŒè±¡é™ -// angle = 360 - angle; -// } -// -// // console.log('angle: ', angle); -// return angle; -// -// } diff --git a/src/app/common/custom-hot-zone/custom-hot-zone.component.html b/src/app/common/custom-hot-zone/custom-hot-zone.component.html index 9028527061890eefb1557c53f49394c7ea827b11..c96f3ac4de355552085113a21f73c3a934edd32d 100644 --- a/src/app/common/custom-hot-zone/custom-hot-zone.component.html +++ b/src/app/common/custom-hot-zone/custom-hot-zone.component.html @@ -32,33 +32,137 @@ <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 *ngIf="customTypeGroupArr[it.gIdx]?.isShowPos" style="display: flex; align-items: center; justify-content: center; margin-top: 5px;"> + x: <input type="text" nz-input [(ngModel)]="it.posX" style="width: 50px; margin-right: 15px;" (blur)="saveItemPos(it)"> + y: <input type="text" nz-input [(ngModel)]="it.posY" style="width: 50px" (blur)="saveItemPos(it)"> + </div> + + <div *ngIf="customTypeGroupArr[it.gIdx]?.select" align="center" > + <nz-select [(ngModel)]="it.selectType" nzAllowClear nzPlaceHolder="Choose" style="width: 70%; margin-top: 5px;"> + <nz-option *ngFor="let s of customTypeGroupArr[it.gIdx]?.select" [nzValue]="s.value" [nzLabel]="s.label"> + </nz-option> + </nz-select> + </div> + + <div *ngIf="customTypeGroupArr[it.gIdx]?.label" align="center" style="margin-top: 5px; display: flex; align-items: center; justify-content: center;"> + <span style="width: 30%;">{{customTypeGroupArr[it.gIdx].label + ':'}}</span> + <input type="text" nz-input [(ngModel)]="it.labelText" (blur)="saveText(it)"> + </div> + + + <div *ngIf="customTypeGroupArr[it.gIdx]?.isCopy" align="center" style="margin-top: 5px; display: flex; align-items: center; justify-content: center;"> + <button nz-button (click)="copyItem(it)" > + <i nz-icon nzType="copy" nzTheme="outline"></i> + å¤åˆ¶ç²˜è´´ + </button> + </div> + </div> + + + <!-- <div *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 +187,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 +219,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> + + diff --git a/src/app/common/custom-hot-zone/custom-hot-zone.component.scss b/src/app/common/custom-hot-zone/custom-hot-zone.component.scss index 9e2c2bf053571db2d78708132b23fe87e0acc9b2..a8f75bfa284d09475309022adfcd8552a212cea4 100644 --- a/src/app/common/custom-hot-zone/custom-hot-zone.component.scss +++ b/src/app/common/custom-hot-zone/custom-hot-zone.component.scss @@ -81,6 +81,10 @@ } } +.anima-upload-btn { + padding: 10px; +} + h5 { margin-top: 1rem; } @@ -89,8 +93,8 @@ h5 { @font-face { - font-family: 'BRLNSR_1'; - src: url("/assets/font/BRLNSR_1.TTF") ; + font-family: 'ahronbd-1'; + src: url("/assets/font/ahronbd-1.ttf") ; } @@ -105,106 +109,3 @@ h5 { - - -//@import '../../../style/common_mixin'; -// -//.p-image-uploader { -// position: relative; -// display: block; -// width: 100%; -// height: 0; -// padding-bottom: 56.25%; -// .p-box { -// position: absolute; -// left: 0; -// top: 0; -// right: 0; -// bottom: 0; -// border: 2px dashed #ddd; -// border-radius: 0.5rem; -// background-color: #fafafa; -// text-align: center; -// color: #aaa; -// .p-upload-icon { -// text-align: center; -// margin: auto; -// .anticon-upload { -// color: #888; -// font-size: 5rem; -// } -// .p-progress-bar { -// position: relative; -// width: 20rem; -// height: 1.5rem; -// border: 1px solid #ccc; -// border-radius: 1rem; -// .p-progress-bg { -// background-color: #1890ff; -// border-radius: 1rem; -// height: 100%; -// } -// .p-progress-value { -// position: absolute; -// top: 0; -// left: 0; -// width: 100%; -// height: 100%; -// text-shadow: 0 0 4px #000; -// color: white; -// text-align: center; -// font-size: 0.9rem; -// line-height: 1.5rem; -// } -// } -// } -// .p-preview { -// width: 100%; -// height: 100%; -// //background-image: url("https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png"); -// @include k-img-bg(); -// } -// } -//} -// -//.p-btn-delete { -// position: absolute; -// right: -0.5rem; -// top: -0.5rem; -// width: 2rem; -// height: 2rem; -// border: 0.2rem solid white; -// border-radius: 50%; -// font-size: 1.2rem; -// background-color: #fb781a; -// color: white; -// text-align: center; -//} -// -//.p-upload-progress-bg { -// position: absolute; -// width: 100%; -// height: 100%; -// display: flex; -// align-items: center; -// justify-content: center; -// & .i-text { -// position: absolute; -// text-align: center; -// color: white; -// text-shadow: 0 0 2px rgba(0, 0, 0, .85); -// } -// & .i-bg { -// position: absolute; -// left: 0; -// top: 0; -// height: 100%; -// background-color: #27b43f; -// border-radius: 0.5rem; -// } -//} -// -// -//:host ::ng-deep .ant-upload { -// display: block; -//} diff --git a/src/app/common/custom-hot-zone/custom-hot-zone.component.ts b/src/app/common/custom-hot-zone/custom-hot-zone.component.ts index dc2a4cf04d4592cc6a399cf5708c713dbb3439fd..3c7cbc84a9fabf1cb2d0068f500d57e614030a04 100644 --- a/src/app/common/custom-hot-zone/custom-hot-zone.component.ts +++ b/src/app/common/custom-hot-zone/custom-hot-zone.component.ts @@ -1,4 +1,6 @@ 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 {DragItem, EditorItem, HotZoneImg, HotZoneItem, HotZoneLabel, 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,31 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { @Input() isHasText = true; @Input() - hotZoneFontObj = { - size: 50, - name: 'BRLNSR_1', - color: '#8f3758' - } + isHasAudio = true; + @Input() + isHasAnima = false; + @Input() + customTypeGroupArr; // [{name:string, rect:boolean, pic:boolean, text:boolean, audio:boolean, anima:boolean, animaNames:['name1', ..]}, ...] + @Input() + // hotZoneFontObj; + @Input() + isCopyData = false; + + hotZoneFontObj; + // hotZoneFontObj = { + // size: 50, + // name: 'ahronbd-1', + // color: '#8f3758' + // } @Input() defaultItemType = 'text'; - @Input() - hotZoneImgSize = 190; + hotZoneImgSize = 0; + + + @Output() + save = new EventEmitter(); + saveDisabled = true; @@ -86,8 +100,42 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { changeSizeFlag = false; changeTopSizeFlag = false; changeRightSizeFlag = false; - - constructor() { + animaPanelVisible = false; + + uploadUrl; + uploadData; + skeJsonData = {}; + texJsonData = {}; + texPngData = {}; + animaName = ''; + curDragonBoneIndex; + curDragonBoneGIdx; + pasteData = ''; + + isSkeJsonLoading = false; + isTexJsonLoading = false; + isTexPngLoading = false; + + isAnimaSmall = false; + + savePropertyArr = [ + 'id', + 'gIdx', + 'selectType', + 'labelText', + 'posX', + 'posY' + ] + + + constructor(private nzMessageService: NzMessageService, private appRef: ApplicationRef, private changeDetectorRef: ChangeDetectorRef) { + this.uploadUrl = (<any> window).courseware.uploadUrl(); + this.uploadData = (<any> window).courseware.uploadData(); + + window['air'].getUploadCallback = (url, data) => { + this.uploadUrl = url; + this.uploadData = data; + }; } _bgItem = null; @@ -110,11 +158,14 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { ngOnInit() { + this.initListener(); // this.init(); this.update(); + this.refresh(); + } ngOnDestroy() { @@ -136,10 +187,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,37 +203,61 @@ 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.removeChildren(); - bg.x = this.canvasWidth / 2; - bg.y = this.canvasHeight / 2; + const bgBorder = new ShapeRectNew(this.ctx); + bgBorder.setSize(bg.width, bg.height, 0); + bgBorder.fillColor = '#ff0000'; + bgBorder.fill = false; + bgBorder.stroke = true; + bgBorder.x = -bg.width / 2; + bgBorder.y = -bg.height / 2; + bgBorder.lineWidth = 0.5; + bg.addChild(bgBorder); - if (callBack) { - callBack(); - } - }); - } + + if (callBack) { + callBack(); + } + + this.refresh(); + + }); + // } } - addBtnClick() { + addBtnClick(data=null) { // this.imgArr.push({}); // this.hotZoneArr.push({}); - const item = this.getHotZoneItem(); + const item = this.getHotZoneItem(data); this.hotZoneArr.push(item); - this.refreshItem(item); + + if (this.customTypeGroupArr) { + this.refreshCustomItem(item); + } else { + this.refreshItem(item); + } this.refreshHotZoneId(); @@ -191,6 +268,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.drag); this.refreshHotZoneId(); @@ -199,6 +277,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 +300,7 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { } } + this.refresh(); } @@ -245,10 +325,18 @@ 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'] = this.createItemId() // new Date().getTime().toString(); + item['data'] = saveData; + + console.log('item.x: ', item.x); if (saveData) { @@ -257,41 +345,203 @@ 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]; + + this.savePropertyArr.forEach((key) => { + if (saveData[key]) { + item[key] = saveData[key]; + } + }) + } + 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.setItemDrag(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.imgScale); + } } + pic.x = item.x; pic.y = item.y; this.renderArr.push(pic); + } + + + setItemDrag(item, saveData) { + + console.log('in setItemDrag ', saveData); + const dragItem = new DragItem(this.ctx); + dragItem.init(); + dragItem.item = item; + item['drag'] = dragItem; + + dragItem.visible = false; + + dragItem.x = item.x; + dragItem.y = item.y; + this.renderArr.push(dragItem); + + if (saveData) { + if (saveData.dragDot) { + dragItem.x = saveData.dragDot.x / saveData.mapScale * this.mapScale; + dragItem.y = saveData.dragDot.y / saveData.mapScale * this.mapScale; + } + } + + + // console.log('item.itemType: ', item.itemType); + // let w = item.width; + // let h = item.height; + // if (saveData) { + // switch (saveData.itemType) { + // case 'rect': + // w = saveData.rect.width; + // h = saveData.rect.height; + // break; + // case 'pic': + // w = saveData.imgSizeW * saveData.imgScale; + // h = saveData.imgSizeH * saveData.imgScale;; + // break; + // case 'text': + // w = saveData.rect.width; + // h = saveData.rect.height; + // break; + // } + // } + + // dragItem.setSize(w, h); + + + + } + + setItemAnima(item, saveData) { + console.log('in setItemAnima ', saveData); + // const pic = new EditorItem(this.ctx); + // pic.visible = false; + // item['pic'] = pic; + // if (saveData) { + + // let picUrl = saveData.pic_url; + // const actionData = saveData['actionData_' + item.gIdx]; + // if (actionData && actionData.type == 'pic') { + // picUrl = actionData.pic_url; + // } + + // console.log('saveData: ', saveData); + // console.log('picUrl: ', picUrl); + + // if (picUrl) { + // this.loadHotZonePic(pic, picUrl, saveData.imgScale); + // } + // } + + // pic.x = item.x; + // pic.y = item.y; + // this.renderArr.push(pic); + } + + + setItemLabel(item, saveData) { const textLabel = new HotZoneLabel(this.ctx); - 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'; + } + } else { + return this.defaultItemType; + } + } getPicItem(img, saveData = null) { @@ -327,9 +577,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 +589,7 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { onAudioUploadSuccessByImg(e, img) { img.audio_url = e.url; + this.refresh(); } deleteItem(e, i) { @@ -345,15 +598,111 @@ 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.refresh(); + // // console.log(' in radioChange e: ', e); + // } - this.refreshItem(item); + 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]; - // console.log(' in radioChange e: ', e); + } + + refreshCustomItem(item) { + this.hideHotZoneItem(item); + const group = this.customTypeGroupArr[item.gIdx]; + if (!group) { + return; + } + + if (group.text) { + this.showItemLabel(item); + } + + if (group.rect) { + this.showItemRect(item, !group.isFixed); + } + + if (group.pic && !group.anima) { + this.showItemPic(item); + } + + if (group.action) { + if (group.action.type == 'pic') { + this.showItemPic(item); + } + if (group.action.type == 'text') { + this.showItemLabel(item); + } + if (group.action.type == 'anima') { + this.showItemRect(item); + } + } + + item.drag.visible = group.drag; + + item.setAnimaStyle(group.animaSmall) + + + } + + showItemDrag(item) { + item.drag.visible = true; + // item.dragBody.visible = true; + // item.itemType = 'pic'; + // this.showArrowTop(item) + } + + + showItemPic(item) { + item.pic.visible = true; + item.itemType = 'pic'; + this.showArrowTop(item) + } + + showItemLabel(item) { + item.textLabel.visible = true; + item.itemType = 'text'; + this.showArrowTop(item) + } + + showItemRect(item, isShowArrowTop = true) { + item.visible = true; + item.itemType = 'rect'; + this.showArrowTop(item, isShowArrowTop) + } + + 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) { @@ -368,33 +717,30 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { this.setTextState(item); break; default: - + this.setNoneState(item); } } init() { + console.log('init'); this.initData(); this.initCtx(); - this.initItem(); } 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 = []; } else { @@ -404,6 +750,7 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { }); } + this.refresh(); } initHotZoneArr() { @@ -427,6 +774,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 +797,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 +817,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 +840,28 @@ 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]; + + if (item && item.drag && item.drag.visible) { + + if (this.checkClickTarget(item.drag)) { + + this.clickedDragPoint(item.drag); + return; + } + } + } + + for (let i = this.hotZoneArr.length - 1; i >= 0; i--) { + const item = this.hotZoneArr[i]; + + console.log('mapDown item: ', item); let callback; let target; switch (item.itemType) { @@ -548,7 +879,7 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { break; } - if (this.checkClickTarget(target)) { + if (target && this.checkClickTarget(target)) { callback(target); return; } @@ -578,15 +909,18 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { const addY = this.my - this.oldPos.y; this.curItem.x += addX; this.curItem.y += addY; + + this.curItem.posX = this.curItem.x; + this.curItem.posY = this.curItem.y; } this.oldPos = {x: this.mx, y: this.my}; - this.saveDisabled = true; + // this.saveDisabled = false; } - mapUp(event) { + mapUp(event=null) { this.curItem = null; this.changeSizeFlag = false; this.changeTopSizeFlag = false; @@ -685,10 +1019,13 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { changeCurItem(item) { + console.log(' in changeCurItem', item) + this.hideAllLineDash(); this.curItem = item; this.curItem.showLineDash(); + } hideAllLineDash() { @@ -711,9 +1048,7 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { // 清除画布内容 this.ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight); - for (let i = 0; i < this.renderArr.length; i++) { - this.renderArr[i].update(this); - } + // for (let i = 0; i < this.imgArr.length; i++) { // const picItem = this.imgArr[i].picItem; @@ -722,8 +1057,16 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { // } // } + for (let i = 0; i < this.renderArr.length; i++) { + this.renderArr[i].update(this); + } + this.updateArr(this.hotZoneArr); - this.updatePos() + + + + this.updatePos(); + TWEEN.update(); @@ -833,7 +1176,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 +1197,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 +1227,52 @@ 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 + imgSizeW: hotZoneArr[i].pic ? hotZoneArr[i].pic.width : 0, + imgSizeH: hotZoneArr[i].pic ? hotZoneArr[i].pic.height : 0, + mapScale: this.mapScale, + skeJsonData: hotZoneArr[i].skeJsonData, + texJsonData: hotZoneArr[i].texJsonData, + texPngData: hotZoneArr[i].texPngData, + dragDot: hotZoneArr[i].drag.getPosition(), + gIdx: hotZoneArr[i].gIdx, }; - hotZoneItem['rect'] = hotZoneArr[i].getBoundingBox(); + + this.savePropertyArr.forEach((key) => { + if (hotZoneArr[i][key]) { + hotZoneItem[key] = hotZoneArr[i][key]; + } + }) + + hotZoneItem['actionData_' + hotZoneItem.gIdx] = hotZoneArr[i]['actionData_' + hotZoneArr[i].gIdx] + + + if (this.hotZoneFontObj) { + hotZoneItem['fontSize'] = this.hotZoneFontObj.size; + hotZoneItem['fontName'] = this.hotZoneFontObj.name; + hotZoneItem['ontColor'] = this.hotZoneFontObj.color; + } + + + if (hotZoneArr[i].itemType == 'pic') { + hotZoneItem['rect'] = hotZoneArr[i].pic.getBoundingBox(); + } else if (hotZoneArr[i].itemType == 'text') { + hotZoneArr[i].textLabel.refreshSize(); + hotZoneItem['rect'] = hotZoneArr[i].textLabel.getLabelRect(); + // hotZoneItem['rect'].width = hotZoneItem['rect'].width / hotZoneArr[i].textLabel.scaleX; + // hotZoneItem['rect'].height = hotZoneArr[i].textLabel.height * hotZoneArr[i].textLabel.scaleY; + + } else { + hotZoneItem['rect'] = hotZoneArr[i].getBoundingBox(); + } + // hotZoneItem['rect'] = hotZoneArr[i].getBoundingBox(); hotZoneItem['rect'].x = Math.round((hotZoneItem['rect'].x - bgItem['rect'].x) * 100) / 100; hotZoneItem['rect'].y = Math.round((hotZoneItem['rect'].y - bgItem['rect'].y) * 100) / 100; hotZoneItem['rect'].width = Math.round((hotZoneItem['rect'].width) * 100) / 100; @@ -894,7 +1284,360 @@ 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; + } + } + + saveItemPos(item) { + + console.log('item.posX: ', item.posX) + console.log('item.posY: ', item.posY) + + item.x = Number(item.posX || 0) + item.y = Number(item.posY || 0) + + + + // this.changeCurItem(item); + + + + // this.curItem.x = item.posX || 0; + // this.curItem.y = item.posY || 0; + + // this.mapUp(); + + + } + + onSaveCustomAction(e, item) { + + const data = e; + item['actionData_' + item.gIdx] = data; + + if (data.type == 'pic') { + let picUrl = data.pic_url; + if (picUrl) { + this.loadHotZonePic(item.pic, picUrl); + } + } + + if (data.type == 'text') { + this.setActionFont(item.textLabel, data); + item.textLabel.refreshSize(); + } + + // if (data.type == 'anima') { + // this.setActionAnima(item.anima, data); + // } + + // this.loadHotZonePic(item.pic, e.url); + this.refresh() + } + + setActionAnima() { + + } + + + setAnimaBtnClick(index) { + + console.log('aaaa') + this.isAnimaSmall = false; + + this.setCurDragonBone(index); + + // this.curDragonBoneIndex = index; + // this.curDragonBoneGIdx = Number(this.hotZoneArr[index].gIdx); + + // const {skeJsonData, texJsonData, texPngData} = this.hotZoneArr[index]; + + // this.skeJsonData = skeJsonData || {}; + // this.texJsonData = texJsonData || {}; + // this.texPngData = texPngData || {}; + + // this.animaPanelVisible = true; + + // this.refresh(); + } + + + setAnimaSmallBtnClick(index) { + + + console.log('bbb') + this.isAnimaSmall = true; + + this.setCurDragonBone(index); + + } + + setCurDragonBone(index) { + this.curDragonBoneIndex = index; + this.curDragonBoneGIdx = Number(this.hotZoneArr[index].gIdx); + + const {skeJsonData, texJsonData, texPngData} = this.hotZoneArr[index]; + + this.skeJsonData = skeJsonData || {}; + this.texJsonData = texJsonData || {}; + this.texPngData = texPngData || {}; + + this.animaPanelVisible = true; + + this.refresh(); + } + + setItemSizeByAnima(jsonData, item) { + console.log('json: ', jsonData); + + const request = new XMLHttpRequest(); + //通过urlèŽ·å–æ–‡ä»¶ï¼Œç¬¬äºŒä¸ªé€‰é¡¹æ˜¯æ–‡ä»¶æ‰€åœ¨çš„å…·ä½“åœ°å€ + request.open('GET', jsonData.url, true); + request.send(null); + request.onreadystatechange = ()=> { + if (request.readyState === 4 && request.status === 200) { + var type = request.getResponseHeader('Content-Type'); + if (type.indexOf("text") !== 1) { + //返回一个文件内容的对象 + + const data = JSON.parse(request.responseText); + console.log('request.responseText;', data) + const animaSize = data.armature[0].canvas; + item.width = animaSize.width; + item.height = animaSize.height; + // return request.responseText; + } + } + } + } + + animaPanelCancel() { + this.animaPanelVisible = false; + this.refresh(); + } + + animaPanelOk() { + + this.setItemDragonBoneData(this.hotZoneArr[this.curDragonBoneIndex]); + console.log('this.hotZoneArr: ', this.hotZoneArr); + this.animaPanelVisible = false; + + if (this.isAnimaSmall) { + this.setItemSizeByAnima(this.skeJsonData, this.hotZoneArr[this.curDragonBoneIndex]); + } + + this.refresh(); + } + + setItemDragonBoneData(item) { + item['skeJsonData'] = this.skeJsonData; + item['texJsonData'] = this.texJsonData; + item['texPngData'] = this.texPngData; + } + + skeJsonHandleChange(e) { + console.log('e: ', e); + switch (e.type) { + case 'start': + this.isSkeJsonLoading = true; + break; + + case 'success': + this.skeJsonData['url'] = e.file.response.url; + this.skeJsonData['name'] = e.file.name; + this.nzMessageService.success('ä¸Šä¼ æˆåŠŸ'); + this.isSkeJsonLoading = false; + break; + + case 'progress': + break; + } + } + + texJsonHandleChange(e) { + console.log('e: ', e); + switch (e.type) { + case 'start': + this.isTexJsonLoading = true; + break; + + case 'success': + this.texJsonData['url'] = e.file.response.url; + this.texJsonData['name'] = e.file.name; + this.nzMessageService.success('ä¸Šä¼ æˆåŠŸ'); + this.isTexJsonLoading = false; + break; + + case 'progress': + break; + } + } + + texPngHandleChange(e) { + console.log('e: ', e); + switch (e.type) { + case 'start': + this.isTexPngLoading = true; + break; + + case 'success': + this.texPngData['url'] = e.file.response.url; + this.texPngData['name'] = e.file.name; + this.nzMessageService.success('ä¸Šä¼ æˆåŠŸ'); + this.isTexPngLoading = false; + break; + + case 'progress': + break; + } + } + + copyItem(it) { + + const {hotZoneItemArr} = this.getSendData(); + let itemData; + hotZoneItemArr.forEach((data) => { + if (data.id == it.id) { + itemData = data; + } + }) + + + let curBgRect; + if (this.bg) { + curBgRect = this.bg.getBoundingBox(); + } else { + curBgRect = {x: 0, y: 0, width: this.canvasWidth, height: this.canvasHeight}; + } + + let oldBgRect = this.bgItem.rect; + if (!oldBgRect) { + oldBgRect = curBgRect; + } + + const rate = curBgRect.width / oldBgRect.width; + + console.log('rate: ', rate); + + + const data = itemData + + data.rect.x *= rate; + data.rect.y *= rate; + data.rect.width *= rate; + data.rect.height *= rate; + + data.rect.x += curBgRect.x; + data.rect.y += curBgRect.y; + + + const item = this.getHotZoneItem(data); + item.audio_url = data.audio_url; + item.pic_url = data.pic_url; + item.text = data.text; + item.itemType = data.itemType; + + this.hotZoneArr.push(item); + + if (this.customTypeGroupArr) { + this.refreshCustomItem(item); + } else { + this.refreshItem(item); + } + + this.refreshHotZoneId(); + + item['id'] = this.createItemId(); + + } + + createItemId() { + return new Date().getTime().toString(); + } + + copyHotZoneData() { + + const {bgItem, hotZoneItemArr} = this.getSendData(); + + // const hotZoneItemArrNew = []; + // const tmpArr = JSON.parse(JSON.stringify(hotZoneItemArr)); + // tmpArr.forEach((item) => { + // if (item.gIdx === '0') { + // hotZoneItemArr.push(item); + // } + // }) + + const jsonData = { + bgItem, + hotZoneItemArr, + isHasRect: this.isHasRect, + isHasPic: this.isHasPic, + isHasText: this.isHasText, + isHasAudio: this.isHasAudio, + isHasAnima: this.isHasAnima, + hotZoneFontObj: this.hotZoneFontObj, + defaultItemType: this.defaultItemType, + hotZoneImgSize: this.hotZoneImgSize, + }; + + + const oInput = document.createElement('input'); + oInput.value = JSON.stringify(jsonData); + document.body.appendChild(oInput); + oInput.select(); // 选择对象 + document.execCommand('Copy'); // 执行æµè§ˆå™¨å¤åˆ¶å‘½ä»¤ + + document.body.removeChild(oInput); + this.nzMessageService.success('å¤åˆ¶æˆåŠŸ'); + // alert('å¤åˆ¶æˆåŠŸ'); + + + } + + importData() { + if (!this.pasteData) { + return; + } + + + try { + const data = JSON.parse(this.pasteData); + console.log('data:', data); + const { + bgItem, + hotZoneItemArr, + isHasRect, + isHasPic, + isHasText, + isHasAudio, + isHasAnima, + hotZoneFontObj, + defaultItemType, + hotZoneImgSize, + } = data; + + this.hotZoneItemArr = hotZoneItemArr; + this.isHasRect = isHasRect; + this.isHasPic = isHasPic; + this.isHasText = isHasText; + this.isHasAudio = isHasAudio; + this.isHasAnima = isHasAnima; + this.hotZoneFontObj = hotZoneFontObj; + this.defaultItemType = defaultItemType; + this.hotZoneImgSize = hotZoneImgSize; + + this.bgItem = bgItem; + + this.pasteData = ''; + } catch (e) { + console.log('err: ', e); + this.nzMessageService.error('导入失败'); + } } private updatePos() { @@ -917,12 +1660,15 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { break; } - item.x = x; - item.y = y; - item.pic.x = x; - item.pic.y = y; - item.textLabel.x = x; - item.textLabel.y = y; + 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; + } + }); } @@ -944,6 +1690,12 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { item.textLabel.visible = true; } + private setNoneState(item: any) { + item.visible = false; + item.pic.visible = false; + item.textLabel.visible = false; + } + private clickedHotZoneRect(item: any) { if (this.checkClickTarget(item)) { @@ -962,6 +1714,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 +1735,42 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { } } - saveText(item) { - item.textLabel.text = item.text; + clickedDragPoint(item) { + this.curItem = item; } - private loadHotZonePic(pic: HotZoneImg, url) { - const baseLen = this.hotZoneImgSize * this.mapScale; + private loadHotZonePic(pic: HotZoneImg, url, scale = null) { + + let baseLen; + if (this.hotZoneImgSize) { + baseLen = this.hotZoneImgSize * this.mapScale; + } + pic.load(url).then(() => { - const s = getMinScale(pic, baseLen); - pic.setScaleXY(s); + if (!scale) { + if (baseLen) { + scale = getMinScale(pic, baseLen); + } else { + scale = this.bg.scaleX; + } + } + + pic.setScaleXY(scale); }); } + + + closeAfterPanel() { + this.refresh(); + } + /** + * 刷新 æ¸²æŸ“é¡µé¢ + */ + refresh() { + setTimeout(() => { + this.appRef.tick(); + }, 1); + } + + } diff --git a/src/app/common/sub-template/sub-template.component.html b/src/app/common/sub-template/sub-template.component.html new file mode 100644 index 0000000000000000000000000000000000000000..676c4257cea8257b2649431b3d87d6cdb6fa1f86 --- /dev/null +++ b/src/app/common/sub-template/sub-template.component.html @@ -0,0 +1,53 @@ +<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 diff --git a/src/app/common/sub-template/sub-template.component.scss b/src/app/common/sub-template/sub-template.component.scss new file mode 100644 index 0000000000000000000000000000000000000000..2270cc0bf5b6b13b5822988ade8cb380ab20729f --- /dev/null +++ b/src/app/common/sub-template/sub-template.component.scss @@ -0,0 +1,18 @@ +@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 diff --git a/src/app/common/sub-template/sub-template.component.ts b/src/app/common/sub-template/sub-template.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..8e462fc35ac65dab6e68a1906c8b399645f76598 --- /dev/null +++ b/src/app/common/sub-template/sub-template.component.ts @@ -0,0 +1,368 @@ +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() { + + } + +} diff --git a/src/app/common/upload-dragon-bone/upload-dragon-bone.component.html b/src/app/common/upload-dragon-bone/upload-dragon-bone.component.html new file mode 100644 index 0000000000000000000000000000000000000000..935479752d531c52e99fa7bfb39b36d49dcc06fc --- /dev/null +++ b/src/app/common/upload-dragon-bone/upload-dragon-bone.component.html @@ -0,0 +1,50 @@ +<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 diff --git a/src/app/common/upload-dragon-bone/upload-dragon-bone.component.scss b/src/app/common/upload-dragon-bone/upload-dragon-bone.component.scss new file mode 100644 index 0000000000000000000000000000000000000000..e9c56bfc8de8aec772d05405514870f9bb6c30f6 --- /dev/null +++ b/src/app/common/upload-dragon-bone/upload-dragon-bone.component.scss @@ -0,0 +1,110 @@ +@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; +} diff --git a/src/app/common/upload-dragon-bone/upload-dragon-bone.component.ts b/src/app/common/upload-dragon-bone/upload-dragon-bone.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..a99c3e4cf7ff4618296ff2f64c0f081e4aaef1e7 --- /dev/null +++ b/src/app/common/upload-dragon-bone/upload-dragon-bone.component.ts @@ -0,0 +1,181 @@ +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() { + } + +} diff --git a/src/app/common/upload-image-with-preview/upload-image-with-preview.component.ts b/src/app/common/upload-image-with-preview/upload-image-with-preview.component.ts index f4694a1f1ae4b582b3c121e601c6322437888820..ec51b2fbee594a12c3eefb1a0b2e1cb41fdd4652 100644 --- a/src/app/common/upload-image-with-preview/upload-image-with-preview.component.ts +++ b/src/app/common/upload-image-with-preview/upload-image-with-preview.component.ts @@ -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; diff --git a/src/app/common/upload-video/upload-video.component.html b/src/app/common/upload-video/upload-video.component.html index 8f1533993f2bdcf3d5f3e0cd4337f3fa96a1ebd7..5ba637166c426dbe6b160d8007b14d2e6c307688 100644 --- a/src/app/common/upload-video/upload-video.component.html +++ b/src/app/common/upload-video/upload-video.component.html @@ -81,8 +81,8 @@ </div> </div> <div class="p-preview" *ngIf="!uploading && videoUrl " > - <!--<video crossorigin="anonymous" [src]="videoUrl" controls #videoNode></video>--> - <video [src]="safeVideoUrl(videoUrl)" controls #videoNode></video> + <video crossorigin="anonymous" [src]="videoUrl" controls #videoNode></video> + <!-- <video [src]="safeVideoUrl(videoUrl)" controls #videoNode></video> --> </div> </div> <div [style.display]="!checkVideoExists?'none':''"> diff --git a/src/app/form/form.component.css b/src/app/form/form.component.css index 41f7757290161973406aeec2177e0feef3ffcdaa..5d78cd06c5f047021baddbe66edf8dae0954fb5d 100644 --- a/src/app/form/form.component.css +++ b/src/app/form/form.component.css @@ -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; +} diff --git a/src/app/form/form.component.html b/src/app/form/form.component.html index a51aa6ba14036cd5e1b9a4544b55a7bf0b75c1c8..f1f9998a13620627b8190417702bff092fd89ebd 100644 --- a/src/app/form/form.component.html +++ b/src/app/form/form.component.html @@ -1,25 +1,299 @@ - <div class="model-content"> + + <div style="padding: 20px;"> + + + <div style="width: 400px; display: flex; justify-content: center; margin-bottom: 50px;"> - <div style="position: absolute; left: 200px; top: 100px; width: 800px;"> + <h2 style="width: 60px;">æ ‡é¢˜:</h2> + <input type="text" nz-input [(ngModel)]="item.title" (blur)="save()" style="margin-left: 15px"> + </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> + <h2>çƒåŒºé…置:</h2> + <app-custom-hot-zone + [bgItem]="item.bgItem" + [hotZoneItemArr]="item.hotZoneItemArr" + [customTypeGroupArr]="customTypeGroupArr" + (save)="saveHotZone(item, $event)" + > - <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> + </app-custom-hot-zone> + + + <div> + <nz-radio-group [(ngModel)]="item.ques_type" style="margin-top: 50px" (ngModelChange)="save()"> + <h2 nz-radio nzValue="single_choice">选择题</h2> + <h2 nz-radio nzValue="short_answer">简ç”题</h2> + </nz-radio-group> + </div> + + <!-- 选择题 --> + + <div *ngIf="item.ques_type == 'single_choice'"> + + <div style="margin-top: 30px; display: flex; width: 1000px;"> + <div style="width: 300px; margin-top: 10px; margin-right: 15px;"> + <span style="margin-right: 5px;">问题:</span> + + <app-upload-image-with-preview + [picUrl]="item.ques_pic_url" + (imageUploaded)="onImageUploadSuccess($event, 'ques_pic_url')"> + </app-upload-image-with-preview> + </div> + + <div style="width: 300px;"> + + <div style="display: flex; align-items: center; height: 30px;"> + <span style="margin-right: 5px; margin-left: 15px;">å°æ ‡é¢˜:</span> + + <app-audio-recorder + [audioUrl]="item.title_audio_url" + (audioUploaded)="onAudioUploadSuccess($event, 'title_audio_url')" + ></app-audio-recorder> + </div> + + <app-upload-image-with-preview + [picUrl]="item.title_pic_url" + (imageUploaded)="onImageUploadSuccess($event, 'title_pic_url')"> + </app-upload-image-with-preview> + </div> + + </div> + + + <div *ngFor="let op of item.optionArr" style="border: 1px solid #ccc; margin: 10px; padding: 10px; border-radius: 5px;"> + <div style="margin-top: 20px; display: flex; align-items: center; width: 500px;"> + <span style="margin-right: 5px;">{{op.id}}:</span> + <div style="width: 300px;"> + <app-upload-image-with-preview + [picUrl]="op.pic_url" + (imageUploaded)="onImageUploadSuccess($event, 'pic_url', op)"> + </app-upload-image-with-preview> + </div> + <div style="margin-left: 20px;"> + <span> æ£ç¡®: </span> + <nz-switch [(ngModel)]="op.is_right" (ngModelChange)="save()"></nz-switch> + </div> + + </div> + + <nz-divider style="margin-top: 20px;"></nz-divider> + + + <div *ngIf="!op.is_right" style="padding: 20px; display: flex; align-items: center;"> + + + <div style="width: 300px;"> + çº é”™è§†é¢‘ï¼š + <app-upload-video + (videoUploaded)="onVideoUploadSuccess($event, op)" + [item]="op" + [videoUrl]="op.video_url"> + </app-upload-video> + </div> + + <div style="margin-left: 20px;"> + + <div style="display: flex; align-items: center;"> + <span style="margin-right: 5px;">å°æ ‡é¢˜2:</span> + <app-audio-recorder + [audioUrl]="op.title_audio_url" + (audioUploaded)="onAudioUploadSuccess($event, 'title_audio_url', op)" + ></app-audio-recorder> + </div> + <div style="width: 300px;"> + <app-upload-image-with-preview + [picUrl]="op.title_pic_url" + (imageUploaded)="onImageUploadSuccess($event, 'title_pic_url', op)"> + </app-upload-image-with-preview> + </div> + + <span style="margin-left: 15px;" >问题2:</span> + <div style="width: 300px;"> + <app-upload-image-with-preview + [picUrl]="op.ques_pic_url" + (imageUploaded)="onImageUploadSuccess($event, 'ques_pic_url', op)"> + </app-upload-image-with-preview> + </div> + + </div> + + <div style="margin-left: 20px;"> + + <div *ngFor="let op2 of op.optionArr" style="display: flex; align-items: center; margin-top: 5px;"> + {{op2.id}} + <div style="width: 150px; margin-left: 5px;"> + <app-upload-image-with-preview + [picUrl]="op2.pic_url" + (imageUploaded)="onImageUploadSuccess($event, 'pic_url', op2)"> + </app-upload-image-with-preview> + </div> + + <div style="margin-left: 5px;"> + <span> æ£ç¡®: </span> + <nz-switch [(ngModel)]="op2.is_right" (ngModelChange)="save()"></nz-switch> + </div> + </div> + + </div> + + </div> + </div> + + </div> + + + + <!-- 简ç”题 --> + + <div *ngIf="item.ques_type == 'short_answer'"> + + + <div style="margin-top: 30px; display: flex; width: 1000px;"> + <div style="width: 300px; margin-top: 10px; margin-right: 15px;"> + <span style="margin-right: 5px;">选择题问题:</span> + + <app-upload-image-with-preview + [picUrl]="item.choice_ques_pic_url" + (imageUploaded)="onImageUploadSuccess($event, 'choice_ques_pic_url')"> + </app-upload-image-with-preview> + </div> + + <div style="width: 300px;"> + + <div style="display: flex; align-items: center; height: 30px;"> + <span style="margin-right: 5px; margin-left: 15px;">é€‰æ‹©å°æ ‡é¢˜:</span> + + <app-audio-recorder + [audioUrl]="item.choice_title_audio_url" + (audioUploaded)="onAudioUploadSuccess($event, 'choice_title_audio_url')" + ></app-audio-recorder> + </div> + + <app-upload-image-with-preview + [picUrl]="item.choice_title_pic_url" + (imageUploaded)="onImageUploadSuccess($event, 'choice_title_pic_url')"> + </app-upload-image-with-preview> + </div> + + </div> + + + <div *ngFor="let op of item.optionArr" style="border: 1px solid #ccc; margin: 10px; padding: 10px; border-radius: 5px;"> + <div style="margin-top: 20px; display: flex; align-items: center; width: 500px;"> + <span style="margin-right: 5px;">{{op.id}}:</span> + <div style="width: 300px;"> + <app-upload-image-with-preview + [picUrl]="op.pic_url" + (imageUploaded)="onImageUploadSuccess($event, 'pic_url', op)"> + </app-upload-image-with-preview> + </div> + <div style="margin-left: 20px;"> + <span> æ£ç¡®: </span> + <nz-switch [(ngModel)]="op.is_right" (ngModelChange)="save()"></nz-switch> + </div> + + </div> + + <nz-divider style="margin-top: 20px;"></nz-divider> + + + + </div> + + <nz-divider style="margin-top: 50px;"></nz-divider> + + <div style="display: flex; align-items: center; margin-bottom: 50px;"> + + <div style="width: 400px; margin-top: 10px; margin-right: 15px;"> + <span style="margin-right: 5px;">新简ç”问题:</span> + + <app-upload-image-with-preview + [picUrl]="item.answer_ques_pic_url" + (imageUploaded)="onImageUploadSuccess($event, 'answer_ques_pic_url')"> + </app-upload-image-with-preview> + </div> + + <div style="width: 400px;"> + + <div style="display: flex; align-items: center; height: 30px;"> + <span style="margin-right: 5px; margin-left: 15px;">新简ç”å°æ ‡é¢˜:</span> + + <app-audio-recorder + [audioUrl]="item.answer_title_audio_url" + (audioUploaded)="onAudioUploadSuccess($event, 'answer_title_audio_url')" + ></app-audio-recorder> + </div> + + <app-upload-image-with-preview + [picUrl]="item.answer_title_pic_url" + (imageUploaded)="onImageUploadSuccess($event, 'answer_title_pic_url')"> + </app-upload-image-with-preview> + </div> + + <div style="width: 400px; margin-left: 15px;"> + <span style="margin-right: 5px; ">新简ç”题 ç”æ¡ˆ:</span> + <div style="width: 200px; display: flex; justify-content: center; align-items: center;"> + <input type="text" nz-input [(ngModel)]="item.new_answer" (blur)="save()" style="margin-top: 5px"> + </div> + </div> + + </div> + + + </div> + + + +<!-- + <div style="width: 100%; margin-top: 15px; margin-bottom: 50px;" align="center"> + <h2>气泡文本</h2> + <div style="width: 80%; display: flex; justify-content: center; align-items: center;"> + <input type="text" nz-input [(ngModel)]="item.title" (blur)="save()" style="margin-top: 5px"> + </div> + + </div> + + <app-custom-hot-zone + [bgItem]="item.bgItem" + [hotZoneItemArr]="item.hotZoneItemArr" + [customTypeGroupArr]="customTypeGroupArr" + (save)="saveHotZone(item, $event)" + > + + </app-custom-hot-zone> --> + <!-- <div style="width: 300px;" align='center'> + <span>图1: </span> + <app-upload-image-with-preview + [picUrl]="item.pic_url" + (imageUploaded)="onImageUploadSuccess($event, 'pic_url')"> + </app-upload-image-with-preview> + </div> + + <div style="width: 300px; margin-top: 5px;" align='center'> + <span>图2: </span> + <app-upload-image-with-preview + [picUrl]="item.pic_url_2" + (imageUploaded)="onImageUploadSuccess($event, 'pic_url_2')"> + </app-upload-image-with-preview> + </div> + + <div style="width: 300px; margin-top: 15px;"> + <span>文本: </span> + <input type="text" nz-input [(ngModel)]="item.text" (blur)="save()"> + </div> + + <div style="margin-top: 5px"> + <span>音频: </span> + <app-audio-recorder + [audioUrl]="item.audio_url" + (audioUploaded)="onAudioUploadSuccess($event, 'audio_url')" + ></app-audio-recorder> + </div> --> + + </div> </div> - \ No newline at end of file diff --git a/src/app/form/form.component.ts b/src/app/form/form.component.ts index 8bf084e921171b4cf11f2779fd6dfc49daa67fdb..1f2309962108619d806808c3246d50f7cb24ddf4 100644 --- a/src/app/form/form.component.ts +++ b/src/app/form/form.component.ts @@ -1,5 +1,5 @@ -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,47 +10,154 @@ import {Component, EventEmitter, Input, OnDestroy, OnChanges, OnInit, Output, Ap export class FormComponent implements OnInit, OnChanges, OnDestroy { // å‚¨å˜æ•°æ®ç”¨ - saveKey = "test_0011"; + saveKey = "JM_MATH01"; // 储å˜å¯¹è±¡ item; + customTypeGroupArr = [ + + { + name: 'è½®æ’图片', + audio: true, + pic: true, + // rect: true, + // isShowPos: true, + // isCopy: true, + + // label: '比对', + }, + { + name: '选择区域', + rect: true, + }, + { + name: '简ç”问题', + pic: true, + }, + { + name: '简ç”填空区', + rect: true, + label: 'ç”æ¡ˆ', + }, + ] + + + 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; } + console.log('this.item: ', this.item); + this.init(); this.changeDetectorRef.markForCheck(); this.changeDetectorRef.detectChanges(); this.refresh(); }, this.saveKey); - } - ngOnChanges() { } ngOnDestroy() { } + init() { + + if (!this.item.sentenceArr) { + this.item.sentenceArr = []; + } + if (!this.item.templateArr) { + this.item.templateArr = []; + } + + if (!this.item.optionArr) { + this.item.optionArr = [ + {id: 'A', optionArr: [{id: 'A'}, {id: 'B'}]}, + {id: 'B', optionArr: [{id: 'A'}, {id: 'B'}]}, + {id: 'C', optionArr: [{id: 'A'}, {id: 'B'}]}, + {id: 'D', optionArr: [{id: 'A'}, {id: 'B'}]}, + ]; + } + + if (!this.item.ques_type) { + this.item.ques_type = 'single_choice' + } + } + + 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(); } @@ -58,30 +165,55 @@ export class FormComponent implements OnInit, OnChanges, OnDestroy { * 储å˜å›¾ç‰‡æ•°æ® * @param e */ - onImageUploadSuccess(e, key) { + onImageUploadSuccess(e, key, item=null) { + if (!item) { + item = this.item; + } - this.item[key] = e.url; - this.save(); + item[key] = e.url; + this.save(); } /** * 储å˜éŸ³é¢‘æ•°æ® * @param e */ - onAudioUploadSuccess(e, key) { + onAudioUploadSuccess(e, key, item=null) { + if (item == null) { + item = this.item; + } + item[key] = e.url; + this.save(); + } - this.item[key] = e.url; + onWordAudioUploadSuccess(e, idx) { + this.item.wordList[idx].audio = e.url; this.save(); } + onBackWordAudioUploadSuccess(e, idx) { + this.item.wordList[idx].backWordAudio = e.url; + this.save(); + } + onVideoUploadSuccess(e, item=null) { + + console.log(' in onVideoUploadSuccess') + if (!item) { + item = this.item; + } + item.video_url = 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 +225,4 @@ export class FormComponent implements OnInit, OnChanges, OnDestroy { }, 1); } -} - +} \ No newline at end of file diff --git a/src/app/play/Unit.ts b/src/app/play/Unit.ts index b78f3f2c65d4e7535cb12b7da1dff9bb746eb0d2..5b74947641828f611993629e402115b43d608965 100644 --- a/src/app/play/Unit.ts +++ b/src/app/play/Unit.ts @@ -1,5 +1,6 @@ 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) { @@ -89,6 +92,8 @@ export class MySprite extends Sprite { this.width = this.img.width; this.height = this.img.height; + // this.img.setAttribute("crossOrigin",'Anonymous') + } this.anchorX = anchorX; @@ -114,16 +119,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 +229,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 +312,8 @@ export class MySprite extends Sprite { child.alpha = this.alpha; } + child.ctx = this.ctx; + } removeChild(child) { const index = this.children.indexOf(child); @@ -567,6 +588,7 @@ export class Label extends MySprite { // fontSize:String = '40px'; fontName = 'Verdana'; textAlign = 'left'; + textBaseline = 'middle'; fontSize = 40; fontColor = '#000000'; fontWeight = 900; @@ -596,7 +618,7 @@ export class Label extends MySprite { 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._width = this.ctx.measureText(this.text).width; @@ -819,11 +841,18 @@ export class RichTextOld extends Label { + export class RichText extends Label { - disH = 30; + topH = 0; + disH = 10; offW = 10; + row = 1; + textBaseline = "middle"; + + isShowWordBg = false; + wordBgData; constructor(ctx?: any) { super(ctx); @@ -831,7 +860,93 @@ 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; + } + + getSubTextRectGroup(text, targetIndex = 0) { + console.log('!!!wordBgData: ', this.wordBgData); + + const rectGroup = []; + const subTextArr = text.split(' '); + let baseIndex = targetIndex; + console.log('subTextArr: ', subTextArr); + for (let i=0; i<subTextArr.length; i++) { + const subText = subTextArr[i]; + if (!subText) { + continue; + } + const subData = this.getSubTextRect(subText, baseIndex) + if (subData) { + console.log('baseIndex1 : ', baseIndex); + rectGroup.push(subData); + baseIndex = Number( subData.index ) + subData.text.length; + console.log('baseIndex2 : ', baseIndex); + } + } + + return rectGroup; + } + + getSubTextRect(subText, targetIndex=0) { + + + + subText = subText.trim(); + if (!subText) { + return; + } + + + 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); + // console.log('targetIndex: ', targetIndex); + // 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() { @@ -839,12 +954,24 @@ export class RichText extends Label { return; } + let curCtx = this.ctx; - this.ctx.font = `${this.fontSize}px ${this.fontName}`; - this.ctx.textAlign = this.textAlign; - this.ctx.textBaseline = 'middle'; - this.ctx.fontWeight = this.fontWeight; - this.ctx.fillStyle = this.fontColor; + if (this._offCtx) { + + + + this._offCtx.save(); + this._offCtx.clearRect(0, 0, this.width, this.height); + + + curCtx = this._offCtx; + } + + curCtx.font = `${this.fontSize}px ${this.fontName}`; + curCtx.textAlign = this.textAlign; + curCtx.textBaseline = this.textBaseline; + curCtx.fontWeight = this.fontWeight; + curCtx.fillStyle = this.fontColor; const selfW = this.width * this.scaleX; @@ -856,39 +983,83 @@ 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 (curCtx.measureText(temp).width < w && curCtx.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 = curCtx.measureText(temp).width + const rectY = ( row.length ) * disH / this.scaleY + const rectW = curCtx.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 = this.topH//-row.length * disH / 2; // for (let b = 0 ; b < row.length; b++) { - // this.ctx.strokeText(row[b], x, y + ( b + 1 ) * disH ); // æ¯è¡Œå—体yåæ ‡é—´éš”20 + // curCtx.strokeText(row[b], x, y + ( b + 1 ) * disH ); // æ¯è¡Œå—体yåæ ‡é—´éš”20 // } if (this._outlineFlag) { - this.ctx.lineWidth = this._outLineWidth; - this.ctx.strokeStyle = this._outLineColor; + curCtx.lineWidth = this._outLineWidth; + curCtx.strokeStyle = this._outLineColor; for (let b = 0 ; b < row.length; b++) { - this.ctx.strokeText(row[b], x, y + ( b + 1 ) * disH ); // æ¯è¡Œå—体yåæ ‡é—´éš”20 + curCtx.strokeText(row[b], x, y + ( b + 0 ) * disH / this.scaleY ); // æ¯è¡Œå—体yåæ ‡é—´éš”20 } - // this.ctx.strokeText(this.text, 0, 0); + // curCtx.strokeText(this.text, 0, 0); } - // this.ctx.fillStyle = '#ff7600'; + // curCtx.fillStyle = '#ff7600'; for (let b = 0 ; b < row.length; b++) { - this.ctx.fillText(row[b], x, y + ( b + 1 ) * disH ); // æ¯è¡Œå—体yåæ ‡é—´éš”20 + curCtx.fillText(row[b], x, y + ( b + 0 ) * disH / this.scaleY ); // æ¯è¡Œå—体yåæ ‡é—´éš”20 + } + + + if (this._offCtx) { + + + 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(); + } + // console.log('aaaaa1'); + } + + this.ctx.drawImage(this._offCanvas, this._offX, this._offY); + this._offCtx.restore(); } } @@ -954,9 +1125,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 +1958,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) { @@ -1835,6 +2100,8 @@ export class MyVideo extends MySprite { this.width = this.element.videoWidth; this.height = this.element.videoHeight; + console.log('this.width: ', this.width); + console.log('this.height: ', this.height); this.element.currentTime = 0.01; } @@ -1846,6 +2113,403 @@ export class MyVideo extends MySprite { } } +export class InputView extends MySprite { + + element; + callback; + _isShowScroll = false; + + constructor(ctx=null) { + super(ctx); + this._createInput() + } + + set isShowScroll(v) { + this._isShowScroll = v; + if (!v) { + this.element.style.overflow = 'hidden'; + } + } + + get isShowScroll() { + return this._isShowScroll; + } + + _createInput() { + const input = document.createElement('textarea'); + input.style.resize = 'none'; + input.style.border = 'none'; + + input.style.position = 'absolute'; + input.onblur = this.onblur.bind(this); + + const div = document.getElementById('div_input'); + div.appendChild(input); + + this.element = input; + } + + onblur() { + + if (this.callback) { + this.callback(this.element.value); + } + this.callback = null; + this.hide(); + } + + set text(v) { + this.element.value = v; + } + + show() { + this.element.hidden = false; + setTimeout(() => { + this.element.focus(); + }, 1); + } + + hide() { + this.element.hidden = true; + } + + setStyle(style) { + for ( let key in style ) { + console.log('key: ', key) + console.log('value: ', style[key]) + this.element.style[key] = style[key]; + } + console.log('this.element: ``````', this.element) + } + + refreshInputStyle() { + this.element.style.left = this.x + 'px'; + this.element.style.top = this.y + 'px'; + this.element.style.width = this.width + 'px'; + this.element.style.height = this.height + 'px'; + } + +} + +export class ScrollView extends MySprite { + + static ScrollSideType = { + VERTICAL : 'VERTICAL', + HORIZONTAL : 'HORIZONTAL', + } + + _offCtx; + _offCanvas; + _scrollBar; + + content; + bgColor; + barColor = '#fbe9b7' + scrollSide = ScrollView.ScrollSideType.VERTICAL; + + scorllBarWidth; + scrollBarHeight; + 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; + } + + setContentScale(s) { + this.content.setScaleXY( 1 / s); + this.refreshScrollBar(); + } + + 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 -------------------- diff --git a/src/app/play/Util.js b/src/app/play/Util.js new file mode 100644 index 0000000000000000000000000000000000000000..7c7d8ae298ba36c8af5e83a50ad3a5af0622b39d --- /dev/null +++ b/src/app/play/Util.js @@ -0,0 +1,34 @@ + + + + +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 -------------------- + diff --git a/src/app/play/checker.ts b/src/app/play/checker.ts new file mode 100644 index 0000000000000000000000000000000000000000..4fe05b5121ddf710d086d7c4640384a3907ab469 --- /dev/null +++ b/src/app/play/checker.ts @@ -0,0 +1,312 @@ +import { data } from "./words"; + +export function checkAnswer(type, string, word) { + console.log('word: ', word); + switch (type) { + case 'device': + case 'side': + case 'work': + case 'adj': + return WordData.getInstance().check(type, string); + case 'name': + case 'city': + return checkCity(string); + case 'time': + return checkTime(string); + case 'date': + return checkDate(string); + case 'word': + return checkWord(string, word); + case 'wordList': + return checkWordInList(string, word); + default: + throw "é”™è¯¯çš„æ ¼å¼"; + } +} + +function checkCity(string) { + const bigCase = ('ABCDEFGHIJKLMNOPQRSTUVWXYZ').split(''); + const smallCase = ('abcdefghijklmnopqrstuvwxyz').split(''); + const right = string.split(' ') + .filter(word => word != '') + .every(word => { + return word.split('') + .every((letter, idx) => { + if (idx == 0) { + return bigCase.includes(letter) + && !smallCase.includes(letter); + } else { + return !bigCase.includes(letter) + && smallCase.includes(letter); + } + }); + }); + + return { + right: right, + info: '专有åè¯é¦–å—æ¯åº”该大写。', + } +} + +function checkTime(string) { + const rightResult = { + right: true, + info: '', + } + const wrongResult = { + right: false, + info: 'timeæ ¼å¼å¡«å†™é”™è¯¯ã€‚æ£ç¡®æ ¼å¼ä¸ºâ€œæ—¶ 分â€, 例如:ten thirty', + }; + if (string.includes(":")) { + const words = string.split(":"); + if (words.length != 2) { + return wrongResult; + } + + if (words.some(word => word.length > 2)) { + return wrongResult; + } + + const hour = parseInt(words[0]); + const minute = parseInt(words[1]); + if (hour < 0 || 12 < hour) { + return wrongResult; + } + if (minute < 0 || 59 < minute) { + return wrongResult; + } + return rightResult; + } + + const hours = [ + "one", "two", "three", "four", "five", "six", + "seven", "eight", "nine", "ten", "eleven", "twelve" + ]; + + const minutes = [ + "o'clock", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", + "eleven", "twelve", "thirteen", "fourteen", "fifteen", "a quarter", "sixteen", "seventeen", "eighteen", "nineteen", "twenty", + "twenty-one", "twenty-two", "twenty-three", "twenty-four", "twenty-five", "twenty-six", "twenty-seven", "twenty-eight", "twenty-nine", "thirty", "half", + "thirty-one", "thirty-two", "thirty-three", "thirty-four", "thirty-five", "thirty-six", "thirty-seven", "thirty-eight", "thirty-nine", "forty", + "forty-one", "forty-two", "forty-three", "forty-four", "forty-five", "three quarter", "forty-six", "forty-seven", "forty-eight", "forty-nine", "fifty", + "fifty-one", "fifty-two", "fifty-three", "fifty-four", "fifty-five", "fifty-six", "fifty-seven", "fifty-eight", "fifty-nine", + ]; + + const middles = [ + 'to', + 'past' + ]; + + const middleWord = middles.find(word => string.includes(word)); + if (middleWord) { + const strings = string.split(middleWord); + if (minutes.some(word => strings[0].trim().toLowerCase() == word)) { + if (hours.some(word => strings[1].trim().toLowerCase() == word)) { + return rightResult; + } + } + return wrongResult; + } + + const strings = string.split(' '); + if (hours.some(word => strings[0].trim().toLowerCase() == word)) { + if (minutes.some(word => strings[1].trim().toLowerCase() == word)) { + return rightResult; + } + } + return wrongResult; +} + +function checkDate(string: string) { + const wrongResult = { + right: false, + info: 'dateæ ¼å¼å¡«å†™é”™è¯¯ã€‚æ£ç¡®æ ¼å¼ä¸ºâ€œæ—¥ 月 å¹´â€, 例如:15th August 2008', + }; + const rightResult = { + right: true, + info: '', + } + + let numberList = []; + + if (string.includes('.')) { + numberList = string.split('.').map(string => parseInt(string)); + } else { + const days1 = [ + 'none', + 'First', 'second', 'third', 'fourth', + 'fifth', 'sixth', 'seventh', 'eighth', + 'ninth', 'tenth', 'eleventh', 'twelfth', + 'thirteenth', 'fourteenth', 'fifteenth', 'sixteenth', + 'seventeenth', 'eighteenth', 'nineteenth', 'Twentieth', + 'twenty-first', 'twenty-second', 'Twenty-third', 'twenty-fourth', + 'Twenty-fifth', 'Twenty-sixth', 'twenty-seventh', 'Twenty-eighth', + 'twenty-ninth', 'Thirtieth', 'Thirty-first' + ]; + const days2 = [ + 'none', + '1st', '2nd', '3rd', '4th', + '5th', '6th', '7th', '8th', + '9th', '10th', '11th', '12th', + '13th', '14th', '15th', '16th', + '17th', '18th', '19th', '20th', + '21st', '22nd', '23rd', '24th', + '25th', '26th', '27th', '28th', + '29th', '30th', '31st' + ] + const months = [ + 'none', + 'January', 'February', 'March', 'April', + 'May', 'June', 'July', 'August', + 'September', 'October', 'November', 'December' + ]; + let yearFlg = false; + let monthFlg = false; + let dayFlg = false; + numberList = string.split(' ').map(string => { + if (!monthFlg) { + const month = months.findIndex(str => str == string); + if (month >= 1) { + monthFlg = true; + return month; + } + } + if (!dayFlg) { + let day = days1.findIndex(str => str == string); + if (day >= 1) { + dayFlg = true; + return day; + } + day = days2.findIndex(str => str == string); + if (day >= 1) { + dayFlg = true; + return day; + } + } + if (!yearFlg) { + const year: number = parseInt(string); + if (!isNaN(year)) { + yearFlg = true; + return year; + } + } + }); + } + + console.log('numberList = ' + JSON.stringify(numberList)); + + if (numberList.length < 2 || 3 < numberList.length) { + return wrongResult; + } + + if (numberList.some(num => !num)) { + // 有null或者undefind + return wrongResult; + } + + if (numberList.some(num => num <= 0)) { + // è´Ÿæ•° + return wrongResult; + } + + let rightFlg = true; + let yearFlg = false; + let monthFlg = false; + let dayFlg = false; + numberList.forEach((number, idx) => { + if (number > 31) { + if (!yearFlg) { + if (idx == 1) { + rightFlg = false; + } else { + yearFlg = true; + } + } else { + rightFlg = false; + } + } else if (number > 12) { + if (!dayFlg) { + dayFlg = true; + } else { + rightFlg = false; + } + } else { + if (!monthFlg) { + monthFlg = true; + } else if (!dayFlg) { + dayFlg = true; + } else { + rightFlg = false; + } + } + }); + + if (!monthFlg || !dayFlg) { + rightFlg = false; + } + + if (rightFlg) { + return rightResult; + } + + return wrongResult; +} + +function checkWord(string: string, word: string) { + if (string.trim() != word.replace(/_/g, " ").trim()) { + return { right: false, info: word.replace(/_/g, " ").trim() }; + } + return { right: true, info: '' }; +} + +function checkWordInList(string: any, word: any) { + const wordList: Array<string> = word; + if (wordList.includes(string)) { + return { + right: wordList.includes(string), + info: '错误的å•è¯ã€‚' + }; + } else { + return { + right: false, + info: '错误的å•è¯ã€‚' + } + } +} + +export class WordData { + + static _instance = null; + static getInstance(): WordData { + if (!WordData._instance) { + WordData._instance = new WordData(); + } + return WordData._instance; + } + + constructor() { + this.device = data.device; + this.side = data.side; + this.work = data.work; + this.adj = data.adj; + } + + device = ['TV', 'heater']; + side = ['north']; + work = ['teacher', 'worker']; + adj = ['big', 'small']; + + check(type: any, string: any) { + const wrongString = { + device: '电器å错误。', + side: 'æ–¹å‘åè¯é”™è¯¯ã€‚', + work: '工作å错误。', + adj: '形容è¯é”™è¯¯ã€‚', + } + return { + right: this[type].includes(string.trim()), + info: wrongString[type], + }; + } +} + diff --git a/src/app/play/play.component.css b/src/app/play/play.component.css index bbda49566c0a6aa2c621e2f863caf1849e492572..5ffd4bb6b12a684b61a6597d079ec95fa70acdd6 100644 --- a/src/app/play/play.component.css +++ b/src/app/play/play.component.css @@ -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 diff --git a/src/app/play/play.component.html b/src/app/play/play.component.html index 960fb495a359c3c7803c4370d8c7d8457517d70e..fe15e8d7bd87865cd914b9699aab9a570664a5b5 100644 --- a/src/app/play/play.component.html +++ b/src/app/play/play.component.html @@ -1,3 +1,24 @@ -<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> + + + +<ng-template #tpl> + <video></video> +</ng-template> +<div style="display: none" #videoContainer></div> + + +<div class="game-container" #wrap > + <canvas id="canvas" style="width: 100%; height: 100%;" #canvas></canvas> </div> + +<div id='div_input'> + +</div> + +<!-- <div style="position: absolute; top: 0"> + <label style="font-family: Aileron-Black;"></label> + <label style="font-family: DroidSansFallback;"></label> +</div> --> diff --git a/src/app/play/play.component.ts b/src/app/play/play.component.ts index 722f061f157a6447b2ffe05ba064b845a7fc5085..c0a3284f1fd42a4227664f65aca24d451414b119 100644 --- a/src/app/play/play.component.ts +++ b/src/app/play/play.component.ts @@ -1,17 +1,28 @@ -import {Component, ElementRef, ViewChild, OnInit, Input, OnDestroy, HostListener} from '@angular/core'; +import { Component, ElementRef, ViewChild, OnInit, Input, OnDestroy, HostListener, ApplicationRef, ViewContainerRef, TemplateRef } 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, InputView, ShapeCircle, MyVideo, getMinScale, } 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 { checkAnswer } from './checker'; +import { HttpClient } from '@angular/common/http'; + @@ -21,23 +32,47 @@ 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; + + @ViewChild('videoNode', {static: true }) videoNode: ElementRef; + @ViewChild('tpl', {static: true }) tpl: TemplateRef<void>; + @ViewChild('videoContainer', {static: true }) videoContainer: 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,137 +84,3743 @@ 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_MATH01'; + + // ----- + 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 http: HttpClient, private sanitizer: DomSanitizer, private appRef: ApplicationRef, private container: ViewContainerRef) { + + } + + isTeacher = false; + + async ngOnInit() { + + + + 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 = { contentObj: data }; + } else { + + this.initDefaultData(); + } + + console.log('data:', data); + if (!this.data) { + this.data.contentObj = {}; + } + + + + + this.initAudio(); + this.initImg(); + this.preloadVideo(); + this.initListener(); + + + }, this.KEY); + + + } + + + + // 用于å˜å‚¨ç§æœ‰æ•°æ® 当翻页时清空 + storeData; + initStoreData(aspect) { + const storeDataStr = aspect?.user_aspect; + if (!storeDataStr) { + this.storeData = {}; + } else { + this.storeData = JSON.parse(storeDataStr); + } + console.log('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); + } + } + } + + + + // 用于å˜å‚¨å…¬å…±æ•°æ® 当翻页时清空 + 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); + } + } + } + + + + initDefaultData() { + + const data = {"sentenceArr":[],"templateArr":[],"bg_url":"http://staging-teach.cdn.ireadabc.com/1aaccbaa8f3a32df099f3308feac49e7.png","title":"new word","bgItem":{"url":"http://staging-teach.cdn.ireadabc.com/e3672206ffa9736c449b64d05f688b30.png","rect":{"x":102.83,"y":0,"width":485.33,"height":273}},"hotZoneItemArr":[{"id":"1634265930328","index":0,"itemType":"rect","fontScale":0.53984375,"imgScale":1,"imgSizeW":0,"imgSizeH":0,"mapScale":0.53984375,"dragDot":{"x":345.5,"y":133.26904532304724},"gIdx":"0","selectType":"JJ","posX":282.5,"posY":52,"rect":{"x":13.35,"y":22.52,"width":136.5,"height":25.94}},{"id":"1634265945079","index":1,"itemType":"rect","fontScale":0.53984375,"imgScale":1,"imgSizeW":0,"imgSizeH":0,"mapScale":0.53984375,"dragDot":{"x":345.5,"y":133.26904532304724},"gIdx":"0","selectType":"RB","posX":552.5,"posY":59,"rect":{"x":197.63,"y":27.98,"width":136.5,"height":24.57}},{"id":"1634265955820","index":2,"itemType":"rect","fontScale":0.53984375,"imgScale":1,"imgSizeW":0,"imgSizeH":0,"mapScale":0.53984375,"dragDot":{"x":345.5,"y":133.26904532304724},"gIdx":"0","selectType":"WP","posX":281.5,"posY":129,"rect":{"x":12.67,"y":73.71,"width":136.5,"height":28.67}},{"id":"1634265962408","index":3,"itemType":"rect","fontScale":0.53984375,"imgScale":1,"imgSizeW":0,"imgSizeH":0,"mapScale":0.53984375,"dragDot":{"x":345.5,"y":133.26904532304724},"gIdx":"0","selectType":"CD","posX":548.5,"posY":132,"rect":{"x":194.9,"y":75.08,"width":136.5,"height":30.03}},{"id":"1634265967558","index":4,"itemType":"rect","fontScale":0.53984375,"imgScale":1,"imgSizeW":0,"imgSizeH":0,"mapScale":0.53984375,"dragDot":{"x":345.5,"y":133.26904532304724},"gIdx":"0","selectType":"IN","posX":284.5,"posY":213,"rect":{"x":14.72,"y":131.72,"width":136.5,"height":27.3}},{"id":"1634266027751","index":5,"itemType":"rect","fontScale":0.53984375,"imgScale":1,"imgSizeW":0,"imgSizeH":0,"mapScale":0.53984375,"dragDot":{"x":345.5,"y":133.26904532304724},"gIdx":"0","selectType":"VB","posX":292.5,"posY":320,"rect":{"x":20.18,"y":202.7,"width":136.5,"height":31.4}},{"id":"1634266044165","index":6,"itemType":"rect","fontScale":0.53984375,"imgScale":1,"imgSizeW":0,"imgSizeH":0,"mapScale":0.53984375,"dragDot":{"x":345.5,"y":133.26904532304724},"gIdx":"0","selectType":"NN","posX":544.5,"posY":308,"rect":{"x":192.17,"y":194.51,"width":136.5,"height":31.4}},{"id":"1634266050496","index":7,"itemType":"rect","fontScale":0.53984375,"imgScale":1,"imgSizeW":0,"imgSizeH":0,"mapScale":0.53984375,"dragDot":{"x":345.5,"y":133.26904532304724},"gIdx":"0","selectType":"NN","posX":759.5,"posY":323,"rect":{"x":338.91,"y":204.75,"width":136.5,"height":31.4}}]} + + this.data = { contentObj: data }; + + + } + + ngOnDestroy() { + window['curCtx'] = null; + window.cancelAnimationFrame(this.animationId); + this.gameEndFlag = true; + } + + sentenceArr = []; + submitCount = 0; + safeDefaultUrl; + resultAnswerArr; + + scrollView; + resultSv; + userResultPic; + userResultData; + uploadUrl; + + + + templateQuesType; + TYPE_SHORT_ANSWER = 'short_answer'; + TYPE_SINGLE_CHOICE = 'single_choice'; + 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.renderArr = []; + this.topArr = []; + this.userResultPic = null; + this.userResultData = null; + + console.log(' in initData', this.data); + + + this.templateQuesType = this.data.contentObj.ques_type; + + + + this.uploadUrl = (<any> window).courseware.uploadUrl(); + window['air'].getUploadCallback = (url, data) => { + this.uploadUrl = url; + }; + + + + 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(/_/, "____________________") + } + } + + + + 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.hotZoneItemArr; + addUrlToAudioObj(contentObj.title_audio_url); + + + if (arr) { + // console.log('arr: ', arr); + for (let i = 0; i < arr.length; i++) { + addUrlToAudioObj(arr[i].audio_url); + } + } + + const optionArr = contentObj.optionArr; + for (let i=0; i<optionArr.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(); + // }; + + + } + + videoObj; + preloadVideo() { + + this.videoObj = {}; + const addVideoUrl = (video_url) => { + + if (!video_url) { + return; + } + + const videoElement = document.createElement('video'); + videoElement.src = video_url; + this.videoContainer.nativeElement.appendChild(videoElement); + + console.log('tmpV: ', videoElement); + + const video = new MyVideo(); + video.initVideoElement(videoElement); + video.setScaleXY(this.mapScale); + video.element.src = video_url; + video.element.load(); + this.videoObj[video_url] = video; + + video.element.addEventListener('canplaythrough', () => { + this.refreshVideoSize(video); + }); + } + + + const optionArr = this.data.contentObj.optionArr; + for (let i=0; i<optionArr.length; i++) { + addVideoUrl(optionArr[i].video_url || ''); + + const op2Arr = optionArr[i]; + for (let j=0; j<op2Arr.length; j++) { + addVideoUrl(op2Arr[j].pic_url || ''); + } + } + } + + initImg() { + + const contentObj = this.data.contentObj; + if (contentObj) { + + + const addPicUrl = (url) => { + if (url) { + this.rawImages.set(url, url); + } + }; + + let arr = contentObj.hotZoneItemArr; + if (arr) { + + for (let i = 0; i < arr.length; i++) { + + console.log('arr[i].pic_url: ', arr[i].pic_url); + addPicUrl(arr[i].pic_url); + } + } + + addPicUrl(contentObj.bgItem?.url || ''); + addPicUrl(contentObj.bg_url || ''); + addPicUrl(contentObj.ques_pic_url || ''); + addPicUrl(contentObj.title_pic_url || ''); + + + const optionArr = contentObj.optionArr; + for (let i=0; i<optionArr.length; i++) { + addPicUrl(optionArr[i].pic_url || ''); + addPicUrl(optionArr[i].title_pic_url || ''); + + + const optionArr2 = optionArr[i].optionArr; + for (let j=0; j<optionArr2.length; j++) { + addPicUrl(optionArr2[j].pic_url || ''); + } + + addPicUrl(optionArr[i].ques_pic_url); + + } + + } + + + + + // this.initFontImg(); + + + + + // é¢„åŠ è½½èµ„æº + + + + this.loadResources().then(() => { + // 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(); + } + }); + } + + + sendServerEvent(key, data) { + + const c = window['courseware']; + if (c) { + c.sendEvent(key, data); + } + } + + localStartTime = new Date().getTime(); + gameStart() { + // this.localStartTime = new Date().getTime(); + // console.log(' in gameStart '); + // if (this.isTeacher) { + // this.sendBtn.visible = false; + // this.sendBtn.shadowSpr.visible = false; + // this.maskPic.visible = true; + // } else { + // // this.changeBtnOn(); + // this.maskPic.visible = false; + + // } } - ngOnInit() { - this.data = {}; - // èŽ·å–æ•°æ® - const getData = (<any> window).courseware.getData; - getData((data) => { - if (data && typeof data == 'object') { - this.data = data; - } - // console.log('data:' , data); - // åˆå§‹åŒ– å„äº‹ä»¶ç›‘å¬ - this.initListener(); - // è‹¥æ— æ•°æ® åˆ™ä¸ºé¢„è§ˆæ¨¡å¼ éœ€è¦å¡«å……一些默认数æ®ç”¨æ¥æ˜¾ç¤º - this.initDefaultData(); + init() { + + this.initData(); + this.initCtx(); + + this.initView(); + + + } + + initCtx() { + + this.ctx = this.canvas.nativeElement.getContext('2d'); + this.canvas.nativeElement.width = this.canvasWidth; + this.canvas.nativeElement.height = this.canvasHeight; + + window['curCtx'] = this.ctx; + + + } + + + + + + + + initView() { + + + this.initBg(); + this.initHotZone(); + // this.setOneBtn(); + // this.initMaskPic(); + // this.relink(); + + // this.checkShowSubmit(); + + + this.initVideo(); + + + + if (this.data.contentObj.ques_type == this.TYPE_SINGLE_CHOICE) { + this.playHotZoneItemSC(); + } else { + this.playHotZoneItemSA(); + } + + + } + + videoCloseBtn; + videoBg; + videoMask; + replayBtn; + initVideo() { + + const videoMask = new ShapeRect(); + videoMask.setSize(this.canvasWidth, this.canvasHeight); + videoMask.fillColor = '#f4ecd8'; + videoMask.alpha = 0.7; + this.topArr.push(videoMask); + this.videoMask = videoMask; + videoMask.visible = false; + + const videoBg = this.getMySprite('video_bg'); + videoBg.setScaleXY(this.mapScale); + videoBg.visible = false; + + // videoBg.anchorX = 1; + videoBg.x = this.canvasWidth / 2 - videoBg.width / 2 * videoBg.scaleX; + videoBg.y = this.canvasHeight / 2; + this.topArr.push(videoBg); + this.videoBg = videoBg; + + const videoCloseBtn = this.getMySprite('btn_close'); + videoCloseBtn.x = videoBg.width / 2 - 100; + videoCloseBtn.y = -videoBg.height / 2 + 53; + videoBg.addChild(videoCloseBtn); + + this.videoCloseBtn = videoCloseBtn; + + const replayBtn = this.getMySprite('btn_replay') + this.videoBg.addChild(replayBtn); + replayBtn.y = this.videoBg.height / 2 - 130; + replayBtn.visible = false; + this.replayBtn = replayBtn; + + + } + + curVideo; + initVideoPlayer(data) { + + if (this.curVideo) { + this.curVideo.parent.removeChild(this.curVideo); + this.curVideo = null; + } + const video = this.videoObj[data.video_url]; + if (video) { + + this.videoBg.addChild(video); + this.refreshVideoSize(video); + video.element.currentTime = 0.01; + video.element.play(); + this.curVideo = video; + + this.replayBtn.visible = false; + + + video.element.onended = () => { + this.replayBtn.visible = true; + } + + } + } + + refreshVideoSize(video) { + if (!video.parent) { + return; + } + + video.width = video.element.videoWidth; + video.height = video.element.videoHeight; + const sx = video.parent.width / video.element.videoWidth; + const sy = video.parent.height / 2 / video.element.videoHeight; + + + console.log('sx: ', sx); + console.log('sy: ', sy); + + + video.setScaleXY(Math.min(sx, sy)); + + video.x = - video.width / 2 * video.scaleX; + video.y = - video.height / 2 * video.scaleY; + + } + + playHotZoneItemSA() { + const arr = this.hotZoneArr; + console.log('in showHotZonePic arr: ', arr); + if (!arr || arr.length == 0) { + return; + } + + console.log('in showHotZonePic 1'); + + let index = 0; + const showOneHotZone = () => { + + console.log(' in showOneHotZone') + if (index > arr.length - 1) { + + return; + } + + + const {data} = arr[index]; + if (data.gIdx == '0' || data.gIdx == '2' || data.gIdx == '3') { + + this.showHotZonePic(arr[index]); + + if (data.gIdx == '0') { + this.lastHotZoneItem = arr[index]; //记录最åŽä¸€ä¸ªæ˜¾ç¤ºitem åŽé¢è¦æ›¿æ¢ + } + + if (data.audio_url) { + this.playAudio(data.audio_url, true, () => { + + index ++; + showOneHotZone(); + }) + } else { + index ++; + showOneHotZone(); + } + + + } else { + index ++; + showOneHotZone(); + } + } + + showOneHotZone(); + } + + + lastHotZoneItem; + playHotZoneItemSC() { + + const arr = this.hotZoneArr; + console.log('in showHotZonePic arr: ', arr); + if (!arr || arr.length == 0) { + return; + } + + console.log('in showHotZonePic 1'); + + let index = 0; + const showOneHotZone = () => { + + console.log(' in showOneHotZone') + if (index > arr.length - 1) { + + return; + } + + + const {data} = arr[index]; + if (data.gIdx == '0' || data.gIdx == '1') { + + this.showHotZonePic(arr[index]); + + if (data.gIdx == '0') { + this.lastHotZoneItem = arr[index]; //记录最åŽä¸€ä¸ªæ˜¾ç¤ºitem åŽé¢è¦æ›¿æ¢ + } + + if (data.audio_url) { + this.playAudio(data.audio_url, true, () => { + + index ++; + showOneHotZone(); + }) + } else { + index ++; + showOneHotZone(); + } + + + } else { + index ++; + showOneHotZone(); + } + } + + showOneHotZone(); + + } + + showSmallTitle(data) { + + const imgObj = this.images.get(data.title_pic_url); + this.lastHotZoneItem.init(imgObj); + this.showHotZonePic(this.lastHotZoneItem); + + + if (data.title_audio_url) { + this.playAudio(data.title_audio_url, true) + } + + } + + showHotZonePic(item) { + console.log('item: ', item); + item.visible = true; + item.alpha = 0; + + tweenChange(item, {alpha: 1}, 0.5); + } + + + + showSubmit() { + if(this.submitBtn){ + this.submitBtn.visible = true; + this.submitBtn.alpha = 1; + this.submitBtn.shadowSpr.visible = true; + this.submitBtn.shadowSpr.alpha = 1; + } + } + + hideSubmit() { + if(this.submitBtn){ + this.submitBtn.visible = false; + this.submitBtn.alpha = 0; + this.submitBtn.shadowSpr.visible = false; + this.submitBtn.shadowSpr.alpha = 0; + } + } + + removeSubmit() { + if(this.submitBtn){ + this.submitBtn.parent.removeChild(this.submitBtn); + this.submitBtn.shadowSpr.parent.removeChild(this.submitBtn.shadowSpr); + + this.submitBtn = null; + } + } + + + testInput() { + + const tmpRect = this.sentenceEmptyArr[0].getBoundingBox(); + + const svBox = this.scrollView.getBoundingBox(); + + + const x = svBox.x + tmpRect.x * this.mapScale; + const y = svBox.y + tmpRect.y * this.mapScale; + const width = tmpRect.width * this.mapScale; + const height = tmpRect.height * this.mapScale; + const rect = {x, y, width, height}; + + + + console.log('rect: ', rect); + + + + // const shape = new ShapeRectNew(); + // shape.setSize(200, 200, 1); + // shape.fillColor = '#0000ff' + // shape.x = 500; + // shape.y = 500; + // this.topArr.push(shape); + + + + } + + inputView; + showInputView(style, rect, value, cb) { + if (!this.inputView) { + this.inputView = new InputView(); + this.inputView.isShowScroll = true; + } + + const inputView = this.inputView; + + if (inputView.callback) { + inputView.onblur(); + } + + inputView.show(); + + inputView.x = rect.x / this.canvasScale ; // this.canvasWidth / 2; + inputView.y = rect.y / this.canvasScale ; // this.canvasHeight / 2; + inputView.width = rect.width / this.canvasScale ; + inputView.height = rect.height / this.canvasScale ; + inputView.text = value; + inputView.callback = cb; + inputView.setStyle(style); + + + inputView.refreshInputStyle(); + } + + hideInputView() { + if (!this.inputView) { + return; + } + this.inputView.hide(); + } + + + + relink() { + + const progress = this.getPageData('progress'); + + if (this.isTeacher) { + if (progress != null) { + this.gameStart(); + return; + } + return; + } + + + if (progress == '1') { + + this.gameStart(); + + const resultData = this.getStoreData('resultData') + if (resultData) { + this.initResultView(resultData); + return; + } + + return; + } + + // if (progress == '2' || progress == '3') { + // const submitCount = this.getPageData('submitCount') + // this.submitCount = submitCount; + // this.checkShowSubTemplateOne(); + // return; + // } + + } + + + maskPic; + initMaskPic() { + const bgUrl = this.data.contentObj.bg_url; + console.log('bgUrl', bgUrl); + + const maskPic = this.getMySprite(bgUrl); + const sx = this.canvasWidth / maskPic.width; + const sy = this.canvasHeight / maskPic.height; + const s = Math.max(sx, sy); + maskPic.setScaleXY(s); + maskPic.x = this.canvasWidth / 2; + maskPic.y = this.canvasHeight / 2; + + if (this.isTeacher) { + maskPic.visible = false; + } + + this.maskPic = maskPic; + } + + + getMySprite(resName, isSetScale = true) { + const spr = new MySprite(); + spr.init(this.images.get(resName)) + if (isSetScale) { + spr.setScaleXY(this.mapScale); + } + return spr; + } + + + setRectRight(data) { + + console.log("in setRectRight : ", data); + + for (let i=0; i<this.hotZoneArr.length; i++) { + this.hotZoneArr[i].result = data[i]; + if (data[i] && data[i].right) { + this.hotZoneArr[i].isRight = true; + } else { + this.hotZoneArr[i].isRight = false; + } + } + } + + resultLayer; + resultPanel; + moreBtn; + initResultView(data = null) { + + + if (data) { + console.log('initResultView data : ', data) + this.setRectRight(data); + } else { + const resultData = this.getResultData(); + this.userResultData = resultData; + this.sendResult(); + 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 = 0 //-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.hotZoneArr.length; i++) { + const result = this.hotZoneArr[i].result; + result.userAnswer = this.hotZoneArr[i].label?.text || ''; + dataArr.push(result); + } + 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; + + console.log('hotZoneArr: ', this.hotZoneArr); + + const tmpLabel = new Label(); + tmpLabel.fontSize = 48; + tmpLabel.fontColor = '#ffffff' + tmpLabel.fontName = 'DroidSansFallback'; + + + let baseY = 0 //-500; + for (let i=0; i<this.hotZoneArr.length; i++) { + + const result = this.hotZoneArr[i].result; + + const richText = new RichText(); + richText.disH = 5; + // richText.x = -this.panel.width / 2 * 0.9 + richText.x = 0.05 * this.resultPanel.width; + richText.y = baseY + 80; + + richText.fontSize = 48; + richText.width = this.resultPanel.width * 0.9; + richText.fontColor = '#ffffff' + richText.fontName = 'DroidSansFallback'; + richText.text = result.userAnswer; + + // this.resultPanel.addChild(richText, 1) + + + + // const rect = richText.getBoundingBox(); + // richText.refreshSize(); + + tmpLabel.text = richText.text; + tmpLabel.refreshSize(); + let rectW = tmpLabel.width < 100 ? 100 : tmpLabel.width; + + const rect = {x: richText.x, y: richText.y, width: rectW, height: richText.fontSize}; + + const addW = 18 + rect.width += addW; + rect.height += 16; + // rect.x += addW / 2; + const colorRect = new ShapeRectNew(); + colorRect.setSize(rect.width, rect.height, 10); + // colorRect.alpha = 0.3; + + colorRect.fillColor = '#007b3e' + const offX = 9; + colorRect.x = rect.x // + offX; + colorRect.y = rect.y - rect.height / 2; + // colorRect.alpha = 0.5; + resultSv.addItem(colorRect); + resultSv.addItem(richText); + + + + baseY = richText.y + richText.getAreaHeight(); + if (result.isAi) { + colorRect.alpha = 0; + + const infoBg = new ShapeRectNew(); + // infoBg.init(this.images.get("info_bg")); + infoBg.setSize(1838, 120, 60); + infoBg.fillColor = '#3b962e'; + infoBg.y = baseY //+ 50; + infoBg.x = (this.resultPanel.width - infoBg.width) / 2//* this.mapScale; + // 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("ai_icon")); + infoIcon.x = 100; + infoIcon.y = 60; + infoBg.addChild(infoIcon); + + + this.addResultLabelCircle(richText, result); + const tmpH = this.getInfoLabelLayer(infoBg, result); + if (tmpH < 60) { + infoBg.visible = false; + } else { + baseY += tmpH; + infoBg.height = tmpH; + resultSv.refreshContentSize(); + } + + + + } else if (!this.hotZoneArr[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.hotZoneArr[i].result?.info || ''; + infoBg.addChild(infoLabel); + + } else { + const labelAnswer = this.getFillLabel(); + labelAnswer.fontSize = 48; + labelAnswer.fontColor = '#ffffff' + labelAnswer.fontName = 'Aileron-Black'; + labelAnswer.text = this.hotZoneArr[i].result?.info || ''; + labelAnswer.setScaleXY(1); + labelAnswer.textAlign = 'center'; + + labelAnswer.refreshSize(); + labelAnswer.x = colorRect.width / 2; + labelAnswer.y = colorRect.height / 2; + + // colorRect.addChild(labelAnswer); + } + + + if (i != this.hotZoneArr.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 + } + + + } + + console.log('this.resultSv.height: ', this.resultSv.heigth); + console.log('this.resultSv.box height: ', this.resultSv.getBoundingBox().height); + + } + + getInfoLabelLayer(infoBg, result) { + + const {resultTextArr, iconData} = result; + + const arr = []; + for (let k in iconData) { + iconData[k].index = k ; + arr.push(iconData[k]) + } + + const layer = new MySprite(); + + let baseIndex = 0; + let tmpH = 40; + for (let i=0; i<arr.length; i++) { + + const circle = new ShapeCircle(); + circle.setRadius(30); + circle.x = 200; + circle.y = tmpH + 20; + circle.fillColor = '#dcc077' + infoBg.addChild(circle); + + const label = new Label(); + label.text = (i+1).toString(); + label.fontColor = '#ffffff'; + label.textAlign = 'center'; + label.fontName = 'Aileron-Bold'; + label.y = 3; + circle.addChild(label); + + const infoLabel = new RichText(); + infoLabel.topH = 0; + infoBg.addChild(infoLabel); + + infoLabel.x = 230; + infoLabel.fontSize = 48; + infoLabel.y = tmpH + 20; + infoLabel.width = infoBg.width * 0.8; + infoLabel.fontColor = '#ffe9b1' + infoLabel.fontName = 'Aileron-Black'; + infoLabel.text = arr[i].dataArr[0].reason; + + tmpH = infoLabel.y + infoLabel.getAreaHeight(); + + // const rect = lastRect.rect; + // rect.x -= rect.width; + // rect.y -= rect.height / 2; + // const colorRect = this.getColorRect(rect); + // colorRect.alpha = 0.5; + // // colorRect.y -= rect.height; + // // infoLabel.addChild(colorRect); + + // const circle = new ShapeCircle(); + // circle.setRadius(20); + // circle.fillColor = '#dcc077'; + // circle.x = rect.x + rect.width; + // circle.y = rect.y; + // infoLabel.addChild(circle); + + // const label = new Label(); + // label.textAlign = 'center'; + // label.fontColor = '#ffffff'; + // label.fontSize = 30; + // label.text = (i + 1).toString() + // circle.addChild(label); + + + } + + return tmpH + + // const infoLabel = new RichText(); + // infoBg.addChild(infoLabel); + + // 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.getOneAiResultText(result);// this.hotZoneArr[i].result?.info || ''; + // this.addResultLabelCircle(infoLabel, result); + + } + + getOneAiResultText(result) { + + const {resultTextArr} = result; + let curText = ''; + for (let i=0; i<resultTextArr.length; i++) { + curText += resultTextArr[i].text + ''; + } + console.log(' in getOneAiResultText ', resultTextArr); + return curText; + } + + addResultLabelCircle(infoLabel, result) { + const {resultTextArr, iconData} = result; + + let baseIndex = 0; + for (let i=0; i<resultTextArr.length; i++) { + const curText = resultTextArr[i].text; + // const rect = infoLabel.getSubTextRect(curText)?.rect; + const rectGroup = infoLabel.getSubTextRectGroup(curText, baseIndex); + if (!rectGroup) { + continue; + } + + console.log('~rectGroup: ', rectGroup); + + // const rectFirst = rectGroup[0]; + + if (!rectGroup || rectGroup.length == 0) { + continue; + } + + const lastRect = rectGroup[rectGroup.length - 1]; + const key = lastRect.index + lastRect.text.length; + + console.log('~key: ', key); + console.log('~rect: ', lastRect); + console.log('iconData: ', iconData); + if (!iconData[key]) { + continue; + } + + const rect = lastRect.rect; + rect.x -= rect.width; + rect.y -= rect.height / 2; + const colorRect = this.getColorRect(rect); + colorRect.alpha = 0.5; + // colorRect.y -= rect.height; + // infoLabel.addChild(colorRect); + + const circle = new ShapeCircle(); + circle.setRadius(20); + circle.fillColor = '#dcc077'; + circle.x = rect.x + rect.width; + circle.y = rect.y; + infoLabel.addChild(circle); + + const label = new Label(); + label.fontName = 'Aileron-Bold'; + label.textAlign = 'center'; + label.fontColor = '#ffffff'; + label.fontSize = 30; + label.text = (i + 1).toString() + label.y = 3; + circle.addChild(label); + + // colorRect.addChild(circle); + } + } + + getColorRect(rect) { + + const colorRect = new ShapeRectNew(); + colorRect.setSize(rect.width, rect.height, 1); + + colorRect.fillColor = Math.random() < 0.5 ? '#ff0000' : '#00ff00' + // const offX = 13; + colorRect.x = rect.x // + offX; + colorRect.y = rect.y // -rect.height / 2; + // console.log('rect.height: ', rect.height); + // colorRect.alpha = 0; + return colorRect; + } + + + submitBtn; + btnArr = []; + btnDisH = 120; + initBtn() { + + this.topArr = []; + + const btnArr = []; + let arr = JSON.parse(JSON.stringify(this.sentenceArr)) ; + arr = randomSortByArr(arr); + if (!arr) { + return; + } + const disW = 400 * this.mapScale; + const disH = this.btnDisH * this.mapScale; + const tmpLen = arr.length > 5 ? 5 : arr.length; + let baseX = this.canvasWidth / 2 - (tmpLen - 1) * disW / 2 + let baseY = this.canvasHeight / 2 - 380 * this.mapScale; + let col = 0; + + for (let i=0; i<arr.length; i++) { + + const btn = new MySprite(); + btn.init(this.images.get("btn")) + btn.x = baseX + disW * col; + btn.y = baseY; + btn['baseX'] = btn.x; + btn['baseY'] = btn.y; + btn.setScaleXY(this.mapScale * 0.8); + + const btnBg = new MySprite(); + btnBg.init(this.images.get("btn_bg")) + btnBg.x = btn.x; + btnBg.y = btn.y; + btnBg.setScaleXY(this.mapScale * 0.8); + + this.renderArr.push(btnBg); + this.topArr.push(btn); + + this.addBtnLabel(btn, arr[i].answer); + + btnArr.push(btn); + + col ++ ; + if (col % 5 == 0) { + col = 0; + baseY += disH; + } + } + + this.btnArr = btnArr; + + + if (this.isTeacher) { + this.initsendBtn(); + return; + } + + + const submitBtn = new MySprite(); + submitBtn.init(this.images.get("submit")); + submitBtn.setScaleXY(this.mapScale); + submitBtn.x = this.canvasWidth / 2 + 650 * this.mapScale; + submitBtn.y = this.canvasHeight / 2 + 650 * this.mapScale; + + + + const submitShadow = new MySprite(); + submitShadow.init(this.images.get("submit_shadow")); + submitShadow.setScaleXY(this.mapScale); + submitShadow.x = submitBtn.x; + submitShadow.y = submitBtn.y + 20 * this.mapScale; + + + + const submitOff = new MySprite(); + submitOff.init(this.images.get("submit_off")); + submitOff.setScaleXY(this.mapScale); + submitOff.x = submitBtn.x; + submitOff.y = submitBtn.y + 5 * this.mapScale; + + + submitBtn['baseY'] = submitBtn.y; + submitBtn['offBtn'] = submitOff; + submitBtn['shadowSpr'] = submitShadow; + submitShadow['baseY'] = submitShadow.y; + + this.renderArr.push(submitShadow); + this.renderArr.push(submitBtn); + this.renderArr.push(submitOff); + + this.submitBtn = submitBtn; + + this.submitOff(); + } + + sendBtn; + initsendBtn() { + + 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.sendBtn = 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.sendBtn.shadowSpr = btnShadow; + + const btnLabel = new Label(); + btnLabel.fontSize = 64; + btnLabel.fontName = 'Aileron-Black'; + btnLabel.textAlign = 'center'; + btnLabel.text = 'Send'; + btnLabel.y = 5; + btnLabel.fontColor = '#ffffff'; + btn.addChild(btnLabel, 3); + + this.renderArr.push(btnShadow); + this.renderArr.push(btn); + } + + + submitOff() { + this.submitBtn.offBtn.visible = true; + + this.submitBtn.visible = false; + this.submitBtn.shadowSpr.visible = false; + } + + submitOn() { + + // this.submitBtn.y = this.submitBtn.baseY; + // this.submitBtn.scale = this.mapScale; + + // this.submitBtn.shadowSpr.alpha = 1; + // this.submitBtn.shadowSpr.y = this.submitBtn.shadowSpr.baseY; + + + this.submitBtn.visible = true; + this.submitBtn.shadowSpr.visible = true; + + this.submitBtn.offBtn.visible = false; + } + + + addBtnLabel(btn, text) { + console.log('text: ', text); + + const label = new Label(); + label.fontSize = 64; + label.fontName = 'Aileron-Black'; + label.textAlign = 'center'; + label.text = text; + // label.x = this.canvasWidth / 2; + label.y = -2; + label.fontColor = '#f1e4c2'; + btn.addChild(label); + btn.text = text; + return label; + } + + sentenceEmptyArr; + initSentence() { + + const row = Math.floor( (this.btnArr.length - 1) / 5 ) + 1; + const subH = row * this.btnDisH ; + + const sv = new ScrollView(); + // sv.setShowSize(this.panel.width, 900 - subH); + // sv.x = -this.panel.width / 2; + // sv.y = -395 + subH; + // sv.setBgColor('#faf7ee') + // // sv.setMapScale(this.mapScale); + // // sv.content.setScaleXY(1/this.mapScale); + // sv.setScrollBarSize(20 * this.mapScale, 5) + // // this.renderArr.push(sv); + // // sv.setScaleXY(this.mapScale); + // // sv.x = 0; + // // sv.y = 200; + // sv.setContentScale(this.mapScale); + + // this.panel.addChild(sv); + // this.scrollView = sv; + + + + this.sentenceEmptyArr = []; + + const arr = this.sentenceArr; + // const arr = this.sentenceArr.concat(this.sentenceArr); + if (!arr) { + return; + } + const baseX = this.panel.width / 2 - 1000 ; + let curY = 70 // this.canvasHeight / 2 - 110 * this.mapScale; + const disH = 70 * this.mapScale; + for (let i=0; i<arr.length; i++) { + const richText = this.getSentenceLabel(); + richText.x = baseX; + richText.y = curY; + richText.text = arr[i].text; + + const rect = richText.getSubTextRect('____________________'); + const colorRect = new ShapeRectNew(); + rect.height += 30; + colorRect.setSize(rect.width, rect.height, 1); + + colorRect.fillColor = '#ff0000' + const offX = 13; + colorRect.x = rect.x + offX; + colorRect.y = -rect.height / 2; + console.log('rect.height: ', rect.height); + colorRect.alpha = 0; + + + + richText.addChild(colorRect); + this.sentenceEmptyArr.push(colorRect); + + curY += richText.getAreaHeight() * this.mapScale + disH; + + richText['data'] = arr[i]; + + + sv.addItem(richText); + + // this.renderArr.push(richText); + colorRect.ctx = colorRect.parent.ctx; + + + } + + + } + + getFillLabel() { + const label = new RichText(); + + label.fontSize = 56; + label.fontColor = '#000000' + label.fontName = 'Aileron-Bold'; + // label.setScaleXY(this.mapScale); + + return label; + } + + getSentenceLabel() { + + const richText = new RichText(); + richText.disH = 0; + + richText.fontSize = 56; + richText.width = 2000 / this.mapScale + richText.fontColor = '#000000' + richText.fontName = 'DroidSansFallback'; + richText.setScaleXY(this.mapScale); + + return richText; + + } + + changeBtnOff() { + + for (let i=0; i<this.btnArr.length; i++) { + if (this.btnArr[i].visible) { + this.btnArr[i].init(this.images.get('btn_off')); + this.btnArr[i].isOff = true; + } + } + + } + + changeBtnOn() { + + for (let i=0; i<this.btnArr.length; i++) { + if (this.btnArr[i].visible) { + this.btnArr[i].init(this.images.get('btn')); + this.btnArr[i].isOff = false; + } + } + + } + + + + + + _initTitle() { + + const label = new Label(); + label.fontSize = 42 * this.mapScale; + label.fontName = 'BRLNSDB'; + label.textAlign = 'center'; + label.setMaxSize(this.canvasWidth * 0.9); + label.x = this.canvasWidth / 2; + label.y = (this.bgRect.y - this.bgRect.height / 2 * this.bgRect.scaleY) / 2; + label.fontColor = '#fff143'; + label.setShadow(0, 5, 5, 'rgba(0,0,0,0.3)'); + this.titleLabel = label; + this.renderArr.push(label); + + const disH = 5 * this.mapScale; + + + const starBg = new MySprite(); + starBg.init(this.images.get('top_star_bg')); + starBg.setScaleXY(this.mapScale); + + const disW = starBg.width / 3 * starBg.scaleX; + + const num = this.picArr.length; + const itemW = starBg.width * starBg.scaleX; + const totalW = (starBg.width) * starBg.scaleX * num + disW * (num - 1); + const offX = this.canvasWidth / 2 - totalW / 2 + itemW / 2; + + this.starBgArr = []; + for (let i = 0; i < num; i++) { + const starBg = new MySprite(); + starBg.init(this.images.get('top_star_bg')); + starBg.setScaleXY(this.mapScale); + starBg.x = offX + (itemW + disW) * i; + starBg.y = label.y - starBg.height / 2 * starBg.scaleY - disH / 2; + + this.renderArr.push(starBg); + + + const star = new MySprite(); + star.init(this.images.get('top_star')); + star.visible = false; + starBg['star'] = star; + starBg.addChild(star); + + this.starBgArr.push(starBg); + } + + + + label.y += label.height / 2 * label.scaleY + disH / 2; + + + // const textBg = new MySprite(); + // textBg.init(this.images.get('text_bg')); + // textBg.setScaleXY(this.mapScale); + // textBg.x = label.x; + // textBg.y = label.y - textBg.height / 2 * textBg.scaleY - disH / 2; + // this.renderArr.push(textBg); + // + // label.y += label.height / 2 * label.scaleY + disH / 2; + // + // + // const pageLabel = new Label(); + // pageLabel.text = '0 / 0'; + // pageLabel.fontName = 'BRLNSDB'; + // pageLabel.fontColor = '#ffffff'; + // pageLabel.textAlign = 'center'; + // pageLabel.fontSize = 24; + // textBg.addChild(pageLabel); + // + // this.pageLabel = pageLabel; + + this.refreshTitleLabel(); + this.refreshPageLabel(); + } + + + refreshTitleLabel(animaFlag = false) { + const data = this.picArr[this.curPageIndex]; + + if (animaFlag) { + + hideItem(this.titleLabel, 0.2, () => { + this.titleLabel.text = data.text; + showItem(this.titleLabel, 0.3); + + this.playAudio('tip', true); + + }); + } else { + this.titleLabel.text = data.text; + + } + } + + + refreshPageLabel() { + + // const label = this.pageLabel; + // label.text = (this.curPageIndex + 1) + ' / ' + this.picArr.length; + + for (let i = 0; i < this.curPageIndex; i++) { + + const starBg = this.starBgArr[i]; + if (starBg) { + const star = starBg.star; + if (!star.visible) { + + star.visible = true; + star.setScaleXY(3); + star.alpha = 0; + + tweenChange(star, { scaleX: 1, scaleY: 1, alpha: 1 }, 1, () => { + + }, TWEEN.Easing.Exponential.In); + + } + + } + + } + } + + showAudio() { + const data = this.picArr[this.curPageIndex]; + const audio = this.audioObj[data.audio_url]; + if (audio) { + audio.play(); + } + } + + + + + + + + + + + + + + + + + panel; + + initBg() { + + const colorBg = this.getMySprite("bg"); + colorBg.setScaleXY(this.mapScaleMax); + this.renderArr.push(colorBg); + colorBg.x = this.canvasWidth / 2; + colorBg.y = this.canvasHeight / 2; + + + const title = new Label(); + title.fontSize = 76 * this.mapScale; + title.fontName = 'Aileron-Bold'; + title.textAlign = 'left'; + // title.setMaxSize(this.canvasWidth * 0.9); + title.x = 240; + title.y = 100 * this.mapScale; + title.fontColor = '#3e9b31'; + title.text = this.data.contentObj.title || ""; + title.refreshSize(); + this.renderArr.push(title); + + + + console.log('this.data: ', this.data); + + + + + const subH = title.fontSize; + const url = this.data.contentObj.bgItem?.url; + if (url) { + const bg = new MySprite(); + bg.init(this.images.get(url)); + + const sx = this.canvasWidth / this.canvasBaseW; + const sy = (this.canvasHeight - subH) / this.canvasBaseH; + const s = Math.min(sx, sy); + + bg.setScaleXY(this.mapScale); + bg.x = this.canvasWidth / 2; + bg.y = this.canvasHeight / 2 + subH; + + bg['data'] = this.data.contentObj.bgItem; + this.bg = bg; + this.renderArr.push(bg); + } + + + + } + + + + + + + okBtnClick() { + this.checkPanel.visible = false; + this.removeSubmit(); + // this.appRef.tick(); + + this.canTouch = false; + setTimeout(() => { + // this.hideSubmit(); + this.convertCanvasToImage(); + // this.hideSubmit(); + setTimeout(() => { + this.setAnswerData(() => { + this.initResultView(); + this.canTouch = true; + }); + + + + }, 500); + }, 500); + + } + + cancelBtnClick() { + this.checkPanel.visible = false; + + } + + + curMoveItem = null; + downFlag = false; + mapDown(event) { + + + if (!this.canTouch) { + return; + } + + if (this.videoMask && this.videoMask.visible) { + + if (this.videoCloseBtn) { + if (this.checkClickTarget(this.videoCloseBtn)) { + this.videoCloseBtnClick(); + return; + } + } + + if (this.replayBtn && this.replayBtn.visible) { + if (this.checkClickTarget(this.replayBtn)) { + this.replayBtnClick(); + return; + } + } + + return; + } + + if (this.templateQuesType == this.TYPE_SINGLE_CHOICE) { + for (let i=0; i<this.optionItemArr.length; i++) { + if (this.checkClickTarget(this.optionItemArr[i])) { + this.optionItemClick(this.optionItemArr[i]); + return; + } + } + } else { + + if (this.checkClickTarget(this.answerRect)) { + this.answerRectClick(); + return; + } + + } + + + + + + } + + + + + mapMove(event) { + + if (event) { + event.preventDefault() + } + + + } + + + mapUp(event) { + + + + } + + + answerRectClick() { + console.log('in answerRectClick'); + + const courseware = window['courseware']; + if (!courseware) { + return; + } + + courseware.activeFormulaBoard((data) => { + // TODO + console.log('in activeFormulaBoard data: ', data); + }); + } + + changeBase64ToPicUrl(base64Data) { + + var arr = base64Data.split(','), mime = arr[0].match(/:(.*?);/)[1], + bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n); + while(n--){ + u8arr[n] = bstr.charCodeAt(n); + } + var obj = new Blob([u8arr], {type:mime}); + var fd = new FormData(); + + fd.append("file", obj, "jm_math.png"); + + // ä¸Šä¼ æˆªå›¾ + this.http.post(this.uploadUrl, fd).subscribe((res) => { + // å˜å‚¨æœåŠ¡å™¨çš„æˆªå›¾url + if (res['url']) { + console.log('res url: ', res['url']); + + } else { + + } + }); + + + } + + + replayBtnClick() { + if (this.curVideo) { + this.curVideo.element.play(); + this.replayBtn.visible = false; + } + } + + videoCloseBtnClick() { + console.log("in videoCloseBtnClick"); + this.videoBg.visible = false; + this.videoMask.visible = false; + if (this.curVideo) { + this.curVideo.element.pause(); + } + if (this.curOpItem) { + this.changeArea(this.curOpItem.data); + } + } + + curOpItem; + optionItemClick(opItem) { + console.log('opItem: ', opItem); + const data = opItem.data; + this.curOpItem = opItem; + this.changeAllOpItem(); + if (data.is_right) { + this.optionRight(opItem); + } else { + this.optionWrong(opItem); + } + } + + optionRight(opItem) { + this.changeOpItemBg(opItem, 'rightPic'); + + } + + optionWrong(opItem) { + this.changeOpItemBg(opItem, 'wrongPic'); + + this.canTouch = false; + setTimeout(() => { + + if (opItem.data.video_url) { + this.showVideo(opItem); + } else { + this.callTeacher(); + } + + this.canTouch = true; + }, 2000); + } + + callTeacher() { + this.changeArea(this.data.contentObj); + } + + showVideo(opItem) { + const {data} = opItem; + this.videoMask.visible = true; + this.videoBg.visible = true; + + this.initVideoPlayer(data); + } + + hideVideo() { + this.videoMask.visible = false; + this.videoBg.visible = false; + } + + changeAllOpItem() { + for (let i=0; i<this.optionItemArr.length; i++) { + this.changeOpItemBg(this.optionItemArr[i], 'normalPic'); + } + } + + changeOpItemBg(opItem, res) { + opItem[opItem.curRes].visible = false; + opItem.curRes = res; + opItem[opItem.curRes].visible = true; + } + + + + moreBtnClick() { + // this.setPageData('progress', '2', false); + // this.setPageData('submitCount', this.submitCount); + this.checkShowSubTemplateOne(); + this.isUpdateStop = true; + + } + + checkShowSubTemplateOne() { + + // this.showSubTemplate(0); + + console.log(' in checkShowSubTemplateOne') + const progress = this.getPageData('progress'); + + console.log(' progress: ', progress); + + + + if (progress == '2') { + if (this.submitCount == 1) { + this.showSubTemplate(1); + this.sendSubTempIsShowMore(1, true); + } else { + this.showSubTemplate(0); + this.sendSubTempIsShowMore(0, true); + } + + return; + } + + if (progress == '3') { + + let index; + if (this.submitCount == 1) { + index = 0; + this.hideSubTemplate(1); + } else { + index = 1; + this.hideSubTemplate(0); + + } + + this.showSubTemplate(index); + this.sendSubTempIsShowMore(index, false); + + } + + } + + sendSubTempIsShowMore(index, isShowMore) { + + setTimeout(() => { + const divArr = this.iframeContent.nativeElement.children; + const iframecont = divArr[index].children[0]; + const data = { msg: 'success', isShowMore}; + iframecont.contentWindow.postMessage({ action: 'is_show_more', data: JSON.stringify(data) }, '*'); + console.log(' post msg is_show_more ') + }, 1000); + + } + + + btnDown(btn) { + this.curMoveItem = btn; + } + + addLabelMask(target, label) { + const box = target.getBoundingBox(); + + + // const mask = new ShapeRect(); + // mask.setSize(400, 400); + // mask.fillColor = '#ff0000'; + + // // const mask = new MySprite(); + // // mask.init(this.images.get("mask")) + // // mask.x = rect.x; + // // mask.y = rect.y; + // // const sx = rect.width / mask.width; + // // const sy = rect.height / mask.height; + // // mask.scaleX = sx; + // // mask.scaleY = sy; + + // // this.scrollView.addItem(mask); + + // // label.addMaskSpr(mask); + // // mask.x = 200; + // // mask.y = 200; + + + + // // const label1 = new MySprite(); + // // label1.init(this.images.get("btn_bg")) + // // label1.setScaleXY(2); + + // const label1 = this.getFillLabel(); + // label1.text = 'aaaaaaaa a a a a a a a a a a a a a a '; + // label1.x = 400; + // label1.y = 400; + // label1.width = mask.width; + // label1.height = mask.height; + // label1.textBaseline = 'top'; + // // label1.setMaxSize(rect.width); + + + // this.renderArr.push(mask); + + // this.renderArr.push(label1); + + + + // // mask.setMaskType("destination-in"); + // // // label1.addMaskSpr(mask) + // // mask.addMaskSpr(label1); + // label1.addMaskSpr(mask); + + label.width = box.width; + label.height = box.height; + label.x = box.width / 2; + label.y = box.height / 2; + + const rect = new ShapeRect(); + rect.setSize(box.width, box.heigth); + label.addMaskSpr(rect); + } + + inputFontSize = 40; + emptyRectDown(targetRect) { + + if (!targetRect.label) { + const label = this.getFillLabel(); + label.fontSize = this.inputFontSize; + label.disH = 0; + label.offW = 0; + label.textBaseline = 'top' + label.width = targetRect.width; + label.fontSize *= (this.bg.scaleX); + // targetRect.label.x = ( targetRect.width / 2 ) + targetRect.label = label; + targetRect.addChild(targetRect.label); + + this.addLabelMask(targetRect, label); + } + + if (targetRect.label.isDefault) { + targetRect.label.text = ''; + targetRect.label.fontColor = '#000000'; + targetRect.label.isDefault = false; + } + + if (true) { + + const scale = 1 // this.mapScale; + + let tmpRect = targetRect.getBoundingBox(); + + const svBox = this.scrollView.getBoundingBox(); + + const x = svBox.x + tmpRect.x * scale; + const y = svBox.y + tmpRect.y * scale; + const width = tmpRect.width * scale; + const height = tmpRect.height * scale; + const rect = {x, y, width, height}; + + const style = { + 'font-size' : this.inputFontSize / this.canvasScale * this.bg.scaleX + 'px', + 'color' : '#000000', + 'font-family' : 'Aileron-Bold', + 'line-height' : this.inputFontSize / this.canvasScale * this.bg.scaleX + 'px', + } + this.showInputView(style, rect, targetRect.label.text || '', (value) => { + targetRect.label.text = value; + this.checkShowSubmit(); + }) + + } + } + + + checkPanel; + okBtn; + cancelBtn; + showCheckPanel() { + if (!this.checkPanel) { + this.checkPanel = new MySprite(); + this.checkPanel.init(this.images.get("check_panel")); + this.checkPanel.setScaleXY(this.mapScale); + this.checkPanel.x = this.canvasWidth / 2; + this.checkPanel.y = this.canvasHeight / 2; + + const label = new Label(); + label.text = '本题åªèƒ½æäº¤ä¸€æ¬¡ï¼Œç¡®è®¤æäº¤å—?' + label.textAlign = 'center'; + label.fontColor = '#ffffff'; + label.fontSize = 56 //* this.mapScale; + label.fontName = 'Aileron-Black'; + label.y = -70; + this.checkPanel.addChild(label); + // label.x = this.checkPanel.width / 2; + // label.y = this.checkPanel.height / 2; + + + + const offX = 300; + const okBtn = new MySprite() + okBtn.init(this.images.get("check_ok")); + this.checkPanel.addChild(okBtn); + okBtn.x = offX; + okBtn.y = 130; + this.okBtn = okBtn; + + const cancelBtn = new MySprite() + cancelBtn.init(this.images.get("check_cancel")); + this.checkPanel.addChild(cancelBtn); + cancelBtn.x = -offX; + cancelBtn.y = okBtn.y; + this.cancelBtn = cancelBtn; + + + + this.renderArr.push(this.checkPanel); + } + + this.checkPanel.visible = true; + } + + submitBtnClick() { + + // this.submitCount ++; + + + const btnBaseY = this.submitBtn.y; + const btnTargetY = btnBaseY + 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) + + tweenChange(this.submitBtn, {y: btnBaseY, scaleX: baseS, scaleY: baseS}, time, () => { + this.canTouch = true; + }) + + this.showCheckPanel(); + + // this.submitOff(); + + // const isAllRight = this.checkAnswer(); + + + // if (isAllRight || this.submitCount >= 2) { + // this.changeBtnOff(); + // this.btnArr = []; + + + + + // delayCall(0.3, ()=> { + // this.initResultView(); + + // this.setPageData('progress', '2', false); + // this.setPageData('submitCount', this.submitCount); + // this.serverSendAnswer('4-1', this.resultAnswerArr); + // }) + // } + + + + }) + + const shadow = this.submitBtn.shadowSpr; + const shadowBaseY = shadow.y //shadow['baseY']; + const shadowTargetY = shadowBaseY - 15 * this.mapScale; + tweenChange(shadow, {y: shadowTargetY, alpha: 0}, time, ()=> { + shadow.y = shadowBaseY; + shadow.alpha = 1; + 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() { + + // if (this.userResultPic && this.userResultData) { + + const c = window['courseware']; + if (!c) { + return; + } + + const duration = new Date().getTime() - this.localStartTime; + c.sendAnswer({resultData: this.userResultData, resultPic: this.userResultPic || '', duration}); + + // } + + + + + } + + + + + async setAnswerData(cb) { + + let isAllRight = true; + for (let i=0; i<this.hotZoneArr.length; i++) { + + const data = this.hotZoneArr[i].data; + console.log('data: ', data); + + let answer = this.hotZoneArr[i].label?.text || ''; + + console.log('answer: ', answer); + console.log('i: ', i); + + // answer = answer.replace(/\n/g," "); + + let result; + if (data.selectType == 'ai') { + result = await this.serverTest(answer); + result.isAi = true; + } else { + + + result = await this.paperForCheck(data, answer, this.hotZoneArr[i].data.labelText) + + + + // result = checkAnswer(data.selectType, answer, this.hotZoneArr[i].data.labelText || null); + } + + + console.log('result: ', JSON.parse(JSON.stringify(result)) ); + + this.hotZoneArr[i].result = result; + + + if (!result.right) { + // this.removeRectText( this.hotZoneArr[i] ); + isAllRight = false; + } else { + this.hotZoneArr[i].isRight = true; + // this.showSentenceRight(this.hotZoneArr[i]); + } + } + + + cb(); + // return isAllRight; + + } + + async paperForCheck(data, answer, labelText = null) { + + return new Promise((resolve, reject) => { + + console.log(' in greadPapersForCheck data: ', {type:data.selectType, blankWord: answer, word: labelText}); + + + window['courseware'].greadPapersForCheck({type:data.selectType, blankWord: answer, word: labelText}, res => { + // res 需è¦toJSON + console.log('in greadPapersForCheck res: ', res); + if (res) { + + resolve(JSON.parse(res)) + } else { + reject(); + } + }); + + + }) + + + + } + + + async serverTest(text) { + + return new Promise((resolve, reject) => { + + const c = window['courseware']; + if (!c) { + console.error('not found window.courseware') + reject(); + return; + } + + + if (text) { + + this.iconData = {}; + + console.log(' greadPapersForText start') + + c.greadPapersForText(text, (res) => { + + console.log(' greadPapersForText end') + + const resData = JSON.parse(res); + const sentsFeedback = resData.detail?.essayFeedback?.sentsFeedback + let startIndex = 0; + if (sentsFeedback) { + for (let i=0; i<sentsFeedback.length; i++) { + const {errorPosInfos, rawSent} = sentsFeedback[i]; + if (!errorPosInfos || !rawSent) { + continue; + } + const baseIndex = text.indexOf(rawSent, startIndex); + + console.log('text: ', text); + console.log('rawSent: ', rawSent); + console.log('baseIndex: ', baseIndex); + for (let j=0; j<errorPosInfos.length; j++) { + const {reason, endPos} = errorPosInfos[j]; + this.addIconData(baseIndex + endPos, {reason}); + } + + startIndex = baseIndex; + } + } + console.log('res : ', res); + console.log('iconData : ', this.iconData); + + this.createResultTextArr(text); + resolve({resultTextArr:this.resultTextArr, iconData: this.iconData, detail: resData.detail}); + // this.setComment(resData); + }) + } + + }); + + + + } + + iconData; + addIconData(index, result) { + if (!this.iconData) { + this.iconData = {}; + } + + const key = index.toString(); + if (!this.iconData[key]) { + this.iconData[key] = {dataArr: []}; + } + + this.iconData[key].dataArr.push(result) + + } + + + resultTextArr = []; + createResultTextArr(text) { + const iconKeys = Object.keys(this.iconData); + iconKeys.sort((a, b) => { + return Number(a) - Number(b); + }) + + this.resultTextArr = []; + let curStartPos = 0; + for (let i=0; i<iconKeys.length; i++) { + const textData = this.iconData[iconKeys[i]]; + const endPos = Number(iconKeys[i]); + textData['text'] = text.substring(curStartPos, endPos); + this.resultTextArr.push(textData) + + curStartPos = endPos; + } + + + const textData = {dataArr: []} + textData['text'] = text.substring(curStartPos) + this.resultTextArr.push(textData) + + + console.log('text: ', text); + console.log('resultTextArr: ', this.resultTextArr); + } + + + + 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() { + + const arr = this.hotZoneArr; + + + + for (let i=0; i<arr.length; i++) { + + + if (arr[i].data.gIdx == '0') { + if (!arr[i].label || !arr[i].label.text || arr[i].label.isDefault) { + this.hideSubmit(); + return; + } + } + + + + } + + this.showSubmit(); + + } + + + + moveItemBack() { + if (this.curMoveItem.targetLabel) { + this.curMoveItem.targetLabel.visible = true; + removeItemFromArr(this.renderArr, this.curMoveItem); + return; + } + + this.curMoveItem.x = this.curMoveItem['baseX']; + this.curMoveItem.y = this.curMoveItem['baseY']; + } + + + + + + + templateArr = []; + initIframe() { + + this.templateArr = this.data.contentObj.templateArr; + + if (this.templateArr.length <= 0) { + return; + } + console.log('arr: ', this.templateArr); + + const c = window['courseware']; + if (!c) { + console.error('not found window.courseware') + return; + } + + + + const addPlayUrl = (name, index) => { + + c.getTemplateUrl(name, (data) => { + console.log('name~: ', name) + + const urlData = JSON.parse(data) + console.log('data~~:' , data) + console.log('urlData~~:' , urlData) + console.log('i~~:' , index) + this.templateArr[index].playUrl = this.sanitizer.bypassSecurityTrustResourceUrl(urlData.play_url + `?key=${index+1}`); + this.appRef.tick(); + + index ++; + if (index < this.templateArr.length) { + const {name, last_version, play_url} = this.templateArr[index].template; + addPlayUrl(name, index); + } + }) + } + + const {name, last_version, play_url} = this.templateArr[0].template; + addPlayUrl(name, 0); + + // for (let i=0; i<this.templateArr.length; i++) { + + // const {name, last_version, play_url} = this.templateArr[i].template; + + // const index = i; + // c.getTemplateUrl(name, (data) => { + // console.log('name~: ', name) + + // const urlData = JSON.parse(data) + // console.log('data~~:' , data) + // console.log('urlData~~:' , urlData) + // console.log('i~~:' , index) + // this.templateArr[index].playUrl = this.sanitizer.bypassSecurityTrustResourceUrl(urlData.play_url + `?key=${index+1}`); + + // }) + + // const playUrl = `https://staging-teach.cdn.ireadabc.com/h5template/${name}/v${last_version}/${play_url}?key=${i+1}` + // this.templateArr[i].playUrl = this.sanitizer.bypassSecurityTrustResourceUrl(playUrl); + // console.log('playUrl: ', playUrl); + // } + + // this.showSubTemplate(0); + + // setTimeout(() => { + // this.showSubTemplate(1); + + // }, 5000); + } + + showSubTemplate(index) { + + if (this.isTeacher) { + return; + } + + console.log('showSubTemplate _ ', index); + const arr = this.templateArr; + console.log('arr: ', arr); + + for (let i=0; i<arr.length; i++) { + arr[i].leftOff = '0vw'; + } + arr[index].leftOff = '100vw'; + this.appRef.tick(); + + if (this.readyObj[(index + 1).toString()]) { + this.sendCourseIn(index); + } + + } + + + hideSubTemplate(index) { + + this.templateArr[index].isHide = true; + this.appRef.tick(); + + } + + + iframeArr; + readyObj; + initWindowListener() { + + + // const iframeArr = this.iframeArr; + + // // setTimeout(() => { + + // console.log("iframeContent: ", this.iframeContent); + // let divArr = this.iframeContent.nativeElement.children; + // console.log('divArr: ', divArr); + // for (let i=0; i<divArr.length; i++) { + // const iframe = divArr[i].children[0]; + // console.log('iframe: ', iframe); + // iframeArr.push(iframe) + // } + + // console.log('iframeArr: ', iframeArr); + // // }, 1); + + this.readyObj = {}; + + window.addEventListener('message', (e) => { + + + let msgData = e.data; + + + if (msgData.action === "getData") { + + + console.log('msgData.urlParams: ', msgData); + const key = this.getQueryVariable(msgData.urlParams, 'key'); + if (!key) { + return; + } + + console.log('key: ', key); + + + const index = key - 1; + const divArr = this.iframeContent.nativeElement.children; + const iframecont = divArr[index].children[0]; + + // const iframecont = iframeArr[key-1] + const saveData = this.templateArr[index].data; + + + console.log("getData e: ", e); + + + + const data = { msg: 'success', data: JSON.stringify(saveData)}; + + iframecont.contentWindow.postMessage({ action: 'getData', data: JSON.stringify(data) }, '*'); + + + + // const data2 = { msg: 'success', data: JSON.stringify({'isShowMore': false})}; + // iframecont.contentWindow.postMessage({ action: 'is_show_more', data: JSON.stringify(data2) }, '*'); + + // setTimeout(() => { + // _this.frameLoaded = true; + // }, 300); + } + + if (msgData.action === "temp_send_result") { + + console.log(' in temp_send_result'); + console.log('msgData.urlParams: ', msgData); + let key = msgData.key; + if (!key) { + key = '4-3'; + } + + console.log("key: ", key); + + this.serverSendAnswer(key, JSON.parse( msgData.data )); + + const progress = this.getPageData('progress'); + if (progress == '2') { + this.setPageData('progress', '3'); + } else { + this.setPageData('progress', '4'); + } + console.log('in temp_send_result __ msgData: ', msgData); + } + + if (msgData.action === "temp_show_more") { + + console.log(' in temp_show_more'); + this.checkShowSubTemplateOne(); + } + + + if (msgData.action == 'course-ready') { + console.log(' in course-ready msgData: ', msgData) + + console.log('msgData.urlParams: ', msgData); + const key = this.getQueryVariable(msgData.urlParams, 'key'); + if (!key) { + return; + } + + this.readyObj[key] = true; + } + + + }); + } + + sendCourseIn(index) { + + const divArr = this.iframeContent.nativeElement.children; + const iframecont = divArr[index].children[0]; + + + const data = { msg: 'success', data: ''}; + + iframecont.contentWindow.postMessage({ action: 'airEvents', evt: 'course-in-screen', data: JSON.stringify(data) }, '*'); + + } + + getQueryVariable(url, variable) { + var query = url.substring(1); + var vars = query.split("&"); + for (var i=0;i<vars.length;i++) { + var pair = vars[i].split("="); + if(pair[0] == variable){return pair[1];} + } + return(false); + } + + + serverResultObj; + serverSendAnswer(key, data) { + const c = window['courseware']; + if (!c) { + return; + } + + if (!this.serverResultObj) { + this.serverResultObj = {}; + } + + this.serverResultObj[key] = data; + this.serverResultObj.duration = new Date().getTime() - this.localStartTime; + + c.sendAnswer(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.hotZoneArr = []; + const arr = this.data.contentObj.hotZoneItemArr; + if (!arr) return; + + console.log('arr: ', arr); + + for (let i = 0; i < arr.length; i++) { + + const data = JSON.parse(JSON.stringify(arr[i])); + + 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, i); + + if (hotZone != null) { + this.hotZoneArr.push(hotZone); + } + + } + + } + + + openBtn; + getHotZoneItem(data, index) { + + switch(data.gIdx) { + case "0": // è½®æ’图 + return this.setOnePic(data, index); + + case "1": // 选择ç”题区域 + return this.setOneArea(data); + + case "2": // 简ç”问题 + return this.setOneShortAnswerPic(data); + + case "3": // 简ç”é¢˜ç”æ¡ˆåŒº + return this.setOneShortAnswerRect(data); + } + + return ; + + } + + setOneShortAnswerPic(data) { + console.log('setOneShortAnswerPic data: ', data) + + const pic = new MySprite(); + pic.init(this.images.get(data.pic_url)) + + const saveRect = data.rect; + + pic.x = saveRect.x + saveRect.width / 2; + pic.y = saveRect.y + saveRect.height / 2; + pic['data'] = data; + + const sx = saveRect.width / pic.width; + const sy = saveRect.height / pic.height; + + pic.scaleX = sx; + pic.scaleY = sy; + pic.visible = false; + // this.openBtn = pic; + this.renderArr.push(pic); + + return pic; + } + + answerRect; + setOneShortAnswerRect(data) { + console.log('setOneShortAnswerRect data: ', data) + + const saveRect = data.rect; + + + + const item = new MySprite(); + item.width = saveRect.width; + item.height = saveRect.height; + item.x = saveRect.x + item.y = saveRect.y + item['data'] = data; + item.alpha = 0; + item.visible = false; + + + const answerNormal = this.getMySprite('answer_normal'); + const sx = saveRect.width / answerNormal.width; + const sy = saveRect.height / answerNormal.height; + const s = Math.min(sx, sy); + answerNormal.setScaleXY(s); + answerNormal.x = answerNormal.width / 2 * answerNormal.scaleX; + answerNormal.y = answerNormal.height / 2 * answerNormal.scaleY; + item.addChild(answerNormal); + item['normalPic'] = answerNormal; + + const answerRight = this.getMySprite('answer_right'); + answerRight.setScaleXY(s); + answerRight.x = answerRight.width / 2 * answerRight.scaleX; + answerRight.y = answerRight.height / 2 * answerRight.scaleY; + item.addChild(answerRight); + item['rightPic'] = answerRight; + answerRight.visible = false; + + const answerWrong = this.getMySprite('answer_wrong'); + answerWrong.setScaleXY(s); + answerWrong.x = answerWrong.width / 2 * answerWrong.scaleX; + answerWrong.y = answerWrong.height / 2 * answerWrong.scaleY; + item.addChild(answerWrong); + item['wrongPic'] = answerWrong; + answerWrong.visible = false; + + this.answerRect = answerNormal; + + + + // const labelPic = new MySprite(); + // labelPic.load(url).then(img => { + + // }); + + + + // item.addChild(label); + + + // const w = item.width; + // const h = item.height; + // const subH = h / 6; + + // const ques = this.getMySprite(this.data.contentObj.ques_pic_url); + // const sx = w / ques.width; + // const sy = subH * 1.5 / ques.height; + // ques.setScaleXY(Math.min(sx, sy)); + // ques.x = w / 2; + // ques.y = subH; + // item.addChild(ques); + + // this.optionItemArr = []; + + // const optionArr = this.data.contentObj.optionArr; + // const baseY = subH * 2.5; + // for (let i=0; i<4; i++) { + + // if (optionArr[i]) { + // const opItem = this.getOneOpItem(optionArr[i]); + // const sx = w / opItem.width; + // const sy = subH / opItem.height; + // opItem.setScaleXY(Math.min(sx, sy)); + // opItem.y = baseY + i * subH; + // opItem.x = w / 2; + // item.addChild(opItem); + + // this.optionItemArr.push(opItem); + // } + + // } + + + // this.curAreaItem = item; + this.renderArr.push(item); + return item; + } + + + setOnePic(data, index) { + console.log('setOnePic data: ', data) + console.log('setOnePic index: ', index) + + const pic = new MySprite(); + pic.init(this.images.get(data.pic_url)) + + const saveRect = data.rect; + + pic.x = saveRect.x + saveRect.width / 2; + pic.y = saveRect.y + saveRect.height / 2; + pic['data'] = data; + + const sx = saveRect.width / pic.width; + const sy = saveRect.height / pic.height; + + pic.scaleX = sx; + pic.scaleY = sy; + pic.visible = false; + // this.openBtn = pic; + this.renderArr.push(pic); + + return pic; + } + + + optionItemArr; + curAreaItem; + setOneArea(data) { + + console.log('setOneBtn data: ', data) + + const saveRect = data.rect; + // const item = new ShapeRect(this.ctx); + // item.setSize(saveRect.width, saveRect.height); + // item.fillColor = '#ff0000'; + + const item = new MySprite(); + item.width = saveRect.width; + item.height = saveRect.height; + item.x = saveRect.x + item.y = saveRect.y + item['data'] = data; + item.alpha = 0; + item.visible = false; + + + const w = item.width; + const h = item.height; + const subH = h / 6; + + const ques = this.getMySprite(this.data.contentObj.ques_pic_url); + const sx = w / ques.width; + const sy = subH * 1.5 / ques.height; + ques.setScaleXY(Math.min(sx, sy)); + ques.x = w / 2; + ques.y = subH; + item.addChild(ques); + + this.optionItemArr = []; + + const optionArr = this.data.contentObj.optionArr; + const baseY = subH * 2.5; + for (let i=0; i<4; i++) { + + if (optionArr[i]) { + const opItem = this.getOneOpItem(optionArr[i]); + const sx = w / opItem.width; + const sy = subH / opItem.height; + opItem.setScaleXY(Math.min(sx, sy)); + opItem.y = baseY + i * subH; + opItem.x = w / 2; + item.addChild(opItem); + + this.optionItemArr.push(opItem); + } + + } + + + this.curAreaItem = item; + this.renderArr.push(item); + return item; + } + + changeArea(data) { + console.log('changeArea data: ', data) + + this.showSmallTitle(data); + + data.rect = this.curAreaItem.data.rect; + + removeItemFromArr(this.renderArr, this.curAreaItem); + + + const saveRect = data.rect; + // const item = new ShapeRect(this.ctx); + // item.setSize(saveRect.width, saveRect.height); + // item.fillColor = '#ff0000'; + + const item = new MySprite(); + item.width = saveRect.width; + item.height = saveRect.height; + item.x = saveRect.x + item.y = saveRect.y + item['data'] = data; + // item.alpha = 0; + // item.visible = false; + + + const w = item.width; + const h = item.height; + const subH = h / 6; + + const ques = this.getMySprite(data.ques_pic_url); + const sx = w / ques.width; + const sy = subH * 1.5 / ques.height; + ques.setScaleXY(Math.min(sx, sy)); + ques.x = w / 2; + ques.y = subH; + item.addChild(ques); + + this.optionItemArr = []; + + const optionArr = data.optionArr; + + console.log('~optionArr: ', optionArr); + + const baseY = subH * 2.5; + for (let i=0; i<optionArr.length; i++) { + + if (optionArr[i]) { + const opItem = this.getOneOpItem(optionArr[i]); + const sx = w / opItem.width; + const sy = subH / opItem.height; + opItem.setScaleXY(Math.min(sx, sy)); + opItem.y = baseY + i * subH; + opItem.x = w / 2; + item.addChild(opItem); + + this.optionItemArr.push(opItem); + } + + } + + + this.curAreaItem = item; + this.renderArr.push(item); + return item; + } + + getOneOpItem(data) { + + + const opItem = this.getMySprite('op_item'); + const opItemNode = this.getMySprite('op_item'); + opItemNode.alpha = 0; + opItemNode.childDepandAlpha = false; + + opItemNode.width = opItem.width; + opItemNode.height = opItem.height; + opItemNode.addChild(opItem); + opItemNode['defaultPic'] = opItem; + opItemNode['curRes'] = 'defaultPic'; + + const opItemWrong = this.getMySprite('op_item_wrong'); + opItemNode.addChild(opItemWrong); + opItemWrong.visible = false; + opItemNode['wrongPic'] = opItemWrong; + const wrongIcon = this.getMySprite('icon_wrong'); + wrongIcon.x = opItemWrong.width / 2; + opItemWrong.addChild(wrongIcon) + + + const opItemRight = this.getMySprite('op_item_right'); + opItemNode.addChild(opItemRight); + opItemRight.visible = false; + opItemNode['rightPic'] = opItemRight; + const rightIcon = this.getMySprite('icon_right'); + rightIcon.x = opItemRight.width / 2; + opItemRight.addChild(rightIcon) + + const opItemNormal = this.getMySprite('op_item_normal'); + opItemNode.addChild(opItemNormal); + opItemNormal.visible = false; + opItemNode['normalPic'] = opItemNormal; + + const label = new Label(); + label.text = data.id; + label.fontColor = '#ffffff'; + label.x = -opItemNode.width / 2 + 50; + opItemNode.addChild(label); + + + const subX = 150; + const opPic = this.getMySprite(data.pic_url); + const sx = (opItemNode.width - subX) / opPic.width; + const sy = (opItemNode.height - 20) / opPic.height; + opPic.setScaleXY(Math.min(sx, sy)); + opPic.anchorX = 0; + opPic.x = - opItemNode.width / 2 + subX; + opItemNode.addChild(opPic); + + console.log('op data: ', data); + + opItemNode['data'] = data; + return opItemNode; + } + + + + setOneRect(data, index) { + + const saveRect = data.rect; + const item = new ShapeRectNew(this.ctx); + item.setSize(saveRect.width, saveRect.height, 5); + item.setOutLine('#dcc077', 2); + item.fill = false; + item.x = saveRect.x + item.y = saveRect.y + // item.setScaleXY(this.bg.scaleX); + item.fillColor = '#dcc077'; + item['data'] = data; + // item.alpha = 0; + this.scrollView.addItem(item); + + + const rectLabel = this.getFillLabel(); + rectLabel.topH = 8; + rectLabel.fontSize = this.inputFontSize; + rectLabel.disH = 0; + rectLabel.offW = 0; + rectLabel.textBaseline = 'top' + rectLabel.width = item.width; + rectLabel.fontSize *= (this.bg.scaleX); + // targetRect.label.x = ( targetRect.width / 2 ) + item['label'] = rectLabel; + item.addChild(item['label']); + + this.addLabelMask(item, rectLabel); + + rectLabel.text = 'Please Enter ...'; + rectLabel.fontColor = '#cccccc' + rectLabel['isDefault'] = true; + + + + // const subX = data.rect.x - this.bg.data.rect.x; + // const subY = data.rect.y - this.bg.data.rect.y; + + // item.x = subX * this.mapScale //- this.bg.width / 2; + // item.y = subY * this.mapScale //- this.bg.height / 2; + // // item.y -= this.bg.height / 2; + // this.bg.addChild(item); + + + const circle = new ShapeCircle(); + circle.setRadius(20 * this.bg.scaleX); + circle.x = item.x + item.width; + circle.y = item.y; + circle.fillColor = '#dcc077' + this.scrollView.addItem(circle); + + const label = new Label(); + label.text = index + 1; + label.fontColor = '#ffffff'; + label.textAlign = 'center'; + label.fontSize = 28 + label.fontName = 'Aileron-Bold'; + label.y = 2; + circle.addChild(label); + + // this.renderArr.push(item); + + return item; + } - // åˆå§‹åŒ– éŸ³é¢‘èµ„æº - this.initAudio(); - // åˆå§‹åŒ– å›¾ç‰‡èµ„æº - this.initImg(); - // å¼€å§‹é¢„åŠ è½½èµ„æº - this.load(); - }, this.saveKey); + showEndPetal() { + this.endPageArr = []; + this.showPetalFlag = true; + this.addPetal(); } - ngOnDestroy() { - window['curCtx'] = null; - window.cancelAnimationFrame(this.animationId); - this.cleanAudio(); + stopEndPetal() { + this.endPageArr = []; + this.showPetalFlag = false; } + addPetal() { - cleanAudio() { - if (this.audioObj) { - for (const key in this.audioObj) { - this.audioObj[key].pause(); - } + if (!this.showPetalFlag) { + return; } - } + const petal = this.getPetal(); + this.endPageArr.push(petal); - load() { - - // é¢„åŠ è½½èµ„æº - this.loadResources().then(() => { - window["air"].hideAirClassLoading(this.saveKey, this.data); - this.init(); - this.update(); + moveItem(petal, petal.x, this.canvasHeight + petal.height * petal.scaleY, petal['time'], () => { + removeItemFromArr(this.endPageArr, petal); }); - } + rotateItem(petal, petal['tr'], petal['time']); - init() { + setTimeout(() => { + this.addPetal(); + }, 100); - this.initCtx(); - this.initData(); - this.initView(); } - initCtx() { - this.canvasWidth = this.wrap.nativeElement.clientWidth; - this.canvasHeight = this.wrap.nativeElement.clientHeight; - this.canvas.nativeElement.width = this.wrap.nativeElement.clientWidth; - this.canvas.nativeElement.height = this.wrap.nativeElement.clientHeight; - - this.ctx = this.canvas.nativeElement.getContext('2d'); - this.canvas.nativeElement.width = this.canvasWidth; - this.canvas.nativeElement.height = this.canvasHeight; + getPetal() { - window['curCtx'] = this.ctx; - window['curImages'] = this.images; - } + const petal = new MySprite(this.ctx); + const id = Math.ceil(Math.random() * 3); + petal.init(this.images.get('petal_' + id)); + const randomS = (Math.random() * 0.4 + 0.6) * this.mapScale; + petal.setScaleXY(randomS); + const randomR = Math.random() * 360; + petal.rotation = randomR; + const randomX = Math.random() * this.canvasWidth; + petal.x = randomX; + petal.y = -petal.height / 2 * petal.scaleY; + const randomT = 0.5 + Math.random() * 2.5; + petal['time'] = randomT; - updateItem(item) { - if (item) { - item.update(); - } - } + let randomTR = 360 * Math.random(); // - 180; + if (Math.random() < 0.5) { randomTR *= -1; } + petal['tr'] = randomTR; - updateArr(arr) { - if (!arr) { - return; - } - for (let i = 0; i < arr.length; i++) { - arr[i].update(this); - } + return petal; } - - initListener() { this.winResizeEventStream @@ -202,13 +3843,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 +3861,7 @@ export class PlayComponent implements OnInit, OnDestroy { firstTouch = false; removeMouseListener(); } + console.log('touch down'); setMxMyByTouch(e); this.mapDown(e); }; @@ -237,6 +3879,7 @@ export class PlayComponent implements OnInit, OnDestroy { firstTouch = false; removeTouchListener(); } + console.log('mouse down'); setMxMyByMouse(e); this.mapDown(e); }; @@ -278,13 +3921,56 @@ 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) { + + const audioNew = new Audio(); + audioNew.src = audio.src; + audioNew.load(); + // audioNew.play(); + if (now) { audio.pause(); audio.currentTime = 0; @@ -301,12 +3987,51 @@ export class PlayComponent implements OnInit, OnDestroy { + + showArr(arr) { + if (!arr) { + return; + } + for (let i = 0; i < arr.length; i++) { + arr[i].visible = true; + } + } + + hideArr(arr) { + if (!arr) { + return; + } + for (let i = 0; i < arr.length; i++) { + arr[i].visible = false; + } + } + + + + IsPC() { + + if (window['ELECTRON']) { + return false; // å°è£…å®¢æˆ·ç«¯æ ‡è®° + } + + + if (document.body.ontouchmove !== undefined && document.body.ontouchmove !== undefined) { + return false; + } else { + return true; + } + + } + + loadResources() { const pr = []; this.rawImages.forEach((value, key) => {// é¢„åŠ è½½å›¾ç‰‡ const p = this.preload(value) .then(img => { + // img['setAttribute']("crossOrigin",'Anonymous') + this.images.set(key, img); }) .catch(err => console.log(err)); @@ -314,7 +4039,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(() => { @@ -330,6 +4055,7 @@ export class PlayComponent implements OnInit, OnDestroy { preload(url) { return new Promise((resolve, reject) => { const img = new Image(); + img['crossOrigin'] = "Anonymous"; // img.crossOrigin = "anonymous"; img.onload = () => resolve(img); img.onerror = reject; @@ -340,8 +4066,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 +4085,60 @@ export class PlayComponent implements OnInit, OnDestroy { this.init(); } + checkClickTargetSv(target) { + + // console.log('target: ', target); + + const scale = 1 // this.mapScale; + + let tmpRect = target.getBoundingBox(); + + const svBox = this.scrollView.getBoundingBox(); + + + const x = svBox.x + tmpRect.x * scale; + const y = svBox.y + tmpRect.y * scale; + const width = tmpRect.width * scale; + const height = tmpRect.height * scale; + const rect = {x, y, width, height}; + + + // const contentBox = this.scrollView.content.getBoundingBox(); + + // rect.x += contentBox.x + svBox.x; + // rect.y += contentBox.y + svBox.y; + + // console.log('rect: ', rect); + // console.log('this.mx: ', this.mx); + // console.log('this.my: ', this.my); + // const shape = new ShapeRectNew(); + // shape.x = rect.x; + // shape.y = rect.y; + // shape.fillColor = '#0000ff' + // shape.alpha = 0.5; + // shape.setSize(rect.width, rect.height, 1); + // this.renderArr.push(shape); + if (this.checkPointInRect(this.mx, this.my, rect)) { + return true; + } + return false; + } checkClickTarget(target) { 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 +4159,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 +4168,96 @@ 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; + return { x, y }; - - addUrlToAudioObj(key, url = null, vlomue = 1, loop = false, callback = null) { - - const audioObj = this.audioObj; - - if (url == null) { - url = key; - } - - this.rawAudios.set(key, url); - - const audio = new Audio(); - audio.src = url; - audio.load(); - audio.loop = loop; - audio.volume = vlomue; - - audioObj[key] = audio; - - if (callback) { - audio.onended = () => { - callback(); - }; - } - } - - addUrlToImages(url) { - this.rawImages.set(url, url); - } - - - - - - - // ======================================================编写区域========================================================================== - - - - - - /** - * æ·»åŠ é»˜è®¤æ•°æ® ä¾¿äºŽæ— æ•°æ®æ—¶çš„展示 - */ - initDefaultData() { - - if (!this.data.pic_url) { - this.data.pic_url = 'assets/play/default/pic.jpg'; - this.data.pic_url_2 = 'assets/play/default/pic.jpg'; - } - } - - - /** - * æ·»åŠ é¢„åŠ è½½å›¾ç‰‡ - */ - initImg() { - - this.addUrlToImages(this.data.pic_url); - this.addUrlToImages(this.data.pic_url_2); - - } - - /** - * æ·»åŠ é¢„åŠ è½½éŸ³é¢‘ - */ - initAudio() { - - // éŸ³é¢‘èµ„æº - this.addUrlToAudioObj(this.data.audio_url); - this.addUrlToAudioObj(this.data.audio_url_2); - - // 音效 - this.addUrlToAudioObj('click', this.rawAudios.get('click'), 0.3); - - } - - - - /** - * åˆå§‹åŒ–æ•°æ® - */ - initData() { - - const sx = this.canvasWidth / this.canvasBaseW; - const sy = this.canvasHeight / this.canvasBaseH; - const s = Math.min(sx, sy); - this.mapScale = s; - - // this.mapScale = sx; - // this.mapScale = sy; - - - this.renderArr = []; - - - - } - - - - /** - * åˆå§‹åŒ–试图 - */ - initView() { - - - this.initPic(); - - this.initBottomPart(); - - } - - initBottomPart() { - - const btnLeft = new MySprite(); - btnLeft.init(this.images.get('btn_left')); - btnLeft.x = this.canvasWidth - 150 * this.mapScale; - btnLeft.y = this.canvasHeight - 100 * this.mapScale; - - btnLeft.setScaleXY(this.mapScale); - - this.renderArr.push(btnLeft); - - this.btnLeft = btnLeft; - - - - const btnRight = new MySprite(); - btnRight.init(this.images.get('btn_right')); - btnRight.x = this.canvasWidth - 50 * this.mapScale; - btnRight.y = this.canvasHeight - 100 * this.mapScale; - btnRight.setScaleXY(this.mapScale); - - this.renderArr.push(btnRight); - - this.btnRight = btnRight; - } - - initPic() { - - const maxW = this.canvasWidth * 0.7; - - const pic1 = new MySprite(); - pic1.init(this.images.get(this.data.pic_url)); - pic1.x = this.canvasWidth / 2; - pic1.y = this.canvasHeight / 2; - pic1.setScaleXY(maxW / pic1.width); - - this.renderArr.push(pic1); - this.pic1 = pic1; - - - const label1 = new Label(); - label1.text = this.data.text; - label1.textAlign = 'center'; - label1.fontSize = 50; - label1.fontName = 'BRLNSDB'; - label1.fontColor = '#ffffff'; - - pic1.addChild(label1); - - - - - - const pic2 = new MySprite(); - pic2.init(this.images.get(this.data.pic_url_2)); - pic2.x = this.canvasWidth / 2 + this.canvasWidth; - pic2.y = this.canvasHeight / 2; - pic2.setScaleXY(maxW / pic2.width); - - this.renderArr.push(pic2); - this.pic2 = pic2; - - this.curPic = pic1; - } - - - btnLeftClicked() { - - this.lastPage(); - } - - btnRightClicked() { - - this.nextPage(); } - lastPage() { - - if (this.curPic == this.pic1) { - return; - } - - this.canTouch = false; + getPosDistance(sx, sy, ex, ey) { - 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; - }); + const _x = ex - sx; + const _y = ey - sy; + const len = Math.sqrt(Math.pow(_x, 2) + Math.pow(_y, 2)); + return len; } - nextPage() { + b64ToUint8Array(b64Image) { - if (this.curPic == this.pic2) { - return; + var img = atob(b64Image.split(',')[1]); + var img_buffer = []; + var i = 0; + + while (i < img.length) { + img_buffer.push(img.charCodeAt(i)); + i++; } - - 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); + + return new Uint8Array(img_buffer); } + convertCanvasToImage() { + console.log('1'); - - - mapDown(event) { - - if (!this.canTouch) { - return; - } - - if ( this.checkClickTarget(this.btnLeft) ) { - this.btnLeftClicked(); - return; - } - - if ( this.checkClickTarget(this.btnRight) ) { - this.btnRightClicked(); - return; + if (!this.uploadUrl) { + // this.userResultPic = ''//true + this.sendResult(); + return } + console.log('2 uploadUrl: ', this.uploadUrl.toString()); - if ( this.checkClickTarget(this.pic1) ) { - this.pic1Clicked(); - return; - } + const src = this.canvas.nativeElement.toDataURL("image/png"); - if ( this.checkClickTarget(this.pic2) ) { - this.pic2Clicked(); - return; + const arr = src.split(','), + mime = arr[0].match(/:(.*?);/)[1], + bstr = atob(arr[1]); + let n = bstr.length; + const u8arr = new Uint8Array(n); + while ( n -- ) { + u8arr[n] = bstr.charCodeAt(n); } + const obj = new Blob([u8arr], {type: mime}); + const fd = new FormData(); + fd.append("file", obj, "cw_cover.png"); + + // ä¸Šä¼ æˆªå›¾ + this.http.post(this.uploadUrl, fd).subscribe((res) => { + // å˜å‚¨æœåŠ¡å™¨çš„æˆªå›¾url + if (res['url']) { + console.log('res url: ', res['url']); + this.userResultPic = res['url']; + this.sendResult(); + } + }); - } - - mapMove(event) { - - } - - mapUp(event) { } + httpServer(type, url, options, cb) { + this.http[type](url, options) + .subscribe( val => { - update() { - - // ---------------------------------------------------------- - this.animationId = window.requestAnimationFrame(this.update.bind(this)); - // 清除画布内容 - this.ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight); - // tween 更新动画 - TWEEN.update(); - // ---------------------------------------------------------- - + console.log("Post call successful value returned in body", val); + cb(val); + + }, error => { + console.log("Post call in error", error); + cb(error); - this.updateArr(this.renderArr); + }, () => { + console.log("The Post observable is now completed."); + cb(null); + } + ); } - - } diff --git a/src/app/play/resources.js b/src/app/play/resources.js index d9b584c92bc24d0c04374cb1568478fdbefba9c7..2ed46fa351f0adac209643f369c8c4f86ef2ae38 100644 --- a/src/app/play/resources.js +++ b/src/app/play/resources.js @@ -1,9 +1,21 @@ 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"], + ['op_item', "assets/play/op_item.png"], + ['op_item_wrong', "assets/play/op_item_wrong.png"], + ['op_item_right', "assets/play/op_item_right.png"], + ['op_item_normal', "assets/play/op_item_normal.png"], + ['btn_close', "assets/play/btn_close.png"], + ['bg', "assets/play/bg.jpg"], + ['video_bg', "assets/play/video_bg.jpg"], + ['btn_replay', "assets/play/btn_replay.png"], + + ['icon_right', "assets/play/icon_right.png"], + ['icon_wrong', "assets/play/icon_wrong.png"], + + ['answer_normal', "assets/play/answer_normal.png"], + ['answer_right', "assets/play/answer_right.png"], + ['answer_wrong', "assets/play/answer_wrong.png"], + ]; @@ -12,7 +24,14 @@ const res = [ const resAudio = [ ['click', "assets/play/music/click.mp3"], + ['submit', "assets/play/music/submit.mp3"], + ['more', "assets/play/music/more.mp3"], + + ]; export {res, resAudio}; + + + diff --git a/src/app/play/words.ts b/src/app/play/words.ts new file mode 100644 index 0000000000000000000000000000000000000000..4b28d508982d6244193a2e96c360af5573190c82 --- /dev/null +++ b/src/app/play/words.ts @@ -0,0 +1,18 @@ +export const data = { + "device": ["vacuum cleaner", "electric fan", "air conditioner", "hair dryerstyler", "electric cooker", "desk lamp", "electric shaver", "micro wave oven", "frige", "washing machine", "electric heater", "fluorescent lamp", "dictaphone, dictating machine", "tape recorder", "television", "electric iron", "electric foot warmer", "electric vacuum cleaner", "bulb", "electronic oven", "radio", "loud-speaker", "refrigerator", "air conditioning", "microwave oven", "dry cell", "tap", "broiler", "defroster", "dicer", "dishwasher", "dryer", "eggbeater", "fan", "air-condition", "vertical disinfection cabinetffice", "horizontal disinfection cabinet", "pasteurize cupboard", "disinfectant tank", "household gas stove", "smoke exhauster", "air exhauster", "soya-bean milk grinder", "soya-bean milking", "food blender", "juice extractor", "filter purifier", "water dispenser", "can opener", "compactor", "freezer", "furnace", "humidifier", "iron", "juicer", "oven ", "percolator", "range hood", "rotisserie", "shaver", "stove", "toaster", "absorber", "ac accumulator", "ac azinuth comprator", "active loudspeaker", "acu automatic calling unit", "electric rice cooker", "electric kettle", "coffee maker", "blender", "toast oven", "exhaust fan", "disinfecting cabinet", "towel dispenser", "lcd tv", "electric fireplace", "wine cabinet", "cool freezer", "massager", "hair dryer", "electric toolbrush", "depilation equipment", "hair crimper", "compactordefroster", "lithium battery/cell", "lcd(liquid crystal displaytv", "electric fireplaceelectric fan", "electric toolbrushelectric iron", "tv", "computer", "drive", "monitor", "speaker", "air-conditioning", "flashlight", "calculator", "electric light", "electric calculator", "tube", "dictaphone,dictating machine", "electric shaverelectric cooker electric heaterelectric vacuum cleanerbulb", "microphone", "air conditioning microwave ovendry cell", "airconditioning", "electricfootwarmer", "electricshaver", "electriccooker", "electricheater", "electricvacuumcleaner", "electronicoven", "loudspeaker", "microwaveoven", "drycell", "boiler", "aircondition", "householdgasstove", "smokeexhauster", "airexhauster", "soyabeanmilkgrinder", "foodblender", "juiceextractor", "filterpurifier", "waterdispenser", "oven", "rangehood", "vacuumcleaner", "electriccalculator", "taperecorder", "projection lamp", "large screen splicing", "professional display", "industry display", "plasma panel display", "digital signage", "led display", "touch one machine", "touch screen", "recreational machine", "psp nds handheld game machine", "recreational machine ", "laser printer", "bubble jet printer", "multifunctional integrated machine", "large format printer", "scanner", "the fax machine", "copier", "copying machine", "dye sublimation printer", "projection booth", "projection screen", "electronic whiteboard", "automobile electric productsthe", "education electric products", "cd", "camera", "digital video (dv)", "camera lens", "mp3", "mp4", "u disk", "e-book", "electric book", "digital voice recorder", "earphone", "electric dictionary", "digital phone frameusb", "repeater", "point reading machine", "multimedia hard disk recoding", "portable source", "digital companion", "pick-up head", "desktop computer", "all-in-one desktops", "workstation", "jotter", "notebook", "netbooks", "iphone", "ipad", "panel computer", "computer components", "mouse", "liquid crystal display", "loudspeaker box", "voice box", "cell phone", "mobile phone", "phone", "gps", "walkie-talkie", "intercom", "telephone", "teleconference", "dial conference", "conference call", "do mobile phone", "electric toothbrush", "bath heater", "soap dispenser", "television set", "washer", "mosquito killer", "electric mosquito swatter", "electric mosquito repellent", "electro-thermal mosquito-repellent incense", "gas water heater", "electric water heater", "solar heater", "air source heat gong water heater", "water heater", "bracker fan", "desk fan", "floor fan", "ceiling fan", "wall fan", "air conditioning fan", "warm fan", "hand warmer", "heat insulation plate", "insulating pad", "insulation chests", "incubator", "hair removal device", "depilator", "shaving device", "electric eyebrow shaving device ", "electric eyelash curler", "beauty device", "crimping iron", "curler", "straighener", "pore cleaner", "nose hair trimmer", "electric manicure", "eyelash pen", "heating apparatus", "electric blanket", "foot bath", "ear cleaner", "hair cap", "electric massager", "barber", "the fat meter", "deaf-aid", "hemomanometer", "sphy gmomanometer", "pedometer", "bathroom scale", "weight balance", "weight scale", "glucometer", "moisture extractor", "humidity regulator", "perfuming machine", "perfuming device", "steam clean machine", "electronic trash", "air purifier", "air-cleaner", "water purifying machine", "vacuum cleaner,", "sweeping machine", "oxygen machine", "oxygen bar", "bread machine", "egg boiler", "steamed egg", "sandwich machine", "electric baking pan", "soybean milk machine", "ice cream machine", "coffee machine", "popcorn machine", "mill", "winepress,juicer", "fruit and vegetable cleaning machine", "clothes drier", "(electric) kettle", "electric cup", "fridge", "shoes dryer", "shoe polisher", "hand dryer", "electronic thermometer", "electronic timer", "reminder", "hair ball trim", "spin drier", "dehydrator", "agitator", "amalgamator", "cooking machine", "dish-washing machine", "food waste processor", "disinfection cabinet", "electric oven", "cheese furnace", "decoction vessel", "block shaving machine", "ice crusher", "fry ice machine", "hotplate,gas cooker", "casserole", "electromagnetic oven", "induction cooker", "electric (rice) cooker", "electric pressure cooker", "electric chafing dish", "the convection oven", "electric frying pan", "electric steamer", "the soup pot", "slow cooker ", "juicer ", "toaster ", "grill/barbeque ", "micro oven ", "toaster over", "coffer maker", "kettle", "ice cream maker", "break maker", "pasta maker", "mixer/blader", "food process", "deep fryer", "dishwasher ", "water pump", "compressed water pump", "Refrigerators", "freezers", "wine cabinets", "ice makers", "air conditioners", "washing machines", "dryers", "televisions", "home theaters", "projectors", "DVD players", "combination audio", "recorders", "tablets", "video game consoles", "Walkmans", "PDAs", "electronic dictionaries", "learning machines", "mobile memory", "digital cameras Electric paper books", "walkie-talkies", "car refrigerators", "mahjong machines", "fumes", "cooktops", "dishwashers", "disinfection cupboards", "gas water heaters", "electric hot water taps", "electric water heaters", "heat pump water heaters", "body cleaners", "hair dryers", "bathers", "dry mobile phones", "integrated ceiling", "soy milk machine", "rice cooker", "electric cake", "electric stew pot", "noodle machine", "yogurt machine", "fruit and vegetable detoxifier Egg-boiling machine", "egg-laying machine", "bean sprout machine", "oil press", "kitchen treasure", "garbage disposal machine", "solar water heater", "solar lawn lamp", "courtyard lamp", "solar toys", "solar panels", "0401 water treatment appliances: water dispensers", "water purifiers", "pure water machines", "soft water machines", "pipeline machines", "straight drinker", "defying vacuum cleaner", "steam mop", "sweeper", "floor waxing machine", "ironing machine", "shoe shine machine", "electric mosquito racket", "toilet deodorant", "cold fan", "dehumidifier", "negative oxygen ion occurrence devices", "small oxygen generators", "electric heaters", "electric blankets", "shavers", "curlers", "electric toothbrushes", "beauty devices", "electric breast pumps", "foot baths", "massage chairs", "massagers", "blood pressure meters", "thermometers", "body fat meters", "smart home systems", "Smart lighting control smart home central control system", "smart home ecological control", "smart shade", "smart door and window control", "smart socket", "security", "monitoring", "access control", "visual intercom", "set-top box", "smart switch", "information appliances", "home network system", "system integration product communication network and component sensor controller", "smart bracelet", "smart watch", "smart toys", "smart drop device", "router", "electrodrill", "electric drill", "electrical drill", "electron telescope", "electronic telescope"], + "side": [ + "east", + "south", + "west", + "north", + "northeast", + "northwest", + "southeast", + "southwest", + "middle" + ], + "work": ["Social workers", "personnelmanagers", "translators", "human mediators", "librarians", "journalists", "newspaper and magazine editors", "screenwriters", "book editors", "stone carvers", "carpenters", "cartoonists", "dancers", "instrument players", "construction and engineering management", "steel structure design and management personnel", "microcomputers", "electronic newspaper/e-magazine editors", "information managers", "kindergarten education teachers", "chain store managers", "marketing planning", "telecommunications engineers", "web designers", "Construction machinery operators", "electrical engineers", "mechanical cartographers", "architectural cartographers", "electronic processing data system operators", "photography staff", "merchant ship staff", "civil aviation transport pilots", "turbine personnel", "flight controllers", "dietitians", "eyewear professionals", "medical records managers", "insurance support personnel", "salesmen", "securities dealers", "sales agents", "real estate agents", "procurement personnel", "import and export clerks", "futures brokers", "accountants", "commercial art designers", "interior designers", "TV presenter", "advertising AE", "international trade practitioner", "international trade English clerk", "Chinese typist", "secretary of affairs", "information login", "assistant accountant", "quality control assistant", "warehouse manager", "production planning assistant", "distribution staff", "postman", "postal staff", "customs clearance Staff", "guest management", "bank clerks", "financial tellers", "foreign exchange traders", "travel agents", "tour guides", "flight attendants", "cultural relics narrator", "chef", "bartender", "Western food chef", "meal attendant", "nanny", "beauty barber", "beautician", "preservation Staff", "police", "fire workers", "fashion models", "merchandise salesmen", "pet beauticians", "horticultural crop growers", "nursery workers", "florists", "builders", "plumbers", "industrial plumbers", "industrial wiring operators", "indoor wiring workers", "electricians", "Sanitary plumbers", "magnetic brick pavers", "wiring workers", "painters", "automotive board goldworkers", "welders", "general board goldworkers", "special welders", "foundries", "metal mold makers", "fitters", "car repairmen", "automotive electricians", "Transaction machine repairer", "heavy mechanical repairman", "car chassis worker", "precision grinder", "milling machine worker", "numerical control lathe operator", "refrigeration air conditioner", "refrigeration air conditioner decorator", "audio-visual electronics worker", "industrial electronic worker", "bread baker", "motor repairer", "electrical repair Workers", "electronic instrument repairers", "jewelry and precious metals manufacturers", "precision gage manufacturers", "instrument tuners", "precision machinery", "ceramics workers", "printers", "printing design and plate makers", "bakers", "food and beverage technicians", "carpentry", "furniture carpentry", "Sewing", "weaver", "suit worker", "national clothing seamstress", "shoemaker", "garment design and production staff", "women's fitter", "garment worker", "heat treatment worker", "metal modeling", "metal surface treatment worker", "plate maker", "cold work", "planer", "metal plating Workers", "plastic mold manufacturers", "plastic products manufacturers", "rubber products manufacturers", "paper products manufacturers", "photo plate makers", "dairy manufacturers", "electronic assembly personnel", "automobile drivers", "fishing boat crews", "lathe workers", "oil and gas pressure automatic control personnel", "cleaning service personnel", "professional athletes teachers worker", "Teachers", "workers", "actors", "cooks", "doctors", "nurses", "drivers", "military personnel", "lawyers", "businessmen", "shop assistants", "cashiers", "writers", "models", "singers", "tailors", "judges", "security guards", "florists Waiter", "Cleaning workers", "architects", "hairdressers", "buyers", "designers", "firefighters", "mechanics", "magicians", "postmen", "lifeguards", "athletes", "engineers", "pilots", "administrators", "brokers", "auditors", "Cartoonist", "gardener", "scientist", "host", "make-up artist", "music festival", "artist", "pastry chef", "dessertr", "athlete", "diplomat", "dancer", "archery", "actor", "skater", "piano player", "guzheng hand", "designer", "bar owner", "CEO", "Amusement park owner", "captain", "journalist", "racer", "lawyer", "barber", "taekwondo coach", "veterinarian", "special police", "masseuse Java software engineer", "ERP software development engineer", "WAP development engineer", "software test engineer", "document engineer", "Internet software development engineer", "search engine engineer", "game development engineer", "web designer", "network engineer", "network administrator", "website editor", "embedded software development engineer", "electronic technology research and development engineer", "electronic engineer", "communication technology engineer", "mobile communication engineer", "3G software engineer", "mobile phone application development engineer", "urban planning designer", "civil engineer", "water supply and drainage engineer", "HVAC engineer", "engineering budgeter", "contract engineer", "property management specialist", "product process engineer", "Quality Management Specialist", "Supply Chain Specialist", "Automotive Electronics Engineer", "Automotive Technical Support Engineer", "Electrical Development Engineer", "Digital Product Development Engineer", "Mold Engineer", "Mechanical Engineer", "Pre-Sales Technical Engineer", "Aftermarket Technical Engineer", "Bioengineering Technician", "Chemical Technology Engineer", "Materials Engineer", "Water Treatment Engineer", "Strong Electrical Engineer", "Weak Electrical Engineer", "Electrical Engineer", "Automation Engineer", "Electrical and Mechanical Engineer", "Mining Engineer", "Geoengineer", "Physician", "Surgeon", "Pharmacist", "Pharmaceutical technology developer", "drug registrar", "bench worker", "drawing worker", "field worker", "forestry worker", "lathe worker", "lifting worker", "harbor worker", "iron worker", "Technical Worker", "accountant", "actress", "airlinerepresentative", "anchor", "announcer", "architect", "associateprofessor", "astronaut.", "attendant", "auditor", "automechanic", "baker", "baseballplayer", "bellboy", "bellhop", "binman", "blacksmith", "boxer", "broker(agent)", "budgeteer", "busdriver", "butcher", "buyer", "carpenter", "cashier", "chemist", "clerk", "clown", "cobbler", "computerprogrammer", "constructionworker", "cook", "cowboy", "customsofficer", "dentist", "deskclerk", "detective", "doctor", "door-to-doorsalesman", "driver", "dustman", "editor", "electrician", "engineer", "farmer", "fashiondesigner", "fireman(firefighter)", "fisherman", "florist", "flyer", "Foreignminister", "gasstationattendant", "geologist", "guard", "guide", "hiredresseer", "housekeeper", "housewife", "interpreter", "janitor", "judge", "librarian.", "lifeguard", "magician", "masseur", "masseuse", "mathematician", "mechanic", "miner", "model", "monk", "moviedirector", "moviestar", "musician", "nun", "nurse", "officeclerk", "officestaff", "operator", "parachutist.", "photographer", "pilot", "planner", "policeman", "postalclerk", "President", "priest", "processfor", "realestateagent", "receptionist", "repairman", "reporter", "sailor", "salesman/selespeople/salesperson", "seamstress", "secretary", "singer", "soldiery", "statistician", "surveyor", "tailor", "taxidriver", "teacher", "technician", "tourguide", "trafficwarden", "translator", "TVproducer", "typist", "vet", "waiter", "waitress", "welder", "writer", "MarketingandSales", "Vice-PresidentofSales", "SeniorCustomerManager", "SalesManager", "RegionalSalesManager", "MerchandisingManager", "SalesAssistant", "WholesaleBuyer", "Tele-Interviewer", "RealEstateAppraiser", "MarketingConsultant", "MarketingandSalesDirector", "MarketResearchAnalyst", "Manufacturer\\'sRepresentative", "DirectorofSubsidiaryRights", "SalesRepresentative", "AssistantCustomerExecutive", "MarketingIntern", "MarketingDirector", "InsuranceAgent", "CustomerManager", "Vice-PresidentofMarketing", "RegionalCustomerManager", "SalesAdministrator", "TelemarketingDirector", "AdvertisingManager", "TravelAgent", "Salesperson", "Telemarketer", "SalesExecutive", "MarketingAssistant", "RetailBuyer", "RealEstateManager", "RealEstateBroker", "PurchasingAgent", "ProductDeveloper", "MarketingManager", "AdvertisingCoordinator", "AdvertisingAssistant", "AdCopywriter(DirectMail)", "CustomerRepresentative", "ComputersandMathematics()", "ManagerofNetworkAdministration", "MISManager", "ProjectManager", "TechnicalEngineer", "DevelopmentalEngineer", "SystemsProgrammer", "Administrator", "OperationsAnalyst", "ComputerOperator", "ProductSupportManager", "ComputerOperationsSupervisor", "DirectorofInformationServices", "SystemsEngineer", "HardwareEngineer", "ApplicationsProgrammer", "InformationAnalyst", "LANSystemsAnalyst", "HumanResources", "DirectorofHumanResources", "AssistantPersonnelOfficer", "CompensationManager", "EmploymentConsultant", "FacilityManager", "JobPlacementOfficer", "LaborRelationsSpecialistRecruiter", "TrainingSpecialist", "Vice-PresidentofHumanResources", "AssistantVice-PresidentofHumanResources", "PersonnelManager", "BenefitsCoordinator", "EmployerRelationsRepresentative", "PersonnelConsultant", "TrainingCoordinator", "ExecutiveandManagerial", "ChiefExecutiveOfficer(CEO)", "DirectorofOperations", "Vice-President", "BranchManager", "RetailStoreManager", "HMOProductManager", "OperationsManager", "AssistantVice-President", "FieldAssuranceCoordinator", "ManagementConsultant", "DistrictManager", "HospitalAdministrator", "Import/ExportManager", "InsuranceClaimsController", "ProgramManager", "InsuranceCoordinator", "InventoryControlManager", "RegionalManager", "ChiefOperationsOfficer(COO)", "GeneralManager", "ExecutiveMarketingDirector", "Controller(International)", "FoodServiceManager", "ProductionManager", "PropertyManager", "ClaimsExaminer", "Controller(General)", "ServiceManager", "ManufacturingManager", "VendingManager", "TelecommunicationsManager", "TransportationManager", "WarehouseManager", "AssistantStoreManager", "Manager(Non-ProfitandCharities)", "simultaneous", "publisher", "graphicdesigner", "deliveryboy", "director", "talent", "producer", "scholar", "novelist", "playwright", "linguist", "botanist", "economist", "philosopher", "politician", "physicist", "astropologist", "archaeologist", "expertonfolklore", "biologist", "zoologist", "physiologist", "futurologist", "artists", "painter", "composer", "sculptor", "fashioncoordinator", "dressmaker", "cutter", "sewer", "ballerina", "firefigher", "chiefofpolice", "mailman", "newspaperboy", "bootblack", "poet", "copywriter", "newscaster", "milkman", "merchant", "greengrocer", "fish-monger", "shoe-maker", "saleswoman", "stewardess", "conductor", "stationagent", "porter", "carmechanic", "civilplanner", "civilengineer", "druggist", "oilsupplier", "(public)healthnurse", "supervisor", "forman", "keypuncher", "stenographer", "telephoneoperator", "programmer", "systemanalyst", "shorthandtypist", "officegirl", "publicservants", "nationalpublicservant", "localpublicserviceemployee", "nationrailroadman", "tracer", "illustrator", "acountant", "businessman", "tradesman", "pedlar", "meson", "spinner", "dyer", "temporaryworker", "probationer", "lecturer", "headmaster", "headmistress", "personnel", "administrative director", "file clerk", "executive assistant", "office manager", "executive secretary", "general office clerk", "inventory control analyst", "staff assistant", "mail room supervisor", "order entry clerk", "telephone operator", "shipping/receiving expediter", "ticket agent", "vice-president of administration", "daycare worker", "esl teacher", "developmental educator '", "head teacher", "foreign language teacher", "librarian", "guidance counselor", "music teacher", "library technician", "physical education teacher", "principal", "school psychologist", "special needs educator", "teacher aide", "art instructor", "computer teacher", "college professor", "coach", "assistant dean of students", "archivist", "vocational counselor", "tutor", "police officer", "fire fighter", "police sergeant", "assistant attorney general", "law clerk", "contracts manager", "law student", "ombudsman", "paralegal", "security manager", "patent agent", "legal assistant", "court officer", "legal secretary", "court reporter", "attorney", "clinical director", "cardiologist", "dental hygienist", "chiropractor", "dental technician", "dental assistant", "dietary technician", "emergency medical technician", "dietician", "fitness instructor", "home health aide", "health services coordinator", "lab technician", "hospital supervisor", "medical records clerk", "nursing aide", "medical technologist", "nursing supervisor", "nursing administrator", "nutritionist", "nursing home manager", "optician", "occupational therapist", "orthodontist", "veterinary assistant", "pharmacy technician", "psychiatrist", "physical therapist", "physician's assistant", "respiratory therapist", "pediatrician", "speech pathologist", "sanitation inspector", "wait person", "customer service manager", "customer service representative", "caterer", "fast food worker", "health club manager", "cosmetologist", "hotel concierge", "hotel manager'", "food inspector", "hotel clerk", "restaurant manager", "hairstylist", "flight attendant", "technical", "technical llustrator", "landscape architect", "research and development technician", "aircraft mechanic", "quality control inspector", "qatest technician", "precision inspector", "drafter", "technical support specialist", "building inspector", "engineering technician", "electronic equipment repairer", "aircraft pilot", "deputy gencral managc", "economic rescarch assistan", "electrical enginccr", "enginccring technician", "english instructor/tcachcr", "export salcs managc", "export salcs staf", "financial controllcrfinancial reportcr", "f.x. (foreign exchangc)clcrk", "f.x. settlcmcnt clcrk", "fund managcr", "gcncral auditor", "gcncral managcr", "gcncral managcr assistant", "gcncral managcr's sccrctary", "hardwarc enginccr )", "accounting assistant", "accounting clcrk", "accounting managcraccounting stall ", "accounting supervisor", "administration managcr", "administration staff", "administrativc assistant ", "administrativc clerk ", "advcrtising staff ", "airlincs sales rcprcscntativc", "airlincs staff ", "application enginccr", "assistant managcr", "bond analyst ", "bond trader", "business controllcr", "business managcr", "buycr ", "cashicr ", "chcmical enginccr", "civil enginccr", "clcrk receptionist", "clerk typist & secrctary", "computcr data input operator", "computcr enginccr", "computcr proccssing operator", "computer systcm managcr", "deputy gcncral managc", "gencral managcrl prcsident", "gcneral managcr assistant.", "gcneral managcr's secrctary", "hardwarc enginecr)", "lmport liaison staff", "import managcr", "insurancc actuary", "intcrnational salcs staff", "intcrprctcr ", "lcgal adviscr", "linc supcrvisor", "maintenancc enginccr", "managcmcnt consultant ", "managcr", "managcr for public rclation", "manufacturing enginccr", "manufacturing workcr", "markct analyst", "markct devclopmcnt managcr", "markcting managcr", "markcting staff", "markcting assistant", "markcting exccutivc", "markcting rcprcscntativc", "markcting rcprcscntativc managcr", "mechanical enginccr", "mining enginccr", "naval architect", "officc assistant", "officc clerk ", "opcrational managcr", "packagc designcr", "passenger rcservation staff", "pcrsonnel clcrk ", "pcrsonncl managcr", "plant/ factory managcr", "postal clerk", "privatc secrctary", "product managcr", "production enginecr", "profcssional staff", "project staff ", "promotional managcr", "proof-rcader", "purchasing agcnt ", "quality control enginccr", "rcal estatc staff", "rccruitment co-ordinator", "rcgional mangcr", "rcscarch&.devclopment enginccr", "rcstaurant managcr", "salcs and planning staff", "salcs assistant ", "salcs clerk ", "salcs coordinator", "salcs enginccr", "salcs exccutivc", "salcs managcr", "scller rprcscntativc", "salcs supcrvisor", "school rcgistrar", "secrctarial assistant", "securitics custody clcrk", "security officcr", "scnior accountant", "senior consultant/adviscr", "scnior employcc", "senior sccrctary", "scrvicc managcr", "simultancous interprctcr", "softwarc enginccr", "systcms adviscr", "systems enginccr", "systems operator ", "tcchnical editor", "technical translator", "tcchnical workcr", "tclecommunication executivc()", "tclcphonist / opcrator", "tourist guidc", "tradc financc exccutivc", "trainec managcr", "translation checkcr", "'translator", "trust banking exccutivc", "wordproccssor operator", "actrcss", "airlinc reprcscntativc ", "announccr", "architcct", "associatc profcssor", "astronaut", "attcndant", "auto mechanic ", "bakcr", "barbcr", "bascball playcr", "bcll boy", "binman,", "boxcr", "broker (agcnt) ", "budgctecr", "bus driver", "taxi driver", "subway driver", "train driver", "butchcr,", "buycr", "carpentcr", "cashicr", "chcmist ", "clerk ", "clown ", "cobblcr", "computcr programmcr ", "construction workcr ", "cowboy ", "customs officcr", "danccr ", "designcr", "dcsk clcrk", "detcctivc", "door-to-door salesmen"], + "adj": [ + "big", "small", "red", "blue", "good", "bad" + ] +} \ No newline at end of file diff --git a/src/assets/font/BRLNSDB_1.TTF b/src/assets/font/BRLNSDB_1.TTF new file mode 100755 index 0000000000000000000000000000000000000000..e5f34b2f342ffcd820a8a0956af3ab36bb1f9e1f Binary files /dev/null and b/src/assets/font/BRLNSDB_1.TTF differ diff --git a/src/assets/libs/tmp_air.js b/src/assets/libs/tmp_air.js new file mode 100644 index 0000000000000000000000000000000000000000..991663d203b0cfd4d5f258618d8d75146b3b0f20 --- /dev/null +++ b/src/assets/libs/tmp_air.js @@ -0,0 +1,430 @@ +// 刷新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; +})(); + diff --git a/src/assets/play/answer_normal.png b/src/assets/play/answer_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..b4de36f26eeb45bab61e6cc28a8c09050810d63b Binary files /dev/null and b/src/assets/play/answer_normal.png differ diff --git a/src/assets/play/answer_right.png b/src/assets/play/answer_right.png new file mode 100644 index 0000000000000000000000000000000000000000..44c392a7ce3971e3d5f8dd24f3afc82138b63b1d Binary files /dev/null and b/src/assets/play/answer_right.png differ diff --git a/src/assets/play/answer_wrong.png b/src/assets/play/answer_wrong.png new file mode 100644 index 0000000000000000000000000000000000000000..d7240b3380e276d2ac945a93431c813547aeff98 Binary files /dev/null and b/src/assets/play/answer_wrong.png differ diff --git a/src/assets/play/bg.jpg b/src/assets/play/bg.jpg old mode 100755 new mode 100644 index 701c49c4c716d9e48412993f87f47d0fdcfbbe44..ab4db4b3ee3153a9669cfa83f511d0d368460ae0 Binary files a/src/assets/play/bg.jpg and b/src/assets/play/bg.jpg differ diff --git a/src/assets/play/btn_close.png b/src/assets/play/btn_close.png new file mode 100644 index 0000000000000000000000000000000000000000..a0822fcaab4587aa205e37d93eba3d63b4349f5b Binary files /dev/null and b/src/assets/play/btn_close.png differ diff --git a/src/assets/play/btn_left.png b/src/assets/play/btn_left.png deleted file mode 100755 index e3428fd5bcda4bad311e87c5aa5669fdb7e96a60..0000000000000000000000000000000000000000 Binary files a/src/assets/play/btn_left.png and /dev/null differ diff --git a/src/assets/play/btn_replay.png b/src/assets/play/btn_replay.png new file mode 100644 index 0000000000000000000000000000000000000000..fa1722c1689141b025d11256be4faa5c84c028ca Binary files /dev/null and b/src/assets/play/btn_replay.png differ diff --git a/src/assets/play/btn_right.png b/src/assets/play/btn_right.png deleted file mode 100755 index db0f274024b4ad41d5219acf3936ec2b2f79459c..0000000000000000000000000000000000000000 Binary files a/src/assets/play/btn_right.png and /dev/null differ diff --git a/src/assets/play/default/audio.mp3 b/src/assets/play/default/audio.mp3 deleted file mode 100755 index 66313dcf084aa98da69908cb6ee9da2d0d4a451e..0000000000000000000000000000000000000000 Binary files a/src/assets/play/default/audio.mp3 and /dev/null differ diff --git a/src/assets/play/default/pic.jpg b/src/assets/play/default/pic.jpg deleted file mode 100755 index 1da3c1135cc324bf3ec67cc0c7b4c19caeef08f1..0000000000000000000000000000000000000000 Binary files a/src/assets/play/default/pic.jpg and /dev/null differ diff --git a/src/assets/play/font/Aileron-Black.ttf b/src/assets/play/font/Aileron-Black.ttf new file mode 100755 index 0000000000000000000000000000000000000000..eea596e5445f32ef11373ae18e4a021fdf1f2232 Binary files /dev/null and b/src/assets/play/font/Aileron-Black.ttf differ diff --git a/src/assets/play/font/Aileron-Bold.ttf b/src/assets/play/font/Aileron-Bold.ttf new file mode 100755 index 0000000000000000000000000000000000000000..c35d2ddadad0984b7405e4467b013695bcd0e915 Binary files /dev/null and b/src/assets/play/font/Aileron-Bold.ttf differ diff --git a/src/assets/play/font/BRLNSDB_1.TTF b/src/assets/play/font/BRLNSDB_1.TTF new file mode 100755 index 0000000000000000000000000000000000000000..e5f34b2f342ffcd820a8a0956af3ab36bb1f9e1f Binary files /dev/null and b/src/assets/play/font/BRLNSDB_1.TTF differ diff --git a/src/assets/play/font/DroidSansFallback.ttf b/src/assets/play/font/DroidSansFallback.ttf new file mode 100755 index 0000000000000000000000000000000000000000..6f928809672fbad6a6c66f57aad46f865b2a5800 Binary files /dev/null and b/src/assets/play/font/DroidSansFallback.ttf differ diff --git a/src/assets/play/icon_right.png b/src/assets/play/icon_right.png new file mode 100644 index 0000000000000000000000000000000000000000..16cee929a6eaabbfa68d00fdbe1b603becc50e8a Binary files /dev/null and b/src/assets/play/icon_right.png differ diff --git a/src/assets/play/icon_wrong.png b/src/assets/play/icon_wrong.png new file mode 100644 index 0000000000000000000000000000000000000000..77571c2b625e38bf00b66e5e6adceec024b95c29 Binary files /dev/null and b/src/assets/play/icon_wrong.png differ diff --git a/src/assets/play/music/click.mp3 b/src/assets/play/music/click.mp3 index f551dc50e89af2d63b79892af8bf1d61ae92f7a5..c3b69b21ac958fc11c3db2c263933a3464e78d3c 100644 Binary files a/src/assets/play/music/click.mp3 and b/src/assets/play/music/click.mp3 differ diff --git a/src/assets/play/music/more.mp3 b/src/assets/play/music/more.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..716d38357af4556779878e421541ac7a84dcc150 Binary files /dev/null and b/src/assets/play/music/more.mp3 differ diff --git a/src/assets/play/music/submit.mp3 b/src/assets/play/music/submit.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..a7988179aef59223734c49ca098323f55b04b93f Binary files /dev/null and b/src/assets/play/music/submit.mp3 differ diff --git a/src/assets/play/op_item.png b/src/assets/play/op_item.png new file mode 100644 index 0000000000000000000000000000000000000000..84bd5d9558ff527aded89de6e3648c3e9509c987 Binary files /dev/null and b/src/assets/play/op_item.png differ diff --git a/src/assets/play/op_item_normal.png b/src/assets/play/op_item_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..d087a3b0a97de671afaa78bc3b4d5b275ced662a Binary files /dev/null and b/src/assets/play/op_item_normal.png differ diff --git a/src/assets/play/op_item_right.png b/src/assets/play/op_item_right.png new file mode 100644 index 0000000000000000000000000000000000000000..060d0df2dbbdf0bcb336966ae913cdb609809c4e Binary files /dev/null and b/src/assets/play/op_item_right.png differ diff --git a/src/assets/play/op_item_wrong.png b/src/assets/play/op_item_wrong.png new file mode 100644 index 0000000000000000000000000000000000000000..dc7f4363e8722e390862ec26a2c8fc91ef3845ca Binary files /dev/null and b/src/assets/play/op_item_wrong.png differ diff --git a/src/assets/play/text_bg.png b/src/assets/play/text_bg.png deleted file mode 100755 index 6084daeadcb2cec320328e7e1f362d104b7ffbaa..0000000000000000000000000000000000000000 Binary files a/src/assets/play/text_bg.png and /dev/null differ diff --git a/src/assets/play/video_bg.jpg b/src/assets/play/video_bg.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e266ea2c96d2f90a6bca0e872fde74e05ce7476d Binary files /dev/null and b/src/assets/play/video_bg.jpg differ diff --git a/src/index.html b/src/index.html index e55641675b96cbe7dae938f19f7d6ba8773e4c42..c7c0f218195d3729294cd01c5d0833413212bfb0 100644 --- a/src/index.html +++ b/src/index.html @@ -9,6 +9,12 @@ <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 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>