Commit 9bc2d435 authored by Chen Jiping's avatar Chen Jiping

feat:完成模板开发

parent 9f3a2900
...@@ -128,5 +128,8 @@ ...@@ -128,5 +128,8 @@
} }
} }
}, },
"defaultProject": "ng-template-generator" "defaultProject": "ng-template-generator",
"cli": {
"analytics": "d019af0c-e48f-4eee-a358-d8a9d240236a"
}
} }
\ No newline at end of file
import { Obj } from "./ObjBean";
export class ExercisesBean extends Obj{
//单词数组
wordArr = [];
picUrl2;
}
export function getDefaultExercises(){
let exercises = new ExercisesBean();
let word = getDefaultWord();
exercises.wordArr.push(word);
return exercises;
}
export class LetterBean extends Obj{
fontColor = "";
}
export function getDefaultLetter(){
let letter = new LetterBean();
return letter;
}
export class WordBean extends Obj{
letterArr = [];
//卡片单词数组
cardWordArr = [];
}
export function getDefaultWord(){
let word = new WordBean();
let cardWord = getDefaultCardWord();
word.cardWordArr.push(cardWord);
return word;
}
export function getDefaultCardWord(){
let cardWord = new Obj();
cardWord['letterArr'] = [];
return cardWord;
}
export class Obj{
/**音频材料 */
audioUrl: String;
/**图片材料 */
picUrl:String;
val : String;
}
\ No newline at end of file
import { Obj } from "./ObjBean";
export class TitleBean extends Obj{
part1 : String;
part2: String;
}
export function getDefaultTile(){
let title = new TitleBean();
title.part1 = "C";
title.part2 = "Read and point";
return title;
}
\ No newline at end of file
<div class="model-content"> <div class="model-content">
<div nz-row>
<div style="position: absolute; left: 200px; top: 100px; width: 800px;"> <div nz-col nzOffset='4'>
<h1 nz-title>课程练习内容编辑</h1>
<input type="text" nz-input [(ngModel)]="item.text" (blur)="save()"> </div>
</div>
<app-upload-image-with-preview <div nz-row>
[picUrl]="item.pic_url" <div nz-col [nzSpan]="15" nzOffset="3">
(imageUploaded)="onImageUploadSuccess($event, 'pic_url')" <div nz-form>
></app-upload-image-with-preview> <div id='title-anchor'>
<nz-divider nzText="课程名称" nzOrientation="left"></nz-divider>
<app-audio-recorder <nz-form-item>
[audioUrl]="item.audio_url" <nz-form-label [nzSpan]="3" nzFor="part1">标题1</nz-form-label>
(audioUploaded)="onAudioUploadSuccess($event, 'audio_url')" <nz-form-control [nzSpan]="6">
></app-audio-recorder> <nz-input-group nzAddOnBefore="Part">
<app-custom-hot-zone></app-custom-hot-zone> <input type="text" id="part1" nz-input [(ngModel)]="item.title.part1" (blur)="save()">
<app-upload-video></app-upload-video> </nz-input-group>
<app-lesson-title-config></app-lesson-title-config> </nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSpan]="3" nzFor="part2">标题2</nz-form-label>
<nz-form-control [nzSpan]="6">
<input nz-input type="text" id="part2" [(ngModel)]="item.title.part2" (blur)="save()">
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSpan]="3" nzFor="audioUrl">发音</nz-form-label>
<nz-form-control [nzSpan]="6">
<app-audio-recorder [audioUrl]="item.title.audioUrl" id="audioUrl"
(audioUploaded)="onAudioUploadSuccess($event, item.title, 'audioUrl')">
</app-audio-recorder>
</nz-form-control>
</nz-form-item>
</div>
<div id='listen-anchor'>
<nz-divider nzText="听力材料" nzOrientation="left"></nz-divider>
<nz-form-item>
<nz-form-control [nzSpan]="6" nzOffset="3">
<app-audio-recorder id="item.listenAudioUrl" [audioUrl]="item.listenAudioUrl"
(audioUploaded)="onAudioUploadSuccess($event, item, 'listenAudioUrl')">
</app-audio-recorder>
</nz-form-control>
</nz-form-item>
</div>
<nz-divider nzText="添加词缀" nzOrientation="left"></nz-divider>
<nz-form-item>
<nz-form-label [nzSpan]="2" nzFor="exercises">操作</nz-form-label>
<nz-form-control [nzSpan]="4">
<button nz-button nzType="dashed" [disabled]="item.letterArr.length == 4 ? true : false" class="add-btn"
id="add-btn" (click)="addLetterItem(item)">
<i nz-icon nzType="plus-circle" nzTheme="outline"></i>添加
</button>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-control [nzOffset]="2" [nzSpan]="15">
<nz-table #lettersTable nzBordered [nzData]="item.letterArr" [nzShowPagination]=false>
<thead>
<tr>
<th>序号</th>
<th>字母组合</th>
<th>音频</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let row of lettersTable.data;let j = index">
<td>{{ j+1 }}</td>
<td><input type="text" nz-input placeholder="max length is 6" [(ngModel)]="row.val" (blur)="save()"
maxlength="6"></td>
<td>
<app-audio-recorder [audioUrl]="row.audioUrl"
(audioUploaded)="onAudioUploadSuccess($event, row, 'audioUrl')">
</app-audio-recorder>
</td>
<td>
<a (click)="delLetter(item, j)">delete</a>
</td>
</tr>
</tbody>
</nz-table>
</nz-form-control>
</nz-form-item>
</div>
</div>
</div> </div>
<!--练习题-->
<div nz-row>
<div nz-col [nzSpan]="23" nzOffset="1">
<nz-divider nzText="内容编辑" nzOrientation="left"></nz-divider>
<nz-collapse nzAccordion>
<nz-collapse-panel *ngFor="let data of item.exercisesArr; let i=index" [nzHeader]="'卡片' + (i + 1)"
[nzActive]="true" [nzShowArrow]="false">
<nz-form-item>
<nz-form-label [nzSpan]="2">图片</nz-form-label>
<nz-form-control [nzSpan]="4">
<app-upload-image-with-preview style="width: 100%" [picUrl]="data.picUrl"
(imageUploaded)="onImageUploadSuccess($event, data, 'picUrl')">
</app-upload-image-with-preview>
</nz-form-control>
</nz-form-item>
<nz-divider nzText="弹窗内容设置" nzOrientation="left"></nz-divider>
<nz-form-item>
<nz-form-label [nzSpan]="2">图片</nz-form-label>
<nz-form-control [nzSpan]="4">
<app-upload-image-with-preview style="width: 100%" [picUrl]="data.picUrl2"
(imageUploaded)="onImageUploadSuccess($event, data, 'picUrl2')">
</app-upload-image-with-preview>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSpan]="2">音频</nz-form-label>
<nz-form-control [nzSpan]="4">
<app-audio-recorder [audioUrl]="data.audioUrl"
(audioUploaded)="onAudioUploadSuccess($event, data, 'audioUrl')">
</app-audio-recorder>
</nz-form-control>
</nz-form-item>
<nz-divider nzText="单词内容设置" nzOrientation="left"></nz-divider>
<nz-form-item>
<nz-form-label [nzSpan]="2">单词</nz-form-label>
<nz-form-control [nzSpan]="5">
<button nz-button nzType="dashed" [disabled]="data.wordArr.length == 2 ? true : false" class="add-btn"
id="add-btn" (click)="addWordItem(data, 'wordArr')">
<i nz-icon nzType="plus-circle" nzTheme="outline"></i>添加
</button>
</nz-form-control>
</nz-form-item>
<div *ngFor="let word of data.wordArr; let j=index" style="padding: 0.5vw;" nz-col [nzXs]='24' [nzSm]='24'
[nzMd]='24' [nzLg]='24'>
<nz-card nzTitle="单词-{{j+1}}" [nzHoverable]="true" [nzExtra]="delWord">
<!--
<nz-form-item>
<nz-form-label [nzSpan]="3">音频</nz-form-label>
<nz-form-control [nzSpan]="5">
<app-audio-recorder [audioUrl]="word.audioUrl"
(audioUploaded)="onAudioUploadSuccess($event, word, 'audioUrl')">
</app-audio-recorder>
</nz-form-control>
</nz-form-item>
-->
<nz-form-item>
<nz-form-label [nzSpan]="3">文本</nz-form-label>
<nz-form-control [nzSpan]="10">
<input type="text" nz-input placeholder="max length is 10" [(ngModel)]="word.val"
(blur)="saveWord(word)" maxlength="10">
</nz-form-control>
</nz-form-item>
<nz-divider nzText="点击字母设置变红" nzOrientation="left"></nz-divider>
<nz-form-item>
<nz-form-control [nzSpan]="20">
<div *ngFor="let letter of word.letterArr; let m = index" style="float: left;">
<a [ngStyle]="{'float': 'left','font-size': '42px','font-family': 'GOTHICB','color':letter.fontColor, 'margin-right': '2px'}"
(click)="clickLetter(letter, m)">{{letter.val == ' ' ? '&nbsp;' : letter.val}}</a>
</div>
</nz-form-control>
</nz-form-item>
<nz-divider nzText="弹窗内容设置" nzOrientation="left"></nz-divider>
<nz-form-item>
<nz-form-label [nzSpan]="2">弹窗内容</nz-form-label>
<nz-form-control [nzSpan]="5">
<button nz-button nzType="dashed" [disabled]="word.cardWordArr.length == 2 ? true : false"
class="add-btn" id="add-btn" (click)="addWordItem(word, 'cardWordArr')">
<i nz-icon nzType="plus-circle" nzTheme="outline"></i>添加
</button>
</nz-form-control>
</nz-form-item>
<div *ngFor="let cardWord of word.cardWordArr; let j=index" nz-col [nzXs]='24' [nzSm]='12' [nzMd]='12'
[nzLg]='12'>
<nz-card nzTitle="内容 + {{j + 1}}" [nzExtra]="delCardWord">
<nz-form-item>
<nz-form-label [nzSpan]="4">图片</nz-form-label>
<nz-form-control [nzSpan]="8">
<app-upload-image-with-preview style="width: 100%" [picUrl]="cardWord.picUrl"
(imageUploaded)="onImageUploadSuccess($event, cardWord, 'picUrl')">
</app-upload-image-with-preview>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSpan]="4">音频</nz-form-label>
<nz-form-control [nzSpan]="8">
<app-audio-recorder [audioUrl]="cardWord.audioUrl"
(audioUploaded)="onAudioUploadSuccess($event, cardWord, 'audioUrl')">
</app-audio-recorder>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSpan]="4">文本</nz-form-label>
<nz-form-control [nzSpan]="8">
<input type="text" nz-input placeholder="max length is 10" [(ngModel)]="cardWord.val"
(blur)="saveWord(cardWord)" maxlength="10">
</nz-form-control>
</nz-form-item>
<nz-divider nzText="点击字母设置变红" nzOrientation="left"></nz-divider>
<nz-form-item>
<nz-form-control [nzSpan]="20">
<div *ngFor="let letter of cardWord.letterArr; let m = index" style="float: left;">
<a [ngStyle]="{'float': 'left','font-size': '42px','font-family': 'GOTHICB','color':letter.fontColor, 'margin-right': '2px'}"
(click)="clickLetter(letter, m)">{{letter.val == ' ' ? '&nbsp;' : letter.val}}</a>
</div>
</nz-form-control>
</nz-form-item>
</nz-card>
<ng-template #delCardWord>
<button nz-button nzType="danger" (click)="delWordItem(word,'cardWordArr',j)"
[disabled]="word.cardWordArr.length == 1 ? true : false">
<i nz-icon nzType="delete" nzTheme="outline"></i>删除
</button>
</ng-template>
</div>
</nz-card>
<ng-template #delWord>
<button nz-button nzType="danger" (click)="delWordItem(data, 'wordArr',j)"
[disabled]="data.wordArr.length == 1 ? true : false">
<i nz-icon nzType="delete" nzTheme="outline"></i>删除
</button>
</ng-template>
</div>
</nz-collapse-panel>
</nz-collapse>
</div>
</div>
</div> </div>
\ No newline at end of file
\ No newline at end of file
import {Component, EventEmitter, Input, OnDestroy, OnChanges, OnInit, Output, ApplicationRef, ChangeDetectorRef} from '@angular/core'; import { Component, EventEmitter, Input, OnDestroy, OnChanges, OnInit, Output, ApplicationRef, ChangeDetectorRef } from '@angular/core';
import { getDefaultCardWord, getDefaultExercises, getDefaultLetter, getDefaultWord, WordBean } from '../bean/ExercisesBean';
import { getDefaultTile } from '../bean/TitleBean';
...@@ -10,12 +12,12 @@ import {Component, EventEmitter, Input, OnDestroy, OnChanges, OnInit, Output, Ap ...@@ -10,12 +12,12 @@ import {Component, EventEmitter, Input, OnDestroy, OnChanges, OnInit, Output, Ap
export class FormComponent implements OnInit, OnChanges, OnDestroy { export class FormComponent implements OnInit, OnChanges, OnDestroy {
// 储存数据用 // 储存数据用
saveKey = "test_0011"; saveKey = "YM5-22";
// 储存对象 // 储存对象
item; item;
constructor(private appRef: ApplicationRef,private changeDetectorRef: ChangeDetectorRef) { constructor(private appRef: ApplicationRef, private changeDetectorRef: ChangeDetectorRef) {
} }
...@@ -24,8 +26,12 @@ export class FormComponent implements OnInit, OnChanges, OnDestroy { ...@@ -24,8 +26,12 @@ export class FormComponent implements OnInit, OnChanges, OnDestroy {
this.item = {}; this.item = {};
this.item.title = getDefaultTile();
this.item.letterArr = [];
// 获取存储的数据 // 获取存储的数据
(<any> window).courseware.getData((data) => { (<any>window).courseware.getData((data) => {
if (data) { if (data) {
this.item = data; this.item = data;
...@@ -50,7 +56,53 @@ export class FormComponent implements OnInit, OnChanges, OnDestroy { ...@@ -50,7 +56,53 @@ export class FormComponent implements OnInit, OnChanges, OnDestroy {
init() { init() {
if (!this.item.title) {
this.item.title = getDefaultTile();
}
if (!this.item.letterArr) {
this.item.letterArr = [];
}
if (!this.item.exercisesArr) {
this.item.exercisesArr = [];
}
for (let i = this.item.exercisesArr.length; i < 4; ++i) {
let exercises = getDefaultExercises();
this.item.exercisesArr.push(exercises);
}
for (let i = 0; i < this.item.exercisesArr.length; ++i) {
let exercises = this.item.exercisesArr[i];
if (!exercises.wordArr) {
exercises.wordArr = [];
}
if (exercises.wordArr.length == 0) {
let word = getDefaultWord();
exercises.wordArr.push(word);
}
for (let j = 0; j < exercises.wordArr.length; ++j) {
let word = exercises.wordArr[j];
if (!word.cardWordArr) {
word.cardWordArr = [];
}
if (word.cardWordArr.length == 0) {
let cardWord = getDefaultCardWord();
word.cardWordArr.push(cardWord);
}
}
}
} }
...@@ -58,9 +110,9 @@ export class FormComponent implements OnInit, OnChanges, OnDestroy { ...@@ -58,9 +110,9 @@ export class FormComponent implements OnInit, OnChanges, OnDestroy {
* 储存图片数据 * 储存图片数据
* @param e * @param e
*/ */
onImageUploadSuccess(e, key) { onImageUploadSuccess(e, item, key) {
this.item[key] = e.url; item[key] = e.url;
this.save(); this.save();
} }
...@@ -68,9 +120,9 @@ export class FormComponent implements OnInit, OnChanges, OnDestroy { ...@@ -68,9 +120,9 @@ export class FormComponent implements OnInit, OnChanges, OnDestroy {
* 储存音频数据 * 储存音频数据
* @param e * @param e
*/ */
onAudioUploadSuccess(e, key) { onAudioUploadSuccess(e, item, key) {
this.item[key] = e.url; item[key] = e.url;
this.save(); this.save();
} }
...@@ -80,7 +132,7 @@ export class FormComponent implements OnInit, OnChanges, OnDestroy { ...@@ -80,7 +132,7 @@ export class FormComponent implements OnInit, OnChanges, OnDestroy {
* 储存数据 * 储存数据
*/ */
save() { save() {
(<any> window).courseware.setData(this.item, null, this.saveKey); (<any>window).courseware.setData(this.item, null, this.saveKey);
this.refresh(); this.refresh();
} }
...@@ -93,5 +145,76 @@ export class FormComponent implements OnInit, OnChanges, OnDestroy { ...@@ -93,5 +145,76 @@ export class FormComponent implements OnInit, OnChanges, OnDestroy {
}, 1); }, 1);
} }
addLetterItem(item) {
let letter = getDefaultLetter();
item.letterArr.push(letter);
item.letterArr = [...item.letterArr];
this.save();
}
delLetter(item, index) {
if (index !== -1) {
item.letterArr.splice(index, 1);
item.letterArr = [...item.letterArr];
this.save();
}
}
addWordItem(exercises, key) {
let word = getDefaultWord();
exercises[key].push(word);
this.save();
}
delWordItem(exercises, key, index) {
if (index !== -1) {
exercises[key].splice(index, 1);
exercises[key] = [...exercises[key]];
this.save();
}
}
saveWord(item) {
let val = "";
if (!item.letterArr) {
item.letterArr = [];
}
for (let i = 0; i < item.letterArr.length; ++i) {
val += item.letterArr[i].val;
}
//值发生改变,则重新处理数据
if (item.val != val) {
item.letterArr = [];
for (let i = 0; i < item.val.length; ++i) {
let letter = getDefaultLetter();
letter.fontColor = "#363333";
letter.val = item.val.charAt(i);
item.letterArr.push(letter);
}
}
this.save();
}
clickLetter(letter, i) {
if (letter.fontColor == "#363333") {
letter.fontColor = "#c8171e";
}
else {
letter.fontColor = "#363333";
}
this.save();
}
} }
/**
*
* @param audio 音频
* @param now true-重新开始播放,flase-继续播放
* @param callback
*/
export function playAudio(audio, now = false, callback = null) {
if (audio) {
if (now) {
audio.pause();
audio.currentTime = 0;
}
if (callback) {
audio.onended = () => {
callback();
};
}
audio.play();
}
}
/**
* 暂停播放音频
* @param audio 音频
* @param reset 暂停是否重置:true-是,false-否
* @param callback
*/
export function pauseAudio(audio, reset = false, callback = null) {
if (audio) {
if (reset) {
audio.currentTime = 0;
}
audio.pause();
if (callback) {
callback();
}
}
}
\ No newline at end of file
import { Label, Label2, LabelText, MySprite, ShapeRect, tweenChange } from "./Unit";
export class BigCard{
data;
images;
scaleX = 1;
scaleY = 1;
bg : ShapeRect;
closePic : MySprite;
shown = false;
contentSpr;
init(images, scaleX = 1, scaleY = 1) {
this.images = images;
this.scaleX = scaleX;
this.scaleY = scaleY;
this.initView();
}
private initView(){
let w = 1040 * this.scaleX;
let h = 640 * this.scaleY
const bg = new ShapeRect();
bg.setSize(w, h);
this.bg = bg;
bg.alpha = 0;
this.initCard();
this.closePic = this.getColsePic(this.bg);
this.bg.setScaleXY(0);
}
private initCard(){
const card = new MySprite();
card.init(this.images.get('card'));
card.setScaleXY(this.scaleX);
card.x = this.bg.width / 2;
card.y = this.bg.height / 2;
this.bg.addChild(card);
}
private getColsePic(parent) {
const closePic = new MySprite();
closePic.init(this.images.get('close'));
closePic.scaleX = this.scaleX;
closePic.scaleY = this.scaleY;
closePic.x = parent.width - 20 * this.scaleX;
closePic.y = 20 * this.scaleY;
parent.addChild(closePic, 99);
return closePic;
}
setContent(data){
this.shown = false;
if(this.contentSpr){
this.bg.removeChild(this.contentSpr);
}
this.data = data;
let mW = 960 * this.scaleX;
let mH = 560 * this.scaleY;
const pic = new MySprite();
pic.init(this.images.get(this.data.picUrl));
pic.x = this.bg.width / 2;
pic.y = this.bg.height / 2 - 10 * this.scaleY;
let scale = Math.min(mW / pic.width, mH / pic.height);
pic.setScaleXY(scale);
this.contentSpr = pic;
this.bg.addChild(pic, 98);
}
showCard(toX, toY, callback = null){
this.shown = true;
tweenChange(this.bg, {scaleX: 1, scaleY: 1, x : toX, y : toY}, 0.3, callback);
}
hideCard(toX, toY, callback = null){
tweenChange(this.bg, { scaleX: 0, scaleY: 0, x: toX, y: toY }, 0.3, () => {
this.shown = false;
callback && callback();
});
}
}
export class WordBigCard extends BigCard{
picBgArr = [];
wordArr = [];
setContent(data){
this.data = data;
this.shown = false;
let len = this.data.cardWordArr.length;
let width = 900 * this.scaleX;
let maxW = 700 * this.scaleX;
let lineW = 400 * this.scaleX;
let totalW = width;
let dW = 31 * this.scaleX;
if(len == 2){
width = 440 * this.scaleX;
maxW = 360 * this.scaleX;
lineW = 180 * this.scaleX;
totalW = width * 2 + dW;
}
let x = (this.bg.width - totalW ) / 2;
for(let i = 0; i < len ; ++ i){
let cardWord = this.data.cardWordArr[i];
let picBg = this.getView(cardWord, width, maxW, lineW);
picBg.x = x;
picBg.y = (this.bg.height - picBg.height) / 2 - 10 * this.scaleY;
picBg['data'] = cardWord;
this.picBgArr.push(picBg);
x += width + dW;
this.bg.addChild(picBg);
}
}
private getView(cardWord, width, maxW, lineW){
let height = 514 * this.scaleY;
const picBg = new ShapeRect();
picBg.setSize(width, height);
picBg.fillColor = "#f7effc";
let maxH = 300 * this.scaleY;
const pic = new MySprite();
pic.init(this.images.get(cardWord.picUrl));
let scale = Math.min(maxW / pic.width, maxH / pic.height);
pic.setScaleXY(scale);
picBg.addChild(pic);
pic.x = width / 2;
if (cardWord.letterArr && cardWord.letterArr.length > 0) {
pic.y = (height - 140 * this.scaleY) / 2 ;
const line = new ShapeRect();
line.setSize(lineW, 7 * this.scaleY);
line.fillColor = "#949494";
line.x = (width - line.width) / 2;
line.y = height - line.height - 42 * this.scaleY;
picBg.addChild(line);
picBg['line'] = line;
let text2 = this.getTextView(cardWord.letterArr);
text2.y = height / 2 - 195 * this.scaleY + 325 * this.scaleY + text2.getBoundingBox().height / 2;
text2.x = (width - text2.getBoundingBox().width) / 2;
text2.alpha = 0;
let text = this.getTextView2(cardWord.letterArr, text2.scaleX);
text.x = text2.x;
text.y = height / 2 - 195 * this.scaleY + 325 * this.scaleY;
text.alpha = 0;
picBg.addChild(text);
picBg.addChild(text2);
picBg['text'] = text;
picBg['text2'] = text2;
}
else {
pic.y = height / 2;
}
return picBg;
}
getTextView(letterArr) {
const getLabelText = (letter) => {
const text = new LabelText();
text.val = letter.val;
text.fontColor = letter.fontColor;
text.underLine = false;
return text;
}
let labelTextArr = [];
for (let i = 0; i < letterArr.length; ++i) {
var letter = letterArr[i];
let label = getLabelText(letter);
labelTextArr.push(label);
}
const answer = new Label2();
answer.textArr = labelTextArr;
answer.fontSize = 88;
answer.fontName = "MMB";
answer.setScaleXY(this.scaleX);
answer.refreshSize();
answer.setMaxSize(360 * this.scaleX);
return answer;
}
getTextView2(letterArr, scale) {
let getLabel = (letter, fontColor) => {
const label = new Label();
label.text = letter;
label.textAlign = 'center';
label.fontSize = 88;
label.fontName = "MMB";
label.fontColor = fontColor;
label.setScaleXY(scale);
label.refreshSize();
label.y = label.getBoundingBox().height / 2;
return label;
}
const bg = new ShapeRect();
let h = 0;
let w = 0;
let x = 0;
let tmpArr = [];
for (let i = 0; i < letterArr.length; ++i) {
let letter = letterArr[i];
if (!letter) {
continue;
}
let fontColor = letter.fontColor;
for (let j = 0; j < letter.val.length; ++j) {
let label = getLabel(letter.val.charAt(j), fontColor);
bg.addChild(label);
tmpArr.push(label);
}
}
for (let i = 0; i < tmpArr.length; ++i) {
let label = tmpArr[i];
label.x = x;
let tW = Math.ceil(label.getBoundingBox().width);
x += tW;
h = label.getBoundingBox().height;
w += tW;
}
bg.alpha = 0;
bg.visible = false;
bg.setSize(w, h);
return bg;
}
}
\ No newline at end of file
import { BigCard, WordBigCard } from "./BigCard";
import { jelly, Label2, LabelText, MySprite, ShapeRect, ShapeRectNew, tweenChange } from "./Unit";
export class Exercises {
images;
data;
scaleX = 1;
scaleY = 1;
width = 458;
height = 289;
bg;
wordArr = []
wordBgArr = []
pic;
bigCard : BigCard;
wordBigCardArr = [];
constructor(data, images) {
this.data = data;
this.images = images;
}
init(scaleX = 1, scaleY = 1) {
this.scaleX = scaleX;
this.scaleY = scaleY;
this.width *= this.scaleX;
this.height *= this.scaleY;
this.initBg();
this.initPic();
this.initBigCard();
this.initWord();
this.initCardWord();
}
private initBg() {
const bg = new ShapeRect();
bg.setSize(this.width, this.height);
bg.fillColor = "#ffffff";
bg.setShadow(0, 2, 4, 'rgba(0, 0, 0, 0.5)');
this.bg = bg;
}
private initPic() {
let maxW = 458 * this.scaleX;
let maxH = 246 * this.scaleY;
const pic = new MySprite();
pic.init(this.images.get(this.data.picUrl));
pic.x = this.width / 2;
pic.y = maxH / 2;
this.bg.addChild(pic);
let scale = Math.min(maxW / pic.width, maxH / pic.height);
pic.setScaleXY(scale);
this.pic = pic;
}
private initWord() {
let wordArr = this.data.wordArr;
let len = wordArr.length;
let h = 42 * this.scaleY;
let w = this.width;
if (len == 2) {
w = 229 * this.scaleX;
}
let x = 0;
for (let i = 0; i < len; ++i) {
const wordBg = new ShapeRect();
wordBg.setSize(w, h);
let flag = "";
if (i == 0) {
wordBg.fillColor = "#ecd1fa";
flag = 'l';
}
else {
wordBg.fillColor = "#f5dc6f";
flag = 'r';
}
wordBg.y = this.bg.height - h;
wordBg.x = x;
x += (i + 1) * w;
this.bg.addChild(wordBg);
this.wordBgArr.push(wordBg);
this.getWord(wordBg, wordArr[i], flag);
}
}
private getWord(parent, val, flag) {
let text = new Label2();
text.fontName = "GOTHICB";
let fontSize = 30;
text.fontSize = fontSize;
let textArr = new Array<LabelText>();
text.textArr = textArr;
for (let i = 0; i < val.letterArr.length; ++i) {
var letter = val.letterArr[i];
let labelText = new LabelText();
labelText.val = letter.val;
labelText.fontColor = letter.fontColor;
textArr.push(labelText);
}
text.scaleX = this.scaleX;
text.scaleY = this.scaleY;
text.refreshSize();
text.y = parent.height / 2;
if('l' == flag){
text.x = 14 * this.scaleX;
}
else{
text.x = parent.width - text.getBoundingBox().width - 10 * this.scaleX;
}
parent.addChild(text);
this.wordArr.push(text);
}
private initBigCard(){
var data = {
picUrl : this.data.picUrl2,
audioUrl : this.data.audioUrl
}
const bigCard = new BigCard();
bigCard.init(this.images, this.scaleX, this.scaleY);
this.bigCard = bigCard;
bigCard.setContent(data);
bigCard['type'] = 'picCard';
}
private initCardWord(){
for(let i = 0; i < this.data.wordArr.length; ++ i){
let data = this.data.wordArr[i];
const bigCard = new WordBigCard();
bigCard.init(this.images, this.scaleX, this.scaleY);
this.wordBigCardArr.push(bigCard);
bigCard.setContent(data);
bigCard['type'] = 'wordCard';
}
}
textAnimal(item, callback = null) {
let labelArr = item.text.children;
const animal = (label, index) => {
tweenChange(label, { y: label.y - 12 * this.scaleY }, 0.08, () => {
let i = index + 1;
if (labelArr[i]) {
animal(labelArr[i], i);
}
tweenChange(label, { y: label.y + 16 * this.scaleY }, 0.08, () => {
tweenChange(label, { y: label.y - 4 * this.scaleY }, 0.04, () => {
if (callback) {
callback();
if (index == labelArr.length - 1) {
item.text2.alpha = 1;
item.text.visible = false;
jelly(item.text2, 0.7)
}
}
});
});
});
}
item.text2.alpha = 0;
item.text.visible = true;
animal(labelArr[0], 0);
}
}
\ No newline at end of file
import { Label, ShapeCircle, ShapeRect, ShapeRectNew } from "./Unit";
export class Letter{
data;
images;
bgColor;
lineColor;
scaleX = 1;
scaleY = 1;
bg : ShapeRectNew;
dW;
canDrag = true;
init(images, data, bgColor, scaleX = 1, scaleY = 1) {
this.images = images;
this.data = data;
this.bgColor = bgColor;
this.scaleX = scaleX;
this.scaleY = scaleY;
this.initBg();
let letter = this.initView();
let w = 20 * this.scaleX + letter.getBoundingBox().width;
let h = 59 * this.scaleY;
this.bg.setSize(w, h, 0);
letter.x = w / 2;
letter.y = h / 2;
}
initBg(){
let bg = new ShapeRectNew();
bg.fillColor = this.bgColor;
this.bg = bg;
}
initView(){
const letter = new Label();
letter.text = this.data.val;
letter.textAlign = 'center';
letter.fontSize = 36;
letter.fontName = "GOTHICB";
letter.fontColor = "#facf46";
letter.setScaleXY(this.scaleX);
letter.refreshSize();
this.bg.addChild(letter);
return letter;
}
}
\ No newline at end of file
import {
Label,
MySprite, ShapeRectNew,
ShapeCircle,
tweenChange,
ShapeRect
} from './Unit';
import {
playAudio,
pauseAudio
} from './AudioUtil';
export class Listening {
audio;
images;
bg;
btnPlay;
btnStop;
playing = false;
constructor(audio, images) {
this.audio = audio;
this.images = images;
}
init(scaleX = 1, scaleY = 1) {
const bg = new ShapeRect();
const btnPlay = new MySprite();
btnPlay.init(this.images.get('play'));
btnPlay.scaleX = scaleX;
btnPlay.scaleY = scaleY;
btnPlay.x = btnPlay.getBoundingBox().width / 2
btnPlay.y = btnPlay.getBoundingBox().height / 2
this.btnPlay = btnPlay;
bg.addChild(btnPlay);
const btnStop = new MySprite();
btnStop.init(this.images.get('stop'));
btnStop.x = btnPlay.x;
btnStop.y = btnPlay.y;
btnStop.alpha = 0;
btnStop.scaleX = scaleX;
btnStop.scaleY = scaleY;
this.btnStop = btnStop;
bg.addChild(btnStop);
bg.setSize(btnPlay.getBoundingBox().width, btnPlay.getBoundingBox().height);
bg.alpha = 0;
this.bg = bg;
}
play(callback = null){
console.log('playing:', this.playing);
if(!this.playing){
this.playAudio(callback);
return this.audio;
}
else{
this.pauseAudio(callback);
}
return null;
}
reset(){
this.btnPlay.alpha = 1;
this.btnStop.alpha = 0;
this.playing = false;
}
playAudio(callback = null){
this.btnPlay.alpha = 0;
this.btnStop.alpha = 1;
playAudio(this.audio, false, callback);
this.playing = true;
return this.audio;
}
pauseAudio(callback){
this.btnPlay.alpha = 1;
this.btnStop.alpha = 0;
this.playing = false;
pauseAudio(this.audio, false, callback)
}
}
\ No newline at end of file
import {
Label,
MySprite, ShapeRect,
} from './Unit';
import {
playAudio,
pauseAudio
} from './AudioUtil';
export class Title {
titleBg: ShapeRect;
audio;
images;
titleData;
constructor(titleData, images) {
this.titleData = titleData;
this.images = images;
}
init(mapScaleX = 1, mapScaleY = 1) {
let titleBg = new ShapeRect();
//初始化标题1背景
const titePart1Bg = new ShapeRect();
titePart1Bg.fillColor="#763c92";
let pWidth = 117 * mapScaleX;
let pHeight = 65 * mapScaleY;
titePart1Bg.setSize(pWidth, pHeight);
titePart1Bg.setShadow(4,4,0, 'rgba(0, 0, 0, 0.2)');
titePart1Bg.x = 0;
titleBg.addChild(titePart1Bg);
//标题1内容
const part1 = new Label();
part1.text = this.titleData.part1;
part1.textAlign = 'left';
part1.fontSize = 48;
part1.fontName = "BRLNSDB";
part1.fontColor = "#facf46";
part1.setScaleXY(mapScaleX);
part1.refreshSize();
part1.x = pWidth - part1.getBoundingBox().width - 13 * mapScaleX;
part1.y = 5 * mapScaleY + part1.getBoundingBox().height / 2;
titleBg.addChild(part1);
//标题2内容
const part2 = new Label();
part2.text = this.titleData.part2;
part2.fontSize = 36;
part2.fontName = "FUTURA";
part2.fontColor = "#000000";
part2.setScaleXY(mapScaleX);
part2.refreshSize();
part2.x = titePart1Bg.getBoundingBox().width + 11 * mapScaleX;
part2.y = 16 * mapScaleY + part2.getBoundingBox().height / 2;
let height = Math.max(titePart1Bg.getBoundingBox().height, part2.getBoundingBox().height);
let width = titePart1Bg.getBoundingBox().width + part2.getBoundingBox().width + 11 * mapScaleX;
titePart1Bg.y = (height - pHeight)/2;
titleBg.setSize(width, height);
titleBg.alpha = 0;
titleBg.addChild(part2);
this.titleBg = titleBg;
}
getTitleBg(){
return this.titleBg;
}
setAudio(audio){
this.audio = audio;
}
playAudio(callback = null){
playAudio(this.audio, true, callback);
return this.audio;
}
pasueAudio(callback){
pauseAudio(this.audio, true, callback)
}
}
\ No newline at end of file
...@@ -709,6 +709,265 @@ export class Label extends MySprite { ...@@ -709,6 +709,265 @@ export class Label extends MySprite {
} }
export class LabelText {
private _val: string;
private _fontColor = "#000000";
private _underLine: boolean = false;
private _visiable = true;
private _fill = false;
private _width = 0;
private _x = 0;
set val(val) {
this._val = val;
}
get val() {
return this._val;
}
set fontColor(fontColor) {
this._fontColor = fontColor;
}
get fontColor() {
return this._fontColor;
}
set underLine(underLine) {
this._underLine = underLine;
}
get underLine() {
return this._underLine;
}
set visiable(visiable){
this._visiable = visiable;
}
get visiable(){
return this._visiable;
}
set fill(file){
this._fill = file;
}
get fill(){
return this._fill;
}
set width(width){
this._width = width;
}
get width(){
return this._width;
}
set x(val){
this._x = val;
}
get x(){
return this._x;
}
}
export class Label2 extends MySprite {
textArr: Array<LabelText> = [];
fontName = 'Verdana';
textAlign = 'left';
fontSize = 40;
fontColor = '#000000';
fontWeight = 900;
_maxWidth;
outline = 0;
outlineColor = '#ffffff';
_outlineFlag = false;
_outLineWidth;
_outLineColor;
underLineWidth: number;
underLineColor = "#000000";
constructor(ctx = null) {
super(ctx);
this.init();
}
refreshSize() {
this.ctx.save();
this.ctx.font = `${this.fontSize}px ${this.fontName}`;
this.ctx.textAlign = this.textAlign;
this.ctx.textBaseline = 'middle';
this.ctx.fontWeight = this.fontWeight;
let text = "";
let count = 0;
for (let i = 0; i < this.textArr.length; ++i) {
if(this.textArr[i].underLine){
count ++;
continue;
}
text += this.textArr[i].val;
}
if(count > 0){
this._width = this.ctx.measureText(text).width + 36 * count + 4 * (count - 1);
}
else{
this._width = this.ctx.measureText(text).width;
}
this._height = this.fontSize;
this.refreshAnchorOff();
this.ctx.restore();
}
setMaxSize(w) {
this._maxWidth = w;
this.refreshSize();
if (this.width >= w) {
this.scaleX *= w / this.width;
this.scaleY *= w / this.width;
}
}
show(callBack = null) {
this.visible = true;
if (this.alpha >= 1) {
return;
}
const tween = new TWEEN.Tween(this)
.to({ alpha: 1 }, 800)
// .easing(TWEEN.Easing.Quadratic.Out) // Use an easing function to make the animation smooth.
.onComplete(() => {
if (callBack) {
callBack();
}
})
.start(); // Start the tween immediately.
}
setOutline(width = 5, color = '#ffffff') {
this._outlineFlag = true;
this._outLineWidth = width;
this._outLineColor = color;
}
drawText() {
if (!this.textArr) { return; }
this.ctx.font = `${this.fontSize}px ${this.fontName}`;
this.ctx.textAlign = this.textAlign;
this.ctx.textBaseline = 'middle';
this.ctx.fontWeight = this.fontWeight;
var startX = 0;
for (let i = 0; i < this.textArr.length; ++i) {
var text = this.textArr[i];
let width = this.ctx.measureText(text.val).width;
text.width = width;
text.x = startX;
let tempStartX = startX;
let dW = 0;
if (text.underLine && this.underLineWidth > 0) {
this.ctx.save();
this.ctx.beginPath();
this.ctx.lineWidth = this.underLineWidth;
this.ctx.strokeStyle = this.underLineColor;
let lineY = this.fontSize / 2;
this.ctx.moveTo(tempStartX, lineY);
this.ctx.lineTo(tempStartX + 36, lineY);
this.ctx.stroke();
this.ctx.restore();
tempStartX += (36 - width) / 2;
dW = 36 ;
if(this.textArr[i + 1] && this.textArr[i + 1].underLine){
dW += 4 ;
}
}
else{
dW = width;
}
if (this._outlineFlag) {
this.ctx.lineWidth = this._outLineWidth;
this.ctx.strokeStyle = this._outLineColor;
this.ctx.strokeText(text.val, tempStartX, 0);
}
if (this.outline > 0) {
this.ctx.lineWidth = this.outline;
this.ctx.strokeStyle = this.outlineColor;
this.ctx.strokeText(text.val, tempStartX, 0);
}
this.ctx.fillStyle = text.fontColor ? text.fontColor : this.fontColor;
if(text.visiable){
this.ctx.fillText(text.val, tempStartX, 0);
}
startX += dW;
}
}
drawSelf() {
super.drawSelf();
this.drawText();
}
}
export class RichTextOld extends Label { export class RichTextOld extends Label {
textArr = []; textArr = [];
......
const defaultVal = {
"title":{
"part1":"C",
"part2":"Read and point"
},
"letterArr":[
{
"fontColor":"",
"val":"li-"
},
{
"fontColor":"",
"val":"-ment"
},
{
"fontColor":"",
"val":"-tions"
}
],
"exercisesArr":[
{
"wordArr":[
{
"letterArr":[
{
"fontColor":"#363333",
"val":"w"
},
{
"fontColor":"#c8171e",
"val":"o"
},
{
"fontColor":"#c8171e",
"val":"r"
},
{
"fontColor":"#363333",
"val":"d"
}
],
"cardWordArr":[
{
"letterArr":[
{
"fontColor":"#363333",
"val":"m"
},
{
"fontColor":"#c8171e",
"val":"e"
},
{
"fontColor":"#c8171e",
"val":"n"
},
{
"fontColor":"#363333",
"val":"t"
}
],
"picUrl":"http://staging-teach.cdn.ireadabc.com/58eed310f61fa54c21cd58370bd7c95b.png",
"val":"ment"
}
],
"val":"word"
}
],
"picUrl":"http://staging-teach.cdn.ireadabc.com/b2eff94a06fa6c4a5ffa4274579e4e06.png",
"picUrl2":"http://staging-teach.cdn.ireadabc.com/24062d7723aaf62ab9347c9865e174ac.jpg",
"audioUrl":"http://staging-teach.cdn.ireadabc.com/40f094919352867eaf6c79995a32adf8.mp3"
},
{
"wordArr":[
{
"letterArr":[
{
"fontColor":"#363333",
"val":"h"
},
{
"fontColor":"#c8171e",
"val":"e"
},
{
"fontColor":"#c8171e",
"val":"a"
},
{
"fontColor":"#363333",
"val":"t"
}
],
"cardWordArr":[
{
"letterArr":[
{
"fontColor":"#c8171e",
"val":"r"
},
{
"fontColor":"#c8171e",
"val":"e"
},
{
"fontColor":"#363333",
"val":"h"
},
{
"fontColor":"#363333",
"val":"e"
},
{
"fontColor":"#363333",
"val":"a"
},
{
"fontColor":"#363333",
"val":"t"
}
],
"picUrl":"http://staging-teach.cdn.ireadabc.com/a41083db803c2f15cd67402f4b751b87.png",
"audioUrl":"http://staging-teach.cdn.ireadabc.com/b62600fd1e72b54d1d1c3bc71b7361af.mp3",
"val":"reheat"
},
{
"letterArr":[
{
"fontColor":"#363333",
"val":"a"
},
{
"fontColor":"#c8171e",
"val":"g"
},
{
"fontColor":"#c8171e",
"val":"r"
},
{
"fontColor":"#363333",
"val":"e"
},
{
"fontColor":"#363333",
"val":"e"
}
],
"cardWordArr":[
{
"letterArr":[
]
}
],
"picUrl":"http://staging-teach.cdn.ireadabc.com/7502f454d1edc0d1d52efbe8a9b2020a.png",
"audioUrl":"http://staging-teach.cdn.ireadabc.com/a252c069d04f8e04f91b2a1394072f30.mp3",
"val":"agree"
}
],
"val":"heat"
},
{
"letterArr":[
{
"fontColor":"#c8171e",
"val":"r"
},
{
"fontColor":"#c8171e",
"val":"e"
},
{
"fontColor":"#363333",
"val":"h"
},
{
"fontColor":"#363333",
"val":"e"
},
{
"fontColor":"#363333",
"val":"a"
},
{
"fontColor":"#363333",
"val":"t"
}
],
"cardWordArr":[
{
"letterArr":[
{
"fontColor":"#363333",
"val":"s"
},
{
"fontColor":"#363333",
"val":"o"
},
{
"fontColor":"#363333",
"val":"r"
},
{
"fontColor":"#c8171e",
"val":"r"
},
{
"fontColor":"#c8171e",
"val":"y"
}
],
"picUrl":"http://staging-teach.cdn.ireadabc.com/86fb8f1694cf0d5d2d81c26fecfae709.png",
"audioUrl":"http://staging-teach.cdn.ireadabc.com/71eb8fcc0895873363840db7bc0c5883.mp3",
"val":"sorry"
}
],
"val":"reheat"
}
],
"picUrl2":"http://staging-teach.cdn.ireadabc.com/9d7bdb483c7690728f0658022753c8ed.png",
"picUrl":"http://staging-teach.cdn.ireadabc.com/7629f54dc9ae5e3c556b4d898509f888.png",
"audioUrl":"http://staging-teach.cdn.ireadabc.com/30621df106455523573e3871a5a5c598.mp3"
},
{
"wordArr":[
{
"letterArr":[
{
"fontColor":"#363333",
"val":"m"
},
{
"fontColor":"#c8171e",
"val":"i"
},
{
"fontColor":"#c8171e",
"val":"l"
},
{
"fontColor":"#363333",
"val":"k"
}
],
"cardWordArr":[
{
"letterArr":[
{
"fontColor":"#c8171e",
"val":"u"
},
{
"fontColor":"#c8171e",
"val":"n"
},
{
"fontColor":"#c8171e",
"val":"d"
},
{
"fontColor":"#c8171e",
"val":"e"
},
{
"fontColor":"#c8171e",
"val":"r"
},
{
"fontColor":"#363333",
"val":"s"
},
{
"fontColor":"#363333",
"val":"t"
},
{
"fontColor":"#363333",
"val":"a"
},
{
"fontColor":"#363333",
"val":"n"
},
{
"fontColor":"#363333",
"val":"d"
}
],
"picUrl":"http://staging-teach.cdn.ireadabc.com/9fb5a33ee489517de5f2a2cf2d926a32.jpg",
"val":"understand"
}
],
"val":"milk"
}
],
"picUrl":"http://staging-teach.cdn.ireadabc.com/10dab2d49188db958a6a6e6b3ab7b5f5.png",
"picUrl2":"http://staging-teach.cdn.ireadabc.com/cb6a2f948c3febbb7881e6b6a7417811.png",
"audioUrl":"http://staging-teach.cdn.ireadabc.com/b62600fd1e72b54d1d1c3bc71b7361af.mp3"
},
{
"wordArr":[
{
"letterArr":[
{
"fontColor":"#363333",
"val":"c"
},
{
"fontColor":"#363333",
"val":"a"
},
{
"fontColor":"#363333",
"val":"r"
},
{
"fontColor":"#c8171e",
"val":"r"
},
{
"fontColor":"#c8171e",
"val":"y"
}
],
"cardWordArr":[
{
"letterArr":[
{
"fontColor":"#363333",
"val":"M"
},
{
"fontColor":"#c8171e",
"val":"i"
},
{
"fontColor":"#c8171e",
"val":"k"
},
{
"fontColor":"#c8171e",
"val":"e"
}
],
"picUrl":"http://staging-teach.cdn.ireadabc.com/a91faf548f5f6ef9e326fc0ea02190e2.png",
"val":"Mike"
}
],
"val":"carry"
}
],
"picUrl":"http://staging-teach.cdn.ireadabc.com/9148a2bd1b91308cb58c843d8874f570.jpg",
"picUrl2":"http://staging-teach.cdn.ireadabc.com/c5b8cb01164ef0e5770de54080ea6cad.jpg",
"audioUrl":"http://staging-teach.cdn.ireadabc.com/a252c069d04f8e04f91b2a1394072f30.mp3"
}
],
"listenAudioUrl":"http://staging-teach.cdn.ireadabc.com/919b2c150b41b3306869ebe78ecb70b3.mp3"
};
export {defaultVal};
\ No newline at end of file
...@@ -17,3 +17,20 @@ ...@@ -17,3 +17,20 @@
src: url("../../assets/font/BRLNSDB.TTF") ; src: url("../../assets/font/BRLNSDB.TTF") ;
} }
@font-face
{
font-family: 'GOTHIC';
src: url("../../assets/font/GOTHIC.TTF") ;
}
@font-face
{
font-family: 'GOTHICB';
src: url("../../assets/font/GOTHICB.TTF") ;
}
@font-face
{
font-family: 'MMB';
src: url("../../assets/font/MMTextBook-Bold.otf") ;
}
\ No newline at end of file
import {Component, ElementRef, ViewChild, OnInit, Input, OnDestroy, HostListener} from '@angular/core'; import { Component, ElementRef, ViewChild, OnInit, OnDestroy, HostListener } from '@angular/core';
import { import {
Label, ShapeRect,
MySprite, tweenChange,
} from './Unit'; } from './Unit';
import {res, resAudio} from './resources'; import { res, resAudio } from './resources';
import {Subject} from 'rxjs'; import { Subject } from 'rxjs';
import {debounceTime} from 'rxjs/operators'; import { debounceTime } from 'rxjs/operators';
import TWEEN from '@tweenjs/tween.js'; import TWEEN from '@tweenjs/tween.js';
import { Listening } from './Listening';
import { Title } from './Title';
import { getDefaultCardWord, getDefaultExercises, getDefaultWord } from '../bean/ExercisesBean';
import { getDefaultTile } from '../bean/TitleBean';
import { Letter } from './Letter';
import { Exercises } from './Exercises';
import { defaultVal } from './defaultValue.js';
...@@ -22,8 +28,8 @@ import TWEEN from '@tweenjs/tween.js'; ...@@ -22,8 +28,8 @@ import TWEEN from '@tweenjs/tween.js';
}) })
export class PlayComponent implements OnInit, OnDestroy { export class PlayComponent implements OnInit, OnDestroy {
@ViewChild('canvas', {static: true }) canvas: ElementRef; @ViewChild('canvas', { static: true }) canvas: ElementRef;
@ViewChild('wrap', {static: true }) wrap: ElementRef; @ViewChild('wrap', { static: true }) wrap: ElementRef;
// 数据 // 数据
data; data;
...@@ -52,22 +58,34 @@ export class PlayComponent implements OnInit, OnDestroy { ...@@ -52,22 +58,34 @@ export class PlayComponent implements OnInit, OnDestroy {
audioObj = {}; audioObj = {};
renderArr; renderArr;
bigCardRenderArr = [];
mapScale = 1; mapScale = 1;
canvasLeft; canvasLeft;
canvasTop; canvasTop;
saveKey = 'test_0011'; saveKey = 'YM5-22';
/**标题*/
title;
btnLeft; listening;
btnRight;
pic1; curAudio;
pic2;
canTouch = true; canTouch = true;
curPic; letterArr = [];
exercisesArr = [];
curBigCard;
curExercises;
curWord;
mask: ShapeRect;
@HostListener('window:resize', ['$event']) @HostListener('window:resize', ['$event'])
onResize(event) { onResize(event) {
...@@ -80,13 +98,16 @@ export class PlayComponent implements OnInit, OnDestroy { ...@@ -80,13 +98,16 @@ export class PlayComponent implements OnInit, OnDestroy {
this.data = {}; this.data = {};
// 获取数据 // 获取数据
const getData = (<any> window).courseware.getData; const getData = (<any>window).courseware.getData;
getData((data) => { getData((data) => {
if (data && typeof data == 'object') { if (data && typeof data == 'object') {
this.data = data; this.data = data;
} }
// console.log('data:' , data); else{
this.data = defaultVal;
}
//console.log('data:', JSON.stringify(data));
// 初始化 各事件监听 // 初始化 各事件监听
this.initListener(); this.initListener();
...@@ -285,6 +306,9 @@ export class PlayComponent implements OnInit, OnDestroy { ...@@ -285,6 +306,9 @@ export class PlayComponent implements OnInit, OnDestroy {
const audio = this.audioObj[key]; const audio = this.audioObj[key];
if (audio) { if (audio) {
this.pauseAudio(this.curAudio);
if (now) { if (now) {
audio.pause(); audio.pause();
audio.currentTime = 0; audio.currentTime = 0;
...@@ -296,6 +320,20 @@ export class PlayComponent implements OnInit, OnDestroy { ...@@ -296,6 +320,20 @@ export class PlayComponent implements OnInit, OnDestroy {
}; };
} }
audio.play(); audio.play();
}
return audio;
}
pauseAudio(audio) {
if (audio) {
if (this.listening && audio == this.listening.audio) {
this.listening.pauseAudio();
}
else {
audio.pause();
}
} }
} }
...@@ -341,7 +379,7 @@ export class PlayComponent implements OnInit, OnDestroy { ...@@ -341,7 +379,7 @@ export class PlayComponent implements OnInit, OnDestroy {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const audio = new Audio(); const audio = new Audio();
audio.oncanplay = (a) => { audio.oncanplay = (a) => {
resolve(); resolve(a);
}; };
audio.onerror = () => { audio.onerror = () => {
reject(); reject();
...@@ -443,10 +481,54 @@ export class PlayComponent implements OnInit, OnDestroy { ...@@ -443,10 +481,54 @@ export class PlayComponent implements OnInit, OnDestroy {
*/ */
initDefaultData() { initDefaultData() {
if (!this.data.pic_url) { if (!this.data.title) {
this.data.pic_url = 'assets/play/default/pic.jpg'; this.data.title = getDefaultTile();
this.data.pic_url_2 = 'assets/play/default/pic.jpg'; }
if (!this.data.letterArr) {
this.data.letterArr = [];
}
if (!this.data.exercisesArr) {
this.data.exercisesArr = [];
}
for (let i = this.data.exercisesArr.length; i < 4; ++i) {
let exercises = getDefaultExercises();
this.data.exercisesArr.push(exercises);
} }
for (let i = 0; i < this.data.exercisesArr.length; ++i) {
let exercises = this.data.exercisesArr[i];
if (!exercises.wordArr) {
exercises.wordArr = [];
}
if (exercises.wordArr.length == 0) {
let word = getDefaultWord();
exercises.wordArr.push(word);
}
for (let j = 0; j < exercises.wordArr.length; ++j) {
let word = exercises.wordArr[j];
if (!word.cardWordArr) {
word.cardWordArr = [];
}
if (word.cardWordArr.length == 0) {
let cardWord = getDefaultCardWord();
word.cardWordArr.push(cardWord);
}
}
}
} }
...@@ -454,9 +536,33 @@ export class PlayComponent implements OnInit, OnDestroy { ...@@ -454,9 +536,33 @@ export class PlayComponent implements OnInit, OnDestroy {
* 添加预加载图片 * 添加预加载图片
*/ */
initImg() { initImg() {
for (let i = 0; i < this.data.exercisesArr.length; ++i) {
let exercises = this.data.exercisesArr[i];
if (exercises.picUrl) {
this.addUrlToImages(exercises.picUrl);
}
if (exercises.picUrl2) {
this.addUrlToImages(exercises.picUrl2);
}
for (let j = 0; j < exercises.wordArr.length; ++j) {
let word = exercises.wordArr[j];
for (let m = 0; m < word.cardWordArr.length; ++m) {
let cardWord = word.cardWordArr[m];
if (cardWord.picUrl) {
this.addUrlToImages(cardWord.picUrl);
}
}
}
}
this.addUrlToImages(this.data.pic_url);
this.addUrlToImages(this.data.pic_url_2);
} }
...@@ -465,13 +571,52 @@ export class PlayComponent implements OnInit, OnDestroy { ...@@ -465,13 +571,52 @@ export class PlayComponent implements OnInit, OnDestroy {
*/ */
initAudio() { initAudio() {
// 音频资源
this.addUrlToAudioObj(this.data.audio_url);
this.addUrlToAudioObj(this.data.audio_url_2);
// 音效 // 音效
this.addUrlToAudioObj('click', this.rawAudios.get('click'), 0.3); this.rawAudios.forEach((item, key) => {
// 音效
this.addUrlToAudioObj(key, item);
})
//标题发音
if (this.data.title.audioUrl) {
this.addUrlToAudioObj('titleAudio', this.data.title.audioUrl);
}
//听力材料
if (this.data.listenAudioUrl) {
this.addUrlToAudioObj('listenAudio', this.data.listenAudioUrl);
}
for (let i = 0; i < this.data.letterArr.length; ++i) {
let letter = this.data.letterArr[i];
if (letter.audioUrl) {
this.addUrlToAudioObj(letter.audioUrl);
}
}
for (let i = 0; i < this.data.exercisesArr.length; ++i) {
let exercises = this.data.exercisesArr[i];
if (exercises.audioUrl) {
this.addUrlToAudioObj(exercises.audioUrl);
}
for (let j = 0; j < exercises.wordArr.length; ++j) {
let word = exercises.wordArr[j];
for (let m = 0; m < word.cardWordArr.length; ++m) {
let cardWord = word.cardWordArr[m];
if (cardWord.audioUrl) {
this.addUrlToAudioObj(cardWord.audioUrl);
}
}
}
}
} }
...@@ -486,14 +631,16 @@ export class PlayComponent implements OnInit, OnDestroy { ...@@ -486,14 +631,16 @@ export class PlayComponent implements OnInit, OnDestroy {
const s = Math.min(sx, sy); const s = Math.min(sx, sy);
this.mapScale = s; this.mapScale = s;
// this.mapScale = sx;
// this.mapScale = sy;
this.renderArr = []; this.renderArr = [];
this.bigCardRenderArr = [];
this.letterArr = [];
this.exercisesArr = [];
this.curBigCard = null;
} }
...@@ -503,159 +650,198 @@ export class PlayComponent implements OnInit, OnDestroy { ...@@ -503,159 +650,198 @@ export class PlayComponent implements OnInit, OnDestroy {
*/ */
initView() { initView() {
this.initTitle();
this.initPic(); this.initLetter();
this.initBottomPart(); this.initBottomPart();
this.initExercises();
this.initMask();
} }
initBottomPart() { initBottomPart() {
const btnLeft = new MySprite(); if (!this.data.listenAudioUrl) {
btnLeft.init(this.images.get('btn_left')); return;
btnLeft.x = this.canvasWidth - 150 * this.mapScale; }
btnLeft.y = this.canvasHeight - 100 * this.mapScale;
btnLeft.setScaleXY(this.mapScale);
this.renderArr.push(btnLeft); const listening = new Listening(this.audioObj['listenAudio'], this.images);
listening.init(this.mapScale, this.mapScale);
this.btnLeft = btnLeft; listening.bg.x = this.canvasWidth - listening.bg.width - 10 * this.mapScale;
listening.bg.y = this.canvasHeight - listening.bg.height - 6.5 * this.mapScale;
this.listening = listening;
this.renderArr.push(listening.bg);
}
initTitle() {
const title = new Title(this.data.title, this.images);
const btnRight = new MySprite(); title.init(this.mapScale, this.mapScale);
btnRight.init(this.images.get('btn_right')); title.audio = this.audioObj['titleAudio'];
btnRight.x = this.canvasWidth - 50 * this.mapScale; this.title = title;
btnRight.y = this.canvasHeight - 100 * this.mapScale;
btnRight.setScaleXY(this.mapScale);
this.renderArr.push(btnRight); title.titleBg.y = 0;
title.titleBg.x = 0;
this.btnRight = btnRight; this.renderArr.push(title.titleBg);
} }
initPic() { initLetter() {
const maxW = this.canvasWidth * 0.7; let x = this.canvasWidth / 2;
const pic1 = new MySprite(); let dw = 17 * this.mapScale;
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); for (let i = 0; i < this.data.letterArr.length; ++i) {
this.pic1 = pic1;
let data = this.data.letterArr[i];
const label1 = new Label(); let letter = new Letter();
label1.text = this.data.text; letter.init(this.images, data, '#763c92', this.mapScale, this.mapScale);
label1.textAlign = 'center';
label1.fontSize = 50;
label1.fontName = 'BRLNSDB';
label1.fontColor = '#ffffff';
pic1.addChild(label1); letter.bg.y = 0;
letter.bg.x = x;
x += letter.bg.width + dw;
this.renderArr.push(letter.bg);
this.letterArr.push(letter);
}
}
const pic2 = new MySprite(); initExercises() {
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); let dw = 40 * this.mapScale;
this.pic2 = pic2;
this.curPic = pic1; let dh = 19 * this.mapScale;
}
let width = 458 * this.mapScale;
btnLeftClicked() { let col = 2;
this.lastPage(); let tW = col * width + (col - 1) * dw;
}
btnRightClicked() { let x = (this.canvasWidth - tW) / 2;
let y = this.canvasHeight / 2 - 255 * this.mapScale;
this.nextPage(); let tempX = x;
}
lastPage() { for (let i = 0; i < this.data.exercisesArr.length; ++i) {
let data = this.data.exercisesArr[i];
if (this.curPic == this.pic1) { let exercises = new Exercises(data, this.images);
return; exercises.init(this.mapScale, this.mapScale);
} exercises.bg.x = x;
exercises.bg.y = y;
this.canTouch = false; if ((i + 1) % 2 == 0) {
const moveLen = this.canvasWidth; //到下一行恢复起始x坐标
tweenChange(this.pic1, {x: this.pic1.x + moveLen}, 1); x = tempX;
tweenChange(this.pic2, {x: this.pic2.x + moveLen}, 1, () => {
this.canTouch = true; y += exercises.bg.height + dh;
this.curPic = this.pic1;
}); }
else {
x += exercises.bg.width + dw;
} }
nextPage() { this.renderArr.push(exercises.bg);
if (this.curPic == this.pic2) { this.exercisesArr.push(exercises);
return; }
} }
this.canTouch = false; initMask() {
const mask = new ShapeRect();
mask.setSize(this.canvasWidth, this.canvasHeight);
mask.visible = false;
mask.alpha = 0.3
mask.fillColor = "#000000";
this.renderArr.push(mask);
this.mask = mask;
}
const moveLen = this.canvasWidth;
tweenChange(this.pic1, {x: this.pic1.x - moveLen}, 1); mapDown(event) {
tweenChange(this.pic2, {x: this.pic2.x - moveLen}, 1, () => {
this.canTouch = true; if (!this.canTouch) {
this.curPic = this.pic2; return;
});
} }
pic1Clicked() { //卡片显示
this.playAudio(this.data.audio_url); if (this.curBigCard) {
if (this.checkClickTarget(this.curBigCard.bg)) {
this.clickCard();
return;
} }
pic2Clicked() { return;
this.playAudio(this.data.audio_url_2);
} }
if (this.listening && this.checkClickTarget(this.listening.bg)) {
let tempAudio = this.curAudio;
if (tempAudio) {
tempAudio.pause();
}
mapDown(event) { this.curAudio = this.listening.play(() => {
this.listening.reset();
});
if (!this.canTouch) {
return; return;
} }
if ( this.checkClickTarget(this.btnLeft) ) { if (this.checkClickTarget(this.title.titleBg)) {
this.btnLeftClicked(); this.pauseAudio(this.curAudio);
let audio = this.title.playAudio();
if (audio) {
this.curAudio = audio;
}
return; return;
} }
if ( this.checkClickTarget(this.btnRight) ) { for (let i = 0; i < this.letterArr.length; ++i) {
this.btnRightClicked(); let letter = this.letterArr[i];
if (this.checkClickTarget(letter.bg)) {
this.playAudio(letter.data.audioUrl);
return; return;
} }
}
if ( this.checkClickTarget(this.pic1) ) { let clicked = false;
this.pic1Clicked();
return; let target;
let callback;
for (let i = 0; i < this.exercisesArr.length; ++i) {
let exer = this.exercisesArr[i];
if (this.checkClickTarget(exer.bg)) {
callback = this.clickExercises.bind(this);
clicked = true;
target = exer;
break;
}
} }
if ( this.checkClickTarget(this.pic2) ) { if (clicked) {
this.pic2Clicked(); this.curExercises = target;
callback(target);
return; return;
} }
} }
mapMove(event) { mapMove(event) {
...@@ -682,9 +868,145 @@ export class PlayComponent implements OnInit, OnDestroy { ...@@ -682,9 +868,145 @@ export class PlayComponent implements OnInit, OnDestroy {
this.updateArr(this.renderArr); this.updateArr(this.renderArr);
this.updateArr(this.bigCardRenderArr);
}
clickExercises(item) {
if (this.checkClickTarget(item.pic)) {
let bigCard = item.bigCard;
let x = this.curExercises.bg.x;
let y = this.curExercises.bg.y;
this.showBigCard(bigCard, x, y, () => {
this.canTouch = true;
})
return;
} }
else {
for (let i = 0; i < item.wordBgArr.length; ++i) {
let wordBg = item.wordBgArr[i];
let word = item.wordArr[i]
this.curWord = word;
if (this.checkClickTarget(wordBg)) {
let bigCard = item.wordBigCardArr[i];
let x = word.getBoundingBox().x;
let y = word.getBoundingBox().y;
this.showBigCard(bigCard, x, y, () => {
this.canTouch = true;
})
return;
}
}
}
}
private showBigCard(bigCard, x, y, callback) {
const index = this.bigCardRenderArr.indexOf(bigCard.bg);
if (index == -1) {
bigCard.bg.x = x;
bigCard.bg.y = y;
this.bigCardRenderArr.push(bigCard.bg);
}
this.playAudio('open', true);
this.mask.visible = true;
this.curBigCard = bigCard;
let toX = (this.canvasWidth - bigCard.bg.width) / 2;
let toY = (this.canvasHeight - bigCard.bg.height) / 2;
this.canTouch = false;
bigCard.showCard(toX, toY, callback);
}
clickCard() {
let bigCard = this.curBigCard;
if (bigCard['type'] == 'picCard') {
if (this.checkClickTarget(bigCard.contentSpr)) {
this.playAudio(bigCard.data.audioUrl);
return;
}
if (this.checkClickTarget(bigCard.closePic)) {
this.playAudio('close', true);
let toX = this.curExercises.bg.x;
let toY = this.curExercises.bg.y;
bigCard.hideCard(toX, toY, () => {
this.mask.visible = false;
this.curBigCard = null;
this.curExercises = null;
});
}
}
else if (bigCard['type'] == 'wordCard') {
if (this.checkClickTarget(bigCard.closePic)) {
this.playAudio('close', true);
let toX = this.curWord.getBoundingBox().x;
let toY = this.curWord.getBoundingBox().y;
bigCard.hideCard(toX, toY, () => {
this.mask.visible = false;
this.curBigCard = null;
this.curExercises = null;
});
return;
}
let picBgArr = bigCard.picBgArr;
for (let i = 0; i < picBgArr.length; ++i) {
let picBg = picBgArr[i];
if (this.checkClickTarget(picBg)) {
this.canTouch = false;
if (picBg.line) {
if (picBg.line.alpha == 1) {
picBg.line.alpha = 0;
picBg.text.visible = true;
this.curExercises.textAnimal(picBg, () => {
this.canTouch = true;
})
}
else {
this.curExercises.textAnimal(picBg, () => {
this.canTouch = true;
})
this.curAudio = this.playAudio(picBg.data.audioUrl, true);
}
}
else {
this.curAudio = this.playAudio(picBg.data.audioUrl, true);
}
return;
}
}
}
}
} }
const res = [ const res = [
// ['bg', "assets/play/bg.jpg"], ['play', "assets/play/play.png"],
['btn_left', "assets/play/btn_left.png"], ['stop', "assets/play/stop.png"],
['btn_right', "assets/play/btn_right.png"], ['close', "assets/play/close.png"],
// ['text_bg', "assets/play/text_bg.png"], ['card', "assets/play/card.png"],
]; ];
...@@ -12,7 +11,9 @@ const res = [ ...@@ -12,7 +11,9 @@ const res = [
const resAudio = [ const resAudio = [
['click', "assets/play/music/click.mp3"], ['click', "assets/play/music/click.mp3"],
['open', "assets/play/music/open.mp3"],
['back', "assets/play/music/back.mp3"],
['close', "assets/play/music/close.mp3"],
]; ];
export {res, resAudio}; export {res, resAudio};
This source diff could not be displayed because it is too large. You can view the blob instead.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment