Commit 77f1d8ef authored by 李维's avatar 李维

dev done

parent 9f3a2900
......@@ -353,64 +353,4 @@ npm start
点击“模板管理” 菜单,找到对应的模板卡片,点击“发布”按钮,在弹出的对话框中选中压缩包,然后点击“确定”,上传完成后,则发布就成功了
## 常见问题汇总
### 静态资源引用路径写法
css文件里面要带 .. , eg:
```
background-image: url("../../assets/playground-house/bg.jpg");
```
其他的文件(html、ts、resources.js)里路径要开头不带斜杠, eg:
```
src="assets/guess-read/btn.png"
```
### no such file or directory,
出现类似如:
```
Error: ENOENT: no such file or directory, open 'C:/publish/resources/xxxx/v1/index.html'
```
这样的代码时, 请确认新建模板的时候表单填写的“配置页面URL”与“展示页面URL” 填写的路径是否正确
### 已经发布的模板,制作课件时看不到
如果模板已经确认发布成功了,制作课件的时候却看不到这个模板,请编辑模板,查看模板类型是否选择为“课中模板”
### 有些模板上传图片或视频时,存在偶尔上传不上去的问题
此问题是因为有些异步的情况下 uploadUrl 获取不到导致的
在 constructor 或者 ngOnInit 方法里,一直轮询,直到获取到 uploadUrl
```
this.uploadUrl = (<any> window).courseware.uploadUrl();
this.uploadData = (<any> window).courseware.uploadData();
const fun = () => {
setTimeout(() => {
this.uploadUrl = (<any> window).courseware.uploadUrl();
this.uploadData = (<any> window).courseware.uploadData();
if(!this.uploadUrl){
fun();
}
}, 1000);
}
if(!this.uploadUrl){
fun();
}
```
### 模板编译CI不通过,报类似如下错误
```
ERROR in ./src/styles.scss Module build failed (from ./node_modules/mini-css-extract-plugin/dist/loader.js): ModuleBuildError: Module build failed (from ./node_modules/sass-loader/dist/cjs.js): Error: Node Sass version 5.0.0 is incompatible with ^4.0.0. at getSassImplementation
```
此情况属于老的模板遗留问题,需要在package.json里面锁一下node-sass的版本
```
"node-sass": "4.0.0"
```
\ No newline at end of file
......@@ -32,7 +32,7 @@
"spark-md5": "^3.0.0",
"tslib": "^1.10.0",
"zone.js": "~0.10.2",
"node-sass": "4.0.0"
"node-sass": "^4.0.0"
},
"devDependencies": {
"@angular-devkit/build-angular": "~0.900.3",
......
......@@ -24,6 +24,10 @@ 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 { CoursewareFolderTableComponent } from './common/courseware-folder-table/courseware-folder-table.component';
import { CustomHotZone2Component } from './common/custom-hot-zone-2/custom-hot-zone-2.component';
// import { ImageChildrenEditorComponent } from './common/image-children-editor/image-children-editor.component';
registerLocaleData(zh);
......@@ -41,6 +45,17 @@ registerLocaleData(zh);
UploadVideoComponent,
CustomHotZoneComponent,
CoursewareFolderTableComponent,
CustomHotZone2Component,
// ImageChildrenEditorComponent,
LessonTitleConfigComponent,
PlayerContentWrapperComponent,
PlayerContentWrapperComponent
],
......
<nz-table
class="table-container"
#rowSelectionTable
[nzData]="data"
[nzScroll]="{ y: 'calc(100vh - 29rem)' }"
>
<thead
(nzSortChange)="sort($event)"
>
<tr>
<th nzWidth="62px"></th>
<th nzShowSort nzSortKey="name">Name</th>
<th nzWidth="200px" nzShowSort nzSortKey="updateon">Last</th>
</tr>
</thead>
<tbody>
<tr
*ngFor="let data of rowSelectionTable.data"
(dragstart)="onHandleDragStart($event, data)"
(drop)="data.type === 1 ? dropFolderHandler($event, data) : null"
(dragover)="data.type === 1 ? dragOverHandler($event, data) : null"
(dragleave)="data.type === 1 ? dragLeaveHandler($event) : null"
>
<td
nzShowCheckbox
[(nzChecked)]="data._checked"
[nzDisabled]="data.disabled"
(nzCheckedChange)="onHandleChecked(data)"
></td>
<td>
<div
class="td-type-name-wrap"
*ngIf="data.type === 1"
>
<img
class="p-icon"
src="./assets/folder.png"
(dblclick)="dbClickFolder(data)"
/>
<span>
<div class="p-name" [title]="data.name" *ngIf="!data._inEdit" (dblclick)="onUpdateName(data)">
{{data.name}}
</div>
<input
class="p-name-input"
appAutofocusSelect
*ngIf="data._inEdit"
(blur)="onConfirmFolderName(data)"
(keydown.enter)="onConfirmFolderName(data)"
[(ngModel)]="data._name"/>
</span>
<img class="p-share-pic" *ngIf="isInLinkFolder" src="./assets/link_share.png" (dblclick)="dbClickFile(data)">
</div>
<div
class="td-type-name-wrap"
*ngIf="data.type === 2"
>
<img
class="p-icon"
src="./assets/cw.png"
(dblclick)="dbClickFile(data)"
/>
<span>
<div class="p-name" title="{{data.name}}" *ngIf="!data._inEdit" (dblclick)="onUpdateName(data)">
{{data.name}}
</div>
<input
class="p-name-input"
appAutofocusSelect
*ngIf="data._inEdit"
(blur)="onConfirmCoursewareName(data)"
(keydown.enter)="onConfirmCoursewareName(data)"
[(ngModel)]="data._name"/>
</span>
<img class="p-share-pic" *ngIf="isInLinkFolder" src="./assets/link_share.png" (dblclick)="dbClickFile(data)">
</div>
</td>
<td>{{data.updateon | date : 'yyyy-MM-dd HH:mm:ss'}}</td>
</tr>
</tbody>
</nz-table>
.table-container {
.td-type-name-wrap {
position: relative;
display: flex;
justify-content: flex-start;
align-items: center;
img {
width: 32px;
margin-right: 8px;
}
}
}
.p-share-pic {
width: 0.8rem !important;
height: 0.8rem;
position: absolute;
left: -0.2rem;
top: 1.3rem;
}
import {Component, EventEmitter, Input, Output} from '@angular/core';
@Component({
selector: 'app-courseware-folder-table',
templateUrl: './courseware-folder-table.component.html',
styleUrls : ['./courseware-folder-table.component.scss']
})
export class CoursewareFolderTableComponent {
@Input() data = [];
@Input() isInLinkFolder = false;
@Output() handleSelect = new EventEmitter();
@Output() enterFolder = new EventEmitter();
@Output() enterCourseware = new EventEmitter();
@Output() updateName = new EventEmitter();
@Output() confirmFolderName = new EventEmitter();
@Output() confirmCoursewareName = new EventEmitter();
@Output() moveByDrag = new EventEmitter();
@Output() handleSort = new EventEmitter();
constructor() {
// console.log(this.data);
}
onHandleChecked(item) {
this.handleSelect.emit(item);
}
dbClickFolder(item) {
this.enterFolder.emit(item);
}
dbClickFile(item) {
this.enterCourseware.emit(item);
}
onUpdateName(item) {
if (this.isInLinkFolder) {
return;
}
item._name = item.name;
item._inEdit = true;
this.updateName.emit(item);
}
onConfirmFolderName(item) {
this.confirmFolderName.emit(item);
}
onConfirmCoursewareName(item) {
this.confirmCoursewareName.emit(item);
}
sort(sort: { key: string, value: string }): void {
const { key, value } = sort;
// remove value suffix 'end', origin value ['descend', 'ascend']
const t = value ? value.substr(0, value.length - 3) : value;
this.handleSort.emit({ key, value: t });
}
onHandleDragStart(ev, item) {
if (this.isInLinkFolder) {
return;
}
ev.dataTransfer.setData('sid', item.sid);
ev.dataTransfer.setData('type', item.type);
}
dragOverHandler(ev, item) {
if (this.isInLinkFolder) {
return;
}
ev.preventDefault();
ev.dataTransfer.dropEffect = 'move';
ev.currentTarget.style.background = '#d4d4d4';
}
dragLeaveHandler(ev) {
if (this.isInLinkFolder) {
return;
}
ev.preventDefault();
ev.currentTarget.style.background = '';
}
dropFolderHandler(ev, item) {
if (this.isInLinkFolder) {
return;
}
ev.preventDefault();
ev.currentTarget.style.background = '';
const sid = ev.dataTransfer.getData('sid');
const type = ev.dataTransfer.getData('type');
const object = { sid, type, item };
this.moveByDrag.emit(object);
}
}
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;
offSetCenter = false;
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;
if(this.offSetCenter){
this.ctx.translate( -( this.width * this.anchorX ), -( this.height * this.anchorY ) );
}
}
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) {
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;
}
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;
text;
arrowTop;
arrowRight;
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.label.color = "#7a4250"
this.addChild(this.label);
this.refreshLabelScale();
}
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;
}
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/l3-34-2/common/arrow.png', 1, 0);
this.arrow.setScaleXY(0.06);
this.arrowTop = new MySprite(this.ctx);
this.arrowTop.load('assets/l3-34-2/common/arrow_top.png', 0.5, 0);
this.arrowTop.setScaleXY(0.06);
this.arrowRight = new MySprite(this.ctx);
this.arrowRight.load('assets/l3-34-2/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.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.stroke();
this.ctx.restore();
}
draw() {
super.draw();
if (this.lineDashFlag) {
this.drawFrame();
this.drawArrow();
}
}
}
export class HotZoneImageItem extends MySprite {
index
lineDashFlag = false;
arrow: MySprite;
label: Label;
image: MySprite;
image_url: String;
labelBox: MySprite;
audio_url: String;
text = "";
type = "text";
card_audio_url: String
scale
arrowTop;
arrowRight;
init(image_url = null, text?, type?, callback?, handleSave?){
let change = true;
if(type == this.type){
change = false
}
if(type && type=="Text"){
image_url = "assets/l3-34-2/default/images/bg_50_50.png";
this.type = "Text"
}else if(!type){
this.type = "Text"
}
if(text){
this.text = text
}else{
this.text = ""
}
this.showImage(image_url, (img)=>{
callback && callback(img.width, img.height)
if(type == "Text"){
this.scaleX = 104 / img.width
this.scaleY = 78 / img.height
this.setSize(img.width*this.scaleX, img.height*this.scaleY)
}else{
this.setSize(img.width*this.image.scaleX, img.height*this.image.scaleY)
}
handleSave && handleSave()
this.lineDashFlag = true;
if(type == "Text"){
this.showLabel(text);
// this.arrow.visible = false
}else{
if(this.label){
this.removeChild(this.label)
}
this.drawArrow()
}
if(change){
this.showLineDash()
}
})
}
initNew(callback?, handleSave?){
if(this.type && this.type=="Text"){
this.image_url = "assets/l3-34-2/default/images/bg_50_50.png";
}
this.showImage(this.image_url, (img)=>{
callback && callback(img.width, img.height)
if(this.type == "Text"){
this.scaleX = 104 / img.width
this.scaleY = 78 / img.height
this.setSize(104, 78)
}else{
this.setSize(img.width*this.image.scaleX, img.height*this.image.scaleY)
}
handleSave && handleSave()
this.lineDashFlag = true;
if(this.type == "Text"){
this.showLabel(this.text);
}else{
this.showLabel(this.index);
}
this.drawArrow()
this.showLineDash()
})
}
setSize(w, h) {
this.width = w;
this.height = h;
}
showLabel(text = null) {
if (!this.label) {
this.labelBox = new MySprite(this.ctx);
this.labelBox.load('assets/l3-34-2/default/images/bg_50_50.png').then(()=>{
this.labelBox.x = this.width/2;
this.labelBox.y = this.height/2;
});
this.label = new Label(this.ctx);
this.label.fontSize = "45";
this.label.textAlign = 'center';
this.label.color = "#7A4250"
if(this.type == "Text"){
this.labelBox.visible = true
}else{
this.labelBox.visible = false
}
this.labelBox.addChild(this.label);
this.addChild(this.labelBox);
this.refreshLabelScale();
}
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;
}
showImage(image_url = null, callback) {
this.loadImage(image_url).then((img)=>{
if(this.image){
this.removeChild(this.image)
}
this.image = new MySprite(this.ctx);
this.image.init(img)
this.image.x = this.image.width/2
this.image.y = this.image.height/2
this.image.alpha = 0.7;
this.image_url = image_url;
this.addChild(this.image,-1);
callback && callback(this.image)
})
}
loadImage(image_url = null){
return new Promise((resolve, reject) => {
const img = new Image();
img.onload = () => resolve(img);
img.onerror = reject;
img.src = image_url;
})
}
hideImage() {
if (!this.image) { return; }
this.image.visible = false;
}
refreshLabelScale() {
this.labelBox.scaleX = 75 / (this.labelBox.width*this.image.scaleX)
}
showLineDash() {
if (this.arrow) {
this.arrow.visible = true;
} else {
this.arrow = new MySprite(this.ctx);
this.arrow.load('assets/l3-34-2/common/arrow.png', 1, 0);
this.arrow.setScaleXY(0.06);
this.arrowTop = new MySprite(this.ctx);
this.arrowTop.load('assets/l3-34-2/common/arrow_top.png', 0.5, 0);
this.arrowTop.setScaleXY(0.06);
this.arrowRight = new MySprite(this.ctx);
this.arrowRight.load('assets/l3-34-2/common/arrow_right.png', 1, 0.5);
this.arrowRight.setScaleXY(0.06);
}
}
hideLineDash() {
this.lineDashFlag = false;
if (this.arrow) {
this.arrow.visible = false;
}
this.hideLabel();
}
drawArrow() {
if(this.offSetCenter){
if (!this.arrow) { return; }
const rect = this.getBoundingBox();
this.arrow.x = rect.x + rect.width / 2;
this.arrow.y = rect.y - rect.height / 2;
this.arrow.update();
this.arrowTop.x = rect.x
this.arrowTop.y = rect.y - rect.height / 2;
this.arrowTop.update();
this.arrowRight.x = rect.x + rect.width / 2;
this.arrowRight.y = rect.y //+ rect.height / 2;
this.arrowRight.update();
}else{
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() {
if(this.offSetCenter){
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.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.stroke();
this.ctx.restore();
}else{
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.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.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);
}
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/l3-34-2/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() {
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 = '#7a4250';
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 = Math.abs(px - mx);
const y = Math.abs(py - my);
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;
}
return angle;
}
<div class="p-image-children-editor">
<div style=" margin: 0 auto; width: 800px;">
<h5 style="margin-left: 2.5%;">预览:</h5>
<div id="canvas-container" style="margin:5px;">
<div class="preview-box" #wrap style="margin-bottom: 20px">
<canvas id="canvas" #canvas></canvas>
</div>
</div>
<div style="width: 100%;">
<!-- <div class="bg-box">
<app-upload-image-with-preview [picUrl]="bgItem.url" (imageUploaded)="onBackgroundUploadSuccess($event)">
</app-upload-image-with-preview>
</div> -->
<div style="display: flex; margin-bottom: 28px;">
<div style="flex: 1;" >
旋转:
</div>
<div style="flex: 5;" >
<nz-select [(ngModel)]="currentSelected" nzAllowClear style="min-width: 200px;" >
<nz-option-group nzLabel="左侧">
<nz-option *ngFor="let it of hotZoneArr_left; let i = index" [nzValue]="it" [nzLabel]="(i+1) + ' - ' + it.text"></nz-option>
</nz-option-group>
<nz-option-group nzLabel="左侧">
<nz-option *ngFor="let it of hotZoneArr_right; let i = index" [nzValue]="it" [nzLabel]="(i+1) + ' - ' + it.text"></nz-option>
</nz-option-group>
</nz-select>
</div>
</div>
<div *ngIf="currentSelected" style="display: flex; margin-bottom: 28px;">
<div style="flex: 5; display: flex;" >
<div style="flex:2; margin-right: 5px;">
<nz-input-group nzAddOnBefore="X:">
<nz-input-number [(ngModel)]="currentSelected.x" (ngModelChange)="autoSave()" ></nz-input-number>
</nz-input-group>
</div>
<div style="flex:2; margin-right: 5px;">
<nz-input-group nzAddOnBefore="Y:">
<nz-input-number [(ngModel)]="currentSelected.y" (ngModelChange)="autoSave()" ></nz-input-number>
</nz-input-group>
</div>
<div style="flex:2; margin-right: 10px;">
<nz-input-group nzAddOnBefore="Rotation:" >
<nz-input-number [nzMin]="-180" [nzMax]="180" [(ngModel)]="currentSelected.rotation" (ngModelChange)="autoSave()" ></nz-input-number>
</nz-input-group>
</div>
<div style="flex:4;">
<nz-slider [nzMin]="-180" [nzMax]="180" [(ngModel)]="currentSelected.rotation" (nzOnAfterChange)="autoSave()" ></nz-slider>
</div>
</div>
</div>
<div style="text-align: center;">
<button nz-button nzType="primary" [nzSize]="'small'" nzShape="round" (click)="saveClick()"
[disabled]="!hotZoneChanged">
<i nz-icon type="save"></i>
Save
</button>
</div>
</div>
</div>
<div >
<div nzAlign="middle">
<div class="img-box clearfix" style="border-bottom: 1px solid #DDD; padding-bottom: 10px;">
<div style="float: left; width: 100px;">
<h3>题号</h3>
<input type="text" nz-input placeholder="" [(ngModel)]="bgItem.title.NO" (blur)="autoSave()" />
</div>
<div style="float: left; width: 300px; margin-left: 50px;">
<h3>课件标题</h3>
<input type="text" nz-input placeholder="" [(ngModel)]="bgItem.title.mainText" (blur)="autoSave()" />
</div>
<div style="float: left; width: 300px; margin-left: 50px;">
<h3>标题发音</h3>
<app-audio-recorder id="index_audio_1" [audioUrl]="bgItem.title.mainTitleAudio" (audioUploaded)="onUploadSuccessByItem($event, bgItem.title,'mainTitleAudio', 'audio')" > </app-audio-recorder>
</div>
<div style="float: left; width: 300px;">
<h3>白板标题</h3>
<input type="text" nz-input placeholder="" [(ngModel)]="bgItem.title.boardTitle" (blur)="autoSave()" />
</div>
<div style="float: left; width: 300px; margin-left: 50px;">
<h3>白板标题发音</h3>
<app-audio-recorder id="index_audio_1" [audioUrl]="bgItem.title.boardTitleAudio" (audioUploaded)="onUploadSuccessByItem($event, bgItem.title,'boardTitleAudio', 'audio')" > </app-audio-recorder>
</div>
<div style="float: left; width: 300px; margin-left: 50px;">
<h3>题目长音频</h3>
<app-audio-recorder id="index_audio_1" [audioUrl]="bgItem.title.mainAudio" (audioUploaded)="onUploadSuccessByItem($event, bgItem.title,'mainAudio', 'audio')" > </app-audio-recorder>
</div>
</div>
</div>
<div style=" float: left; width: 50%; border-right: 1px solid #DDD;" >
<div nzAlign="middle">
<div class="img-box clearfix" style="border-bottom: 1px solid #DDD; padding-bottom: 10px;">
<div style="float: left; display: flex;">
<div style="flex:1">
<h3>左侧词组</h3>
</div>
<div style="flex:1" style="margin-left: 10px;">
<app-audio-recorder id="index_audio_1" [audioUrl]="bgItem.title.leftAudio" (audioUploaded)="onUploadSuccessByItem($event, bgItem.title, 'leftAudio', 'audio')" > </app-audio-recorder>
</div>
<div style="flex:1" style="margin-left: 10px;">
<input type="text" nz-input placeholder="" [(ngModel)]="bgItem.title.leftText" (blur)="autoSave()" />
</div>
</div>
</div>
</div>
<div class="img-box clearfix" *ngFor="let it of hotZoneArr_left; let i = index" style="border-bottom: 1px solid #DDD; padding-bottom: 10px;">
<div>
<h2> 词组-{{ i + 1 }}</h2>
</div>
<div style="position: relative; display: flex; ">
<div style="flex: 6; display: flex; flex-direction: column;">
<div style="flex: 1; display: flex; margin-bottom: 28px;" >
<div style="flex: 1;" >
文字:
</div>
<div style="flex: 5;" >
<input type="text" nz-input placeholder="" [(ngModel)]="it.text" (blur)="autoSave()" />
</div>
</div>
<div style="flex: 1; display: flex; margin-bottom: 28px;">
<div style="flex: 1;" >
音频:
</div>
<div style="flex: 5;" >
<app-audio-recorder [audioUrl]="it.audio_url" (audioUploaded)="onUploadSuccessByItem($event, it, 'audio_url', 'audio')" ></app-audio-recorder>
</div>
</div>
</div>
<div style="flex:1; margin-left: 10px;">
图片
</div>
<div style="flex:5">
<div style="width:200px">
<app-upload-image-with-preview [picUrl]="it.image_url" (imageUploaded)="onUploadSuccessByItem($event, it, 'image_url', 'image')"></app-upload-image-with-preview>
</div>
</div>
</div>
<div style="flex: 1; display: flex; margin-bottom: 28px;">
<div style="flex: 4 ; display: flex;" >
<div style="flex:2; margin-right: 5px;">
<nz-input-group nzAddOnBefore="X:">
<nz-input-number [(ngModel)]="it.x" (ngModelChange)="autoSave()" ></nz-input-number>
</nz-input-group>
</div>
<div style="flex:2; margin-right: 5px;">
<nz-input-group nzAddOnBefore="Y:">
<nz-input-number [(ngModel)]="it.y" (ngModelChange)="autoSave()" ></nz-input-number>
</nz-input-group>
</div>
<div style="flex:2; margin-right: 10px;">
<nz-input-group nzAddOnBefore="Rotation:" >
<nz-input-number [nzMin]="-180" [nzMax]="180" [(ngModel)]="it.rotation" (ngModelChange)="autoSave()" ></nz-input-number>
</nz-input-group>
</div>
<div style="flex:1;">
<button style="flex:1; margin-bottom: 5px;" nz-button (click)="copyPositionData(it)">
<i nz-icon nzType="copy" nzTheme="outline"></i>
复制
</button>
</div>
<div style="flex:1;">
<button style="flex:1; margin-bottom: 5px;" (click)="showPasteModal(it)" nz-button>
<i nz-icon nzType="form" nzTheme="outline"></i>
黏贴
</button>
</div>
</div>
<div style="flex: 1 ; display: flex;" ></div>
</div>
<div style="float: right; display: flex; margin-top: 5px; margin-right: 40px; ">
<!-- <button style="flex:1; margin-bottom: 5px;" nz-button nzType="dashed" (click)="handleMoveItemUp($event, i)"
[disabled]="i==0">
<i nz-icon nzType="up" nzTheme="outline"></i>
上移
</button>
<button style="flex:1; margin-bottom: 5px;" nz-button nzType="dashed" (click)="handleMoveItemDown($event, i)"
[disabled]="i==hotZoneArr.length-1">
<i nz-icon nzType="down" nzTheme="outline"></i>
下移
</button> -->
<button style="flex:1; margin-bottom: 5px;" nz-button nzType="danger" (click)="deleteItem(hotZoneArr_left, i)">
<i nz-icon nzType="delete" nzTheme="outline"></i>
删除
</button>
</div>
</div>
<div *ngIf="hotZoneArr_left.length<4">
<button nz-button nzType="dashed" (click)="addBtnClick(hotZoneArr_left)" class="add-btn" style="margin:0 auto" >
<i nz-icon nzType="plus-circle" nzTheme="outline"></i>
新建词组
</button>
</div>
</div>
<div style=" float: left; width: 50%; border-left: 1px solid #DDD;" >
<div nzAlign="middle">
<div class="img-box clearfix" style="border-bottom: 1px solid #DDD; padding-bottom: 10px;">
<div style="float: left; display: flex;">
<div style="flex:1">
<h3>右侧词组</h3>
</div>
<div style="flex:1" style="margin-left: 10px;">
<app-audio-recorder id="index_audio_1" [audioUrl]="bgItem.title.rightAudio" (audioUploaded)="onUploadSuccessByItem($event, bgItem.title, 'rightAudio', 'audio')" > </app-audio-recorder>
</div>
<div style="flex:1" style="margin-left: 10px;">
<input type="text" nz-input placeholder="" [(ngModel)]="bgItem.title.rightText" (blur)="autoSave()" />
</div>
</div>
</div>
</div>
<div class="img-box clearfix" *ngFor="let it of hotZoneArr_right; let i = index" style="border-bottom: 1px solid #DDD; padding-bottom: 10px;">
<div>
<h2> 词组-{{ i + 1 }}</h2>
</div>
<div style="position: relative; display: flex; ">
<div style="flex: 6; display: flex; flex-direction: column;">
<div style="flex: 1; display: flex; margin-bottom: 28px;" >
<div style="flex: 1;" >
文字:
</div>
<div style="flex: 5;" >
<input type="text" nz-input placeholder="" [(ngModel)]="it.text" (blur)="autoSave()" />
</div>
</div>
<div style="flex: 1; display: flex; margin-bottom: 28px;">
<div style="flex: 1;" >
音频:
</div>
<div style="flex: 5;" >
<app-audio-recorder [audioUrl]="it.audio_url" (audioUploaded)="onUploadSuccessByItem($event, it, 'audio_url', 'audio')" ></app-audio-recorder>
</div>
</div>
</div>
<div style="flex:1; margin-left: 10px;">
图片
</div>
<div style="flex:5">
<div style="width:200px">
<app-upload-image-with-preview [picUrl]="it.image_url" (imageUploaded)="onUploadSuccessByItem($event, it, 'image_url', 'image')"></app-upload-image-with-preview>
</div>
</div>
</div>
<div style="flex: 1; display: flex; margin-bottom: 28px;">
<div style="flex: 4 ; display: flex;" >
<div style="flex:2; margin-right: 5px;">
<nz-input-group nzAddOnBefore="X:">
<nz-input-number [(ngModel)]="it.x" (ngModelChange)="autoSave()" ></nz-input-number>
</nz-input-group>
</div>
<div style="flex:2; margin-right: 5px;">
<nz-input-group nzAddOnBefore="Y:">
<nz-input-number [(ngModel)]="it.y" (ngModelChange)="autoSave()" ></nz-input-number>
</nz-input-group>
</div>
<div style="flex:2; margin-right: 10px;">
<nz-input-group nzAddOnBefore="Rotation:" >
<nz-input-number [nzMin]="-180" [nzMax]="180" [(ngModel)]="it.rotation" (ngModelChange)="autoSave()" ></nz-input-number>
</nz-input-group>
</div>
<div style="flex:1;">
<button style="flex:1; margin-bottom: 5px;" nz-button (click)="copyPositionData(it)">
<i nz-icon nzType="copy" nzTheme="outline"></i>
复制
</button>
</div>
<div style="flex:1;">
<button style="flex:1; margin-bottom: 5px;" (click)="showPasteModal(it)" nz-button >
<i nz-icon nzType="form" nzTheme="outline"></i>
黏贴
</button>
</div>
</div>
<div style="flex: 1 ; display: flex;" ></div>
</div>
<div style="float: right; display: flex; margin-top: 5px; margin-right: 40px; ">
<!-- <button style="flex:1; margin-bottom: 5px;" nz-button nzType="dashed" (click)="handleMoveItemUp($event, i)"
[disabled]="i==0">
<i nz-icon nzType="up" nzTheme="outline"></i>
上移
</button>
<button style="flex:1; margin-bottom: 5px;" nz-button nzType="dashed" (click)="handleMoveItemDown($event, i)"
[disabled]="i==hotZoneArr.length-1">
<i nz-icon nzType="down" nzTheme="outline"></i>
下移
</button> -->
<button style="flex:1; margin-bottom: 5px;" nz-button nzType="danger" (click)="deleteItem(hotZoneArr_right, i)">
<i nz-icon nzType="delete" nzTheme="outline"></i>
删除
</button>
</div>
</div>
<div *ngIf="hotZoneArr_right.length<4">
<button nz-button nzType="dashed" (click)="addBtnClick(hotZoneArr_right)" class="add-btn" style="margin:0 auto">
<i nz-icon nzType="plus-circle" nzTheme="outline"></i>
新建词组
</button>
</div>
</div>
</div>
<nz-divider></nz-divider>
<div class="save-box">
</div>
<nz-modal [(nzVisible)]="showModalWindow" nzTitle="坐标粘贴" (nzOnCancel)="handlePasteCancle()" (nzOnOk)="handlePasteOk()" ng-paste="alert('d')">
<textarea #pasteDataContainer rows="4" nz-input [(ngModel)]="pasteData"></textarea>
</nz-modal>
</div>
\ No newline at end of file
.p-image-children-editor {
width: 100%;
height: 100%;
border-radius: 0.5rem;
min-width: 1200px;
border: 2px solid #ddd;
.preview-box {
margin: auto;
width: 100%;
// height: 35vw;
border: 2px dashed #ddd;
border-radius: 0.5rem;
background-color: #fafafa;
text-align: center;
color: #aaa;
.preview-img {
height: 100%;
width: auto;
}
}
.bg-box {
margin-bottom: 1rem;
}
.clearfix:after {
content: ".";
display: block;
height: 0;
clear: both;
visibility: hidden;
}
.img-box {
margin: 1rem;
}
.img-box-upload {
width: 120px;
height: 80px;
}
.add-btn {
margin-top: 1rem;
width: 200px;
height: 90px;
display: flex;
align-items: center;
justify-content: center;
}
}
.save-box {
width: 100%;
display: flex;
align-items: center;
justify-content: center;
.save-btn {
width: 160px;
height: 40px;
//margin-top: 20px;
margin-bottom: 20px;
display: flex;
align-items: center;
justify-content: center;
}
}
h5 {
margin-top: 1rem;
}
//@import '../../../style/common_mixin';
//
//.p-image-uploader {
// position: relative;
// display: block;
// width: 100%;
// height: 0;
// padding-bottom: 56.25%;
// .p-box {
// position: absolute;
// left: 0;
// top: 0;
// right: 0;
// bottom: 0;
// border: 2px dashed #ddd;
// border-radius: 0.5rem;
// background-color: #fafafa;
// text-align: center;
// color: #aaa;
// .p-upload-icon {
// text-align: center;
// margin: auto;
// .anticon-upload {
// color: #888;
// font-size: 5rem;
// }
// .p-progress-bar {
// position: relative;
// width: 20rem;
// height: 1.5rem;
// border: 1px solid #ccc;
// border-radius: 1rem;
// .p-progress-bg {
// background-color: #1890ff;
// border-radius: 1rem;
// height: 100%;
// }
// .p-progress-value {
// position: absolute;
// top: 0;
// left: 0;
// width: 100%;
// height: 100%;
// text-shadow: 0 0 4px #000;
// color: white;
// text-align: center;
// font-size: 0.9rem;
// line-height: 1.5rem;
// }
// }
// }
// .p-preview {
// width: 100%;
// height: 100%;
// //background-image: url("https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png");
// @include k-img-bg();
// }
// }
//}
//
//.p-btn-delete {
// position: absolute;
// right: -0.5rem;
// top: -0.5rem;
// width: 2rem;
// height: 2rem;
// border: 0.2rem solid white;
// border-radius: 50%;
// font-size: 1.2rem;
// background-color: #fb781a;
// color: white;
// text-align: center;
//}
//
//.p-upload-progress-bg {
// position: absolute;
// width: 100%;
// height: 100%;
// display: flex;
// align-items: center;
// justify-content: center;
// & .i-text {
// position: absolute;
// text-align: center;
// color: white;
// text-shadow: 0 0 2px rgba(0, 0, 0, .85);
// }
// & .i-bg {
// position: absolute;
// left: 0;
// top: 0;
// height: 100%;
// background-color: #27b43f;
// border-radius: 0.5rem;
// }
//}
//
//
//:host ::ng-deep .ant-upload {
// display: block;
//}
import { Component, ElementRef, EventEmitter, HostListener, Input, OnChanges, OnDestroy, OnInit, Output, ViewChild } from '@angular/core';
import {NzMessageService, NzNotificationService, UploadFile} from 'ng-zorro-antd';
import { Subject } from 'rxjs';
import { debounceTime } from 'rxjs/operators';
import { EditorItem, HotZoneImageItem, Label, MySprite } from './Unit';
import TWEEN from '@tweenjs/tween.js';
@Component({
selector: 'app-custom-hot-zone-2',
templateUrl: './custom-hot-zone-2.component.html',
styleUrls: ['./custom-hot-zone-2.component.scss']
})
export class CustomHotZone2Component implements OnInit, OnDestroy, OnChanges {
_bgItem = null;
@Input()
set bgItem(v) {
this._bgItem = v;
this.init();
}
get bgItem() {
return this._bgItem;
}
@Input()
imgItemArr = null;
@Input()
hotZoneItemArr = null;
@Input()
hotZoneItem_left = null;
@Input()
hotZoneItem_right = null;
@Input()
hotZoneArr = null;
hotZoneArr_left = null;
hotZoneArr_right = null;
@Output()
save = new EventEmitter();
@ViewChild('canvas') canvas: ElementRef;
@ViewChild('wrap') wrap: ElementRef;
@ViewChild('pasteDataContainer') pasteDataContainer: ElementRef;
@HostListener('window:resize', ['$event'])
onResize(event) {
this.g_winResizeEventStream.next();
}
g_winResizeEventStream = new Subject();
firstTouch = true;
canvasWidth = 1280;
canvasHeight = 720;
canvasBaseW = 1280;
canvasBaseH = 720;
mapScale = 1;
currentSelected = null
ctx;
mx;
my; // 点击坐标
// 资源
// rawImages = new Map(res);
// 声音
bgAudio = new Audio();
images = new Map();
animationId: any;
// winResizeEventStream = new Subject();
canvasLeft;
canvasTop;
renderArr;
imgArr = [];
oldPos;
curItem;
bg: MySprite;
changeSizeFlag = false;
changeTopSizeFlag = false;
changeRightSizeFlag = false;
hotZoneChanged = false;
showModalWindow = false;
currentPasteItem = null
copyData = ""
pasteData = ""
scale = 1;
constructor( private nzMessageService: NzMessageService, private el: ElementRef) {
}
ngOnInit() {
if(!this.bgItem.url){
this.bgItem.url = "assets/l3-34-2/hot-zoo-bg.png"
}
this.initListener();
this.update();
}
ngOnDestroy() {
window.cancelAnimationFrame(this.animationId);
}
ngOnChanges() {
}
onBackgroundUploadSuccess(e) {
this.bgItem.url = e.url;
this.refreshBackground(() => {
this.autoSave()
});
}
refreshBackground(callBack = null) {
if (!this.bg) {
this.bg = new MySprite(this.ctx);
this.renderArr.push(this.bg);
}
const bg = this.bg;
bg.load("assets/l3-34-2/hot-zoo-bg.png").then(() => {
const rate1 = this.canvasWidth / bg.width;
const rate2 = this.canvasHeight / bg.height;
const rate = Math.min(rate1, rate2);
bg.setScaleXY(rate);
bg.x = this.canvasWidth / 2;
bg.y = this.canvasHeight / 2;
if (callBack) {
callBack();
}
}).catch((error) => {
console.log(error)
})
}
addBtnClick(array) {
const item = this.getHotZoneItem(null, null, true);
item.type = "Image"
array.push(item);
this.refreshHotZoneId();
this.autoSave()
}
deleteItem(array, i) {
array.splice(i, 1);
this.refreshHotZoneId();
this.autoSave()
}
handleMoveItemUp(items, index) {
if (index != 0) {
items[index] =items.splice(index - 1, 1,items[index])[0];
} else {
items.push(this.hotZoneArr.shift());
}
this.autoSave()
}
handleMoveItemDown(items, index) {
if (index != items.length - 1) {
items[index] = items.splice(index + 1, 1, items[index])[0];
} else {
items.unshift(items.splice(index, 1)[0]);
}
this.autoSave()
}
onImgUploadSuccessByImg(e, item) {
item.pic_url = e.url;
item.image_url = e.url;
item.initNew((w, h) => {
item.setScaleXY(Math.min(100 / w, 150 / h))
})
this.refreshImage(item);
this.autoSave()
}
onUploadSuccessByItem(e, items, key, type){
items[key] = e.url;
let textSaved = items.text
if(type == "image"){
items.initNew((w, h) => {
items.text = textSaved
items.setScaleXY(Math.min(100 / w, 150 / h))
})
this.refreshImage(items)
}
this.autoSave()
}
showPasteModal(it): void {
this.currentPasteItem = it
this.showModalWindow = true;
setTimeout(() => {
this.pasteDataContainer.nativeElement.focus();
}, 10);
}
handlePasteOk(){
if(this.pasteData && this.currentPasteItem){
let pos = this.pasteData.split(";")
if(pos.length == 5){
let result = true;
let reg = /^[-+]?(([0-9]+)([.]([0-9]+))?|([.]([0-9]+))?)$/
pos.forEach(item=>{
if(!reg.test(item)){
result = false;
}
})
if(result){
this.currentPasteItem.x = Number(pos[0])
this.currentPasteItem.y = Number(pos[1])
this.currentPasteItem.width = Number(pos[2]) / this.currentPasteItem.scaleX
this.currentPasteItem.height = Number(pos[3]) / this.currentPasteItem.scaleY
this.currentPasteItem.rotation = Number(pos[4])
this.autoSave()
this.init()
}
}
}
this.pasteData = ""
this.currentPasteItem = null
this.showModalWindow = false;
}
handlePasteCancle(){
this.pasteData = ""
this.currentPasteItem = null
this.showModalWindow = false;
}
copyPositionData(item){
this.nzMessageService.info('Copied');
document.addEventListener('copy', handleData);
document.execCommand('copy');
document.removeEventListener('copy', handleData);
function handleData(e) {
let bb = item.getBoundingBox()
e.clipboardData.setData('text/plain', `${Math.round(item.x*100)/100};${Math.round(item.y*100)/100};${Math.round(bb.width*100)/100};${Math.round(bb.height*100)/100};${Math.round(item.rotation*100)/100}`);
e.preventDefault();
}
}
refreshImage(img) {
this.hideAllLineDash();
img.picItem = this.getPicItem(img);
this.refreshImageId();
}
refreshHotZoneId() {
for (let i = 0; i < this.hotZoneArr_left.length; i++) {
this.hotZoneArr_left[i].index = i;
}
for (let i = 0; i < this.hotZoneArr_right.length; i++) {
this.hotZoneArr_right[i].index = i;
}
}
refreshHotZoneText(item) {
item.initNew()
}
refreshImageId() {
for (let i = 0; i < this.imgArr.length; i++) {
this.imgArr[i].id = i;
if (this.imgArr[i].picItem) {
this.imgArr[i].picItem.text = 'Image-' + (i + 1);
}
}
}
getHotZoneItem(saveData = null, newRect?, offSetCenter=false) {
const itemW = 200;
const itemH = 200;
const item = new HotZoneImageItem(this.ctx);
item.offSetCenter = offSetCenter
if (saveData) {
item.init(saveData.media.image_url, saveData.media.text, saveData.media.type, (w, h) => {
const saveRect = saveData.rect;
console.log(saveRect.rotation)
item.scaleX = (saveData.rect.width / saveData.scale) / w;
item.scaleY = (saveData.rect.height / saveData.scale) / h;
if(item.offSetCenter){
item.x = (saveRect.x + saveRect.width/2) / saveData.scale + newRect.x
item.y = (saveRect.y + saveRect.height/2) / saveData.scale + newRect.y
}else{
item.x = saveRect.x / saveData.scale + newRect.x
item.y = saveRect.y / saveData.scale + newRect.y
}
});
item.rotation = saveData.rect.rotation
item.image_url = saveData.media.image_url
item.audio_url = saveData.media.audio_url
item.text = saveData.media.text
item.type = saveData.media.type
} else {
item.init("assets/l3-34-2/bg_sentence.png", null, "Image", () => {
item.image_url = "assets/l3-34-2/bg_sentence.png"
item.x = this.canvasWidth / 2 - 142;
item.y = this.canvasHeight / 2 - 15;
}, () => this.autoSave());
}
item.anchorX = 0.5;
item.anchorY = 0.5;
return item;
}
getPicItem(img, saveData = null) {
const item = new EditorItem(this.ctx);
item.load(img.image_url).then(img => {
let maxW, maxH;
if (this.bg) {
maxW = this.bg.width * this.bg.scaleX;
maxH = this.bg.height * this.bg.scaleY;
} else {
maxW = this.canvasWidth;
maxH = this.canvasHeight;
}
let scaleX = maxW / 3 / item.width;
let scaleY = maxH / 3 / item.height;
if (item.height * scaleX < this.canvasHeight) {
item.setScaleXY(scaleX);
} else {
item.setScaleXY(scaleY);
}
item.x = this.canvasWidth / 2;
item.y = this.canvasHeight / 2;
if (saveData) {
const saveRect = saveData.rect;
item.setScaleXY(saveRect.width / item.width);
item.x = saveRect.x + saveRect.width / 2;
item.y = saveRect.y + saveRect.height / 2;
} else {
item.showLineDash();
}
this.autoSave()
})
return item;
}
init() {
this.initData();
this.initCtx();
this.initItem();
}
initItem() {
if (!this.bgItem) {
this.bgItem = {
title: {
mainText: "Read then write a rhyme.",
mainTitleAudio: "",
boardTitle: "Make rhymes",
boardTitleAudio: "",
mainAudio: "",
leftText: "Rhyme 2",
rightText: "Rhyme 1",
leftAudio: "",
rightAudio: ""
}
};
} else {
this.refreshBackground(() => {
// if (!this.hotZoneItemArr) {
// this.hotZoneItemArr = [];
// } else {
// this.initHotZoneArr();
// }
if (!this.hotZoneItem_left) {
this.hotZoneItem_left = [];
} else if (!this.hotZoneItem_right) {
this.hotZoneItem_right = [];
} else {
this.initHotZoneArr();
}
});
}
}
initHotZoneArr() {
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;
const arr_left = this.hotZoneItem_left.concat();
for (let i = 0; i < arr_left.length; i++) {
const data = JSON.parse(JSON.stringify(arr_left[i]));
data.rect.x *= rate;
data.rect.y *= rate;
data.rect.width *= rate;
data.rect.height *= rate;
const item = this.getHotZoneItem(data, { x: curBgRect.x, y: curBgRect.y }, true);
this.hotZoneArr_left.push(item);
}
const arr_right = this.hotZoneItem_right.concat();
for (let i = 0; i < arr_right.length; i++) {
const data = JSON.parse(JSON.stringify(arr_right[i]));
data.rect.x *= rate;
data.rect.y *= rate;
data.rect.width *= rate;
data.rect.height *= rate;
const item = this.getHotZoneItem(data, { x: curBgRect.x, y: curBgRect.y }, true);
this.hotZoneArr_right.push(item);
}
this.refreshHotZoneId();
}
initImgArr() {
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;
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;
this.canvasHeight = this.wrap.nativeElement.clientWidth * (332 / 640);
this.scale = 640 / this.wrap.nativeElement.clientWidth
this.mapScale = this.canvasWidth / this.canvasBaseW;
this.renderArr = [];
this.bg = null;
this.imgArr = [];
this.hotZoneArr = [];
this.hotZoneArr_left = [];
this.hotZoneArr_right = [];
}
initCtx() {
this.ctx = this.canvas.nativeElement.getContext('2d');
this.canvas.nativeElement.width = this.canvasWidth;
this.canvas.nativeElement.height = this.canvasHeight;
}
mapDown(event) {
this.oldPos = { x: this.mx, y: this.my };
const arr = this.hotZoneArr_left.concat(this.hotZoneArr_right);
for (let i = arr.length - 1; i >= 0; i--) {
const item = arr[i];
if (item) {
if (this.checkClickTarget(item)) {
if (item.lineDashFlag && this.checkClickTarget(item.arrow)) {
if(item.type == "Text"){
return
}
this.changeItemSize(item);
} else if (item.lineDashFlag && this.checkClickTarget(item.arrowTop)) {
if(item.type == "Text"){
return
}
this.changeItemTopSize(item);
} else if (item.lineDashFlag && this.checkClickTarget(item.arrowRight)) {
if(item.type == "Text"){
return
}
this.changeItemRightSize(item);
} else {
this.changeCurItem(item);
}
this.hotZoneChanged = true;
return;
}
}
}
}
mapMove(event) {
if (!this.curItem) { return; }
if (this.changeSizeFlag) {
this.changeSize();
} else if (this.changeTopSizeFlag) {
this.changeTopSize();
} else if (this.changeRightSizeFlag) {
this.changeRightSize();
} else {
let addX = this.mx - this.oldPos.x;
let addY = this.my - this.oldPos.y;
this.curItem.x += addX;
this.curItem.y += addY;
}
this.oldPos = { x: this.mx, y: this.my };
}
mapUp(event) {
this.curItem = null;
this.changeSizeFlag = false;
this.changeTopSizeFlag = false;
this.changeRightSizeFlag = false;
}
changeSize() {
const rect = this.curItem.getBoundingBox();
let distance = null;
let lenW = null;
if(this.curItem.offSetCenter){
distance = (this.my + rect.height/2) - rect.y
lenW = (this.mx + rect.width/2) - rect.x;
}else{
distance = this.my - rect.y;
lenW = this.mx - rect.x;
}
let lenH = rect.height - distance
let minLen = 20;
let sx, sy;
if (lenW < minLen) {
lenW = minLen;
}
sx = lenW / this.curItem.width;
if (lenH < minLen) {
lenH = minLen;
}
sy = lenH / this.curItem.height;
this.curItem.y = this.curItem.y + distance
this.curItem.scaleX = sx;
this.curItem.scaleY = sy;
}
changeTopSize() {
const rect = this.curItem.getBoundingBox();
let lenH = null
if(this.curItem.offSetCenter){
lenH = rect.y - (this.my + rect.height/2) + rect.height;
this.curItem.y = this.my + rect.height/2
}else{
lenH = rect.y - this.my + rect.height;
this.curItem.y = this.my
}
let minLen = 20;
let s;
if (lenH < minLen) {
lenH = minLen;
}
s = lenH / this.curItem.height;
this.curItem.setScaleXY(s);
}
changeRightSize() {
const rect = this.curItem.getBoundingBox();
let lenW = null
if(this.curItem.offSetCenter){
lenW = this.mx - rect.x + rect.width/2;
}else{
lenW = this.mx - rect.x;
}
let minLen = 20;
let s;
if (lenW < minLen) {
lenW = minLen;
}
s = lenW / this.curItem.width;
this.curItem.setScaleXY(s);
}
changeItemSize(item) {
this.curItem = item;
this.changeSizeFlag = true;
}
changeItemTopSize(item) {
this.curItem = item;
this.changeTopSizeFlag = true;
}
changeItemRightSize(item) {
this.curItem = item;
this.changeRightSizeFlag = true;
}
changeCurItem(item) {
this.hideAllLineDash();
this.curItem = item;
this.curItem.showLineDash();
}
hideAllLineDash() {
for (let i = 0; i < this.imgArr.length; i++) {
if (this.imgArr[i].picItem) {
this.imgArr[i].picItem.hideLineDash();
}
}
}
update() {
this.animationId = window.requestAnimationFrame(this.update.bind(this));
// 清除画布内容
this.ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight);
for (let i = 0; i < this.renderArr.length; i++) {
this.renderArr[i].update(this);
}
// this.updateArr(this.hotZoneArr);
this.updateArr(this.hotZoneArr_left);
this.updateArr(this.hotZoneArr_right);
TWEEN.update();
}
updateArr(arr) {
if (arr) {
for (let i = 0; i < arr.length; i++) {
arr[i].update();
}
}
}
renderAfterResize() {
this.canvasWidth = this.wrap.nativeElement.clientWidth;
this.canvasHeight = this.wrap.nativeElement.clientHeight;
this.init();
}
initListener() {
const element = this.canvas.nativeElement;
this.g_winResizeEventStream.pipe(debounceTime(500)).subscribe(data => {
this.renderAfterResize();
});
const addTouchListener = () => {
element.addEventListener('touchstart', touchDownFunc);
element.addEventListener('touchmove', touchMoveFunc);
element.addEventListener('touchend', touchUpFunc);
element.addEventListener('touchcancel', touchUpFunc);
};
const removeTouchListener = () => {
element.removeEventListener('touchstart', touchDownFunc);
element.removeEventListener('touchmove', touchMoveFunc);
element.removeEventListener('touchend', touchUpFunc);
element.removeEventListener('touchcancel', touchUpFunc);
};
const addMouseListener = () => {
element.addEventListener('mousedown', mouseDownFunc);
element.addEventListener('mousemove', mouseMoveFunc);
element.addEventListener('mouseup', mouseUpFunc);
};
const removeMouseListener = () => {
element.removeEventListener('mousedown', mouseDownFunc);
element.removeEventListener('mousemove', mouseMoveFunc);
element.removeEventListener('mouseup', mouseUpFunc);
};
const touchDownFunc = (e) => {
if (this.firstTouch) {
this.firstTouch = false;
removeMouseListener();
}
setMxMyByTouch(e);
this.mapDown(e);
};
const touchMoveFunc = (e) => {
setMxMyByTouch(e);
this.mapMove(e);
};
const touchUpFunc = (e) => {
setMxMyByTouch(e);
this.mapUp(e);
};
const mouseDownFunc = (e) => {
if (this.firstTouch) {
this.firstTouch = false;
removeTouchListener();
}
setMxMyByMouse(e);
this.mapDown(e);
};
const mouseMoveFunc = (e) => {
setMxMyByMouse(e);
this.mapMove(e);
};
const mouseUpFunc = (e) => {
setMxMyByMouse(e);
this.mapUp(e);
};
const setMxMyByTouch = event => {
if (event.touches.length <= 0) {
return;
}
if (this.canvasLeft == null) {
setParentOffset();
}
this.mx = event.touches[0].pageX - this.canvasLeft;
this.my = event.touches[0].pageY - this.canvasTop;
};
const setParentOffset = () => {
const rect = this.canvas.nativeElement.getBoundingClientRect();
this.canvasLeft = rect.left;
this.canvasTop = rect.top;
};
const setMxMyByMouse = (event) => {
this.mx = event.offsetX;
this.my = event.offsetY;
};
addMouseListener();
addTouchListener();
}
IsPC() {
if (window['ELECTRON']) {
return false; // 封装客户端标记
}
if (document.body.ontouchstart !== undefined) {
return false;
} else {
return true;
}
}
checkClickTarget(target) {
const rect = target.getBoundingBox();
if(target.offSetCenter){
if (this.checkPointInRectOffSetCenter(this.mx, this.my, rect)) {
return true;
}
}else{
if (this.checkPointInRect(this.mx, this.my, rect)) {
return true;
}
}
return false;
}
checkPointInRect(x, y, rect) {
if (x >= rect.x && x <= rect.x + rect.width) {
if (y >= rect.y && y <= rect.y + rect.height) {
return true;
}
}
return false;
}
checkPointInRectOffSetCenter(x, y, rect) {
if (x >= rect.x - rect.width/2 && x <= rect.x + rect.width/2) {
if (y >= rect.y - rect.height/2 && y <= rect.y + rect.height/2) {
return true;
}
}
return false;
}
autoSave() {
// console.log("Auto save")
const bgItem = this.bgItem;
if (this.bg) {
bgItem['rect'] = this.bg.getBoundingBox();
} else {
bgItem['rect'] = { x: 0, y: 0, width: Math.round(this.canvasWidth * 100) / 100, height: Math.round(this.canvasHeight * 100) / 100 };
}
const hotZoneItem_left = [];
const hotZoneArr_left = this.hotZoneArr_left;
for (let i = 0; i < hotZoneArr_left.length; i++) {
const hotZoneItem = {
index: hotZoneArr_left[i].index,
};
hotZoneItem['rect'] = hotZoneArr_left[i].getBoundingBox();
console.log( hotZoneArr_left[i].rotation )
const currentX = hotZoneItem['rect'].x
const currentY = hotZoneItem['rect'].y
hotZoneItem['media'] = {}
hotZoneItem['scale'] = this.scale
if(hotZoneArr_left[i].offSetCenter){
hotZoneItem['rect'].x = (Math.round((currentX - bgItem['rect'].x - hotZoneItem['rect'].width / 2) * 100) / 100) * this.scale;
hotZoneItem['rect'].y = (Math.round((currentY - bgItem['rect'].y - hotZoneItem['rect'].height /2) * 100) / 100) * this.scale;
}else{
hotZoneItem['rect'].x = (Math.round((currentX - bgItem['rect'].x) * 100) / 100) * this.scale;
hotZoneItem['rect'].y = (Math.round((currentY - bgItem['rect'].y) * 100) / 100) * this.scale;
}
hotZoneItem['rect'].width = (Math.round((hotZoneItem['rect'].width) * 100) / 100) * this.scale;
hotZoneItem['rect'].height = (Math.round((hotZoneItem['rect'].height) * 100) / 100) * this.scale;
hotZoneItem['rect'].rotation = hotZoneArr_left[i].rotation
hotZoneItem['media'].image_url = hotZoneArr_left[i].image_url
hotZoneItem['media'].audio_url = hotZoneArr_left[i].audio_url
hotZoneItem['media'].text = hotZoneArr_left[i].text
hotZoneItem['media'].type = hotZoneArr_left[i].type
hotZoneItem_left.push(hotZoneItem);
}
const hotZoneItem_right = [];
const hotZoneArr_right = this.hotZoneArr_right;
for (let i = 0; i < hotZoneArr_right.length; i++) {
const hotZoneItem = {
index: hotZoneArr_right[i].index,
};
hotZoneItem['rect'] = hotZoneArr_right[i].getBoundingBox();
console.log( hotZoneArr_right[i].rotation )
const currentX = hotZoneItem['rect'].x
const currentY = hotZoneItem['rect'].y
hotZoneItem['media'] = {}
hotZoneItem['scale'] = this.scale
if(hotZoneArr_right[i].offSetCenter){
hotZoneItem['rect'].x = (Math.round((currentX - bgItem['rect'].x - hotZoneItem['rect'].width / 2) * 100) / 100) * this.scale;
hotZoneItem['rect'].y = (Math.round((currentY - bgItem['rect'].y - hotZoneItem['rect'].height /2) * 100) / 100) * this.scale;
}else{
hotZoneItem['rect'].x = (Math.round((currentX - bgItem['rect'].x) * 100) / 100) * this.scale;
hotZoneItem['rect'].y = (Math.round((currentY - bgItem['rect'].y) * 100) / 100) * this.scale;
}
hotZoneItem['rect'].width = (Math.round((hotZoneItem['rect'].width) * 100) / 100) * this.scale;
hotZoneItem['rect'].height = (Math.round((hotZoneItem['rect'].height) * 100) / 100) * this.scale;
hotZoneItem['rect'].rotation = hotZoneArr_right[i].rotation
hotZoneItem['media'].image_url = hotZoneArr_right[i].image_url
hotZoneItem['media'].audio_url = hotZoneArr_right[i].audio_url
hotZoneItem['media'].text = hotZoneArr_right[i].text
hotZoneItem['media'].type = hotZoneArr_right[i].type;
hotZoneItem_right.push(hotZoneItem);
}
this.save.emit({ bgItem, hotZoneItem_left, hotZoneItem_right });
this.hotZoneChanged = false;
}
saveClick() {
// console.log("Saved")
this.autoSave()
}
}
......@@ -14,7 +14,7 @@ import {Subject} from 'rxjs';
import {debounceTime} from 'rxjs/operators';
import {EditorItem, HotZoneImg, HotZoneItem, HotZoneLabel, Label, MySprite, removeItemFromArr} from './Unit';
import TWEEN from '@tweenjs/tween.js';
import {getMinScale} from "../../play/Unit";
import {getMinScale} from "./Unit";
import {tar} from "compressing";
......
@import '../style/common_mixin.css';
.model-content {
width: 100%;
height: 100%;
}
<div class="model-content">
<div nz-row>
<div nz-col nzOffset='4'>
<h1 nz-title>课程内容编辑</h1>
</div>
</div>
<div nz-form>
<div id='title-anchor'>
<nz-divider nzText="标题一" nzOrientation="left"></nz-divider>
<nz-form-item>
<nz-form-label [nzSpan]="3" nzFor="t_val1">标题</nz-form-label>
<nz-form-control [nzSpan]="6">
<nz-input-group nzAddOnBefore="Part">
<input type="text" id="t_val1" nz-input [(ngModel)]="saveData.title.t_val1" (blur)="save()">
</nz-input-group>
</nz-form-control>
</nz-form-item>
<!-- <nz-form-item>
<nz-form-label [nzSpan]="3" nzFor="t_font_size1">字体大小</nz-form-label>
<nz-form-control [nzSpan]="6">
<nz-input-number [(ngModel)]="saveData.title.t_font_size1" [nzMin]="1" [nzStep]="1" (nzBlur)="save()">
</nz-input-number>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSpan]="3" nzFor="t_font1">字体</nz-form-label>
<nz-form-control [nzSpan]="4">
<nz-select [(ngModel)]="saveData.title.t_font1" [nzShowSearch]='true' nzAllowClear
nzPlaceHolder="Please select the font" (ngModelChange)="save()">
<nz-option nzValue="BRLNSB" nzLabel="BRLNSB"></nz-option>
<nz-option nzValue="BRLNSDB" nzLabel="BRLNSDB"></nz-option>
<nz-option nzValue="BRLNSR" nzLabel="BRLNSR"></nz-option>
<nz-option nzValue="GOTHIC" nzLabel="GOTHIC"></nz-option>
<nz-option nzValue="GOTHICB" nzLabel="GOTHICB"></nz-option>
<nz-option nzValue="GOTHICBI" nzLabel="GOTHICBI"></nz-option>
<nz-option nzValue="GOTHICI" nzLabel="GOTHICI"></nz-option>
<nz-option nzValue="MMTextBook" nzLabel="MMTextBook"></nz-option>
<nz-option nzValue="MMTextBook-Bold" nzLabel="MMTextBook-Bold"></nz-option>
<nz-option nzValue="MMTextBook-Italic" nzLabel="MMTextBook-Italic"></nz-option>
<nz-option nzValue="MMTextBook-BoldItalic" nzLabel="MMTextBook-BoldItalic"></nz-option>
</nz-select>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSpan]="3" nzFor="t_font_color1">颜色</nz-form-label>
<nz-form-control [nzSpan]="4">
<nz-select [(ngModel)]="saveData.title.t_font_color1" [nzShowSearch]='true' nzAllowClear
nzPlaceHolder="Please select the color" (ngModelChange)="save()">
<nz-option nzValue="#008000" nzLabel="绿色"></nz-option>
<nz-option nzValue="#FF0000" nzLabel="红色"></nz-option>
<nz-option nzValue="#70401e" nzLabel="巧克力色"></nz-option>
<nz-option nzValue="#000000" nzLabel="黑色"></nz-option>
</nz-select>
</nz-form-control>
</nz-form-item> -->
<nz-divider nzText="标题二" nzOrientation="left"></nz-divider>
<nz-form-item>
<nz-form-label [nzSpan]="3" nzFor="t_val2">标题</nz-form-label>
<nz-form-control [nzSpan]="6">
<input nz-input type="text" id="t_val2" [(ngModel)]="saveData.title.t_val2" (blur)="save()">
</nz-form-control>
</nz-form-item>
<!-- <nz-form-item>
<nz-form-label [nzSpan]="3" nzFor="t_audio_url">发音</nz-form-label>
<nz-form-control [nzSpan]="6">
<app-audio-recorder [audioUrl]="saveData.title.t_audio_url" id="t_audio_url"
(audioUploaded)="onAudioUploadSuccess($event, saveData.title, 't_audio_url')">
</app-audio-recorder>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSpan]="3" nzFor="t_font_size">字体大小</nz-form-label>
<nz-form-control [nzSpan]="6">
<nz-input-number [(ngModel)]="saveData.title.t_font_size" [nzMin]="1" [nzStep]="1" (nzBlur)="save()">
</nz-input-number>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSpan]="3" nzFor="t_font">字体</nz-form-label>
<nz-form-control [nzSpan]="4">
<nz-select [(ngModel)]="saveData.title.t_font" [nzShowSearch]='true' nzAllowClear
nzPlaceHolder="Please select the font" (ngModelChange)="save()">
<nz-option nzValue="BRLNSB" nzLabel="BRLNSB"></nz-option>
<nz-option nzValue="BRLNSDB" nzLabel="BRLNSDB"></nz-option>
<nz-option nzValue="BRLNSR" nzLabel="BRLNSR"></nz-option>
<nz-option nzValue="GOTHIC" nzLabel="GOTHIC"></nz-option>
<nz-option nzValue="GOTHICB" nzLabel="GOTHICB"></nz-option>
<nz-option nzValue="GOTHICBI" nzLabel="GOTHICBI"></nz-option>
<nz-option nzValue="GOTHICI" nzLabel="GOTHICI"></nz-option>
<nz-option nzValue="MMTextBook" nzLabel="MMTextBook"></nz-option>
<nz-option nzValue="MMTextBook-Bold" nzLabel="MMTextBook-Bold"></nz-option>
<nz-option nzValue="MMTextBook-Italic" nzLabel="MMTextBook-Italic"></nz-option>
<nz-option nzValue="MMTextBook-BoldItalic" nzLabel="MMTextBook-BoldItalic"></nz-option>
</nz-select>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSpan]="3" nzFor="t_font_color">颜色</nz-form-label>
<nz-form-control [nzSpan]="4">
<nz-select [(ngModel)]="saveData.title.t_font_color" [nzShowSearch]='true' nzAllowClear
nzPlaceHolder="Please select the color" (ngModelChange)="save()">
<nz-option nzValue="#008000" nzLabel="绿色"></nz-option>
<nz-option nzValue="#FF0000" nzLabel="红色"></nz-option>
<nz-option nzValue="#D2691E" nzLabel="巧克力色"></nz-option>
<nz-option nzValue="#000000" nzLabel="黑色"></nz-option>
</nz-select>
</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 [audioUrl]="saveData.listen_audio_url"
(audioUploaded)="onAudioUploadSuccess($event, saveData, 'listen_audio_url')">
</app-audio-recorder>
</nz-form-control>
</nz-form-item>
</div>
<nz-form-item>
<nz-form-control [nzSpan]="20" nzOffset="2">
<div class="card-item">
<nz-divider nzText="序号音频" nzOrientation="left" style="width: 100%;" ></nz-divider>
<nz-form-item>
<div style="width: 250px; float: left; display: flex;">
<div style="flex:1; text-align: right; margin-right: 10px;">1:</div>
<div style="flex:5">
<app-audio-recorder id="index_audio_0" [audioUrl]="indexAudio[0]" (audioUploaded)="onAudioUploadSuccessByItem_new($event, 0)" > </app-audio-recorder>
</div>
</div>
<div style="width: 250px; float: left; display: flex;">
<div style="flex:1; text-align: right; margin-right: 10px;">2:</div>
<div style="flex:5">
<app-audio-recorder id="index_audio_1" [audioUrl]="indexAudio[1]" (audioUploaded)="onAudioUploadSuccessByItem_new($event, 1)" > </app-audio-recorder>
</div>
</div>
<div style="width: 250px; float: left; display: flex;">
<div style="flex:1; text-align: right; margin-right: 10px;">3:</div>
<div style="flex:5">
<app-audio-recorder id="index_audio_2" [audioUrl]="indexAudio[2]" (audioUploaded)="onAudioUploadSuccessByItem_new($event, 2)" > </app-audio-recorder>
</div>
</div>
<div style="width: 250px; float: left; display: flex;">
<div style="flex:1; text-align: right; margin-right: 10px;">4:</div>
<div style="flex:5">
<app-audio-recorder id="index_audio_3" [audioUrl]="indexAudio[3]" (audioUploaded)="onAudioUploadSuccessByItem_new($event, 3)" > </app-audio-recorder>
</div>
</div>
</nz-form-item>
<nz-form-item>
<div style="width: 250px; float: left; display: flex;">
<div style="flex:1; text-align: right; margin-right: 10px;">5:</div>
<div style="flex:5">
<app-audio-recorder id="index_audio_4" [audioUrl]="indexAudio[4]" (audioUploaded)="onAudioUploadSuccessByItem_new($event, 4)" > </app-audio-recorder>
</div>
</div>
<div style="width: 250px; float: left; display: flex;">
<div style="flex:1; text-align: right; margin-right: 10px;">6:</div>
<div style="flex:5">
<app-audio-recorder id="index_audio_5" [audioUrl]="indexAudio[5]" (audioUploaded)="onAudioUploadSuccessByItem_new($event, 5)" > </app-audio-recorder>
</div>
</div>
<div style="width: 250px; float: left; display: flex;">
<div style="flex:1; text-align: right; margin-right: 10px;">7:</div>
<div style="flex:5">
<app-audio-recorder id="index_audio_6" [audioUrl]="indexAudio[6]" (audioUploaded)="onAudioUploadSuccessByItem_new($event, 6)" > </app-audio-recorder>
</div>
</div>
<div style="width: 250px; float: left; display: flex;">
<div style="flex:1; text-align: right; margin-right: 10px;">4:</div>
<div style="flex:5">
<app-audio-recorder id="index_audio_7" [audioUrl]="indexAudio[7]" (audioUploaded)="onAudioUploadSuccessByItem_new($event, 7)" > </app-audio-recorder>
</div>
</div>
</nz-form-item>
</div>
</nz-form-control>
<div style="position: absolute; left: 200px; top: 100px; width: 800px;">
<nz-form-control [nzSpan]="20" nzOffset="2">
<div class="card-item">
<nz-divider nzText="背景色" nzOrientation="left" style="width: 100%;" ></nz-divider>
<nz-form-item>
<nz-form-label [nzSpan]="6">区块背景</nz-form-label>
<nz-form-control [nzSpan]="4">
<nz-input-group nzAddOnBefore="#">
<input type="text" nz-input [(ngModel)]="saveData.blockColor" (blur)="save()">
</nz-input-group>
</nz-form-control>
<nz-form-control [nzSpan]="2">
<div [ngStyle]="{'backgroundColor': '#' + saveData.blockColor}" class="colorDemo" ></div>
</nz-form-control>
</nz-form-item>
<input type="text" nz-input [(ngModel)]="item.text" (blur)="save()">
<nz-form-item>
<nz-form-label [nzSpan]="6">序号背景</nz-form-label>
<nz-form-control [nzSpan]="4">
<nz-input-group nzAddOnBefore="#">
<input type="text" nz-input [(ngModel)]="saveData.indexColor" (blur)="save()">
</nz-input-group>
</nz-form-control>
<nz-form-control [nzSpan]="2">
<div [ngStyle]="{'backgroundColor': '#' + saveData.indexColor}" class="colorDemo" ></div>
</nz-form-control>
</nz-form-item>
<app-upload-image-with-preview
[picUrl]="item.pic_url"
(imageUploaded)="onImageUploadSuccess($event, 'pic_url')"
></app-upload-image-with-preview>
<nz-form-item>
<nz-form-label [nzSpan]="6">选项背景-左</nz-form-label>
<nz-form-control [nzSpan]="4">
<nz-input-group nzAddOnBefore="#">
<input type="text" nz-input [(ngModel)]="saveData.optionColor_left" (blur)="save()">
</nz-input-group>
</nz-form-control>
<nz-form-control [nzSpan]="2">
<div [ngStyle]="{'backgroundColor': '#' + saveData.optionColor_left}" class="colorDemo" ></div>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSpan]="6">选项背景-右</nz-form-label>
<nz-form-control [nzSpan]="4">
<nz-input-group nzAddOnBefore="#">
<input type="text" nz-input [(ngModel)]="saveData.optionColor_right" (blur)="save()">
</nz-input-group>
</nz-form-control>
<nz-form-control [nzSpan]="2">
<div [ngStyle]="{'backgroundColor': '#' + saveData.optionColor_right}" class="colorDemo" ></div>
</nz-form-control>
</nz-form-item>
</div>
</nz-form-control>
</nz-form-item>
<div>
<nz-divider nzText="单词组" nzOrientation="left"></nz-divider>
<nz-form-item>
<nz-form-control [nzSpan]="20" nzOffset="2">
<div *ngFor="let it of wordArr; let i = index" class="card-item" style="padding: 0.5vw;">
<div class="border">
<div nz-form>
<nz-divider nzText="选项" nzOrientation="left"></nz-divider>
<nz-form-item>
<nz-form-label [nzSpan]="3" nzFor="words">左侧</nz-form-label>
<nz-form-control [nzSpan]="6">
<input nz-input type="text" [(ngModel)]="it.words_left" (blur)="save()">
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSpan]="3">右侧</nz-form-label>
<nz-form-control [nzSpan]="6">
<input nz-input type="text" [(ngModel)]="it.words_right" (blur)="save()">
</nz-form-control>
</nz-form-item>
<nz-divider nzText="单词" nzOrientation="left"></nz-divider>
<nz-form-item>
<nz-form-label [nzSpan]="3" nzFor="it.word_val">单词</nz-form-label>
<nz-form-control [nzSpan]="6">
<input type="text" nz-input placeholder="请录入单词"
[(ngModel)]="it.word_val"
(blur)="saveWordItem(i,'left')">
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSpan]="3" nzFor="it.word_audio_url">发音</nz-form-label>
<nz-form-control [nzSpan]="6">
<app-audio-recorder id="it.word_audio_url"
[audioUrl]="it.word_audio_url"
(audioUploaded)="onAudioUploadSuccessByItem($event, it,'word_audio_url')">
</app-audio-recorder>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSpan]="3">正确选项</nz-form-label>
<nz-form-control [nzSpan]="6">
<nz-select [(ngModel)]="it.correctOption" (ngModelChange)="saveItem()">
<nz-option nzValue="left" nzLabel="左选项"></nz-option>
<nz-option nzValue="right" nzLabel="右选项"></nz-option>
</nz-select>
</nz-form-control>
</nz-form-item>
<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>
<nz-form-item>
<div nz-col [nzSpan]="15" nzOffset="2">
<nz-table [nzData]="it.letters" [nzHideOnSinglePage]="true" [nzBordered]="true">
<thead>
<tr>
<th>字母</th>
<th>颜色</th>
<th>是否填空</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let data of it.letters;let j = index">
<td>{{data.letter_val}}</td>
<td>
<nz-select [(ngModel)]="data.letter_color" (ngModelChange)="saveItem()">
<nz-option nzValue="C05" nzLabel="红色"></nz-option>
<nz-option nzValue="C04" nzLabel="黑色"></nz-option>
</nz-select>
</td>
<td>
<nz-select [(ngModel)]="data.is_" (ngModelChange)="saveItem()">
<nz-option nzValue="1" nzLabel="是"></nz-option>
<nz-option nzValue="0" nzLabel="否"></nz-option>
</nz-select>
</td>
</tr>
</tbody>
</nz-table>
</div>
</nz-form-item>
</div>
<button style="margin: 10px;" nz-button nzType="danger" (click)="deleteItem(i)">
<span>删除</span>
</button>
</div>
</div>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-control [nzSpan]="3" nzOffset="3" class="add-btn-box">
<button nz-button nzType="dashed" class="add-btn" id="add-btn" (click)="addItem()" [disabled]="wordArr.length>=8">
<i nz-icon nzType="plus-circle" nzTheme="outline"></i>添加
</button>
</nz-form-control>
</nz-form-item>
</div>
</div>
</div>
\ No newline at end of file
@import '../style/common_mixin';
.colorDemo {
width: 20px;
height: 32px;
margin-left: 5px;
}
.model-content {
width: 100%;
height: 100%;
}
nz-select {
width: 100%;
}
@font-face
{
font-family: 'BRLNSDB';
src: url("../../assets/font/BRLNSDB.TTF") ;
}
@font-face
{
font-family: 'BRLNSB';
src: url("../../assets/font/BRLNSB.TTF") ;
}
@font-face
{
font-family: 'BRLNSR';
src: url("../../assets/font/BRLNSR.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: 'GOTHICBI';
src: url("../../assets/font/GOTHICBI.TTF") ;
}
@font-face
{
font-family: 'GOTHICI';
src: url("../../assets/font/GOTHICI.TTF") ;
}
@font-face
{
font-family: 'MMTextBook';
src: url("../../assets/font/MMTextBook.otf") ;
}
@font-face
{
font-family: 'MMTextBook-Bold';
src: url("../../assets/font/MMTextBook-Bold.otf") ;
}
@font-face
{
font-family: 'MMTextBook-BoldItalic';
src: url("../../assets/font/MMTextBook-BoldItalic.otf") ;
}
@font-face
{
font-family: 'MMTextBook-Italic';
src: url("../../assets/font/MMTextBook-Italic.otf") ;
}
import {Component, EventEmitter, Input, OnDestroy, OnChanges, OnInit, Output, ApplicationRef, ChangeDetectorRef} from '@angular/core';
import {Component, EventEmitter, Input, OnDestroy, OnChanges, OnInit, Output, ApplicationRef} from '@angular/core';
import {ChangeDetectorRef} from '@angular/core';
@Component({
selector: 'app-form',
templateUrl: './form.component.html',
styleUrls: ['./form.component.css']
styleUrls: ['./form.component.scss']
})
export class FormComponent implements OnInit, OnChanges, OnDestroy {
// 储存数据用
saveKey = "test_0011";
// 储存对象
item;
constructor(private appRef: ApplicationRef,private changeDetectorRef: ChangeDetectorRef) {
}
picArr = [];
_item: any;
saveData;
wordArr = [];
saveKey='YM5-6'
constructor(private appRef: ApplicationRef,private changeDetectorRef: ChangeDetectorRef) {}
ngOnInit() {
this.item = {};
this.item = {contentObj: {}};
// 获取存储的数据
(<any> window).courseware.getData((data) => {
(<any> window).courseware.getData(( data ) => {
if(data && !data.contentObj) {data.contentObj={}}
if (data) {
this.item = data;
}
this.init();
this.ngOnInit2()
this.changeDetectorRef.markForCheck();
this.changeDetectorRef.detectChanges();
this.refresh();
}, this.saveKey);
}
@Input()
set item(item) {
this._item = item;
this.getData(item.contentObj.data);
}
get item() {
return this._item;
}
@Output()
update = new EventEmitter();
constructor2() {
}
ngOnInit2() {
// this.initData();
}
ngOnChanges() {
}
ngOnDestroy() {
}
recordingIndex = []
listOfOption = ['1', '2', '3', '4'];
indexAudio = [];
onAudioUploadSuccessByItem_new(e, key, item?) {
if(item){
item[key] = e.url;
}else{
this.indexAudio[key] = e.url;
}
this.save();
}
getData(data) {
this.saveData = {};
this.saveData.title = {
t_font_color1:'#70401e',
t_font1:'BRLNSDB',
t_font_size1:40,
t_font_color:'#000000',
t_font:'BRLNSDB',
t_font_size:40,
t_val1: "C",
t_val2: "Listen, write circle and read"
};
// 获取存储的数据
if (data) {
this.saveData = data;
}
if ( !this.saveData.wordArr ) {
this.saveData.wordArr = [];
}
if(!this.saveData.indexAudio) {
this.saveData.indexAudio = []
}
if(!this.saveData.recordingIndex) {
this.saveData.recordingIndex = []
}
this.init2();
this.item.contentObj.data = this.saveData;
console.log(this.saveData)
}
init() {
mapToOptionLabel(index) {
let lebel = ""
switch(index) {
case "1": lebel = "左上"; break;
case "2": lebel = "左下"; break;
case "3": lebel = "右上"; break;
case "4": lebel = "右下"; break;
}
return lebel
}
init2(){
//标题
if(!this.saveData.title){
this.saveData.title = {
t_font_color1:'#70401e',
t_font1:'BRLNSDB',
t_font_size1:40,
t_font_color:'#000000',
t_font:'BRLNSDB',
t_font_size:40,
t_val1: "", // "C",
t_val2: "" // "Listen, write circle and read"
};
}
if (this.saveData.wordArr) {
this.wordArr = this.saveData.wordArr;
} else {
this.wordArr = this.getDefaultWordArr();
this.saveData.wordArr = this.wordArr;
}
if(this.saveData.indexAudio) {
this.indexAudio = this.saveData.indexAudio
} else {
this.indexAudio = ["", "", "", ""]
this.saveData.indexAudio = this.indexAudio
}
}
......@@ -60,26 +168,122 @@ export class FormComponent implements OnInit, OnChanges, OnDestroy {
*/
onImageUploadSuccess(e, key) {
this.item[key] = e.url;
this.save();
this.saveData[key] = e.url;
this.save();
}
/**
* 储存音频数据
* @param e
*/
onAudioUploadSuccess(e, key) {
this.item[key] = e.url;
onAudioUploadSuccess(e, item, key) {
item[key] = e.url;
this.save();
}
onAudioUploadSuccessByItem(e, item, key) {
item[key] = e.url;
this.save();
}
/**
* 储存数据
*/
save() {
saveOld() {
this.item.contentObj.data = this.saveData;
this.save();
}
/**
* 刷新 渲染页面
*/
refreshOld() {
// setTimeout(() => {
// this.appRef.tick();
// }, 1);
}
deleteItem(index) {
if (index !== -1) {
this.wordArr.splice(index, 1);
}
// this.save();
this.save();
}
addItem() {
let item = this.wordItemData();
this.wordArr.push(item);
this.saveItem();
}
// addLetterItem(letters){
// let letter = this.letterData();
// letters.push(letter);
// this.save();
// }
deleteLetterItem(letters, index){
if (index !== -1) {
letters.splice(index, 1);
}
this.save();
}
wordItemData() {
let color = "E5F4F9"
switch(this.wordArr.length) {
case 0: color = "E5F4F9"; break;
case 1: color = "F0EAF4"; break;
case 2: color = "F5F9EA"; break;
case 3: color = "FFF1EB"; break;
}
return {
words_left: "",
words_right: "",
correctOption: "left",
word_val: '',
word_audio_url: '',
letters: []
};
}
saveWordItem(index) {
let val = this.wordArr[index].word_val;
this.wordArr[index].letters = [];
for(let i=0;i<val.length;i++){
this.wordArr[index].letters.push({
letter_val: val[i],
letter_color: 'C04',
is_: '0'
});
}
this.save();
}
saveItem() {
this.save();
}
getDefaultWordArr() {
let arr = [];
return arr;
}
save () {
if(this.item && this.saveData) {
if(!this.item.contentObj) {
this.item.contentObj={}
}
this.item.contentObj.data = this.saveData
// console.log(this.saveData)
}
(<any> window).courseware.setData(this.item, null, this.saveKey);
this.refresh();
}
......
import TWEEN from '@tweenjs/tween.js';
interface AirWindow extends Window {
air: any;
curCtx: any;
curImages: any;
}
declare let window: AirWindow;
class Sprite {
x = 0;
......@@ -20,7 +15,7 @@ class Sprite {
constructor(ctx = null) {
if (!ctx) {
this.ctx = window.curCtx;
this.ctx = window['curCtx'];
} else {
this.ctx = ctx;
}
......@@ -37,6 +32,7 @@ class Sprite {
export class MySprite extends Sprite {
_width = 0;
......@@ -69,18 +65,8 @@ export class MySprite extends Sprite {
img;
_z = 0;
_showRect;
_bitmapFlag = false;
_offCanvas;
_offCtx;
isCircleStyle = false; // 切成圆形
parent;
_maskSpr;
init(imgObj = null, anchorX: number = 0.5, anchorY: number = 0.5) {
init(imgObj = null, anchorX:number = 0.5, anchorY:number = 0.5) {
if (imgObj) {
......@@ -89,6 +75,7 @@ export class MySprite extends Sprite {
this.width = this.img.width;
this.height = this.img.height;
}
this.anchorX = anchorX;
......@@ -96,12 +83,9 @@ export class MySprite extends Sprite {
}
setShowRect(rect) {
this._showRect = rect;
}
setShadow(offX, offY, blur, color = 'rgba(0, 0, 0, 0.3)') {
this._shadowFlag = true;
this._shadowColor = color;
this._shadowOffsetX = offX;
......@@ -114,19 +98,6 @@ export class MySprite extends Sprite {
this._radius = r;
}
setMaskSpr(spr) {
this._maskSpr = spr;
this._createOffCtx();
}
_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._offCtx = this._offCanvas.getContext('2d');
}
}
update($event = null) {
if (!this.visible && this.childDepandVisible) {
......@@ -162,22 +133,7 @@ export class MySprite extends Sprite {
this.ctx.transform(1, this.skewX, this.skewY, 1, 0, 0);
}
drawSelf() {
if (this._shadowFlag) {
this.ctx.shadowOffsetX = this._shadowOffsetX;
this.ctx.shadowOffsetY = this._shadowOffsetY;
this.ctx.shadowBlur = this._shadowBlur;
this.ctx.shadowColor = this._shadowColor;
} else {
this.ctx.shadowOffsetX = 0;
this.ctx.shadowOffsetY = 0;
this.ctx.shadowBlur = null;
this.ctx.shadowColor = null;
}
if (this._radius) {
......@@ -186,78 +142,55 @@ export class MySprite extends Sprite {
const w = this.width;
const h = this.height;
this.ctx.beginPath()
this._roundRect(-w / 2, - h / 2, w, h, r * 1 || 0);
this.ctx.clip();
}
this.ctx.lineTo(-w / 2, h / 2); // 创建水平线
this.ctx.arcTo(-w / 2, -h / 2, -w / 2 + r, -h / 2, r);
this.ctx.arcTo(w / 2, -h / 2, w / 2, -h / 2 + r, r);
this.ctx.arcTo(w / 2, h / 2, w / 2 - r, h / 2, r);
this.ctx.arcTo(-w / 2, h / 2, -w / 2, h / 2 - r, r);
if (this.isCircleStyle) {
this.ctx.beginPath()
this.ctx.arc(0, 0, Math.max(this.width, this.height) / 2, 0, Math.PI * 2, false); // 圆形
this.ctx.clip();
}
if (this.img) {
if (this._showRect) {
const rect = this._showRect;
this.ctx.drawImage(this.img, rect.x, rect.y, rect.width, rect.height, this._offX + rect.x, this._offY + rect.y, rect.width, rect.height);
} else {
if (this._offCtx) {
this._offScreenRender();
} else {
this.ctx.drawImage(this.img, this._offX, this._offY);
}
}
}
}
_offScreenRender() {
drawSelf() {
this._offCtx.save();
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);
if (this._shadowFlag) {
this.ctx.shadowOffsetX = this._shadowOffsetX;
this.ctx.shadowOffsetY = this._shadowOffsetY;
this.ctx.shadowBlur = this._shadowBlur;
this.ctx.shadowColor = this._shadowColor;
} else {
this.ctx.shadowOffsetX = 0;
this.ctx.shadowOffsetY = 0;
this.ctx.shadowBlur = null;
this.ctx.shadowColor = null;
}
this.ctx.drawImage(this._offCanvas, this._offX, this._offY);
this._offCtx.restore();
if (this.img) {
this.ctx.drawImage(this.img, this._offX, this._offY);
}
}
_roundRect(x, y, w, h, r) {
const min_size = Math.min(w, h);
if (r > min_size / 2) r = min_size / 2;
// 开始绘制
const ctx = this.ctx;
ctx.beginPath();
ctx.moveTo(x + r, y);
ctx.arcTo(x + w, y, x + w, y + h, r);
ctx.arcTo(x + w, y + h, x, y + h, r);
ctx.arcTo(x, y + h, x, y, r);
ctx.arcTo(x, y, x + w, y, r);
ctx.closePath();
}
updateChildren() {
updateChildren() {
if (this.children.length <= 0) { return; }
for (const child of this.children) {
if (child === this) {
for (let i = 0; i < this.children.length; i++) {
if (this.children[i] === this) {
if (this.visible) {
this.drawSelf();
}
} else {
child.update();
this.children[i].update();
}
}
}
......@@ -304,7 +237,7 @@ export class MySprite extends Sprite {
removeChildren() {
for (let i = 0; i < this.children.length; i++) {
if (this.children[i]) {
if (this.children[i] !== this) {
if (this.children[i] != this) {
this.children.splice(i, 1);
i --;
}
......@@ -313,20 +246,13 @@ export class MySprite extends Sprite {
}
_changeChildAlpha(alpha) {
for (const child of this.children) {
if (child !== this) {
child.alpha = alpha;
for (let i = 0; i < this.children.length; i++) {
if (this.children[i] != this) {
this.children[i].alpha = alpha;
}
}
}
set bitmapFlag(v) {
this._bitmapFlag = v;
}
get bitmapFlag() {
return this._bitmapFlag;
}
set alpha(v) {
this._alpha = v;
if (this.childDepandAlpha) {
......@@ -375,6 +301,7 @@ export class MySprite extends Sprite {
getBoundingBox() {
const getParentData = (item) => {
let px = item.x;
......@@ -412,6 +339,11 @@ export class MySprite extends Sprite {
const width = this.width * Math.abs(data.sx);
const height = this.height * Math.abs(data.sy);
// const x = this.x + this._offX * Math.abs(this.scaleX);
// const y = this.y + this._offY * Math.abs(this.scaleY);
// const width = this.width * Math.abs(this.scaleX);
// const height = this.height * Math.abs(this.scaleY);
return {x, y, width, height};
}
......@@ -442,8 +374,8 @@ export class ColorSpr extends MySprite {
const c = this.ctx.getImageData(rect.x, rect.y, rect.width, rect.height);
for ( let i = 0; i < c.height; i++) {
for ( let j = 0; j < c.width; j++) {
for( let i = 0; i < c.height; i++){
for( let j = 0; j < c.width; j++){
const x = (i * 4) * c.width + ( j * 4 );
const r = c.data[x];
......@@ -477,7 +409,7 @@ export class GrayscaleSpr extends MySprite {
grayScale = 120;
createGSCanvas() {
createGSCanvas(){
if (!this.img) {
return;
......@@ -488,8 +420,8 @@ export class GrayscaleSpr extends MySprite {
const rect = this.getBoundingBox();
const c = this.ctx.getImageData(rect.x, rect.y, rect.width, rect.height);
for ( let i = 0; i < c.height; i++) {
for ( let j = 0; j < c.width; j++) {
for( let i = 0; i < c.height; i++){
for( let j = 0; j < c.width; j++){
const x = (i * 4) * c.width + ( j * 4 );
const r = c.data[x];
......@@ -532,10 +464,10 @@ export class BitMapLabel extends MySprite {
const tmpArr = text.split('');
let totalW = 0;
let h = 0;
for (const tmp of tmpArr) {
for (let i = 0; i < tmpArr.length; i++) {
const label = new MySprite(this.ctx);
label.init(data[tmp], 0);
label.init(data[tmpArr[i]], 0);
this.addChild(label);
labelArr.push(label);
......@@ -548,9 +480,9 @@ export class BitMapLabel extends MySprite {
this.height = h;
let offX = -totalW / 2;
for (const label of labelArr) {
label.x = offX;
offX += label.width;
for (let i = 0; i < labelArr.length; i++) {
labelArr[i].x = offX;
offX += labelArr[i].width;
}
this.labelArr = labelArr;
......@@ -563,22 +495,22 @@ export class BitMapLabel extends MySprite {
export class Label extends MySprite {
text: string;
text: String;
// fontSize:String = '40px';
fontName = 'Verdana';
textAlign = 'left';
fontName: String = 'Verdana';
textAlign: String = 'left';
fontSize = 40;
fontColor = '#000000';
fontWeight = 900;
_maxWidth;
maxWidth;
outline = 0;
outlineColor = '#ffffff';
// _shadowFlag = false;
// _shadowColor;
// _shadowOffsetX;
// _shadowOffsetY;
// _shadowBlur;
_shadowFlag = false;
_shadowColor;
_shadowOffsetX;
_shadowOffsetY;
_shadowBlur;
_outlineFlag = false;
_outLineWidth;
......@@ -609,7 +541,7 @@ export class Label extends MySprite {
setMaxSize(w) {
this._maxWidth = w;
this.maxWidth = w;
this.refreshSize();
if (this.width >= w) {
this.scaleX *= w / this.width;
......@@ -628,7 +560,7 @@ export class Label extends MySprite {
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(() => {
.onComplete(function() {
if (callBack) {
callBack();
}
......@@ -636,16 +568,16 @@ export class Label extends MySprite {
.start(); // Start the tween immediately.
}
// setShadow(offX = 0, offY = 2, blur = 2, color = 'rgba(0, 0, 0, 0.2)') {
//
// this._shadowFlag = true;
// this._shadowColor = color;
// // 将阴影向右移动15px,向上移动10px
// this._shadowOffsetX = 5;
// this._shadowOffsetY = 5;
// // 轻微模糊阴影
// this._shadowBlur = 5;
// }
setShadow(offX = 2, offY = 2, blur = 2, color = 'rgba(0, 0, 0, 0.2)') {
this._shadowFlag = true;
this._shadowColor = color;
// 将阴影向右移动15px,向上移动10px
this._shadowOffsetX = 5;
this._shadowOffsetY = 5;
// 轻微模糊阴影
this._shadowBlur = 5;
}
setOutline(width = 5, color = '#ffffff') {
......@@ -714,10 +646,11 @@ export class RichTextOld extends Label {
textArr = [];
fontSize = 40;
setText(text: string, words) {
setText(text:string, words) {
let newText = text;
for (const word of words) {
for (let i = 0; i < words.length; i++) {
const word = words[i];
const re = new RegExp(word, 'g');
newText = newText.replace( re, `#${word}#`);
......@@ -740,8 +673,8 @@ export class RichTextOld extends Label {
this.ctx.fontWeight = this.fontWeight;
let curX = 0;
for (const text of this.textArr) {
const w = this.ctx.measureText(text).width;
for (let i = 0; i < this.textArr.length; i++) {
const w = this.ctx.measureText(this.textArr[i]).width;
curX += w;
}
......@@ -763,7 +696,7 @@ export class RichTextOld extends Label {
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(() => {
.onComplete(function() {
if (callBack) {
callBack();
}
......@@ -799,7 +732,7 @@ export class RichTextOld extends Label {
const w = this.ctx.measureText(this.textArr[i]).width;
if ((i + 1) % 2 === 0) {
if ((i + 1) % 2 == 0) {
this.ctx.fillStyle = '#c8171e';
} else {
this.ctx.fillStyle = '#000000';
......@@ -822,10 +755,9 @@ export class RichTextOld extends Label {
export class RichText extends Label {
disH = 30;
offW = 10;
disH = 30;
constructor(ctx?: any) {
constructor(ctx) {
super(ctx);
// this.dataArr = dataArr;
......@@ -853,18 +785,18 @@ export class RichText extends Label {
const chr = this.text.split(' ');
let temp = '';
const row = [];
const w = selfW - this.offW * 2;
const w = selfW - 80;
const disH = (this.fontSize + this.disH) * this.scaleY;
for (const c of chr) {
if (this.ctx.measureText(temp).width < w && this.ctx.measureText(temp + (c)).width <= w) {
temp += ' ' + c;
for (let a = 0; a < chr.length; a++) {
if (this.ctx.measureText(temp).width < w && this.ctx.measureText(temp + (chr[a])).width <= w) {
temp += ' ' + chr[a];
} else {
row.push(temp);
temp = ' ' + c;
temp = ' ' + chr[a];
}
}
row.push(temp);
......@@ -904,40 +836,6 @@ export class RichText extends Label {
export class LineRect extends MySprite {
lineColor = '#ffffff';
lineWidth = 10;
setSize(w, h) {
this.width = w;
this.height = h;
}
drawLine() {
this.ctx.beginPath();
this.ctx.moveTo(this._offX, this._offY);
this.ctx.lineTo(this._offX + this.width, this._offY);
this.ctx.lineTo(this._offX + this.width, this._offY + this.height);
this.ctx.lineTo(this._offX, this._offY + this.height);
this.ctx.closePath();
this.ctx.lineWidth = this.lineWidth;
// this.ctx.fillStyle = "rgb(2,33,42)"; //指定填充颜色
// this.ctx.fill(); //对多边形进行填充
this.ctx.strokeStyle = this.lineColor; // "#ffffff";
this.ctx.stroke();
}
drawSelf() {
super.drawSelf();
this.drawLine();
}
}
export class ShapeRect extends MySprite {
......@@ -966,37 +864,7 @@ export class ShapeRect extends MySprite {
}
}
export class ShapeCircle extends MySprite {
fillColor = '#FF0000';
radius = 0;
setRadius(r) {
this.anchorX = this.anchorY = 0.5;
this.radius = r;
this.width = r * 2;
this.height = r * 2;
}
drawShape() {
this.ctx.beginPath();
this.ctx.fillStyle = this.fillColor;
this.ctx.arc(0, 0, this.radius, 0, angleToRadian(360));
this.ctx.fill();
}
drawSelf() {
super.drawSelf();
this.drawShape();
}
}
export class ShapeRectNew extends MySprite {
export class ShapeRoundRect extends MySprite {
radius = 0;
......@@ -1029,28 +897,28 @@ export class ShapeRectNew extends MySprite {
ctx.save();
ctx.beginPath(0);
// 从右下角顺时针绘制,弧度从0到1/2PI
ctx.arc(width - radius + this._offX, height - radius + this._offY, radius, 0, Math.PI / 2);
ctx.arc(width - radius, height - radius, radius, 0, Math.PI / 2);
// 矩形下边线
ctx.lineTo(radius + this._offX, height + this._offY);
ctx.lineTo(radius, height);
// 左下角圆弧,弧度从1/2PI到PI
ctx.arc(radius + this._offX, height - radius + this._offY, radius, Math.PI / 2, Math.PI);
ctx.arc(radius, height - radius, radius, Math.PI / 2, Math.PI);
// 矩形左边线
ctx.lineTo(0 + this._offX, radius + this._offY);
ctx.lineTo(0, radius);
// 左上角圆弧,弧度从PI到3/2PI
ctx.arc(radius + this._offX, radius + this._offY, radius, Math.PI, Math.PI * 3 / 2);
ctx.arc(radius, radius, radius, Math.PI, Math.PI * 3 / 2);
// 上边线
ctx.lineTo(width - radius + this._offX, 0 + this._offY);
ctx.lineTo(width - radius, 0);
// 右上角圆弧
ctx.arc(width - radius + this._offX, radius + this._offY, radius, Math.PI * 3 / 2, Math.PI * 2);
ctx.arc(width - radius, radius, radius, Math.PI * 3 / 2, Math.PI * 2);
// 右边线
ctx.lineTo(width + this._offX, height - radius + this._offY);
ctx.lineTo(width, height - radius);
ctx.closePath();
if (this.fill) {
......@@ -1073,6 +941,36 @@ export class ShapeRectNew extends MySprite {
}
}
export class ShapeCircle extends MySprite {
fillColor = '#FF0000';
radius = 0;
setRadius(r) {
this.anchorX = this.anchorY = 0.5;
this.radius = r;
this.width = r * 2;
this.height = r * 2;
}
drawShape() {
this.ctx.beginPath();
this.ctx.fillStyle = this.fillColor;
this.ctx.arc(0, 0, this.radius, 0, angleToRadian(360));
this.ctx.fill();
}
drawSelf() {
super.drawSelf();
this.drawShape();
}
}
export class MyAnimation extends MySprite {
......@@ -1085,7 +983,7 @@ export class MyAnimation extends MySprite {
loop = false;
playEndFunc;
delayPerUnit = 0.07;
delayPerUnit = 1;
restartFlag = false;
reverseFlag = false;
......@@ -1119,13 +1017,13 @@ export class MyAnimation extends MySprite {
this.frameArr[this.frameIndex].visible = true;
}
_refreshSize(img: any) {
_refreshSize(img) {
if (this.width < img.width) {
this.width = img.width;
if (this.width < img['width']) {
this.width = img['width'];
}
if (this.height < img.height) {
this.height = img.height;
if (this.height < img['height']) {
this.height = img['height'];
}
}
......@@ -1154,14 +1052,14 @@ export class MyAnimation extends MySprite {
}
showAllFrame() {
for (const frame of this.frameArr ) {
frame.alpha = 1;
for (let i = 0; i < this.frameArr.length; i++) {
this.frameArr[i].alpha = 1;
}
}
hideAllFrame() {
for (const frame of this.frameArr) {
frame.alpha = 0;
for (let i = 0; i < this.frameArr.length; i++) {
this.frameArr[i].alpha = 0;
}
}
......@@ -1174,9 +1072,8 @@ export class MyAnimation extends MySprite {
this.frameArr[this.frameIndex].visible = true;
if (this.playEndFunc) {
const func = this.playEndFunc;
this.playEndFunc();
this.playEndFunc = null;
func();
}
}
......@@ -1243,14 +1140,6 @@ export class MyAnimation extends MySprite {
export function tweenChange(item, obj, time = 0.8, callBack = null, easing = null, update = null) {
const tween = createTween(item, obj, time, callBack, easing, update)
tween.start();
return tween;
}
export function createTween(item, obj, time = 0.8, callBack = null, easing = null, update = null) {
const tween = new TWEEN.Tween(item).to(obj, time * 1000);
if (callBack) {
......@@ -1266,28 +1155,15 @@ export function createTween(item, obj, time = 0.8, callBack = null, easing = nul
update(a, b);
});
}
return tween;
}
export function tweenQueue(arr) {
const showOneTween = () => {
const tween = arr.shift();
if (arr.length > 0) {
tween.onComplete( () => {
showOneTween();
});
}
tween.start();
};
showOneTween();
tween.start();
return tween;
}
export function rotateItem(item, rotation, time = 0.8, callBack = null, easing = null, loop = false) {
export function rotateItem(item, rotation, time = 0.8, callBack = null, easing = null) {
const tween = new TWEEN.Tween(item).to({ rotation }, time * 1000);
......@@ -1295,14 +1171,7 @@ export function rotateItem(item, rotation, time = 0.8, callBack = null, easing =
tween.onComplete(() => {
callBack();
});
} else if (loop) {
const speed = (rotation - item.rotation) / time;
tween.onComplete(() => {
item.rotation %= 360;
rotateItem(item, item.rotation + speed * time, time, null, easing, true);
});
}
if (easing) {
tween.easing(easing);
}
......@@ -1362,7 +1231,7 @@ export function endShow(item, s = 1) {
const tween = new TWEEN.Tween(item)
.to({ alpha: 1, scaleX: s, scaleY: s }, 800)
.easing(TWEEN.Easing.Elastic.Out) // Use an easing function to make the animation smooth.
.onComplete(() => {
.onComplete(function() {
})
.start();
......@@ -1370,14 +1239,14 @@ export function endShow(item, s = 1) {
export function hideItem(item, time = 0.8, callBack = null, easing = null) {
if (item.alpha === 0) {
if (item.alpha == 0) {
return;
}
const tween = new TWEEN.Tween(item)
.to({alpha: 0}, time * 1000)
// .easing(TWEEN.Easing.Quadratic.Out) // Use an easing function to make the animation smooth.
.onComplete(() => {
.onComplete(function () {
if (callBack) {
callBack();
}
......@@ -1393,7 +1262,7 @@ export function hideItem(item, time = 0.8, callBack = null, easing = null) {
export function showItem(item, time = 0.8, callBack = null, easing = null) {
if (item.alpha === 1) {
if (item.alpha == 1) {
if (callBack) {
callBack();
}
......@@ -1404,7 +1273,7 @@ export function showItem(item, time = 0.8, callBack = null, easing = null) {
const tween = new TWEEN.Tween(item)
.to({alpha: 1}, time * 1000)
// .easing(TWEEN.Easing.Quadratic.Out) // Use an easing function to make the animation smooth.
.onComplete(() => {
.onComplete(function () {
if (callBack) {
callBack();
}
......@@ -1422,9 +1291,9 @@ export function alphaItem(item, alpha, time = 0.8, callBack = null, easing = nul
const tween = new TWEEN.Tween(item)
.to({alpha}, time * 1000)
.to({alpha: alpha}, time * 1000)
// .easing(TWEEN.Easing.Quadratic.Out) // Use an easing function to make the animation smooth.
.onComplete(() => {
.onComplete(function () {
if (callBack) {
callBack();
}
......@@ -1444,7 +1313,7 @@ export function showStar(item, time = 0.8, callBack = null, easing = null) {
const tween = new TWEEN.Tween(item)
.to({alpha: 1, scale: 1}, time * 1000)
// .easing(TWEEN.Easing.Quadratic.Out) // Use an easing function to make the animation smooth.
.onComplete(() => {
.onComplete(function () {
if (callBack) {
callBack();
}
......@@ -1500,22 +1369,22 @@ export function getAngleByPos(px, py, mx, my) {
const radina = Math.acos(cos); // 用反三角函数求弧度
let angle = Math.floor(180 / (Math.PI / radina) * 100) / 100; // 将弧度转换成角度
if (mx > px && my > py) {// 鼠标在第四象限
if(mx > px && my > py) {// 鼠标在第四象限
angle = 180 - angle;
}
if (mx === px && my > py) {// 鼠标在y轴负方向上
if(mx === px && my > py) {// 鼠标在y轴负方向上
angle = 180;
}
if (mx > px && my === py) {// 鼠标在x轴正方向上
if(mx > px && my === py) {// 鼠标在x轴正方向上
angle = 90;
}
if (mx < px && my > py) {// 鼠标在第三象限
if(mx < px && my > py) {// 鼠标在第三象限
angle = 180 + angle;
}
if (mx < px && my === py) {// 鼠标在x轴负方向
if(mx < px && my === py) {// 鼠标在x轴负方向
angle = 270;
}
if (mx < px && my < py) {// 鼠标在第二象限
if(mx < px && my < py) {// 鼠标在第二象限
angle = 360 - angle;
}
......@@ -1527,17 +1396,27 @@ export function getAngleByPos(px, py, mx, my) {
export function removeItemFromArr(arr, item) {
const index = arr.indexOf(item);
if (index !== -1) {
if (index != -1) {
arr.splice(index, 1);
}
}
export function getPosDistance(sx, sy, ex, ey) {
const _x = ex - sx;
const _y = ey - sy;
const len = Math.sqrt( Math.pow(_x, 2) + Math.pow(_y, 2) );
return len;
}
export function circleMove(item, x0, y0, time = 2, addR = 360, xPer = 1, yPer = 1, callBack = null, easing = null) {
export function circleMove(item, x0, y0, time = 2, addR = 360, xPer = 1, yPer = 1, callBack = null, easing = null){
const r = getPosDistance(item.x, item.y, x0, y0);
let a = getAngleByPos(item.x, item.y, x0, y0);
......@@ -1577,15 +1456,8 @@ export function circleMove(item, x0, y0, time = 2, addR = 360, xPer = 1, yPer =
}
export function getPosDistance(sx, sy, ex, ey) {
const _x = ex - sx;
const _y = ey - sy;
const len = Math.sqrt( Math.pow(_x, 2) + Math.pow(_y, 2) );
return len;
}
export function delayCall(second, callback) {
export function delayCall(callback, second) {
const tween = new TWEEN.Tween(this)
.delay(second * 1000)
.onComplete(() => {
......@@ -1602,32 +1474,25 @@ export function formatTime(fmt, date) {
// "yyyy-MM-dd HH:mm:ss";
const o = {
'M+': date.getMonth() + 1, // 月份
'd+': date.getDate(), // 日
'h+': date.getHours(), // 小时
'm+': date.getMinutes(), // 分
's+': date.getSeconds(), // 秒
'q+': Math.floor((date.getMonth() + 3) / 3), // 季度
S: date.getMilliseconds() // 毫秒
"M+": date.getMonth() + 1, // 月份
"d+": date.getDate(), // 日
"h+": date.getHours(), // 小时
"m+": date.getMinutes(), // 分
"s+": date.getSeconds(), // 秒
"q+": Math.floor((date.getMonth() + 3) / 3), // 季度
"S": date.getMilliseconds() // 毫秒
};
if (/(y+)/.test(fmt)) { fmt = fmt.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length)); }
for (const k in o) {
if (new RegExp('(' + k + ')').test(fmt)) { fmt = fmt.replace(RegExp.$1, (RegExp.$1.length === 1)
? (o[k]) : (('00' + o[k]).substr(('' + o[k]).length)));
}
}
if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (date.getFullYear() + "").substr(4 - RegExp.$1.length));
for (var k in o)
if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1)
? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
return fmt;
}
export function getMinScale(item, maxW, maxH = null) {
if (!maxH) {
maxH = maxW;
}
const sx = maxW / item.width;
const sy = maxH / item.height;
export function getMinScale(item, maxLen) {
const sx = maxLen / item.width;
const sy = maxLen / item.height;
const minS = Math.min(sx, sy);
return minS;
}
......@@ -1670,51 +1535,11 @@ export function jelly(item, time = 0.7) {
run();
}
export function jellyPop(item, time) {
if (item.jellyTween) {
TWEEN.remove(item.jellyTween);
}
const t = time / 6;
const baseSX = item.scaleX;
const baseSY = item.scaleY;
let index = 0;
const run = () => {
if (index >= arr.length) {
item.jellyTween = null;
return;
}
const data = arr[index];
const t = tweenChange(item, {scaleX: data[0], scaleY: data[1]}, data[2], () => {
index ++;
run();
}, TWEEN.Easing.Sinusoidal.InOut);
item.jellyTween = t;
};
const arr = [
[baseSX * 1.3, baseSY * 1.3, t],
[baseSX * 0.85, baseSY * 0.85, t * 1],
[baseSX * 1.1, baseSY * 1.1, t * 1],
[baseSX * 0.95, baseSY * 0.95, t * 1],
[baseSX * 1.02, baseSY * 1.02, t * 1],
[baseSX * 1, baseSY * 1, t * 1],
];
item.setScaleXY(0);
run();
}
export function showPopParticle(img, pos, parent) {
export function showPopParticle(img, pos, parent, num = 20, minLen = 40, maxLen = 80, showTime = 0.4) {
const num = 20;
for (let i = 0; i < num; i ++) {
const particle = new MySprite();
......@@ -1726,8 +1551,8 @@ export function showPopParticle(img, pos, parent, num = 20, minLen = 40, maxLen
const randomR = 360 * Math.random();
particle.rotation = randomR;
const randomS = 0.3 + Math.random() * 0.7;
particle.setScaleXY(randomS * 0.3);
const randomS = 0.5 + Math.random() * 0.5;
particle.setScaleXY(randomS);
const randomX = Math.random() * 20 - 10;
particle.x += randomX;
......@@ -1735,32 +1560,16 @@ export function showPopParticle(img, pos, parent, num = 20, minLen = 40, maxLen
const randomY = Math.random() * 20 - 10;
particle.y += randomY;
const randomL = minLen + Math.random() * (maxLen - minLen);
const randomL = 40 + Math.random() * 40;
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, () => {
moveItem(particle, particle.x + randomT.x, particle.y + randomT.y, 0.4, () => {
}, TWEEN.Easing.Exponential.Out);
setTimeout(() => {
hideItem(particle, 0.4, () => {
}, TWEEN.Easing.Cubic.In);
}, showTime * 0.5 * 1000);
scaleItem(particle, 0, 0.6, () => {
});
}
}
......@@ -1802,7 +1611,7 @@ export function shake(item, time = 0.5, callback = null, rate = 1) {
};
const move1 = () => {
moveItem(item, baseX + offX, baseY + offY, time / 7.5, () => {
moveItem(item, baseX + offX, baseY + offY, time / 8, () => {
move2();
}, easing);
};
......@@ -1811,41 +1620,5 @@ export function shake(item, time = 0.5, callback = null, rate = 1) {
}
export function getMaxScale(item, maxW, maxH) {
const sx = maxW / item.width;
const sy = maxH / item.height;
const maxS = Math.max(sx, sy);
return maxS;
}
export function createSprite(key) {
const image = window.curImages;
const spr = new MySprite();
spr.init(image.get(key));
return spr;
}
export class MyVideo extends MySprite {
element;
initVideoElement(videoElement) {
this.element = videoElement;
this.width = this.element.videoWidth;
this.height = this.element.videoHeight;
this.element.currentTime = 0.01;
}
drawSelf() {
super.drawSelf();
this.ctx.drawImage(this.element, 0, 0, this.width, this.height);
}
}
// --------------- custom class --------------------
.game-container {
width: 100%;
height: 100%;
background: #ffffff;
background-size: cover;
}
#canvas {
}
@font-face
{
font-family: 'BRLNSDB';
src: url("../../assets/font/BRLNSDB.TTF") ;
}
.game-container {
width: 100%;
height: 100%;
background: #ffffff;
background-size: cover;
}
#canvas {
}
@font-face
{
font-family: 'BRLNSDB';
src: url("../../assets/font/BRLNSDB.TTF") ;
}
@font-face
{
font-family: 'BRLNSB';
src: url("../../assets/font/BRLNSB.TTF") ;
}
@font-face
{
font-family: 'BRLNSR';
src: url("../../assets/font/BRLNSR.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: 'GOTHICBI';
src: url("../../assets/font/GOTHICBI.TTF") ;
}
@font-face
{
font-family: 'GOTHICI';
src: url("../../assets/font/GOTHICI.TTF") ;
}
@font-face
{
font-family: 'MMTextBook';
src: url("../../assets/font/MMTextBook.otf") ;
}
@font-face
{
font-family: 'MMTextBook-Bold';
src: url("../../assets/font/MMTextBook-Bold.otf") ;
}
@font-face
{
font-family: 'MMTextBook-BoldItalic';
src: url("../../assets/font/MMTextBook-BoldItalic.otf") ;
}
@font-face
{
font-family: 'MMTextBook-Italic';
src: url("../../assets/font/MMTextBook-Italic.otf") ;
}
import {Component, ElementRef, ViewChild, OnInit, Input, OnDestroy, HostListener} from '@angular/core';
import {Component, ElementRef, ViewChild, OnInit, Input, OnDestroy, HostListener} from '@angular/core';
import defaultData from "../../assets/YM5-6/default/data.js"
import {
Label,
MySprite, tweenChange,
MySprite, ShapeCircle, ShapeRect, ShapeRoundRect, tweenChange,
getMinScale
} from './Unit';
// import res from './resources';
import {res, resAudio} from './resources';
import {Subject} from 'rxjs';
import {debounceTime} from 'rxjs/operators';
import * as _ from 'lodash';
import TWEEN from '@tweenjs/tween.js';
import {del} from 'selenium-webdriver/http';
@Component({
selector: 'app-play',
templateUrl: './play.component.html',
styleUrls: ['./play.component.css']
styleUrls: ['./play.component.scss']
})
export class PlayComponent implements OnInit, OnDestroy {
// 数据
_data;
m_currentStartIndex: number = 1;
ngOnInit() {
console.log("ver.202101100140")
this.data = {contentObj: {}};
// 获取数据
const getData = (<any> window).courseware.getData;
getData((data) => {
if (data && !data.contentObj) data.contentObj = {};
if (data && typeof data == 'object') {
this.data = data;
}
if (this.ngOnInit2) this.ngOnInit2();
}, this.saveKey);
}
saveKey='YM5-6'
@Input()
set data(data) {
this._data = data;
}
get data() {
return this._data;
}
@Input()
sid;
@ViewChild('canvas', {static: true }) canvas: ElementRef;
@ViewChild('wrap', {static: true }) wrap: ElementRef;
@ViewChild('canvas', {static:true}) canvas: ElementRef;
@ViewChild('wrap', {static:true}) wrap: ElementRef;
// 数据
data;
saveData;
ctx;
......@@ -57,43 +88,145 @@ export class PlayComponent implements OnInit, OnDestroy {
canvasLeft;
canvasTop;
saveKey = 'test_0011';
saveKeyOld='test_008';
btnLeft;
btnRight;
pic1;
pic2;
canTouch = true;
curPic;
//单词画面数组
word_arr_left = [] ;
word_arr = [];
wordNumSelected = []
word_bg_x ;
word_height ;
all_words_loaded = false;
curAudio ;
play = false;
words_bg ;
words_bg_right ;
title_bg ;
optionsAll = [];
opend = [false, false, false, false, false, false, false, false];
wordLoad :{[key:string]:{loaded : boolean;letters:{[key:string]:{loaded:boolean, letter:Label}}}} = {};
setWordLoad(id: string, letterId:string, loaded:boolean, letter: Label):void{
if(!this.wordLoad[id]){
this.wordLoad[id] = {
loaded:false,
letters:{}
}
}
let letters = this.wordLoad[id].letters;
if(!letters[letterId]){
letters[letterId] = {
loaded:loaded,
letter:letter
}
}
//是否存在未加载完成的字母
let flag = false;
for(let tKey in letters){
if(!letters[tKey].loaded){
flag = true;
break;
}
}
if(!flag){
this.wordLoad[id].loaded = true;
}
else{
this.wordLoad[id].loaded = false;
}
}
getWordLoaded(id: string):boolean{
if(!this.wordLoad[id]){
return false;
}
return this.wordLoad[id].loaded;
}
/**
* 检查单词是否加载完成
* @param id 单词id
*/
checkWordLoaded(id: string):void{
if(!this.wordLoad[id]){
return;
}
let letters = this.wordLoad[id].letters;
//是否存在未加载完成的字母
let flag = false;
for(let tKey in letters){
if(!letters[tKey].loaded){
flag = true;
break;
}
}
if(!flag){
this.wordLoad[id].loaded = true;
}
else{
this.wordLoad[id].loaded = false;
}
}
getLetterSpriteFromWordLoaded(id: string){
if(!this.wordLoad[id]){
return;
}
let letters = this.wordLoad[id].letters;
return letters;
}
@HostListener('window:resize', ['$event'])
onResize(event) {
this.winResizeEventStream.next();
}
ngOnInit() {
ngOnInit2() {
this.data = {};
this.saveData = {};
// 获取数据
const getData = (<any> window).courseware.getData;
getData((data) => {
// const getData = (<any> window).courseware.getData;
// getData((data) => {
if (data && typeof data == 'object') {
this.data = data;
if (this.data.contentObj.data) {
this.saveData = this.data.contentObj.data;
} else {
this.saveData = defaultData.contentObj.data;
}
// console.log('data:' , data);
// 初始化 各事件监听
this.initListener();
// 若无数据 则为预览模式 需要填充一些默认数据用来显示
this.initDefaultData();
// 初始化 音频资源
this.initAudio();
// 初始化 图片资源
......@@ -101,42 +234,90 @@ export class PlayComponent implements OnInit, OnDestroy {
// 开始预加载资源
this.load();
}, this.saveKey);
// }, this.saveKey);
}
initTitle() {
const subject = this.saveData.title;
if (subject) {
const { t_val1, t_font_color1, t_font_size1, t_font1, t_val2, t_font_color, t_font, t_font_size } = subject;
// 课程章节内容
const bgRect = new ShapeRect();
bgRect.setSize(57, 65);
bgRect.fillColor = '#567790';
const sx = this.canvasWidth / this.canvasBaseW;
bgRect.setScaleXY(sx);
bgRect.x = 65 * sx;
const label1 = new Label();
label1.x = bgRect.width / 2;
label1.y = bgRect.height / 2;
label1.text = t_val1;
label1.fontSize = 48 * 0.9 // t_font_size1;
label1.fontName = "BRLNSDB" // t_font1;
label1.fontColor = "#FFFFFF" // t_font_color1 || '#70401e';
bgRect.addChild(label1);
label1.textAlign = 'center';
this.renderArr.push(bgRect);
// 题目内容
const label2 = new Label();
label2.x = bgRect.x + bgRect.width * bgRect.scaleX + 20 * this.mapScale;
label2.y = bgRect.y + bgRect.height / 2 * bgRect.scaleY + 2 * this.mapScale;
label2.text = t_val2;
label2.fontSize = 36 * 0.9 // t_font_size;
label2.fontName = "FuturaBT-Medium" // t_font;
label2.fontColor = "#000000" // t_font_color;
label2.setScaleXY(sx);
label2.refreshSize();
label2.anchorX = 0;
this.renderArr.push(label2);
this.title_bg = label2;
}
}
ngOnDestroy() {
window['curCtx'] = null;
window.cancelAnimationFrame(this.animationId);
this.cleanAudio();
}
cleanAudio() {
if (this.audioObj) {
for (const key in this.audioObj) {
for(let key in this.audioObj) {
this.audioObj[key].pause();
}
}
}
load() {
// 预加载资源
this.loadResources().then(() => {
window["air"].hideAirClassLoading(this.saveKey, this.data);
window['air'].hideAirClassLoading(this.saveKey, this.data);
this.init();
this.update();
});
}
init() {
this.initCtx();
this.initData();
this.initView();
this.initTitle();
// 加载完成播放音乐
this.playAudio("newpage");
}
initCtx() {
......@@ -145,20 +326,16 @@ export class PlayComponent implements OnInit, OnDestroy {
this.canvas.nativeElement.width = this.wrap.nativeElement.clientWidth;
this.canvas.nativeElement.height = this.wrap.nativeElement.clientHeight;
this.ctx = this.canvas.nativeElement.getContext('2d');
this.canvas.nativeElement.width = this.canvasWidth;
this.canvas.nativeElement.height = this.canvasHeight;
window['curCtx'] = this.ctx;
window['curImages'] = this.images;
}
updateItem(item) {
if (item) {
item.update();
......@@ -300,6 +477,22 @@ export class PlayComponent implements OnInit, OnDestroy {
}
pauseAudio(key, callback = null){
const audio = this.audioObj[key];
if (audio) {
if (callback) {
audio.onended = () => {
callback();
};
}
audio.pause();
}
}
loadResources() {
const pr = [];
......@@ -341,13 +534,14 @@ export class PlayComponent implements OnInit, OnDestroy {
return new Promise((resolve, reject) => {
const audio = new Audio();
audio.oncanplay = (a) => {
resolve();
};
audio.onerror = () => {
reject();
};
audio.src = url;
audio.load();
resolve("");
});
}
......@@ -359,25 +553,20 @@ export class PlayComponent implements OnInit, OnDestroy {
}
checkClickTarget(target) {
const rect = target.getBoundingBox();
if (this.checkPointInRect(this.mx, this.my, rect)) {
return true;
if(target) {
const rect = target.getBoundingBox();
if (this.checkPointInRect(this.mx, this.my, rect)) {
return true;
}
}
return false;
}
getWorlRect(target) {
let rect = target.getBoundingBox();
if (target.parent) {
const pRect = this.getWorlRect(target.parent);
rect.x += pRect.x;
rect.y += pRect.y;
......@@ -398,55 +587,51 @@ export class PlayComponent implements OnInit, OnDestroy {
addUrlToAudioObj(key, url = null, vlomue = 1, loop = false, callback = null) {
addUrlToAudioObj(key, url = null, vlomue = 1, loop = false, callback = null, callbackParam = null) {
if(!key){
return;
}
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();
};
}
audio.addEventListener('ended', function () {
if (callback) {
callback(callbackParam);
}
}, false);
}
addUrlToImages(url) {
this.rawImages.set(url, url);
}
// ======================================================编写区域==========================================================================
/**
* 添加默认数据 便于无数据时的展示
*/
initDefaultData() {
this.title_bg = {};
this.listenPlaying = false;
this.listenPlayStatus = {};
}
if (!this.data.pic_url) {
this.data.pic_url = 'assets/play/default/pic.jpg';
this.data.pic_url_2 = 'assets/play/default/pic.jpg';
}
getDefaultTitle(){
return {
t_val1:'C',
t_val2:'Listen, write circle and read.',
t_font_color:'#70401e',
t_font:'BRLNSDB',
t_font_size:40
};
}
......@@ -454,24 +639,48 @@ export class PlayComponent implements OnInit, OnDestroy {
* 添加预加载图片
*/
initImg() {
this.addUrlToImages(this.data.pic_url);
this.addUrlToImages(this.data.pic_url_2);
this.addUrlToImages(this.saveData.pic_url);
this.addUrlToImages(this.saveData.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);
this.addUrlToAudioObj('newpage', this.rawAudios.get('newpage'));
this.addUrlToAudioObj('sm-choice-correct', this.rawAudios.get('sm-choice-correct'));
// 听力资料
this.addUrlToAudioObj(this.saveData.listen_audio_url, null,1, false, function(listenPlayStatus){
listenPlayStatus.play.alpha=1;
listenPlayStatus.pasue.alpha = 0;
},this.listenPlayStatus);
// 音频资源
if(this.saveData.title){
this.addUrlToAudioObj(this.saveData.title.t_audio_url);
}
this.addUrlToAudioObj(this.saveData.words_audio_url);
this.addUrlToAudioObj(this.saveData.words_two_audio_url);
// 初始化单词音效
for (let i = 0; i < this.saveData.wordArr.length; ++ i) {
let wordLeft = this.saveData.wordArr[i];
if (wordLeft.word_audio_url && wordLeft.word_audio_url != '') {
this.addUrlToAudioObj(wordLeft.word_audio_url);
}
}
// 序号音频
for (let i = 0; i < this.saveData.indexAudio.length; ++ i) {
let audio = this.saveData.indexAudio[i];
if (audio && audio != '') {
this.addUrlToAudioObj(audio);
}
}
}
......@@ -480,20 +689,20 @@ export class PlayComponent implements OnInit, OnDestroy {
* 初始化数据
*/
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 = [];
this.word_arr_left = [] ;
this.word_arr = [];
this.word_bg_x = 200 ;
this.wordNumSelected = []
this.m_currentStartIndex = 1;
this.word_height = 0 ;
this.all_words_loaded = false;
this.wordLoad = {};
this.play = false ;
}
......@@ -502,157 +711,485 @@ export class PlayComponent implements OnInit, OnDestroy {
* 初始化试图
*/
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;
const btnPlay = new MySprite();
btnPlay.init(this.images.get('play'));
btnPlay.x = this.canvasWidth - 50 * this.mapScale;
btnPlay.y = this.canvasHeight - 50 * this.mapScale;
btnPlay.setScaleXY(this.mapScale);
btnPlay.alpha = 1;
this.renderArr.push(btnPlay);
this.listenPlayBtn = btnPlay;
this.listenPlayStatus.play = btnPlay;
const btnPause = new MySprite();
btnPause.init(this.images.get('pause'));
btnPause.x = btnPlay.x;
btnPause.y = btnPlay.y;
btnPause.alpha = 0;
btnPause.setScaleXY(this.mapScale);
this.renderArr.push(btnPause);
this.listenPauseBtn = btnPause;
this.listenPlayStatus.pasue = btnPause;
}
body_bg;
initPic() {
this.body_bg = new ShapeRoundRect();
this.body_bg.setSize(1083*this.mapScale, 555*this.mapScale, 30*this.mapScale) ;
this.body_bg.x = (this.canvasWidth - this.body_bg.width) / 2 ;
this.body_bg.y = this.canvasHeight - this.body_bg.height - (this.canvasHeight - this.body_bg.height)/3 ;
this.renderArr.push(this.body_bg);
let colorBlock_left = new ShapeRoundRect()
colorBlock_left.x = 0;
colorBlock_left.y = 0;
colorBlock_left.fillColor = `#${this.saveData.blockColor}`;
colorBlock_left.setSize(560*this.mapScale, 500*this.mapScale, 30)
this.body_bg.addChild(colorBlock_left)
let colorBlock_right = new ShapeRoundRect()
colorBlock_right.x = 580*this.mapScale;
colorBlock_right.y = 0;
colorBlock_right.fillColor = `#${this.saveData.blockColor}`;
colorBlock_right.setSize(560*this.mapScale, 500*this.mapScale, 30);
this.body_bg.addChild(colorBlock_right);
// 初始化单词显示
this.initWord();
}
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';
/**
* 初始化单词显示
*/
initWord() {
this.drawWordSprite();
}
pic1.addChild(label1);
cricleNumber(num){
const bg = new ShapeCircle();
bg.setRadius(23);
bg.fillColor = `#${this.saveData.indexColor?this.saveData.indexColor:'f2a14d'}`;
const bg_1 = new ShapeCircle();
bg_1.setRadius(22);
bg_1.fillColor = `#${this.saveData.indexColor?this.saveData.indexColor:'f2a14d'}`;
bg.addChild(bg_1);
const words_content = new Label();
words_content.text = num;
words_content.textAlign = 'center';
words_content.fontSize = 36;
words_content.fontName = 'MMTextBookBold';
words_content.fontWeight = 600;
words_content.fontColor = "#FFFFFF";
words_content.refreshSize();
words_content.alpha = 50
words_content.y = 4;
bg.addChild(words_content);
bg["selected"] = false;
bg["index"] = num;
bg["content"] = words_content
return bg;
}
/**
* 绘画单词
*/
word_bg_groups = [];
drawWordSprite() {
const getWordSprite = (index , x , y, index_New) => {
let letterFontSize = 48;
// 单词背景
let word_bg_group = new ShapeRoundRect()
word_bg_group.width = 560;
word_bg_group.height = 57;
word_bg_group.x = x * this.mapScale;
word_bg_group.y = y * this.mapScale;
word_bg_group.fillColor = "#FFFF00"
word_bg_group.alpha = 0;
let startWidth = 80;
//单词
let word_bg = new ShapeRect();
word_bg.fillColor = 'transparent' ;
word_bg.x = startWidth ; //序号间距
word_bg.y = 0;
let word_content = this.saveData.wordArr[index];
this.creatOptions(index, word_bg_group, word_content.words_left, word_content.words_right, word_content.correctOption);
let start = this.cricleNumber(index_New+1);
start.y = 28;
start.x = 20 + start.height / 2;
word_bg_group.addChild(start) ;
this.wordNumSelected.push(start)
word_bg["number"] = start
let totalWidth = 0;
let height = 0;
let letter_spr_arr = [];
for(let i = 0; i < word_content.letters.length; ++ i) {
//字母
let letter = word_content.letters[i];
let letter_spr = new Label();
letter_spr.text = letter.letter_val;
if(letter.is_=="0"){
//设置不显示
letter_spr.visible = true;
}else{
word_bg["wordLoaded"] = false;
//设置不显示
letter_spr.visible = false;
}
letter_spr.textAlign = 'center';
// letter_spr.fontSize = word_content.word_font_size ? word_content.word_font_size : 110;
letter_spr.fontSize = letterFontSize;
letter_spr.fontName = 'MMTextBook-Bold';
letter_spr.fontColor = this.getColor(letter.letter_color);
letter_spr.refreshSize();
if(letter.is_=="1") {
letter_spr.width = 35;
}
letter_spr_arr.push(letter_spr);
let ltBounds = letter_spr.getBoundingBox();
//设置坐标
letter_spr.x = ltBounds.width / 2 + totalWidth + 5;
letter_spr.y = letter_spr.height / 2;
ltBounds = letter_spr.getBoundingBox();
if(letter.is_=="1"){
let lts_ = new ShapeRect();
lts_.x = 5 + ltBounds.x;
lts_.y = ltBounds.y+ltBounds.height;
lts_.setSize(ltBounds.width, 2);
lts_.fillColor = "#949494" // this.getColor(letter.letter_color);
word_bg.addChild(lts_);
}
height = letter_spr.height;
if(index === 0){
this.word_height = height ;
}
totalWidth += ltBounds.width;
word_bg.addChild(letter_spr);
}
word_bg.setSize(totalWidth, height * 2);
word_bg_group.addChild(word_bg);
this.word_arr_left.push(word_bg);
word_bg_group.setScaleXY(this.mapScale);
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.word_bg_groups.push(word_bg_group);
this.body_bg.addChild(word_bg_group);
};
this.renderArr.push(pic2);
this.pic2 = pic2;
let wordNum = this.saveData.wordArr.length
for (let i = 0; i < wordNum; i++) {
let tIndex = i + 1 + "";
let x = 0;
let y = 50 + 114 * i;
if(i>3){
x = 580;
y = 50 + 114 * (i - 4);
}
let index_1 = i // this.saveData.recordingIndex.indexOf(tIndex)
if(index_1!=-1) {
getWordSprite(i , x , y, index_1 );
} else {
getWordSprite(i , x , y, 9999 );
}
}
}
this.curPic = pic1;
creatOptions(index, parent, leftText, rightText, correctOption) {
let baseX = parent.width - 99 * 2
let bgLeft = new ShapeRoundRect()
bgLeft.x = baseX;
bgLeft.y = 0;
bgLeft.fillColor = `#${this.saveData.optionColor_left?this.saveData.optionColor_left:"FFFFFF"}`;
bgLeft.setSize(99, 57, 0);
bgLeft["index"] = index
bgLeft["correct"] = correctOption=="left"?true:false;
let textLeft = new Label();
textLeft.text = leftText;
textLeft.fontSize = 48;
textLeft.fontName = "MMTextBook";
textLeft.fontColor = '#FFFFFF';
textLeft.textAlign = "center";
textLeft.x = 99 / 2;
textLeft.y = 57 / 2;
bgLeft.addChild(textLeft);
parent.addChild(bgLeft);
let bgRight = new ShapeRoundRect()
bgRight.x = baseX + 99;
bgRight.y = 0;
bgRight.fillColor = `#${this.saveData.optionColor_right?this.saveData.optionColor_right:"FFFFFF"}`;
bgRight.setSize(99, 57, 0)
bgRight["index"] = index
bgRight["correct"] = correctOption=="left"?false:true;
let textRight = new Label();
textRight.text = rightText;
textRight.fontSize = 48;
textRight.fontName = "MMTextBook";
textRight.fontColor = '#FFFFFF';
textRight.textAlign = "center";
textRight.x = 99 / 2;
textRight.y = 57 / 2;
bgRight.addChild(textRight);
parent.addChild(bgRight);
this.optionsAll.push(bgLeft)
this.optionsAll.push(bgRight)
}
/**
* 根据颜色id获取对应的颜色
* @param colorId 颜色id
*/
getColor(colorId){
let color = "#000000";
switch(colorId){
case "C01":
color = "#008000";
break;
case "C02":
color = "#FF0000";
break;
case "C03":
color = "#D2691E";
break;
case "C04":
color = "#000000";
break;
case "C05":
color = "#c8161e";
break;
}
btnLeftClicked() {
return color;
}
this.lastPage();
pauseClicked() {
if(this.curAudio){
if(this.play){
this.curAudio.pause() ;
this.play = false ;
}else {
this.curAudio.play() ;
this.play = true ;
}
}
}
btnRightClicked() {
this.nextPage();
}
//听力材播放按钮
listenPlayBtn;
lastPage() {
//听力材暂停按钮
listenPauseBtn;
if (this.curPic == this.pic1) {
return;
}
listenPlaying = false;
this.canTouch = false;
listenPlayStatus;
const moveLen = this.canvasWidth;
tweenChange(this.pic1, {x: this.pic1.x + moveLen}, 1);
tweenChange(this.pic2, {x: this.pic2.x + moveLen}, 1, () => {
this.canTouch = true;
this.curPic = this.pic1;
});
}
nextPage() {
mapDown(event) {
if (this.curPic == this.pic2) {
if (!this.canTouch) {
return;
}
this.canTouch = false;
const moveLen = this.canvasWidth;
tweenChange(this.pic1, {x: this.pic1.x - moveLen}, 1);
tweenChange(this.pic2, {x: this.pic2.x - moveLen}, 1, () => {
this.canTouch = true;
this.curPic = this.pic2;
});
}
if (this.checkClickTarget(this.title_bg)) {
// console.log('click the words :' , this.data.words_audio_url) ;
this.playAudio(this.saveData.title.t_audio_url) ;
return ;
}
pic1Clicked() {
this.playAudio(this.data.audio_url);
}
if (this.checkClickTarget(this.words_bg)) {
// console.log('click the words :' , this.data.words_audio_url) ;
this.playAudio(this.saveData.words_audio_url) ;
return ;
}
pic2Clicked() {
this.playAudio(this.data.audio_url_2);
}
if (this.words_bg_right&&this.checkClickTarget(this.words_bg_right)) {
this.playAudio(this.saveData.words_two_audio_url) ;
return ;
}
for(let i = 0; i < this.optionsAll.length; ++ i) {
let option = this.optionsAll[i];
if (this.checkClickTarget(option)) {
if(option["correct"]) {
// this.playAudio("sm-choice-correct", false, ()=>{
// if(this.saveData.indexAudio[option["index"]]) {
// this.playAudio(this.saveData.indexAudio[option["index"]], true, ()=>{
// this.canTouch = true;
// })
// } else {
// this.canTouch = true;
// }
// })
this.opend[option["index"]] = true;
let word = this.word_arr_left[option["index"]];
let letters:Array<Label> = word.children.slice(1);
for (let j=0; j<letters.length;j++) {
let labelItem = letters[j];
if(!labelItem.visible){
labelItem.visible = true;
}
}
word.wordLoaded = true;
this.playAudio("sm-choice-correct", false, ()=>{
this.playAudio(this.saveData.wordArr[option["index"]].word_audio_url);
})
} else {
}
}
}
for(let i = 0; i < this.wordNumSelected.length; ++ i) {
let numberStart = this.wordNumSelected[i];
if (this.checkClickTarget(numberStart)) {
// if(numberStart.index <= this.m_currentStartIndex) {
// let flag = false;
// if(numberStart.index == this.m_currentStartIndex) {
// this.m_currentStartIndex ++;
// numberStart.content.alpha = 1;
// if(!numberStart["selected"]) {
// flag = true;
// }
numberStart["selected"] = true;
// }
this.canTouch = false;
// if(numberStart["selected"] && !flag) {
// if(this.saveData.indexAudio[numberStart.index-1]) {
// this.playAudio(this.saveData.indexAudio[numberStart.index-1], true, ()=>{
// this.canTouch = true;
// })
// } else {
// this.canTouch = true;
// }
// } else {
// this.playAudio("sm-choice-correct", false, ()=>{
if(this.saveData.indexAudio[numberStart.index-1]) {
this.playAudio(this.saveData.indexAudio[numberStart.index-1], true, ()=>{
this.canTouch = true;
})
} else {
this.canTouch = true;
}
// })
// }
// }
}
}
for(let i = 0; i < this.word_arr_left.length; ++ i){
let word = this.word_arr_left[i];
// console.log('word', word) ;
if (this.checkClickTarget(word)) {
// 如果前面序号没有被点亮,后面的单词不做响应
let selected = this.opend[i]
if(selected) {
// 获取是否加载完成
let loaded = word.wordLoaded;
// 未加载,不触发音效,加载单词
if (!loaded) {
let letters:Array<Label> = word.children.slice(1);
for (let j=0; j<letters.length;j++) {
let labelItem = letters[j];
if(!labelItem.visible){
labelItem.visible = true;
}
}
word.wordLoaded = true;
this.playAudio("sm-choice-correct", false, ()=>{
// this.playAudio(this.saveData.wordArr[i].word_audio_url);
})
return ;
}
this.playAudio(this.saveData.wordArr[i].word_audio_url);
}
return ;
}
}
mapDown(event) {
// for(let i = 0; i < this.word_arr.length; ++ i){
// let word = this.word_arr[i];
// // console.log('word', word) ;
// if (word&&this.checkClickTarget(word)) {
// // 如果前面序号没有被点亮,后面的单词不做响应
// let selected = word.number.selected
// if(selected) {
// // 获取是否加载完成
// let loaded = word.wordLoaded;
// // 未加载,不触发音效,加载单词
// if (!loaded) {
// let letters:Array<Label> = word.children.slice(1);
// for (let j=0; j<letters.length;j++) {
// let labelItem = letters[j];
// if(!labelItem.visible){
// labelItem.visible = true;
// }
// }
// word.wordLoaded = true;
// this.playAudio("sm-choice-correct", false, ()=>{
// // this.playAudio(this.saveData.wordArr[i].word_audio_url);
// })
// return ;
// }
// this.playAudio(this.saveData.wordArr[i].right.word_audio_url);
// }
// return ;
// }
// }
if (this.checkClickTarget(this.listenPlayBtn) && !this.listenPlaying) {
this.listenPlayBtn.alpha = 0;
this.listenPauseBtn.alpha = 1;
this.playAudio(this.saveData.listen_audio_url);
this.listenPlaying = true;
if (!this.canTouch) {
return;
}
if ( this.checkClickTarget(this.btnLeft) ) {
this.btnLeftClicked();
return;
}
if (this.checkClickTarget(this.listenPauseBtn) && this.listenPlaying) {
if ( this.checkClickTarget(this.btnRight) ) {
this.btnRightClicked();
return;
}
this.listenPlayBtn.alpha = 1;
if ( this.checkClickTarget(this.pic1) ) {
this.pic1Clicked();
return;
}
this.listenPauseBtn.alpha = 0;
this.pauseAudio(this.saveData.listen_audio_url);
this.listenPlaying = false;
if ( this.checkClickTarget(this.pic2) ) {
this.pic2Clicked();
return;
}
......@@ -688,3 +1225,8 @@ export class PlayComponent implements OnInit, OnDestroy {
}
const res = [
// ['bg', "assets/play/bg.jpg"],
['btn_left', "assets/play/btn_left.png"],
['btn_right', "assets/play/btn_right.png"],
// ['text_bg', "assets/play/text_bg.png"],
// ['bg', "assets/YM5-6/bg.jpg"],
['btn_left', "assets/YM5-6/btn_left.png"],
['btn_right', "assets/YM5-6/btn_right.png"],
['pause', "assets/YM5-6/pause.png"],
['play', "assets/YM5-6/play.png"]
// ['text_bg', "assets/YM5-6/text_bg.png"],
];
......@@ -11,8 +13,11 @@ const res = [
const resAudio = [
['click', "assets/play/music/click.mp3"],
['click', "assets/YM5-6/music/click.mp3"],
['newpage', "assets/YM5-6/music/newpage.mp3"],
['sm-choice-correct', "assets/YM5-6/music/sm-choice-correct.mp3"]
];
export {res, resAudio};
export default {
contentObj: {
data: {
title: {
t_font_color1: "#70401e",
t_font1: "BRLNSDB",
t_font_size1: 40,
t_font_color: "#000000",
t_font: "BRLNSDB",
t_font_size: 40,
t_val1: "C",
t_val2: "Listen, write circle and read",
},
wordArr: [
{
correctOption: "left",
words_left: "ear",
words_right: "eer",
word_val: "pea",
letters: [
{ letter_val: "p", letter_color: "C04", is_: "0" },
{ letter_val: "e", letter_color: "C05", is_: "1" },
{ letter_val: "a", letter_color: "C05", is_: "1" },
],
},
{
words_left: "ear",
words_right: "eer",
correctOption: "right",
word_val: "steer",
word_audio_url: "",
letters: [
{ letter_val: "s", letter_color: "C04", is_: "0" },
{ letter_val: "t", letter_color: "C04", is_: "0" },
{ letter_val: "e", letter_color: "C05", is_: "1" },
{ letter_val: "e", letter_color: "C05", is_: "1" },
{ letter_val: "r", letter_color: "C05", is_: "1" },
],
},
{
words_left: "ear",
words_right: "eer",
correctOption: "right",
word_val: "beer",
word_audio_url: "",
letters: [
{ letter_val: "b", letter_color: "C04", is_: "0" },
{ letter_val: "e", letter_color: "C05", is_: "1" },
{ letter_val: "e", letter_color: "C05", is_: "1" },
{ letter_val: "r", letter_color: "C05", is_: "1" },
],
},
{
words_left: "ear",
words_right: "eer",
correctOption: "left",
word_val: "near",
word_audio_url: "",
letters: [
{ letter_val: "n", letter_color: "C04", is_: "0" },
{ letter_val: "e", letter_color: "C05", is_: "1" },
{ letter_val: "a", letter_color: "C05", is_: "1" },
{ letter_val: "r", letter_color: "C05", is_: "1" },
],
},
{
words_left: "ear",
words_right: "eer",
correctOption: "right",
word_val: "engineer",
word_audio_url: "",
letters: [
{ letter_val: "e", letter_color: "C04", is_: "0" },
{ letter_val: "n", letter_color: "C04", is_: "0" },
{ letter_val: "g", letter_color: "C04", is_: "0" },
{ letter_val: "i", letter_color: "C04", is_: "0" },
{ letter_val: "n", letter_color: "C04", is_: "0" },
{ letter_val: "e", letter_color: "C05", is_: "1" },
{ letter_val: "e", letter_color: "C05", is_: "1" },
{ letter_val: "r", letter_color: "C05", is_: "1" },
],
},
{
words_left: "ear",
words_right: "eer",
correctOption: "left",
word_val: "earth",
word_audio_url: "",
letters: [
{ letter_val: "e", letter_color: "C05", is_: "1" },
{ letter_val: "a", letter_color: "C05", is_: "1" },
{ letter_val: "r", letter_color: "C05", is_: "1" },
{ letter_val: "t", letter_color: "C04", is_: "0" },
{ letter_val: "h", letter_color: "C04", is_: "0" },
],
},
{
words_left: "ear",
words_right: "eer",
correctOption: "left",
word_val: "",
word_audio_url: "",
letters: [],
},
{
words_left: "ear",
words_right: "eer",
correctOption: "left",
word_val: "",
word_audio_url: "",
letters: [],
},
],
indexAudio: [],
recordingIndex: [],
blockColor: "F02",
indexColor: "FFFF00",
optionColor_left: "FFFF00",
optionColor_right: "CCCCCC",
},
},
};
......@@ -7,6 +7,13 @@
<!-- <meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">-->
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico">
<style>
html, body{
width: 100%;
height: 100%;
margin: 0;
}
</style>
<script type="text/javascript" src="https://staging-teach.cdn.ireadabc.com/h5template/h5-static-lib/js/air.js"></script>
</head>
......
/* You can add global styles to this file, and also import other style files */
@import "~ng-zorro-antd/ng-zorro-antd.min.css";
\ No newline at end of file
......@@ -21,6 +21,7 @@
]
},
"angularCompilerOptions": {
"enableIvy": false,
"fullTemplateTypeCheck": true,
"strictInjectionParameters": true
}
......
......@@ -92,8 +92,7 @@
"variable-name": false,
"no-unused-expression": false,
"align": false,
"no-string-literal": false
"align": false
},
"rulesDirectory": [
"codelyzer"
......
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