Commit e9250568 authored by liujiangnan's avatar liujiangnan

feat: 整改表单

parent 9b2c4eb6
No preview for this file type
# ng-template-generator # ng-template-generator
angularjs技术框架下的H5互动模板框架脚手架 angularjs技术框架下的H5互动模板框架脚手架,基于NG-ZORRO实现快速开发基于绘玩云的H5互动课件。
\ No newline at end of file
# 使用简介
## 前期准备
* git下载 https://git-scm.com/downloads
* nodejs下载 https://nodejs.org/zh-cn/download/
* 谷歌浏览器下载 https://www.google.cn/chrome/
都下载最新版就行,然后默认安装就可以
## 生成项目
* 登录绘玩云课件开发平台:http://staging-teach.ireadabc.com/
* 点击“登录账号,查看我的课件”
* 输入测试的用户名/密码:developers/12345678
* 在右上角“个人中心”的下拉菜单里,点击“我的模板” 菜单,然后点击“新建模板”, 填写必要的信息,在“技术选型”一项上选择“Angular”
* 点击“确定”后,列表页就会出现一个新生成的模板项目
* 在项目的卡片下找到“开发”按钮,则会弹出相对应的git地址
## 获取并启动项目
```
// xxx 是上面项目对应的Git地址
git clone xxx
cd 项目名称/
npm install -g yarn
yarn install
npm start
//启动成功后打开浏览器,输入:http://localhost:4200 则可以看到这个项目的初始化效果了
```
## 项目结构
|-- bin
|-- dist
|-- e2e
|-- node_modules
|-- publish
|-- src
| |-- app
| | |-- common
| | |-- form
| | |-- pipes
| | |-- play
| | |-- services
| | |-- style
| | |-- app.component.html
| | |-- app.component.scss
| | |-- app.component.ts
| | |-- app.module.ts
| |-- assets
| |-- environments
| |-- services
| |-- index.html
| |-- main.ts
| |--.......
* 其中 play 文件夹是H5模板展示页面,form文件夹是模板的配置页面
* common文件夹是以往做过的模板积累的一些比较常用的 AngularJs 的组件
* assets文件夹存放模板样式的静态资源,例如小图标、背景图片、字体、样式等等
* 其他文件夹开发者可以不做任何更改
## 开始开发
本脚手架的页面类UI框架是基于 [NG-ZORRO](https://ng.ant.design/docs/introduce/zh "With a Title") 框架实现的,在配置页面(form文件夹),一些表单输入,上传图片等组件也可以使用 NG-ZORRO 现成的组件
### 开发配置页面(form/)
配置页面主要作用是为了呈现多样化模板,提高H5模板的高复用性、灵活性提供的一个配置工具,根据H5模板的设计规划或特性,会规定某些元素是可以配置的,比如背景图片、音频、选项、标题等等等等。(课件制作者) 通过配置页面,就可以灵活的更换这些,从而形成多种多样的课件。
配置页面的开发要求很简单,我们不关心布局、样式、交互等所有实现细节与效果,只需调用两个内置的全局接口即可:
* setData 接口,用于将配置的数据存储到云端。
此方法是一个异步的方法,接收三个必要参数
obj: 一个json对象
callback: 回调函数
t_name: 模板名称
一般使用例子如下:
```
// ts语法,不能直接使用js的window对象自定义方法
(<any> window).courseware.setData(obj, callback, t_name);
```
* getData 接口,用于当点击修改的时候将配置的数据从云端获取下来。
此方法是一个异步的方法,接收两个必要参数
> callback: 回调函数, 回调函数里会得到云端保存的数据
> t_name: 模板名称
一般使用例子如下:
```
// ts语法,不能直接使用js的window对象自定义方法
const getData = (<any> window).courseware.getData;
getData((data) => {
//data 就是云端获取的数据,也就是setData方法存到云端的那个obj
//模板开发者需要根据数据,依次填写到表单的相应位置,方便用户二次修改编辑
});
```
### 开发展示页面(play/)
展示页面主要是呈现模板,通过H5技术,实现多样化的交互与展示方式。
展示页面更简单,开发者可以运用各种技术,实现Web端可以实现的任何效果,包括2D、3D、动画、游戏等各种场景,把表单配置的数据获取到,用于渲染相对应的页面即可:
* getData 接口,用于当点击修改的时候将配置的数据从云端获取下来。
此方法是一个异步的方法,接收两个必要参数
> callback: 回调函数, 回调函数里会得到云端保存的数据
> t_name: 模板名称
一般使用例子如下:
```
// ts语法,不能直接使用js的window对象自定义方法
const getData = (<any> window).courseware.getData;
getData((data) => {
//data 就是云端获取的数据,也就是setData方法存到云端的那个obj
//模板开发者需要根据数据来渲染或控制展示页面的呈现,达到模板的互动目的
});
```
### 互动课件
通过H5的交互方式,我们可以很轻松的制作在线的互动课件,使老师端与学生端实现联动,使在线课堂更具有交互性。
* onEvent 定义事件:用于自定义同步事件,配合多端互动使用,与sendEvent方法配合使用,用于监听多端发送的同步事件
参数
> evtName : 自定义事件的名称
> callback : 回调函数,回调函数里会得到传过来的数据
使用例子:
```
const cw = (<any> window).courseware;
//订阅一个事件
cw.onEvent('testEvent', (data,next) => {
console.log(data);
//处理事件的同步逻辑
//在逻辑处理完之后一定要执行next方法,用于解锁事件队列
next();
});
```
* sendEvent 发送事件:用于自定义同步事件,配合多端互动使用,与onEvent方法配合使用,用于对端发送同步事件
参数
> evtName : 自定义事件的名称
> data : 传递的参数
使用例子:
```
const cw = (<any> window).courseware;
//发送事件
//这样,所有端(教师、学生) 都会触发 testEvent 方法
cw.sendEvent('testEvent', 'Hello world');
```
* storeAspect 存储切面数据: 课件的切面状态数据;互动课件需要每一个开发者设计切面状态,用于学生进入已经进行的课件,恢复课件同步。例如老师讲图片轮播到第四页,这个时候学生进入教师,要恢复到第四页,才能跟老师同步上课。
参数
> data : 保存的数据,一个JSON对象
使用例子:
```
const cw = (<any> window).courseware;
//存储切面数据,用于学生进入教室,同步课堂信息等
cw.storeAspect({page: 5});
```
* getAspect 获取切面数据: 课件的切面状态数据;互动课件需要每一个开发者设计切面状态,用于学生进入已经进行的课件,恢复课件同步。例如老师讲图片轮播到第四页,这个时候学生进入教师,要恢复到第四页,才能跟老师同步上课。
参数
> callback : 获取切面数据的回调函数
使用例子:
```
const cw = (<any> window).courseware;
//存储切面数据,用于学生进入教室,同步课堂信息等
cw.getAspect(function(aspect){
//恢复切面状态的逻辑
});
```
* 补充项
1) 有时候我们在实现模板效果的时候,需要一些基本的信息,比如教室信息、当前用户信息等等,例如,老师会显示某个按钮,而学生不显示,我们可以用如下方式获取教室信息;后续大部分静态信息都会完善到这个对象里
```
//获取教室信息,值得注意的是获取这个信息一定要再 getData方法之后,或者确保页面完成之后
getData((data, aspect) => {
let airClassInfo = window["air"].airClassInfo;
console.log(airClassInfo);
});
```
2) 互动课件的 getData 方法的回调函数里多返回了一个切面参数,类似如下:
```
const getData = (<any> window).courseware.getData;
getData((data, aspect) => {
//data 就是云端获取的数据,也就是setData方法存到云端的那个obj
//aspect 切面参数,用于恢复页面的状态
//模板开发者需要根据数据来渲染或控制展示页面的呈现,达到模板的互动目的
});
```
3) 一些必要的内置事件,通过监听这些事件,我们可以实现一些相关的功能
* userchange 事件,用来监听教室内部的人员变动情况,例如某人进入,某人退出都会触发此事件
示例:
```
const cw = (<any> window).courseware;
//订阅一个事件
cw.onEvent('userchange', (data,next) => {
//data的结构如下
/*{
* id: '变动用户的ID',
* connected: true/false, true: 连接的,false:d断开的
* status: 'connect/reconnect', connect:新建连接,reconnect:重新连接;这个字段在断开连接的事件里是缺失的
* all_user: [] 这个是现有的用户列表
*}
*/
console.log(data);
//处理事件的同步逻辑
//在逻辑处理完之后一定要执行next方法,用于解锁事件队列
next();
});
```
4) 测试互动课件
我们在本地开发中,无法模拟线上老师和学生互动的交互场景,所以提供了一套开发者测试的账号,如下:
测试地址:http://staging-ac.ireadabc.com/
老师用户名/密码:devtea / 1
学生用户名/密码: 学生1(13877777711 / 1) 学生2(13877777712 / 1)
测试方法:
1、首先开发者发布完模板之后,在制作课件的菜单下用这个模板制作一个课件
2、在本地打开两个浏览器窗口 一个登陆老师用户,另一个登陆学生用户
3、老师用户进去之后,就会有很多课件,这个时候双击自己制作的课件,学生的窗口就会同步的打开课件了
4、测试自己的交互事件,看看老师端和学生端是否是自己想要的展示效果
### 补充方法
在模板的编辑或展示过程中,还会经常遇到如下两个场景,特提供针对性的解决办法
1) 表单录入往往需要上传图片、音视频等多媒体文件,所以脚手架内置如下方法,用于获取一个上传到云端的接口方法
```
const uploadUrl = (<any> window).courseware.uploadUrl;
const uploadData = (<any> window).courseware.uploadData;
//例如用于NG-ZORRO的上传组件则如下写法:
<nz-upload class="p-image-uploader" [nzDisabled]="disableUpload"
[nzShowUploadList]="false"
nzAccept = "image/*"
[nzAction]="uploadUrl" <!-- 注意这里 -->
[nzData]="uploadData" <!-- 注意这里 -->
(nzChange)="handleChange($event)">
</nz-upload>
```
2) 在展示页面加载完成的时候,需要调用一下下面的方法,用于释放切换课件的遮罩层
```
//此方法为固定写法,
//其中t_name为模板名称,obj是云端存储的配置数据
window["air"].hideAirClassLoading(t_name,obj);
```
## 打包发布
模板开发完成之后,要推送到云平台上使用则需要进行打包发布操作
```
npm run publish
```
在项目根目录下执行上述命令,则在 ./publish 目录下生产一个 .zip的压缩包,此时打开云平台
http://staging-teach.ireadabc.com/
点击“模板管理” 菜单,找到对应的模板卡片,点击“发布”按钮,在弹出的对话框中选中压缩包,然后点击“确定”,上传完成后,则发布就成功了
\ No newline at end of file
...@@ -3,13 +3,9 @@ ...@@ -3,13 +3,9 @@
"version": 1, "version": 1,
"newProjectRoot": "projects", "newProjectRoot": "projects",
"projects": { "projects": {
"ng-one": { "ng-template-generator": {
"projectType": "application", "projectType": "application",
"schematics": { "schematics": {},
"@schematics/angular:component": {
"style": "scss"
}
},
"root": "", "root": "",
"sourceRoot": "src", "sourceRoot": "src",
"prefix": "app", "prefix": "app",
...@@ -17,39 +13,26 @@ ...@@ -17,39 +13,26 @@
"build": { "build": {
"builder": "@angular-devkit/build-angular:browser", "builder": "@angular-devkit/build-angular:browser",
"options": { "options": {
"outputPath": "dist", "outputPath": "dist/ng-template-generator",
"index": "src/index.html", "index": "src/index.html",
"main": "src/main.ts", "main": "src/main.ts",
"polyfills": "src/polyfills.ts", "polyfills": "src/polyfills.ts",
"tsConfig": "tsconfig.app.json", "tsConfig": "tsconfig.app.json",
"aot": false, "aot": true,
"assets": [ "assets": [
"src/favicon.ico", "src/favicon.ico",
"src/assets", "src/assets",
{ "glob": "**/*", "input": "src/assets/libs/service-worker/", "output": "/" },
{ {
"glob": "**/*", "glob": "**/*",
"input": "./node_modules/@ant-design/icons-angular/src/inline-svg/", "input": "./node_modules/@ant-design/icons-angular/src/inline-svg/",
"output": "/assets/" "output": "/assets/"
},
{
"glob": "**/*",
"input": "./dist/game/",
"output": "/assets/cocos/"
} }
], ],
"styles": [ "styles": [
"src/styles.scss",
"./node_modules/ng-zorro-antd/ng-zorro-antd.min.css", "./node_modules/ng-zorro-antd/ng-zorro-antd.min.css",
"./node_modules/font-awesome/css/font-awesome.css", "src/styles.css"
"./node_modules/bootstrap/dist/css/bootstrap.min.css",
"./node_modules/animate.css/animate.min.css"
], ],
"scripts": [ "scripts": []
"src/assets/libs/audio-recorder/lame.min.js",
"src/assets/libs/audio-recorder/worker.js",
"src/assets/libs/audio-recorder/recorder.js"
]
}, },
"configurations": { "configurations": {
"production": { "production": {
...@@ -64,28 +47,39 @@ ...@@ -64,28 +47,39 @@
"sourceMap": false, "sourceMap": false,
"extractCss": true, "extractCss": true,
"namedChunks": false, "namedChunks": false,
"aot": true,
"extractLicenses": true, "extractLicenses": true,
"vendorChunk": false, "vendorChunk": false,
"buildOptimizer": true "buildOptimizer": true,
"budgets": [
{
"type": "initial",
"maximumWarning": "2mb",
"maximumError": "5mb"
},
{
"type": "anyComponentStyle",
"maximumWarning": "6kb",
"maximumError": "10kb"
}
]
} }
} }
}, },
"serve": { "serve": {
"builder": "@angular-devkit/build-angular:dev-server", "builder": "@angular-devkit/build-angular:dev-server",
"options": { "options": {
"browserTarget": "ng-one:build" "browserTarget": "ng-template-generator:build"
}, },
"configurations": { "configurations": {
"production": { "production": {
"browserTarget": "ng-one:build:production" "browserTarget": "ng-template-generator:build:production"
} }
} }
}, },
"extract-i18n": { "extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n", "builder": "@angular-devkit/build-angular:extract-i18n",
"options": { "options": {
"browserTarget": "ng-one:build" "browserTarget": "ng-template-generator:build"
} }
}, },
"test": { "test": {
...@@ -100,7 +94,8 @@ ...@@ -100,7 +94,8 @@
"src/assets" "src/assets"
], ],
"styles": [ "styles": [
"src/styles.scss" "./node_modules/ng-zorro-antd/ng-zorro-antd.min.css",
"src/styles.css"
], ],
"scripts": [] "scripts": []
} }
...@@ -122,15 +117,19 @@ ...@@ -122,15 +117,19 @@
"builder": "@angular-devkit/build-angular:protractor", "builder": "@angular-devkit/build-angular:protractor",
"options": { "options": {
"protractorConfig": "e2e/protractor.conf.js", "protractorConfig": "e2e/protractor.conf.js",
"devServerTarget": "ng-one:serve" "devServerTarget": "ng-template-generator:serve"
}, },
"configurations": { "configurations": {
"production": { "production": {
"devServerTarget": "ng-one:serve:production" "devServerTarget": "ng-template-generator:serve:production"
}
} }
} }
} }
} }
}}, },
"defaultProject": "ng-one" "defaultProject": "ng-template-generator",
"cli": {
"analytics": "5f501d82-8f25-4817-a608-9ac70d1f1f70"
}
} }
\ No newline at end of file
...@@ -16,15 +16,15 @@ const compressing = require("compressing"); ...@@ -16,15 +16,15 @@ const compressing = require("compressing");
//Windows系统上'Windows_NT' //Windows系统上'Windows_NT'
let sysType = os.type(); let sysType = os.type();
Date.prototype.Format = function(fmt) { Date.prototype.Format = function (fmt) {
var o = { var o = {
"M+" : this.getMonth() + 1, "M+": this.getMonth() + 1,
"d+" : this.getDate(), "d+": this.getDate(),
"h+" : this.getHours(), "h+": this.getHours(),
"m+" : this.getMinutes(), "m+": this.getMinutes(),
"s+" : this.getSeconds(), "s+": this.getSeconds(),
"q+" : Math.floor((this.getMonth() + 3) / 3), "q+": Math.floor((this.getMonth() + 3) / 3),
"S" : this.getMilliseconds() "S": this.getMilliseconds()
}; };
if (/(y+)/.test(fmt)) if (/(y+)/.test(fmt))
fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length)); fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
...@@ -34,24 +34,24 @@ Date.prototype.Format = function(fmt) { ...@@ -34,24 +34,24 @@ Date.prototype.Format = function(fmt) {
return fmt; return fmt;
} }
function clean(zipPath){ function clean(zipPath) {
if(fs.existsSync(zipPath)){ if (fs.existsSync(zipPath)) {
fs.unlinkSync(zipPath); fs.unlinkSync(zipPath);
} }
} }
const runSpawn = async function (){ const runSpawn = async function () {
await new Promise(function(resolve,reject){ await new Promise(function (resolve, reject) {
let pkg = require("../package.json"); let pkg = require("../package.json");
let ls; let ls;
if(sysType==="Windows_NT"){ if (sysType === "Windows_NT") {
//ng build --prod --build--optimizer --base-href /ng-one/ //ng build --prod --build--optimizer --base-href /ng-one/
ls = spawn("cmd.exe", ['/c', 'ng', 'build', '--prod', '--build--optimizer', '--base-href', '/template-base-href/'] ); ls = spawn("cmd.exe", ['/c', 'ng', 'build', '--prod', '--build--optimizer', '--base-href', '/template-base-href/']);
}else{ } else {
ls = spawn("ng", ['build', '--prod', '--build--optimizer', '--base-href', '/template-base-href/'] ); ls = spawn("ng", ['build', '--prod', '--build--optimizer', '--base-href', '/template-base-href/']);
} }
ls.stdout.on('data', (data) => { ls.stdout.on('data', (data) => {
...@@ -66,22 +66,23 @@ const runSpawn = async function (){ ...@@ -66,22 +66,23 @@ const runSpawn = async function (){
ls.on('close', (code) => { ls.on('close', (code) => {
console.log(`child process exited with code ${code}`); console.log(`child process exited with code ${code}`);
//要压缩的目录 //要压缩的目录
let zippath = path.resolve(__dirname,"../dist"); let zippath = path.resolve(__dirname, "../dist", pkg.name);
//压缩包的存放目录 //压缩包的存放目录
let date = new Date(); let date = new Date();
let zipname = pkg.name+"_"+date.Format("yyyyMMdd hh-mm-ss"); // let zipname = pkg.name+"_"+date.Format("yyyyMMdd hh-mm-ss");
let zipdir = path.resolve(__dirname,"../publish/"+zipname+".zip"); let zipname = 'form';
let zipdir = path.resolve(__dirname, "../publish/" + zipname + ".zip");
clean(zipdir); //删除原有的包 clean(zipdir); //删除原有的包
const tarStream = new compressing.zip.Stream(); const tarStream = new compressing.zip.Stream();
fs.readdir(zippath,function(err,files){ fs.readdir(zippath, function (err, files) {
if(err){ if (err) {
console.log("======文件打开异常======"); console.log("======文件打开异常======");
console.log(err); console.log(err);
reject(); reject();
} }
for(let i=0;i<files.length;i++){ for (let i = 0; i < files.length; i++) {
tarStream.addEntry(zippath+"/"+files[i]); tarStream.addEntry(zippath + "/" + files[i]);
} }
let writeStream = fs.createWriteStream(zipdir); let writeStream = fs.createWriteStream(zipdir);
tarStream.pipe(writeStream); tarStream.pipe(writeStream);
...@@ -103,7 +104,7 @@ const runSpawn = async function (){ ...@@ -103,7 +104,7 @@ const runSpawn = async function (){
// } // }
// projects = process.argv[2]; // projects = process.argv[2];
let exec = async function(){ let exec = async function () {
//压缩模板 //压缩模板
await runSpawn(); await runSpawn();
} }
...@@ -112,4 +113,3 @@ exec(); ...@@ -112,4 +113,3 @@ exec();
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -4,72 +4,56 @@ ...@@ -4,72 +4,56 @@
"scripts": { "scripts": {
"start": "ng serve", "start": "ng serve",
"build": "ng build --build--optimizer --aot --base-href /JGT/v3/", "build": "ng build --build--optimizer --aot --base-href /JGT/v3/",
"publish": "node ./bin/publish.js" "publish": "node ./bin/publish.js",
"ng": "ng",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e"
}, },
"private": true, "private": true,
"dependencies": { "dependencies": {
"@angular/animations": "^7.2.10", "@angular/animations": "~9.0.2",
"@angular/cdk": "^7.2.2", "@angular/common": "~9.0.2",
"@angular/common": "^7.2.10", "@angular/compiler": "~9.0.2",
"@angular/compiler": "^7.2.10", "@angular/core": "~9.0.2",
"@angular/core": "^7.2.10", "@angular/forms": "~9.0.2",
"@angular/flex-layout": "^7.0.0-beta.24", "@angular/platform-browser": "~9.0.2",
"@angular/forms": "^7.2.10", "@angular/platform-browser-dynamic": "~9.0.2",
"@angular/http": "^7.2.10", "@angular/router": "~9.0.2",
"@angular/material": "^7.2.2", "@fortawesome/angular-fontawesome": "^0.6.0",
"@angular/platform-browser": "^7.2.10", "@fortawesome/fontawesome-svg-core": "^1.2.27",
"@angular/platform-browser-dynamic": "^7.2.10", "@fortawesome/free-regular-svg-icons": "^5.12.1",
"@angular/platform-server": "^7.2.10", "@fortawesome/free-solid-svg-icons": "^5.12.1",
"@angular/router": "^7.2.10", "@tweenjs/tween.js": "~18.5.0",
"@tweenjs/tween.js": "^17.3.0", "ali-oss": "^6.5.1",
"ali-oss": "^6.0.0", "compressing": "^1.5.0",
"angular-cropperjs": "^1.0.1", "ng-zorro-antd": "^8.5.2",
"angular2-draggable": "^2.1.9", "node-sass": "^4.0.0",
"angular2-fontawesome": "^5.2.1", "rxjs": "~6.5.4",
"angularx-qrcode": "^1.5.3",
"animate.css": "^3.7.0",
"bootstrap": "^4.1.1",
"browser-image-compression": "^1.0.5",
"compressing": "^1.4.0",
"core-js": "^2.6.1",
"cropperjs": "1.4.1",
"css-element-queries": "^1.0.2",
"decimal.js": "^10.0.1",
"font-awesome": "^4.7.0",
"hammerjs": "^2.0.8",
"install": "^0.12.2",
"karma-cli": "^2.0.0",
"lodash": "^4.17.10",
"nedb": "^1.8.0",
"ng-lottie": "^0.3.1",
"ng-zorro-antd": "^7.2.0",
"npm": "^6.5.0",
"rxjs": "^6.3.3",
"rxjs-compat": "^6.3.3",
"rxjs-tslint": "^0.1.6",
"spark-md5": "^3.0.0", "spark-md5": "^3.0.0",
"webpack": "^4.28.2", "tslib": "^1.10.0",
"zone.js": "^0.8.26" "yarn": "^1.22.19",
"zone.js": "~0.10.2"
}, },
"devDependencies": { "devDependencies": {
"@angular-devkit/build-angular": "^0.11.4", "@angular-devkit/build-angular": "~0.900.3",
"@angular/cli": "^7.2.10", "@angular/cli": "~9.0.3",
"@angular/compiler-cli": "^7.2.10", "@angular/compiler-cli": "~9.0.2",
"@angular/language-service": "^7.2.10", "@angular/language-service": "~9.0.2",
"@types/jasmine": "^3.3.5", "@types/jasmine": "~3.5.0",
"@types/jasminewd2": "~2.0.3", "@types/jasminewd2": "~2.0.3",
"@types/node": "^10.12.18", "@types/node": "^12.11.1",
"codelyzer": "^4.5.0", "codelyzer": "^5.1.2",
"jasmine-core": "^3.3.0", "jasmine-core": "~3.5.0",
"jasmine-spec-reporter": "^4.2.1", "jasmine-spec-reporter": "~4.2.1",
"karma": "^3.1.4", "karma": "~4.3.0",
"karma-chrome-launcher": "^2.2.0", "karma-chrome-launcher": "~3.1.0",
"karma-coverage-istanbul-reporter": "~2.0.0", "karma-coverage-istanbul-reporter": "~2.1.0",
"karma-jasmine": "^2.0.1", "karma-jasmine": "~2.0.1",
"karma-jasmine-html-reporter": "^1.4.0", "karma-jasmine-html-reporter": "^1.4.2",
"protractor": "^5.4.2", "protractor": "~5.4.3",
"ts-node": "~5.0.1", "ts-node": "~8.3.0",
"tslint": "^5.12.0", "tslint": "~5.18.0",
"typescript": "3.1.1" "typescript": "~3.7.5"
} }
} }
import { ErrorHandler } from '@angular/core';
export class MyErrorHandler implements ErrorHandler {
handleError(error) {
console.log(error.stack);
(<any> window).courseware.sendErrorLog(error);
}
}
\ No newline at end of file
...@@ -5,12 +5,12 @@ import { Component , OnInit} from '@angular/core'; ...@@ -5,12 +5,12 @@ import { Component , OnInit} from '@angular/core';
templateUrl: './app.component.html', templateUrl: './app.component.html',
styleUrls: ['./app.component.scss'] styleUrls: ['./app.component.scss']
}) })
export class AppComponent implements OnInit{ export class AppComponent implements OnInit {
type = 'play'; type = 'form';
constructor() { constructor() {
let tp = this.getQueryString("type"); const tp = this.getQueryString('type');
if (tp){ if (tp) {
this.type = tp; this.type = tp;
} }
} }
......
import { BrowserModule } from '@angular/platform-browser'; import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { NgModule, ErrorHandler } from '@angular/core';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { HttpClientModule } from '@angular/common/http';
import { NgZorroAntdModule, NZ_I18N, zh_CN } from 'ng-zorro-antd';
import {Angular2FontawesomeModule} from 'angular2-fontawesome/angular2-fontawesome';
import { AppComponent } from './app.component'; import {MyErrorHandler} from './MyError';
import { FormComponent } from './form/form.component';
import { PlayComponent } from "./play/play.component";
import { AppComponent } from './app.component';
import { LessonTitleConfigComponent } from './common/lesson-title-config/lesson-title-config.component'; import { NgZorroAntdModule, NZ_I18N, zh_CN } from 'ng-zorro-antd';
import { AudioRecorderComponent } from './common/audio-recorder/audio-recorder.component'; import { FormsModule } from '@angular/forms';
import { PlayerContentWrapperComponent } from './common/player-content-wrapper/player-content-wrapper.component'; import { HttpClientModule } from '@angular/common/http';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
/** 配置 angular i18n **/
import { registerLocaleData } from '@angular/common'; import { registerLocaleData } from '@angular/common';
import zh from '@angular/common/locales/zh'; import zh from '@angular/common/locales/zh';
import {UploadImageWithPreviewComponent} from "./common/upload-image-with-preview/upload-image-with-preview.component"; import {FormComponent} from './form/form.component';
import {BackgroundImagePipe} from "./pipes/background-image.pipe"; import {PlayComponent} from './play/play.component';
import {UploadVideoComponent} from "./common/upload-video/upload-video.component"; import {LessonTitleConfigComponent} from './common/lesson-title-config/lesson-title-config.component';
import {ResourcePipe} from "./pipes/resource.pipe"; import {BackgroundImagePipe} from './pipes/background-image.pipe';
import {TimePipe} from "./pipes/time.pipe"; import {UploadImageWithPreviewComponent} from './common/upload-image-with-preview/upload-image-with-preview.component';
import {CustomHotZoneComponent} from "./common/custom-hot-zone/custom-hot-zone.component"; import {PlayerContentWrapperComponent} from './common/player-content-wrapper/player-content-wrapper.component';
import {CustomHotZoneComponent} from './common/custom-hot-zone/custom-hot-zone.component';
import {UploadVideoComponent} from './common/upload-video/upload-video.component';
import {TimePipe} from './pipes/time.pipe';
import {ResourcePipe} from './pipes/resource.pipe';
import {AudioRecorderComponent} from './common/audio-recorder/audio-recorder.component';
import { FontAwesomeModule, FaIconLibrary } from '@fortawesome/angular-fontawesome';
import { fas } from '@fortawesome/free-solid-svg-icons';
import { far } from '@fortawesome/free-regular-svg-icons';
import { UploadDragonBoneComponent } from './common/upload-dragon-bone/upload-dragon-bone.component';
registerLocaleData(zh); registerLocaleData(zh);
@NgModule({ @NgModule({
...@@ -40,22 +41,28 @@ registerLocaleData(zh); ...@@ -40,22 +41,28 @@ registerLocaleData(zh);
TimePipe, TimePipe,
UploadVideoComponent, UploadVideoComponent,
CustomHotZoneComponent, CustomHotZoneComponent,
UploadDragonBoneComponent,
PlayerContentWrapperComponent PlayerContentWrapperComponent
], ],
imports: [ imports: [
BrowserModule,
NgZorroAntdModule,
FormsModule, FormsModule,
HttpClientModule, HttpClientModule,
BrowserAnimationsModule, BrowserAnimationsModule,
BrowserModule, FontAwesomeModule
Angular2FontawesomeModule,
NgZorroAntdModule,
], ],
/** 配置 ng-zorro-antd 国际化(文案 及 日期) **/ providers: [
providers : [ {provide: ErrorHandler, useClass: MyErrorHandler},
{ provide: NZ_I18N, useValue: zh_CN } { provide: NZ_I18N, useValue: zh_CN }
], ],
bootstrap: [AppComponent] bootstrap: [AppComponent]
}) })
export class AppModule { } export class AppModule {
constructor(library: FaIconLibrary) {
const fa:any = fas;
const fr:any = far;
library.addIconPacks(fa, fr);
}
}
<div class="d-flex"> <div class="d-flex" (drop)="handle_drop($event)" (dragover)="handle_dragover($event)">
<div class="p-btn-record d-flex"> <div class="p-btn-record d-flex">
<div class="btn-clear" (click)="onBtnClearAudio()" *ngIf="withRmBtn && (audioUrl || audioBlob)"> <div class="btn-clear" style="cursor: pointer" (click)="onBtnClearAudio()" *ngIf="withRmBtn && (audioUrl || audioBlob)">
<fa name="close"></fa> <fa-icon icon="times"></fa-icon>
</div> </div>
<div class="btn-record" *ngIf="type===Type.RECORD && !isUploading" <div class="btn-record" *ngIf="type===Type.RECORD && !isUploading"
[class.p-recording]="isRecording" [class.p-recording]="isRecording"
(click)="onBtnRecord()"> (click)="onBtnRecord()">
<fa name="microphone"></fa> <fa-icon icon="microphone"></fa-icon>
Record Audio Record Audio
</div> </div>
<nz-upload <nz-upload
...@@ -17,14 +17,14 @@ ...@@ -17,14 +17,14 @@
(nzChange)="handleChange($event)"> (nzChange)="handleChange($event)">
<div class="btn-upload" [ngClass]="{'has-clear': withRmBtn && (audioUrl || audioBlob)}" *ngIf="type===Type.UPLOAD && !isUploading"> <div class="btn-upload" [ngClass]="{'has-clear': withRmBtn && (audioUrl || audioBlob)}" *ngIf="type===Type.UPLOAD && !isUploading">
<fa name="upload"></fa> <fa-icon icon="upload"></fa-icon>
Upload Audio Upload Audio
</div> </div>
</nz-upload> </nz-upload>
<div class="p-upload-progress-bg" *ngIf="isUploading"> <div class="p-upload-progress-bg" *ngIf="isUploading">
<div class="i-bg" [style.width]="progress+'%'"></div> <div class="i-bg" [style.width]="progress+'%'"></div>
<div class="i-text"> <div class="i-text">
<fa name="cloud-upload"></fa> <fa-icon icon="cloud-upload-alt"></fa-icon>
Uploading... Uploading...
</div> </div>
</div> </div>
...@@ -35,27 +35,29 @@ ...@@ -35,27 +35,29 @@
<ng-template #truthyTemplate > <ng-template #truthyTemplate >
<div class="btn-delete" (click)="onBtnDeleteAudio()"> <div class="btn-delete" (click)="onBtnDeleteAudio()">
<fa name="close"></fa> <fa-icon icon="close"></fa-icon>
</div> </div>
</ng-template> </ng-template>
<ng-template #falsyTemplate> <ng-template #falsyTemplate>
<div class="btn-switch" (click)="onBtnSwitchType()"> <div class="btn-switch" (click)="onBtnSwitchType()">
<fa name="cog"></fa> <fa-icon icon="cog"></fa-icon>
</div> </div>
</ng-template> </ng-template>
</div> </div>
<div class="p-progress ml-2" (click)="onBtnPlay()" *ngIf="audioUrl || audioBlob"> <div class="p-progress ml-2" (click)="onBtnPlay()" *ngIf="audioUrl || audioBlob"
<nz-progress [nzPercent]="percent" [nzWidth]="30" [nzFormat]="progressText" style="background-color: #70B603; width: 35px; height: 35px; border-radius: 35px; margin-left: 10px;margin-top:-1px">
nzType="circle"></nz-progress> <nz-progress [nzPercent]="percent" [nzWidth]="35" [nzFormat]="progressText"
<div class="p-btn-play" [style.left]="isPlaying?'8px':''"> nzType="circle">
<fa [name]="playIcon"></fa> </nz-progress>
<div class="p-btn-play"
style="color: white;margin-left: 2px;margin-top: 1px;"
[style.left]="isPlaying?'8px':''">
<fa-icon [icon]="playIcon"></fa-icon>
</div> </div>
</div> </div>
<div class="audio-name">{{_audioName}}</div>
</div> </div>
.d-flex{
display: flex;
}
.p-btn-record { .p-btn-record {
font-size: 0.9rem; font-size: 0.9rem;
color: #555; color: #555;
...@@ -87,17 +90,26 @@ ...@@ -87,17 +90,26 @@
} }
.p-progress { .p-progress {
margin-top: 2px; margin-top: 3.5px;
position: relative; position: relative;
background-color: #27b43f;
border-radius: 15px;
line-height: 26px; line-height: 26px;
.p-btn-play { .p-btn-play {
position: absolute; position: absolute;
left: 10px; left: 11px;
top: 3px; top: 3px;
color: #555; color: #ffffff;
} }
} }
.audio-name{
margin-top: 3.5px;
position: relative;
margin-left: 7px;;
line-height: 26px;
}
:host ::ng-deep nz-upload { :host ::ng-deep nz-upload {
line-height: 33px; line-height: 33px;
} }
......
...@@ -19,10 +19,11 @@ export class AudioRecorderComponent implements OnInit, OnChanges, OnDestroy { ...@@ -19,10 +19,11 @@ export class AudioRecorderComponent implements OnInit, OnChanges, OnDestroy {
isUploading = false; isUploading = false;
type = Type.UPLOAD; // record | upload type = Type.UPLOAD; // record | upload
Type = Type; Type = Type;
@Input()
withRmBtn = false; withRmBtn = false;
uploadUrl = (<any>window).courseware.uploadUrl(); uploadUrl;
uploadData = (<any>window).courseware.uploadData(); uploadData;
@Input() @Input()
needRemove = false; needRemove = false;
...@@ -30,12 +31,21 @@ export class AudioRecorderComponent implements OnInit, OnChanges, OnDestroy { ...@@ -30,12 +31,21 @@ export class AudioRecorderComponent implements OnInit, OnChanges, OnDestroy {
@Input() @Input()
audioItem: any = null; audioItem: any = null;
@Input()
_audioName: any = null;
@Input() @Input()
set audioUrl(url) { set audioUrl(url) {
this._audioUrl = url this._audioUrl = url;
if (url) { if (url) {
this.httpHeadCall(this._audioUrl, flag => {
if (flag) {
this.audio.src = this._audioUrl; this.audio.src = this._audioUrl;
} else {
this.audio.src = this._audioUrl.replace("_l.", ".");
}
this.audio.load(); this.audio.load();
});
} }
this.init(); this.init();
} }
...@@ -47,6 +57,7 @@ export class AudioRecorderComponent implements OnInit, OnChanges, OnDestroy { ...@@ -47,6 +57,7 @@ export class AudioRecorderComponent implements OnInit, OnChanges, OnDestroy {
@Output() audioUploaded = new EventEmitter(); @Output() audioUploaded = new EventEmitter();
@Output() audioUploadFailure = new EventEmitter(); @Output() audioUploadFailure = new EventEmitter();
@Output() audioRemoved = new EventEmitter(); @Output() audioRemoved = new EventEmitter();
@Output() audioName = new EventEmitter();
percent = 0; percent = 0;
progress = 0; progress = 0;
recorder: any; recorder: any;
...@@ -54,7 +65,48 @@ export class AudioRecorderComponent implements OnInit, OnChanges, OnDestroy { ...@@ -54,7 +65,48 @@ export class AudioRecorderComponent implements OnInit, OnChanges, OnDestroy {
constructor( private nzMessageService: NzMessageService ) { constructor( private nzMessageService: NzMessageService ) {
this.uploadUrl = (<any> window).courseware.uploadUrl();
this.uploadData = (<any> window).courseware.uploadData();
window['air'].getUploadCallback = (url, data) => {
this.uploadUrl = url;
this.uploadData = data;
};
}
httpHeadCall(requsetUrl: string, callback) {
let xhr = new XMLHttpRequest();
console.log("Status: Send Post Request to " + requsetUrl);
try {
xhr.onreadystatechange = () => {
try {
console.log('xhr.readyState: ', xhr.readyState);
if (xhr.readyState == 4) {
if ((xhr.status >= 200 && xhr.status < 400)) {
callback(true);
} else {
callback(false);
}
}
} catch (e) {
console.log(e)
}
};
xhr.open("HEAD", requsetUrl, true);
xhr.send();
xhr.timeout = 15000;
xhr.onerror = (e) => {
console.log("汪汪汪 posterror", e);
callback(false);
};
xhr.ontimeout = (e) => {
console.log("汪汪汪 ontimeout", e);
callback(false);
};
} catch (e) {
console.log("Send Get Request error: ", e)
}
} }
init() { init() {
...@@ -144,6 +196,7 @@ export class AudioRecorderComponent implements OnInit, OnChanges, OnDestroy { ...@@ -144,6 +196,7 @@ export class AudioRecorderComponent implements OnInit, OnChanges, OnDestroy {
onBtnSwitchType() { onBtnSwitchType() {
} }
onBtnClearAudio() { onBtnClearAudio() {
this.audioUrl = null;
this.audioRemoved.emit(); this.audioRemoved.emit();
} }
...@@ -160,8 +213,12 @@ export class AudioRecorderComponent implements OnInit, OnChanges, OnDestroy { ...@@ -160,8 +213,12 @@ export class AudioRecorderComponent implements OnInit, OnChanges, OnDestroy {
break; break;
case 'success': case 'success':
this.isUploading = false; this.isUploading = false;
let url = info.file.response.url;
url = url.substring(0, url.lastIndexOf(".")) + "_l.mp3";
info.file.response.url = url;
this.uploadSuccess(info.file.response); this.uploadSuccess(info.file.response);
this.audioUploaded.emit(info.file.response); this.audioUploaded.emit({...info.file.response, name: info.file.name});
this.audioName.emit(info.file.name);
break; break;
case 'progress': case 'progress':
this.progress = parseInt(info.event.percent, 10); this.progress = parseInt(info.event.percent, 10);
...@@ -194,10 +251,10 @@ export class AudioRecorderComponent implements OnInit, OnChanges, OnDestroy { ...@@ -194,10 +251,10 @@ export class AudioRecorderComponent implements OnInit, OnChanges, OnDestroy {
this.isUploading = true; this.isUploading = true;
this.progress = 0; this.progress = 0;
} }
uploadSuccess = (url) => { uploadSuccess = (res) => {
this.nzMessageService.info('Upload Success'); this.nzMessageService.info('Upload Success');
this.isUploading = false; this.isUploading = false;
this.audioUrl = url; this.audioUrl = res.url;
} }
uploadFailure = (err, file) => { uploadFailure = (err, file) => {
this.isUploading = false; this.isUploading = false;
...@@ -219,6 +276,39 @@ export class AudioRecorderComponent implements OnInit, OnChanges, OnDestroy { ...@@ -219,6 +276,39 @@ export class AudioRecorderComponent implements OnInit, OnChanges, OnDestroy {
this.progress = Math.floor(p * 100); this.progress = Math.floor(p * 100);
} }
linkInputed (url, name) {
url = url.substring(0, url.lastIndexOf(".")) + "_l.mp3";
this.audioUrl = url;
this.audioUploaded.emit({url});
this.audioName.emit(name);
}
handle_dragover(e) {
e.preventDefault();
}
handle_drop(e) {
const dt = e.dataTransfer.getData("text/plain");
console.log("handle_drop===", dt);
if (!dt) {
return;
}
try {
const {url, name} = JSON.parse(dt);
if (url.indexOf("teach")<0 || url.indexOf("cdn")<0) {
return;
}
const white = [".mp3"];
if (!white.includes(url.substr(url.lastIndexOf(".")))) {
return;
}
this.linkInputed(url, name);
} catch (error) {
console.warn("handle_drop拖拽在线音频传递参数不合法,应该是{url:'', name:''}");
}
}
} }
enum Type { enum Type {
......
import TWEEN from '@tweenjs/tween.js'; import TWEEN from '@tweenjs/tween.js';
interface AirWindow extends Window {
air: any;
curCtx: any;
}
declare let window: AirWindow;
class Sprite { class Sprite {
x = 0; x = 0;
...@@ -12,9 +17,13 @@ class Sprite { ...@@ -12,9 +17,13 @@ class Sprite {
angle = 0; angle = 0;
ctx; ctx;
constructor(ctx) { constructor(ctx = null) {
if (!ctx) {
this.ctx = window.curCtx;
} else {
this.ctx = ctx; this.ctx = ctx;
} }
}
update($event) { update($event) {
this.draw(); this.draw();
} }
...@@ -30,25 +39,45 @@ class Sprite { ...@@ -30,25 +39,45 @@ class Sprite {
export class MySprite extends Sprite { export class MySprite extends Sprite {
width = 0; _width = 0;
height = 0; _height = 0;
_anchorX = 0; _anchorX = 0;
_anchorY = 0; _anchorY = 0;
_offX = 0; _offX = 0;
_offY = 0; _offY = 0;
scaleX = 1; scaleX = 1;
scaleY = 1; scaleY = 1;
alpha = 1; _alpha = 1;
rotation = 0; rotation = 0;
visible = true; visible = true;
skewX = 0;
skewY = 0;
_shadowFlag = false;
_shadowColor;
_shadowOffsetX = 0;
_shadowOffsetY = 0;
_shadowBlur = 5;
_radius = 0;
children = [this]; children = [this];
childDepandVisible = true;
childDepandAlpha = false;
img; img;
_z = 0; _z = 0;
_showRect;
_bitmapFlag = false;
_offCanvas;
_offCtx;
init(imgObj = null, anchorX:number = 0.5, anchorY:number = 0.5) {
init(imgObj = null, anchorX: number = 0.5, anchorY: number = 0.5) {
if (imgObj) { if (imgObj) {
...@@ -56,6 +85,8 @@ export class MySprite extends Sprite { ...@@ -56,6 +85,8 @@ export class MySprite extends Sprite {
this.width = this.img.width; this.width = this.img.width;
this.height = this.img.height; this.height = this.img.height;
} }
this.anchorX = anchorX; this.anchorX = anchorX;
...@@ -63,11 +94,35 @@ export class MySprite extends Sprite { ...@@ -63,11 +94,35 @@ 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;
this._shadowOffsetY = offY;
this._shadowBlur = blur;
}
setRadius(r) {
this._radius = r;
}
update($event = null) { update($event = null) {
if (this.visible) { if (!this.visible && this.childDepandVisible) {
this.draw(); return;
} }
this.draw();
} }
draw() { draw() {
...@@ -78,6 +133,8 @@ export class MySprite extends Sprite { ...@@ -78,6 +133,8 @@ export class MySprite extends Sprite {
this.updateChildren(); this.updateChildren();
this.ctx.restore(); this.ctx.restore();
} }
drawInit() { drawInit() {
...@@ -90,26 +147,73 @@ export class MySprite extends Sprite { ...@@ -90,26 +147,73 @@ export class MySprite extends Sprite {
this.ctx.globalAlpha = this.alpha; this.ctx.globalAlpha = this.alpha;
this.ctx.transform(1, this.skewX, this.skewY, 1, 0, 0);
//
// if (this._radius) {
//
// const r = this._radius;
// const w = this.width;
// const h = this.height;
//
// 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);
//
// this.ctx.clip();
// }
} }
drawSelf() { 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.img) { 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, this._offY + rect.y, this.width, rect.height);
} else {
this.ctx.drawImage(this.img, this._offX, this._offY); 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) { }
updateChildren() {
if (this.children.length <= 0) { return; }
for (const child of this.children) {
if (child === this) {
if (this.visible) {
this.drawSelf(); this.drawSelf();
}
} else { } else {
child.update();
this.children[i].update();
} }
} }
} }
...@@ -140,6 +244,11 @@ export class MySprite extends Sprite { ...@@ -140,6 +244,11 @@ export class MySprite extends Sprite {
return a._z - b._z; return a._z - b._z;
}); });
if (this.childDepandAlpha) {
child.alpha = this.alpha;
}
} }
removeChild(child) { removeChild(child) {
const index = this.children.indexOf(child); const index = this.children.indexOf(child);
...@@ -148,6 +257,55 @@ export class MySprite extends Sprite { ...@@ -148,6 +257,55 @@ export class MySprite extends Sprite {
} }
} }
removeChildren() {
for (let i = 0; i < this.children.length; i++) {
if (this.children[i]) {
if (this.children[i] !== this) {
this.children.splice(i, 1);
i --;
}
}
}
}
_changeChildAlpha(alpha) {
for (const child of this.children) {
if (child !== this) {
child.alpha = alpha;
}
}
}
set btimapFlag(v) {
this._bitmapFlag = v;
}
get btimapFlag() {
return this._bitmapFlag;
}
set alpha(v) {
this._alpha = v;
if (this.childDepandAlpha) {
this._changeChildAlpha(v);
}
}
get alpha() {
return this._alpha;
}
set width(v) {
this._width = v;
this.refreshAnchorOff();
}
get width() {
return this._width;
}
set height(v) {
this._height = v;
this.refreshAnchorOff();
}
get height() {
return this._height;
}
set anchorX(value) { set anchorX(value) {
this._anchorX = value; this._anchorX = value;
this.refreshAnchorOff(); this.refreshAnchorOff();
...@@ -163,333 +321,1830 @@ export class MySprite extends Sprite { ...@@ -163,333 +321,1830 @@ export class MySprite extends Sprite {
return this._anchorY; return this._anchorY;
} }
refreshAnchorOff() { refreshAnchorOff() {
this._offX = -this.width * this.anchorX; this._offX = -this._width * this.anchorX;
this._offY = -this.height * this.anchorY; this._offY = -this._height * this.anchorY;
} }
setScaleXY(value) { setScaleXY(value) {
this.scaleX = this.scaleY = value; this.scaleX = this.scaleY = value;
} }
getBoundingBox() { getBoundingBox() {
const x = this.x + this._offX * this.scaleX; const getParentData = (item) => {
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}; let px = item.x;
} let py = item.y;
} let sx = item.scaleX;
let sy = item.scaleY;
const parent = item.parent;
if (parent) {
const obj = getParentData(parent);
const _x = obj.px;
const _y = obj.py;
const _sx = obj.sx;
const _sy = obj.sy;
px = _x + item.x * _sx;
py = _y + item.y * _sy;
sx *= _sx;
sy *= _sy;
export class Item extends MySprite { }
baseX; return {px, py, sx, sy};
};
move(targetY, callBack) {
const self = this; const data = getParentData(this);
const tween = new TWEEN.Tween(this)
.to({ y: targetY }, 2500)
.easing(TWEEN.Easing.Quintic.Out)
.onComplete(function() {
self.hide(callBack); const x = data.px + this._offX * Math.abs(data.sx);
// if (callBack) { const y = data.py + this._offY * Math.abs(data.sy);
// callBack(); const width = this.width * Math.abs(data.sx);
// } const height = this.height * Math.abs(data.sy);
})
.start();
return {x, y, width, height};
} }
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.
} export class RoundSprite extends MySprite {
hide(callBack = null) { _newCtx;
const tween = new TWEEN.Tween(this) init(imgObj = null, anchorX: number = 0.5, anchorY: number = 0.5) {
.to({ alpha: 0 }, 800)
// .easing(TWEEN.Easing.Quadratic.Out) // Use an easing function to make the animation smooth. if (imgObj) {
.onComplete(function() {
if (callBack) {
callBack();
}
})
.start(); // Start the tween immediately.
}
this.img = imgObj;
shake(id) { this.width = this.img.width;
this.height = this.img.height;
if (!this.baseX) {
this.baseX = this.x;
} }
const baseX = this.baseX; this.anchorX = anchorX;
const baseTime = 50; this.anchorY = anchorY;
const sequence = [
{target: {x: baseX + 40 * id}, time: baseTime - 25}, const canvas = window['curCanvas'];
{target: {x: baseX - 20 * id}, time: baseTime}, const w = canvas.nativeElement.width;
{target: {x: baseX + 10 * id}, time: baseTime}, const h = canvas.nativeElement.height;
{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},
];
this._offCanvas = document.createElement('canvas');
this._offCanvas.width = w;
this._offCanvas.height = h;
const self = this; this._offCtx = this._offCanvas.getContext('2d');
function runSequence() { // this._newCtx = this.ctx;
// this.ctx = this._offCtx;
if (self['shakeTween']) {
self['shakeTween'].stop();
} }
const tween = new TWEEN.Tween(self);
if (sequence.length > 0) {
// console.log('sequence.length: ', sequence.length);
const action = sequence.shift();
tween.to(action['target'], action['time']);
tween.onComplete( () => {
runSequence();
});
tween.start();
self['shakeTween'] = tween; 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) {
const r = this._radius;
const w = this.width;
const h = this.height;
const x = -this._offX;
const y = -this._offY;
this._offCtx.lineTo(x - w / 2, y + h / 2); // 创建水平线
this._offCtx.arcTo(x - w / 2, y - h / 2, x - w / 2 + r, y - h / 2, r);
this._offCtx.arcTo(x + w / 2, y - h / 2, x + w / 2, y - h / 2 + r, r);
this._offCtx.arcTo(x + w / 2, y + h / 2, x + w / 2 - r, y + h / 2, r);
this._offCtx.arcTo(x - w / 2, y + h / 2, x - w / 2, y + h / 2 - r, r);
this._offCtx.clip();
} }
runSequence();
if (this.img) {
this._offCtx.drawImage(this.img, 0, 0);
this.ctx.drawImage(this._offCanvas,this._offX, this._offX);
}
} }
}
drop(targetY, callBack = null) {
const self = this;
const time = Math.abs(targetY - this.y) * 2.4; export class ColorSpr extends MySprite {
this.alpha = 1; r = 0;
g = 0;
b = 0;
const tween = new TWEEN.Tween(this) createGSCanvas() {
.to({ y: targetY }, time)
.easing(TWEEN.Easing.Cubic.In)
.onComplete(function() {
// self.hideItem(callBack); if (!this.img) {
if (callBack) { return;
callBack();
} }
})
.start();
const rect = this.getBoundingBox();
if (rect.width <= 1 || rect.height <= 1) {
return;
} }
} 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++) {
const x = (i * 4) * c.width + ( j * 4 );
const r = c.data[x];
const g = c.data[x + 1];
const b = c.data[x + 2];
export class EndSpr extends MySprite { c.data[x] = this.r;
c.data[x + 1] = this.g;
c.data[x + 2] = this.b;
show(s) {
this.scaleX = this.scaleY = 0;
this.alpha = 0;
const tween = new TWEEN.Tween(this) // c.data[x] = c.data[x + 1] = c.data[x + 2] = (r + g + b) / 3 ;
.to({ alpha: 1, scaleX: s, scaleY: s }, 800) // // c.data[x + 3] = 255;
.easing(TWEEN.Easing.Elastic.Out) // Use an easing function to make the animation smooth. }
.onComplete(function() { }
this.ctx.putImageData(c, rect.x, rect.y, 0, 0, rect.width, rect.height);
}
})
.start(); // Start the tween immediately.
drawSelf() {
super.drawSelf();
this.createGSCanvas();
} }
}
}
export class ShapeRect extends MySprite { export class GrayscaleSpr extends MySprite {
fillColor = '#FF0000'; grayScale = 120;
setSize(w, h) { createGSCanvas() {
this.width = w;
this.height = h;
console.log('w:', w); if (!this.img) {
console.log('h:', h); return;
} }
drawShape() {
this.ctx.fillStyle = this.fillColor;
this.ctx.fillRect(this._offX, this._offY, this.width, this.height);
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++) {
const x = (i * 4) * c.width + ( j * 4 );
const r = c.data[x];
const g = c.data[x + 1];
const b = c.data[x + 2];
// const a = c.data[x + 3];
c.data[x] = c.data[x + 1] = c.data[x + 2] = this.grayScale; // (r + g + b) / 3;
// c.data[x + 3] = 255;
}
}
this.ctx.putImageData(c, rect.x, rect.y, 0, 0, rect.width, rect.height);
} }
drawSelf() { drawSelf() {
super.drawSelf(); super.drawSelf();
this.drawShape(); this.createGSCanvas();
} }
}
}
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); export class BitMapLabel extends MySprite {
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) {
labelArr;
baseUrl;
if (!this.label) { setText(data, text) {
this.label = new Label(this.ctx);
this.label.anchorY = 0;
this.label.fontSize = '40px';
this.label.textAlign = 'center';
this.addChild(this.label);
// this.label.scaleX = 1 / this.scaleX;
// this.label.scaleY = 1 / this.scaleY;
this.refreshLabelScale(); this.labelArr = [];
} const labelArr = [];
const tmpArr = text.split('');
let totalW = 0;
let h = 0;
for (const tmp of tmpArr) {
if (text) { const label = new MySprite(this.ctx);
this.label.text = text; label.init(data[tmp], 0);
} else if (this.text) { this.addChild(label);
this.label.text = this.text; labelArr.push(label);
}
this.label.visible = true;
totalW += label.width;
h = label.height;
} }
hideLabel() {
if (!this.label) { return; }
this.label.visible = false; this.width = totalW;
} this.height = h;
refreshLabelScale() { let offX = -totalW / 2;
if (this.scaleX == this.scaleY) { for (const label of labelArr) {
this.label.setScaleXY(1); label.x = offX;
offX += label.width;
} }
if (this.scaleX > this.scaleY) { this.labelArr = labelArr;
this.label.scaleX = this.scaleY / this.scaleX;
} else {
this.label.scaleY = this.scaleX / this.scaleY;
}
} }
showLineDash() { }
this.lineDashFlag = true;
if (this.arrow) {
this.arrow.visible = true;
} else {
this.arrow = new MySprite(this.ctx);
this.arrow.load('assets/common/arrow.png', 1, 0);
this.arrow.setScaleXY(0.06);
this.arrowTop = new MySprite(this.ctx);
this.arrowTop.load('assets/common/arrow_top.png', 0.5, 0);
this.arrowTop.setScaleXY(0.06);
this.arrowRight = new MySprite(this.ctx);
this.arrowRight.load('assets/common/arrow_right.png', 1, 0.5);
this.arrowRight.setScaleXY(0.06);
}
this.showLabel(); export class Label extends MySprite {
private _text: string;
// fontSize:String = '40px';
fontName = 'Verdana';
textAlign = 'left';
fontSize = 40;
fontColor = '#000000';
fontWeight = 900;
_maxWidth;
outline = 0;
outlineColor = '#ffffff';
// _shadowFlag = false;
// _shadowColor;
// _shadowOffsetX;
// _shadowOffsetY;
// _shadowBlur;
_outlineFlag = false;
_outLineWidth;
_outLineColor;
constructor(ctx = null) {
super(ctx);
this.init();
} }
hideLineDash() {
this.lineDashFlag = false;
if (this.arrow) { get text(): string {
this.arrow.visible = false; return this._text;
} }
this.hideLabel(); set text(value: string) {
this._text = value;
this.refreshSize();
} }
refreshSize() {
this.ctx.save();
drawArrow() { this.ctx.font = `${this.fontSize * this.scaleX}px ${this.fontName}`;
if (!this.arrow) { return; } this.ctx.textAlign = this.textAlign;
this.ctx.textBaseline = 'middle';
this.ctx.fontWeight = this.fontWeight;
this._width = this.ctx.measureText(this.text).width;
this._height = this.fontSize;
this.refreshAnchorOff();
this.ctx.restore();
}
setMaxSize(w) {
this._maxWidth = w;
this.refreshSize();
if (this.width >= w) {
this.scaleX *= w / this.width;
this.scaleY *= w / this.width;
}
}
show(callBack = null) {
this.visible = true;
if (this.alpha >= 1) {
return;
}
const tween = new TWEEN.Tween(this)
.to({ alpha: 1 }, 800)
// .easing(TWEEN.Easing.Quadratic.Out) // Use an easing function to make the animation smooth.
.onComplete(() => {
if (callBack) {
callBack();
}
})
.start(); // Start the tween immediately.
}
setOutline(width = 5, color = '#ffffff') {
this._outlineFlag = true;
this._outLineWidth = width;
this._outLineColor = color;
}
drawText() {
if (!this.text) { return; }
this.ctx.font = `${this.fontSize}px ${this.fontName}`;
this.ctx.textAlign = this.textAlign;
this.ctx.textBaseline = 'middle';
this.ctx.fontWeight = this.fontWeight;
if (this._outlineFlag) {
this.ctx.lineWidth = this._outLineWidth;
this.ctx.strokeStyle = this._outLineColor;
this.ctx.strokeText(this.text, 0, 0);
}
this.ctx.fillStyle = this.fontColor;
if (this.outline > 0) {
this.ctx.lineWidth = this.outline;
this.ctx.strokeStyle = this.outlineColor;
this.ctx.strokeText(this.text, 0, 0);
}
this.ctx.fillText(this.text, 0, 0);
}
drawSelf() {
super.drawSelf();
this.drawText();
}
}
export class RichTextOld extends Label {
textArr = [];
fontSize = 40;
setText(text: string, words) {
let newText = text;
for (const word of words) {
const re = new RegExp(word, 'g');
newText = newText.replace( re, `#${word}#`);
// newText = newText.replace(word, `#${word}#`);
}
this.textArr = newText.split('#');
this.text = newText;
// this.setSize();
}
refreshSize() {
this.ctx.save();
this.ctx.font = `${this.fontSize}px ${this.fontName}`;
this.ctx.textAlign = this.textAlign;
this.ctx.textBaseline = 'middle';
this.ctx.fontWeight = this.fontWeight;
let curX = 0;
for (const text of this.textArr) {
const w = this.ctx.measureText(text).width;
curX += w;
}
this.width = curX;
this.height = this.fontSize;
this.refreshAnchorOff();
this.ctx.restore();
}
show(callBack = null) {
// console.log(' in show ');
this.visible = true;
// this.alpha = 0;
const tween = new TWEEN.Tween(this)
.to({ alpha: 1 }, 800)
// .easing(TWEEN.Easing.Quadratic.Out) // Use an easing function to make the animation smooth.
.onComplete(() => {
if (callBack) {
callBack();
}
})
.start(); // Start the tween immediately.
}
drawText() {
// console.log('in drawText', this.text);
if (!this.text) { return; }
this.ctx.font = `${this.fontSize}px ${this.fontName}`;
this.ctx.textAlign = this.textAlign;
this.ctx.textBaseline = 'middle';
this.ctx.fontWeight = 900;
this.ctx.lineWidth = 5;
this.ctx.strokeStyle = '#ffffff';
// this.ctx.strokeText(this.text, 0, 0);
this.ctx.fillStyle = '#000000';
// this.ctx.fillText(this.text, 0, 0);
let curX = 0;
for (let i = 0; i < this.textArr.length; i++) {
const w = this.ctx.measureText(this.textArr[i]).width;
if ((i + 1) % 2 === 0) {
this.ctx.fillStyle = '#c8171e';
} else {
this.ctx.fillStyle = '#000000';
}
this.ctx.fillText(this.textArr[i], curX, 0);
curX += w;
}
}
}
export class RichText extends Label {
disH = 30;
constructor(ctx?: any) {
super(ctx);
// this.dataArr = dataArr;
}
drawText() {
if (!this.text) {
return;
}
this.ctx.font = `${this.fontSize}px ${this.fontName}`;
this.ctx.textAlign = this.textAlign;
this.ctx.textBaseline = 'middle';
this.ctx.fontWeight = this.fontWeight;
this.ctx.fillStyle = this.fontColor;
const selfW = this.width * this.scaleX;
const chr = this.text.split(' ');
let temp = '';
const row = [];
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;
} else {
row.push(temp);
temp = ' ' + c;
}
}
row.push(temp);
const x = 0;
const y = -row.length * disH / 2;
// for (let b = 0 ; b < row.length; b++) {
// this.ctx.strokeText(row[b], x, y + ( b + 1 ) * disH ); // 每行字体y坐标间隔20
// }
if (this._outlineFlag) {
this.ctx.lineWidth = this._outLineWidth;
this.ctx.strokeStyle = this._outLineColor;
for (let b = 0 ; b < row.length; b++) {
this.ctx.strokeText(row[b], x, y + ( b + 1 ) * disH ); // 每行字体y坐标间隔20
}
// this.ctx.strokeText(this.text, 0, 0);
}
// this.ctx.fillStyle = '#ff7600';
for (let b = 0 ; b < row.length; b++) {
this.ctx.fillText(row[b], x, y + ( b + 1 ) * disH ); // 每行字体y坐标间隔20
}
}
drawSelf() {
super.drawSelf();
this.drawText();
}
}
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 {
fillColor = '#FF0000';
setSize(w, h) {
this.width = w;
this.height = h;
// console.log('w:', w);
// console.log('h:', h);
}
drawShape() {
this.ctx.fillStyle = this.fillColor;
this.ctx.fillRect(this._offX, this._offY, this.width, this.height);
}
drawSelf() {
super.drawSelf();
this.drawShape();
}
}
export class Line extends MySprite {
lineWidth = 5;
lineColor = '#000000';
_pointArr = [];
roundFlag = true;
_pointS = 1;
imgObj;
bitMap;
_offCtx;
_offCanvas;
lastPointIndex = 0;
init() {
const canvas = window['curCanvas'];
const w = canvas.nativeElement.width;
const h = canvas.nativeElement.height;
console.log('w: ', w);
console.log('h: ', h);
this._offCanvas = document.createElement('canvas');
this._offCanvas.width = w;
this._offCanvas.height = h;
// this._offCanvas = _offCanvas;
// this._offCtx = this._offCanvas.getContext('2d');
// this._offCanvas = new OffscreenCanvas(w, h);
this._offCtx = this._offCanvas.getContext('2d');
}
addPoint(x, y) {
this._pointArr.push([x, y]);
if (this._pointArr.length < 2) {
return;
}
//
// const lastP = this._pointArr[this._pointArr.length - 1];
//
//
// const context = this._offCtx;
// context.moveTo (lastP[0], lastP[1]); // 设置起点状态
// context.lineTo (x, y); // 设置末端状态
//
// context.lineWidth = this.lineWidth; //设置线宽状态
// context.strokeStyle = this.lineColor;
// context.stroke();
//
//
// this.bitMap = this._offCanvas.transferToImageBitmap();
// const tmpLine = new MySprite(this._offCtx);
// tmpLine.init(this.imgObj);
// tmpLine.anchorY = 1;
// tmpLine.anchorX = 0.5;
// tmpLine.x = lastP[0];
// tmpLine.y = lastP[1];
//
// const disH = getPosDistance(lastP[0], lastP[1], x, y);
// tmpLine.scaleX = this.lineWidth / tmpLine.width;
// tmpLine.scaleY = disH / tmpLine.height * 1.1;
//
// const angle = getAngleByPos(lastP[0], lastP[1], x, y);
// tmpLine.rotation = angle;
//
// this.addChild(tmpLine);
}
setPointArr(arr, imgObj) {
this.removeChildren();
if (arr.length < 2) {
return;
}
let p1 = arr[0];
let p2;
for (let i = 1; i < arr.length; i++) {
p2 = arr[i];
const tmpLine = new MySprite();
tmpLine.init(imgObj);
tmpLine.anchorY = 1;
tmpLine.anchorX = 0.5;
tmpLine.x = p1[0];
tmpLine.y = p1[1];
const disH = getPosDistance(p1[0], p1[1], p2[0], p2[1]);
tmpLine.scaleX = this.lineWidth / tmpLine.width;
tmpLine.scaleY = disH / tmpLine.height * 1.1;
const angle = getAngleByPos(p1[0], p1[1], p2[0], p2[1]);
tmpLine.rotation = angle;
this.addChild(tmpLine);
p1 = p2;
}
}
drawLine() {
if (this._pointArr.length < 2) {
return;
}
const curMaxPointIndex = this._pointArr.length - 1;
if (curMaxPointIndex > this.lastPointIndex) {
const arr = this._pointArr;
const context = this._offCtx;
context.moveTo (arr[this.lastPointIndex][0] * this._pointS, arr[this.lastPointIndex][1] * this._pointS); // 设置起点状态
for (let i = this.lastPointIndex + 1; i < arr.length; i++) {
context.lineTo (arr[i][0] * this._pointS, arr[i][1] * this._pointS); // 设置末端状态
}
if (this.roundFlag) {
context.lineCap = "round";
}
context.lineWidth = this.lineWidth; //设置线宽状态
context.strokeStyle = this.lineColor;
context.stroke();
this.lastPointIndex = curMaxPointIndex;
// this.bitMap = this._offCanvas.transferToImageBitmap();
}
// this.ctx.drawImage(this.bitMap, this._offX, this._offY);
this.ctx.drawImage(this._offCanvas, this._offX, this._offY);
}
drawSelf() {
super.drawSelf();
this.drawLine();
// if (this.img) {
// this.ctx.drawImage(this._offCanvas, 0, 0, this.width, this.height);
// }
// if (this.bitMap) {
// this.bitMap = this._offCanvas.transferToImageBitmap();
// this.ctx.drawImage(this.bitMap, 0, 0, this.width, this.height);
// }
}
}
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 {
radius = 0;
fillColor = '#ffffff';
strokeColor = '#000000';
fill = true;
stroke = false;
lineWidth = 1;
setSize(w, h, r) {
this.width = w;
this.height = h;
this.radius = r;
}
setOutLine(color, lineWidth) {
this.stroke = true;
this.strokeColor = color;
this.lineWidth = lineWidth;
}
drawShape() {
const ctx = this.ctx;
const width = this.width;
const height = this.height;
const radius = this.radius;
ctx.save();
ctx.beginPath(0);
// 从右下角顺时针绘制,弧度从0到1/2PI
ctx.arc(width - radius, height - radius, radius, 0, Math.PI / 2);
// 矩形下边线
ctx.lineTo(radius, height);
// 左下角圆弧,弧度从1/2PI到PI
ctx.arc(radius, height - radius, radius, Math.PI / 2, Math.PI);
// 矩形左边线
ctx.lineTo(0, radius);
// 左上角圆弧,弧度从PI到3/2PI
ctx.arc(radius, radius, radius, Math.PI, Math.PI * 3 / 2);
// 上边线
ctx.lineTo(width - radius, 0);
// 右上角圆弧
ctx.arc(width - radius, radius, radius, Math.PI * 3 / 2, Math.PI * 2);
// 右边线
ctx.lineTo(width, height - radius);
ctx.closePath();
if (this.fill) {
ctx.fillStyle = this.fillColor;
ctx.fill();
}
if (this.stroke) {
ctx.lineWidth = this.lineWidth;
ctx.strokeStyle = this.strokeColor;
ctx.stroke();
}
ctx.restore();
}
drawSelf() {
super.drawSelf();
this.drawShape();
}
}
export class MyAnimation extends MySprite {
frameArr = [];
frameIndex = 0;
playFlag = false;
lastDateTime;
curDelay = 0;
loop = false;
playEndFunc;
delayPerUnit = 1;
restartFlag = false;
reverseFlag = false;
addFrameByImg(img) {
const spr = new MySprite(this.ctx);
spr.init(img);
this._refreshSize(img);
spr.visible = false;
this.addChild(spr);
this.frameArr.push(spr);
this.frameArr[this.frameIndex].visible = true;
}
addFrameByUrl(url) {
const spr = new MySprite(this.ctx);
spr.load(url).then(img => {
this._refreshSize(img);
});
spr.visible = false;
this.addChild(spr);
this.frameArr.push(spr);
this.frameArr[this.frameIndex].visible = true;
}
_refreshSize(img: any) {
if (this.width < img.width) {
this.width = img.width;
}
if (this.height < img.height) {
this.height = img.height;
}
}
play() {
this.playFlag = true;
this.lastDateTime = new Date().getTime();
}
stop() {
this.playFlag = false;
}
replay() {
this.restartFlag = true;
this.play();
}
reverse() {
this.reverseFlag = !this.reverseFlag;
this.frameArr.reverse();
this.frameIndex = 0;
}
showAllFrame() {
for (const frame of this.frameArr ) {
frame.alpha = 1;
}
}
hideAllFrame() {
for (const frame of this.frameArr) {
frame.alpha = 0;
}
}
playEnd() {
this.playFlag = false;
this.curDelay = 0;
this.frameArr[this.frameIndex].visible = true;
if (this.playEndFunc) {
this.playEndFunc();
this.playEndFunc = null;
}
}
updateFrame() {
if (this.frameArr[this.frameIndex]) {
this.frameArr[this.frameIndex].visible = false;
}
this.frameIndex ++;
if (this.frameIndex >= this.frameArr.length) {
if (this.loop) {
this.frameIndex = 0;
} else if (this.restartFlag) {
this.restartFlag = false;
this.frameIndex = 0;
} else {
this.frameIndex -- ;
this.playEnd();
return;
}
}
this.frameArr[this.frameIndex].visible = true;
}
_updateDelay(delay) {
this.curDelay += delay;
if (this.curDelay < this.delayPerUnit) {
return;
}
this.curDelay -= this.delayPerUnit;
this.updateFrame();
}
_updateLastDate() {
if (!this.playFlag) { return; }
let delay = 0;
if (this.lastDateTime) {
delay = (new Date().getTime() - this.lastDateTime) / 1000;
}
this.lastDateTime = new Date().getTime();
this._updateDelay(delay);
}
update($event: any = null) {
super.update($event);
this._updateLastDate();
}
}
// --------=========== util func =============-------------
export function tweenChange(item, obj, time = 0.8, callBack = null, easing = null, update = null) {
const tween = new TWEEN.Tween(item).to(obj, time * 1000);
if (callBack) {
tween.onComplete(() => {
callBack();
});
}
if (easing) {
tween.easing(easing);
}
if (update) {
tween.onUpdate( (a, b) => {
update(a, b);
});
}
tween.start();
return tween;
}
export function rotateItem(item, rotation, time = 0.8, callBack = null, easing = null) {
const tween = new TWEEN.Tween(item).to({ rotation }, time * 1000);
if (callBack) {
tween.onComplete(() => {
callBack();
});
}
if (easing) {
tween.easing(easing);
}
tween.start();
}
export function scaleItem(item, scale, time = 0.8, callBack = null, easing = null) {
const tween = new TWEEN.Tween(item).to({ scaleX: scale, scaleY: scale}, time * 1000);
if (callBack) {
tween.onComplete(() => {
callBack();
});
}
if (easing) {
tween.easing(easing);
}
tween.start();
return tween;
}
export function moveItem(item, x, y, time = 0.8, callBack = null, easing = null) {
const tween = new TWEEN.Tween(item).to({ x, y}, time * 1000);
if (callBack) {
tween.onComplete(() => {
callBack();
});
}
if (easing) {
tween.easing(easing);
}
tween.start();
return tween;
}
export function endShow(item, s = 1) {
item.scaleX = item.scaleY = 0;
item.alpha = 0;
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(() => {
})
.start();
}
export function hideItem(item, time = 0.8, callBack = null, easing = null) {
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(() => {
if (callBack) {
callBack();
}
});
if (easing) {
tween.easing(easing);
}
tween.start();
}
export function showItem(item, time = 0.8, callBack = null, easing = null) {
if (item.alpha === 1) {
if (callBack) {
callBack();
}
return;
}
item.visible = true;
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(() => {
if (callBack) {
callBack();
}
});
if (easing) {
tween.easing(easing);
}
tween.start();
}
export function alphaItem(item, alpha, time = 0.8, callBack = null, easing = null) {
const tween = new TWEEN.Tween(item)
.to({alpha}, time * 1000)
// .easing(TWEEN.Easing.Quadratic.Out) // Use an easing function to make the animation smooth.
.onComplete(() => {
if (callBack) {
callBack();
}
});
if (easing) {
tween.easing(easing);
}
tween.start();
}
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(() => {
if (callBack) {
callBack();
}
});
if (easing) {
tween.easing(easing);
}
tween.start();
}
export function randomSortByArr(arr) {
if (!arr) {
return;
}
const newArr = [];
const tmpArr = arr.concat();
while (tmpArr.length > 0) {
const randomIndex = Math.floor( tmpArr.length * Math.random() );
newArr.push(tmpArr[randomIndex]);
tmpArr.splice(randomIndex, 1);
}
return newArr;
}
export function radianToAngle(radian) {
return radian * 180 / Math.PI;
// 角度 = 弧度 * 180 / Math.PI;
}
export function angleToRadian(angle) {
return angle * Math.PI / 180;
// 弧度= 角度 * Math.PI / 180;
}
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;
}
// console.log('angle: ', angle);
return angle;
}
export function removeItemFromArr(arr, item) {
const index = arr.indexOf(item);
if (index !== -1) {
arr.splice(index, 1);
}
}
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);
a += 90;
const obj = {r, a};
item._circleAngle = a;
const targetA = a + addR;
const tween = new TWEEN.Tween(item).to({_circleAngle: targetA}, time * 1000);
if (callBack) {
tween.onComplete(() => {
callBack();
});
}
if (easing) {
tween.easing(easing);
}
tween.onUpdate( (item, progress) => {
// console.log(item._circleAngle);
const r = obj.r;
const a = item._circleAngle;
const x = x0 + r * xPer * Math.cos(a * Math.PI / 180);
const y = y0 + r * yPer * Math.sin(a * Math.PI / 180);
item.x = x;
item.y = y;
// obj.a ++;
});
tween.start();
}
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(callback, second) {
const tween = new TWEEN.Tween(this)
.delay(second * 1000)
.onComplete(() => {
if (callback) {
callback();
}
})
.start();
}
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() // 毫秒
};
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)));
}
}
return fmt;
}
export function getMinScale(item, maxLen) {
const sx = maxLen / item.width;
const sy = maxLen / item.height;
const minS = Math.min(sx, sy);
return minS;
}
export function jelly(item, time = 0.7) {
if (item.jellyTween) {
TWEEN.remove(item.jellyTween);
}
const t = time / 9;
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.1, baseSY * 0.9, t],
[baseSX * 0.98, baseSY * 1.02, t * 2],
[baseSX * 1.02, baseSY * 0.98, t * 2],
[baseSX * 0.99, baseSY * 1.01, t * 2],
[baseSX * 1.0, baseSY * 1.0, t * 2],
];
run();
}
export function showPopParticle(img, pos, parent, num = 20, minLen = 40, maxLen = 80, showTime = 0.4) {
for (let i = 0; i < num; i ++) {
const particle = new MySprite();
particle.init(img);
particle.x = pos.x;
particle.y = pos.y;
parent.addChild(particle);
const randomR = 360 * Math.random();
particle.rotation = randomR;
const randomS = 0.3 + Math.random() * 0.7;
particle.setScaleXY(randomS * 0.3);
const randomX = Math.random() * 20 - 10;
particle.x += randomX;
const randomY = Math.random() * 20 - 10;
particle.y += randomY;
const randomL = minLen + Math.random() * (maxLen - minLen);
const randomA = 360 * Math.random();
const randomT = getPosByAngle(randomA, randomL);
moveItem(particle, particle.x + randomT.x, particle.y + randomT.y, showTime, () => {
}, TWEEN.Easing.Exponential.Out);
// scaleItem(particle, 0, 0.6, () => {
//
// });
scaleItem(particle, randomS, 0.6, () => {
}, TWEEN.Easing.Exponential.Out);
setTimeout(() => {
hideItem(particle, 0.4, () => {
}, TWEEN.Easing.Cubic.In);
}, showTime * 0.5 * 1000);
}
}
export function shake(item, time = 0.5, callback = null, rate = 1) {
if (item.shakeTween) {
return;
}
item.shakeTween = true;
const offX = 15 * item.scaleX * rate;
const offY = 15 * item.scaleX * rate;
const baseX = item.x;
const baseY = item.y;
const easing = TWEEN.Easing.Sinusoidal.InOut;
const move4 = () => {
moveItem(item, baseX, baseY, time / 4, () => {
item.shakeTween = false;
if (callback) {
callback();
}
}, easing);
};
const move3 = () => {
moveItem(item, baseX + offX / 4, baseY + offY / 4, time / 4, () => {
move4();
}, easing);
};
const move2 = () => {
moveItem(item, baseX - offX / 4 * 3, baseY - offY / 4 * 3, time / 4, () => {
move3();
}, easing);
};
const move1 = () => {
moveItem(item, baseX + offX, baseY + offY, time / 7.5, () => {
move2();
}, easing);
};
move1();
}
// --------------- custom class --------------------
export class HotZoneItem extends MySprite {
lineDashFlag = false;
arrow: MySprite;
label: Label;
title;
arrowTop;
arrowRight;
audio_url;
pic_url;
text;
gIdx;
isAnimaStyle = false;
private _itemType;
private shapeRect: ShapeRect;
get itemType() {
return this._itemType;
}
set itemType(value) {
this._itemType = value;
}
setSize(w, h) {
this.width = w;
this.height = h;
const rect = new ShapeRect(this.ctx);
rect.x = -w / 2;
rect.y = -h / 2;
rect.setSize(w, h);
rect.fillColor = '#ffffff';
rect.alpha = 0.2;
this.addChild(rect);
}
showLabel(text = null) {
if (!this.label) {
this.label = new Label(this.ctx);
this.label.anchorY = 0;
this.label.fontSize = 40;
this.label.textAlign = 'center';
this.addChild(this.label);
// this.label.scaleX = 1 / this.scaleX;
// this.label.scaleY = 1 / this.scaleY;
this.refreshLabelScale();
}
if (text) {
this.label.text = text;
} else if (this.title) {
this.label.text = this.title;
}
this.label.visible = true;
}
hideLabel() {
if (!this.label) { return; }
this.label.visible = false;
}
refreshLabelScale() {
if (this.scaleX == this.scaleY) {
this.label.setScaleXY(1);
}
if (this.scaleX > this.scaleY) {
this.label.scaleX = this.scaleY / this.scaleX;
} else {
this.label.scaleY = this.scaleX / this.scaleY;
}
}
showLineDash() {
this.lineDashFlag = true;
if (this.arrow) {
this.arrow.visible = true;
} else {
this.arrow = new MySprite(this.ctx);
this.arrow.load('assets/common/arrow.png', 1, 0);
this.arrow.setScaleXY(0.06);
this.arrowTop = new MySprite(this.ctx);
this.arrowTop.load('assets/common/arrow_top.png', 0.5, 0);
this.arrowTop.setScaleXY(0.06);
this.arrowRight = new MySprite(this.ctx);
this.arrowRight.load('assets/common/arrow_right.png', 1, 0.5);
this.arrowRight.setScaleXY(0.06);
}
this.showLabel();
}
hideLineDash() {
this.lineDashFlag = false;
if (this.arrow) {
this.arrow.visible = false;
}
this.hideLabel();
}
setAnimaStyle(isAnimaStyle) {
this.isAnimaStyle = isAnimaStyle;
console.log('in setAnimaStyle ')
}
drawArrow() {
if (!this.arrow) { return; }
const rect = this.getBoundingBox();
this.arrow.x = rect.x + rect.width;
this.arrow.y = rect.y;
this.arrow.update();
if (!this.isAnimaStyle) {
this.arrowTop.x = rect.x + rect.width / 2;
this.arrowTop.y = rect.y;
this.arrowTop.update();
this.arrowRight.x = rect.x + rect.width;
this.arrowRight.y = rect.y + rect.height / 2;
this.arrowRight.update();
}
}
drawFrame() {
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);
const rect = this.getBoundingBox(); this.ctx.lineTo(x + w / 2, y - h / 2);
this.arrow.x = rect.x + rect.width;
this.arrow.y = rect.y;
this.arrow.update(); this.ctx.lineTo(x + w / 2, y + h / 2);
this.ctx.lineTo(x - w / 2, y + h / 2);
this.arrowTop.x = rect.x + rect.width / 2; this.ctx.lineTo(x - w / 2, y - h / 2);
this.arrowTop.y = rect.y;
this.arrowTop.update(); // this.ctx.fill();
this.ctx.stroke();
this.ctx.restore();
this.arrowRight.x = rect.x + rect.width;
this.arrowRight.y = rect.y + rect.height / 2;
this.arrowRight.update();
} }
drawFrame() { draw() {
super.draw();
if (this.lineDashFlag) {
this.drawFrame();
this.drawArrow();
}
}
}
export class HotZoneImg extends MySprite {
this.ctx.save(); drawFrame() {
this.ctx.save();
const rect = this.getBoundingBox(); const rect = this.getBoundingBox();
const w = rect.width; const w = rect.width;
const h = rect.height; const h = rect.height;
const x = rect.x + w / 2; const x = rect.x + w / 2;
...@@ -498,6 +2153,176 @@ export class HotZoneItem extends MySprite { ...@@ -498,6 +2153,176 @@ export class HotZoneItem extends MySprite {
this.ctx.setLineDash([5, 5]); this.ctx.setLineDash([5, 5]);
this.ctx.lineWidth = 2; this.ctx.lineWidth = 2;
this.ctx.strokeStyle = '#1bfff7'; 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.fill();
this.ctx.stroke();
this.ctx.restore();
}
draw() {
super.draw();
this.drawFrame();
}
}
export class HotZoneLabel extends Label {
drawFrame() {
this.ctx.save();
const rect = this.getBoundingBox();
const w = rect.width / this.scaleX;
const h = this.height * this.scaleY;
const x = this.x;
const y = this.y;
this.ctx.setLineDash([5, 5]);
this.ctx.lineWidth = 2;
this.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.fill();
this.ctx.stroke();
this.ctx.restore();
}
draw() {
super.draw();
this.drawFrame();
}
getLabelRect() {
const rect = this.getBoundingBox();
const width = rect.width / this.scaleX;
const height = this.height * this.scaleY;
const x = this.x - width / 2;
const y = this.y - height / 2;
return {width, height, x, y};
}
}
export class HotZoneAction extends MySprite {
}
export class DragItem extends MySprite {
lineDashFlag = true;
item;
init() {
this.anchorX = 0.5;
this.anchorY = 0.5;
this.initCenterCircle();
}
setSize(w, h) {
this.anchorX = 0.5;
this.anchorY = 0.5;
this.width = w;
this.height = h;
// const rect = new ShapeRect(this.ctx);
// rect.x = -w / 2;
// rect.y = -h / 2;
// rect.setSize(w, h);
// rect.fillColor = '#000000';
// rect.alpha = 0.1;
// this.addChild(rect);
}
initCenterCircle() {
const circle = new ShapeCircle(this.ctx);
circle.setRadius(10);
circle.fillColor = '#ffa568'
this.addChild(circle);
this.width = circle.width;
this.height = circle.height;
}
getPosition() {
return {x: this.x, y: this.y};
}
drawLine() {
if (!this.item) {
return;
}
this.ctx.save();
const rect = this.getBoundingBox();
const w = rect.width;
const h = rect.height;
const x = rect.x //+ w / 2;
const y = rect.y //+ h / 2;
this.ctx.setLineDash([4, 4]);
this.ctx.lineWidth = 1;
this.ctx.strokeStyle = '#ffa568';
this.ctx.beginPath();
this.ctx.moveTo( x + w / 2 , y + h / 2 );
this.ctx.lineTo(this.item.x, this.item.y);
// this.ctx.fill();
this.ctx.stroke();
this.ctx.restore();
}
drawFrame() {
this.ctx.save();
const rect = this.getBoundingBox();
const w = rect.width;
const h = rect.height;
const x = rect.x //+ w / 2;
const y = rect.y //+ h / 2;
this.ctx.setLineDash([4, 4]);
this.ctx.lineWidth = 2;
this.ctx.strokeStyle = '#ffa568';
// this.ctx.fillStyle = '#ffffff'; // this.ctx.fillStyle = '#ffffff';
this.ctx.beginPath(); this.ctx.beginPath();
...@@ -526,19 +2351,21 @@ export class HotZoneItem extends MySprite { ...@@ -526,19 +2351,21 @@ export class HotZoneItem extends MySprite {
super.draw(); super.draw();
if (this.lineDashFlag) { if (this.lineDashFlag) {
this.drawFrame(); this.drawLine();
this.drawArrow(); // this.drawFrame();
// this.drawArrow();
} }
} }
} }
export class EditorItem extends MySprite { export class EditorItem extends MySprite {
lineDashFlag = false; lineDashFlag = false;
arrow: MySprite; arrow: MySprite;
label:Label; label: Label;
text; text;
arrowTop;
arrowRight;
showLabel(text = null) { showLabel(text = null) {
...@@ -546,7 +2373,7 @@ export class EditorItem extends MySprite { ...@@ -546,7 +2373,7 @@ export class EditorItem extends MySprite {
if (!this.label) { if (!this.label) {
this.label = new Label(this.ctx); this.label = new Label(this.ctx);
this.label.anchorY = 0; this.label.anchorY = 0;
this.label.fontSize = '50px'; this.label.fontSize = 50;
this.label.textAlign = 'center'; this.label.textAlign = 'center';
this.addChild(this.label); this.addChild(this.label);
this.label.setScaleXY(1 / this.scaleX); this.label.setScaleXY(1 / this.scaleX);
...@@ -577,6 +2404,13 @@ export class EditorItem extends MySprite { ...@@ -577,6 +2404,13 @@ export class EditorItem extends MySprite {
this.arrow.load('assets/common/arrow.png', 1, 0); this.arrow.load('assets/common/arrow.png', 1, 0);
this.arrow.setScaleXY(0.06); this.arrow.setScaleXY(0.06);
// this.arrowTop = new MySprite(this.ctx);
// this.arrowTop.load('assets/common/arrow_top.png', 0.5, 0);
// this.arrowTop.setScaleXY(0.06);
//
// this.arrowRight = new MySprite(this.ctx);
// this.arrowRight.load('assets/common/arrow_right.png', 1, 0.5);
// this.arrowRight.setScaleXY(0.06);
} }
this.showLabel(); this.showLabel();
...@@ -593,16 +2427,25 @@ export class EditorItem extends MySprite { ...@@ -593,16 +2427,25 @@ export class EditorItem extends MySprite {
this.hideLabel(); this.hideLabel();
} }
refreshLabelScale() {}
drawArrow() { drawArrow() {
if (!this.arrow) { return; } if (!this.arrow) { return; }
const rect = this.getBoundingBox(); const rect = this.getBoundingBox();
this.arrow.x = rect.x + rect.width; this.arrow.x = rect.x + rect.width;
this.arrow.y = rect.y; this.arrow.y = rect.y;
this.arrow.update(); this.arrow.update();
// this.arrowTop.x = rect.x + rect.width / 2;
// this.arrowTop.y = rect.y;
// this.arrowTop.update();
//
// this.arrowRight.x = rect.x + rect.width;
// this.arrowRight.y = rect.y + rect.height / 2;
// this.arrowRight.update();
} }
drawFrame() { drawFrame() {
...@@ -656,110 +2499,3 @@ export class EditorItem extends MySprite { ...@@ -656,110 +2499,3 @@ export class EditorItem extends MySprite {
} }
export class Label extends MySprite {
text:String;
fontSize:String = '40px';
fontName:String = 'Verdana';
textAlign:String = 'left';
constructor(ctx) {
super(ctx);
this.init();
}
drawText() {
// console.log('in drawText', this.text);
if (!this.text) { return; }
this.ctx.font = `${this.fontSize} ${this.fontName}`;
this.ctx.textAlign = this.textAlign;
this.ctx.textBaseline = 'middle';
this.ctx.fontWeight = 900;
this.ctx.lineWidth = 5;
this.ctx.strokeStyle = '#ffffff';
this.ctx.strokeText(this.text, 0, 0);
this.ctx.fillStyle = '#000000';
this.ctx.fillText(this.text, 0, 0);
}
drawSelf() {
super.drawSelf();
this.drawText();
}
}
export function getPosByAngle(angle, len) {
const radian = angle * Math.PI / 180;
const x = Math.sin(radian) * len;
const y = Math.cos(radian) * len;
return {x, y};
}
export function getAngleByPos(px, py, mx, my) {
// const _x = p2x - p1x;
// const _y = p2y - p1y;
// const tan = _y / _x;
//
// const radina = Math.atan(tan); // 用反三角函数求弧度
// const angle = Math.floor(180 / (Math.PI / radina)); //
//
// console.log('r: ' , angle);
// return angle;
//
const x = Math.abs(px - mx);
const y = Math.abs(py - my);
// const x = Math.abs(mx - px);
// const y = Math.abs(my - py);
const z = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
const cos = y / z;
const radina = Math.acos(cos); // 用反三角函数求弧度
let angle = Math.floor(180 / (Math.PI / radina) * 100) / 100; // 将弧度转换成角度
if(mx > px && my > py) {// 鼠标在第四象限
angle = 180 - angle;
}
if(mx === px && my > py) {// 鼠标在y轴负方向上
angle = 180;
}
if(mx > px && my === py) {// 鼠标在x轴正方向上
angle = 90;
}
if(mx < px && my > py) {// 鼠标在第三象限
angle = 180 + angle;
}
if(mx < px && my === py) {// 鼠标在x轴负方向
angle = 270;
}
if(mx < px && my < py) {// 鼠标在第二象限
angle = 360 - angle;
}
// console.log('angle: ', angle);
return angle;
}
<div class="p-image-children-editor"> <div class="p-image-children-editor">
<h5 style="margin-left: 2.5%;"> preview: </h5> <h5 style="margin-left: 2.5%;"> preview: </h5>
<div class="preview-box" #wrap> <div class="preview-box" #wrap>
<canvas id="canvas" #canvas></canvas> <canvas id="canvas" #canvas></canvas>
</div> </div>
<div nz-row nzType="flex" nzAlign="middle"> <div nz-row nzType="flex" nzAlign="middle">
<div nz-col nzSpan="5" nzOffset="1"> <div nz-col nzSpan="5" nzOffset="1">
...@@ -16,43 +13,165 @@ ...@@ -16,43 +13,165 @@
<div class="bg-box"> <div class="bg-box">
<app-upload-image-with-preview <app-upload-image-with-preview
[picUrl]="bgItem.url" [picUrl]="bgItem?.url"
(imageUploaded)="onBackgroundUploadSuccess($event)"> (imageUploaded)="onBackgroundUploadSuccess($event)">
</app-upload-image-with-preview> </app-upload-image-with-preview>
</div> </div>
</div>
<div nz-col nzSpan="5" nzOffset="1" class="img-box"
*ngFor="let it of hotZoneArr; let i = index">
<div
style="margin: auto; padding: 5px; margin-top: 30px; width:90%; border: 2px dashed #ddd; border-radius: 10px">
<span style="margin-left: 40%;"> item-{{i + 1}}
</span>
<button style="float: right;" nz-button nzType="danger" nzSize="small" (click)="deleteBtnClick(i)">
X
</button>
<nz-divider style="margin-top: 10px;"></nz-divider>
<div style="margin-top: -20px; margin-bottom: 5px; width: 100%;">
<div *ngIf="customTypeGroupArr">
<nz-radio-group [ngModel]="it.gIdx" (ngModelChange)="customRadioChange($event, it)" style="display: flex; align-items: center; justify-content: center; flex-wrap: wrap;">
<div *ngFor="let group of customTypeGroupArr; let gIdx = index" style="display: flex; ">
<label nz-radio nzValue="{{gIdx}}">{{group.name}}</label>
</div> </div>
</nz-radio-group>
</div>
<!-- <div *ngIf="!customTypeGroupArr">
<nz-radio-group [ngModel]="it.itemType" (ngModelChange)="radioChange($event, it)" style="display: flex; align-items: center; justify-content: center">
<div nz-col nzSpan="5" nzOffset="1" class="img-box" <label *ngIf="isHasRect" nz-radio nzValue="rect">矩形</label>
*ngFor="let it of hotZoneArr; let i = index" > <label *ngIf="isHasPic" nz-radio nzValue="pic">图片</label>
<label *ngIf="isHasText" nz-radio nzValue="text">文本</label>
</nz-radio-group>
</div> -->
</div>
<div *ngIf="customTypeGroupArr && customTypeGroupArr[it.gIdx]">
<div *ngIf="customTypeGroupArr[it.gIdx].pic">
<app-upload-image-with-preview
[picUrl]="it?.pic_url"
(imageUploaded)="onItemImgUploadSuccess($event, it)">
</app-upload-image-with-preview>
</div>
<div *ngIf="customTypeGroupArr[it.gIdx].text" style="margin-top: 5px">
<input type="text" nz-input [(ngModel)]="it.text" (blur)="saveText(it)">
</div>
<div *ngIf="customTypeGroupArr[it.gIdx].anima" align="center" style="margin-top: 5px">
<button nz-button (click)="setAnimaBtnClick(i)" >
<i nz-icon nzType="tool" nzTheme="outline"></i>
配置龙骨动画
</button>
</div>
<div *ngIf="customTypeGroupArr[it.gIdx].animaSmall" align="center" style="margin-top: 5px">
<button nz-button (click)="setAnimaSmallBtnClick(i)" >
<i nz-icon nzType="tool" nzTheme="outline"></i>
配置龙骨动画(小)
</button>
</div>
<div *ngIf="customTypeGroupArr[it.gIdx].audio" style="display: flex;align-items: center; margin-top: 5px">
<app-audio-recorder
style="margin: auto"
[audioUrl]="it.audio_url"
(audioUploaded)="onItemAudioUploadSuccess($event, it)"
></app-audio-recorder>
</div>
<!-- <div *ngIf="customTypeGroupArr[it.gIdx]?.action" style="display: flex;align-items: center; margin-top: 5px">-->
<!-- <app-custom-action-->
<!-- style="margin: auto"-->
<!-- [item]="it ? it['actionData_' + it.gIdx] : {}"-->
<!-- [type]="customTypeGroupArr[it.gIdx].action.type"-->
<!-- [option]="customTypeGroupArr[it.gIdx].action.option"-->
<!-- (save)="onSaveCustomAction($event, it)">-->
<!-- ></app-custom-action>-->
<!-- </div>-->
<div *ngIf="customTypeGroupArr[it.gIdx]?.isShowPos" style="display: flex; align-items: center; justify-content: center; margin-top: 5px;">
x: <input type="text" nz-input [(ngModel)]="it.posX" style="width: 50px; margin-right: 15px;" (blur)="saveItemPos(it)">
y: <input type="text" nz-input [(ngModel)]="it.posY" style="width: 50px" (blur)="saveItemPos(it)">
</div>
<div *ngIf="customTypeGroupArr[it.gIdx]?.select" align="center" >
<nz-select [(ngModel)]="it.selectType" nzAllowClear nzPlaceHolder="Choose" style="width: 70%; margin-top: 5px;">
<nz-option *ngFor="let s of customTypeGroupArr[it.gIdx]?.select" [nzValue]="s.value" [nzLabel]="s.label">
</nz-option>
</nz-select>
</div>
<div *ngIf="customTypeGroupArr[it.gIdx]?.label" align="center" style="margin-top: 5px; display: flex; align-items: center; justify-content: center;">
<span style="width: 30%;">{{customTypeGroupArr[it.gIdx].label + ':'}}</span>
<input type="text" nz-input [(ngModel)]="it.labelText" (blur)="saveText(it)">
</div>
<!-- <div *ngIf="customTypeGroupArr[it.gIdx]?.mathLabel" align="center" style="margin-top: 5px; display: flex; align-items: center; justify-content: center;">-->
<!-- <span style="width: 30%;">{{customTypeGroupArr[it.gIdx].mathLabel + ':'}}</span>-->
<!-- <app-formula-input [(ngfModel)]="it.mathLabel" ></app-formula-input>-->
<!-- </div>-->
<div style=" height: 40px;">
<h5> item-{{i+1}}
<i style="margin-left: 20px; margin-top: 2px; float: right; cursor:pointer" (click)="deleteItem($event, i)" <div *ngIf="customTypeGroupArr[it.gIdx]?.isCopy" align="center" style="margin-top: 5px; display: flex; align-items: center; justify-content: center;">
nz-icon [nzTheme]="'twotone'" [nzType]="'close-circle'" [nzTwotoneColor]="'#ff0000'"></i> <button nz-button (click)="copyItem(it)" >
</h5> <i nz-icon nzType="copy" nzTheme="outline"></i>
复制粘贴
</button>
</div>
</div> </div>
<!--<div class="img-box-upload">-->
<!--<app-upload-image-with-preview-->
<!--[picUrl]="it.pic_url"-->
<!--(imageUploaded)="onImgUploadSuccessByImg($event, it)">-->
<!--</app-upload-image-with-preview>-->
<!--</div>-->
<!-- <div *ngIf="!customTypeGroupArr">
<div *ngIf="it.itemType == 'pic'">
<app-upload-image-with-preview
[picUrl]="it?.pic_url"
(imageUploaded)="onItemImgUploadSuccess($event, it)">
</app-upload-image-with-preview>
</div>
<!--<app-audio-recorder--> <div *ngIf="it.itemType == 'text'">
<!--[audioUrl]="it.audio_url ? it.audio_url : null "--> <input type="text" nz-input [(ngModel)]="it.text" (blur)="saveText(it)">
<!--(audioUploaded)="onAudioUploadSuccessByImg($event, it)"--> </div>
<!--&gt;</app-audio-recorder>-->
<div *ngIf="isHasAudio"
style="width: 100%; margin-top: 5px; display: flex; align-items: center; justify-items: center;">
<app-audio-recorder
style="margin: auto"
[audioUrl]="it.audio_url"
(audioUploaded)="onItemAudioUploadSuccess($event, it)"
></app-audio-recorder>
</div>
<div *ngIf="it.itemType == 'rect' && isHasAnima" align="center" style="margin-bottom: 5px">
<button nz-button (click)="setAnimaBtnClick(i)" >
<i nz-icon nzType="tool" nzTheme="outline"></i>
配置龙骨动画
</button>
</div> </div>
</div> -->
</div>
</div>
<div nz-col nzSpan="5" nzOffset="1"> <div nz-col nzSpan="5" nzOffset="1">
...@@ -74,16 +193,84 @@ ...@@ -74,16 +193,84 @@
<div class="save-box"> <div class="save-box">
<button class="save-btn" nz-button nzType="primary" [nzSize]="'large'" nzShape="round" <button style="margin-left: 200px" class="save-btn" nz-button nzType="primary" [nzSize]="'large'" nzShape="round"
(click)="saveClick()"> (click)="saveClick()" >
<i nz-icon type="save"></i> <i nz-icon nzType="save"></i>
Save Save
</button> </button>
<div *ngIf="isCopyData" style="height: 40px; display: flex; justify-items: center;" >
<label style="margin-left: 40px" nz-checkbox [(ngModel)]="bgItem.isShowDebugLine">显示辅助框</label>
<button style="margin-left: 20px; margin-top: -5px" nz-button (click)="copyHotZoneData()"> 复制基础数据 </button>
<div style="margin-left: 10px; margin-top: -5px" >
<span>粘贴数据: </span>
<input style="width: 100px;" type="text" nz-input [(ngModel)]="pasteData" >
<button style="margin-left: 5px;" nz-button [disabled]="pasteData==''" nzType="primary" (click)="importData()">导入</button>
</div> </div>
</div>
</div>
</div> </div>
<label style="opacity: 0; position: absolute; top: 0px; font-family: 'BRLNSR_1'">1</label>
<!--龙骨面板-->
<nz-modal [(nzVisible)]="animaPanelVisible" nzTitle="配置资源文件" (nzAfterClose)="closeAfterPanel()" (nzOnCancel)="animaPanelCancel()" (nzOnOk)="animaPanelOk()" nzOkText="保存">
<div class="anima-upload-btn">
<span style="margin-right: 10px">上传 ske_json 文件: </span>
<nz-upload [nzShowUploadList]="false"
nzAccept="application/json"
[nzAction]="uploadUrl"
[nzData]="uploadData"
(nzChange)="skeJsonHandleChange($event)">
<button nz-button><i nz-icon nzType="upload"></i><span>Upload</span></button>
</nz-upload>
<i *ngIf="isSkeJsonLoading" style="margin-left: 10px;" nz-icon [nzType]="'loading'"></i>
<span *ngIf="skeJsonData['name']" style="margin-left: 10px"><u> {{skeJsonData['name']}} </u></span>
</div>
<div class="anima-upload-btn">
<span style="margin-right: 10px">上传 tex_json 文件: </span>
<nz-upload [nzShowUploadList]="false"
nzAccept="application/json"
[nzAction]="uploadUrl"
[nzData]="uploadData"
(nzChange)="texJsonHandleChange($event)">
<button nz-button><i nz-icon nzType="upload"></i><span>Upload</span></button>
</nz-upload>
<i *ngIf="isTexJsonLoading" style="margin-left: 10px;" nz-icon [nzType]="'loading'"></i>
<span *ngIf="texJsonData['name']" style="margin-left: 10px"><u> {{texJsonData['name']}} </u></span>
</div>
<div class="anima-upload-btn">
<span style="margin-right: 10px">上传 tex_png 文件: </span>
<nz-upload [nzShowUploadList]="false"
nzAccept = "image/*"
[nzAction]="uploadUrl"
[nzData]="uploadData"
(nzChange)="texPngHandleChange($event)">
<button nz-button><i nz-icon nzType="upload"></i><span>Upload</span></button>
</nz-upload>
<i *ngIf="isTexPngLoading" style="margin-left: 10px;" nz-icon [nzType]="'loading'"></i>
<span *ngIf="texPngData['name']" style="margin-left: 10px"><u> {{texPngData['name']}} </u></span>
</div>
<div class="anima-upload-btn" *ngIf="customTypeGroupArr && customTypeGroupArr[curDragonBoneGIdx] && customTypeGroupArr[curDragonBoneGIdx].animaNames">
提示:需包含以下动画: {{customTypeGroupArr[curDragonBoneGIdx].animaNames.toString()}}
</div>
</nz-modal>
...@@ -81,12 +81,21 @@ ...@@ -81,12 +81,21 @@
} }
} }
.anima-upload-btn {
padding: 10px;
}
h5 { h5 {
margin-top: 1rem; margin-top: 1rem;
} }
@font-face
{
font-family: 'ahronbd-1';
src: url("/assets/font/ahronbd-1.ttf") ;
}
...@@ -100,104 +109,3 @@ h5 { ...@@ -100,104 +109,3 @@ h5 {
//@import '../../../style/common_mixin';
//
//.p-image-uploader {
// position: relative;
// display: block;
// width: 100%;
// height: 0;
// padding-bottom: 56.25%;
// .p-box {
// position: absolute;
// left: 0;
// top: 0;
// right: 0;
// bottom: 0;
// border: 2px dashed #ddd;
// border-radius: 0.5rem;
// background-color: #fafafa;
// text-align: center;
// color: #aaa;
// .p-upload-icon {
// text-align: center;
// margin: auto;
// .anticon-upload {
// color: #888;
// font-size: 5rem;
// }
// .p-progress-bar {
// position: relative;
// width: 20rem;
// height: 1.5rem;
// border: 1px solid #ccc;
// border-radius: 1rem;
// .p-progress-bg {
// background-color: #1890ff;
// border-radius: 1rem;
// height: 100%;
// }
// .p-progress-value {
// position: absolute;
// top: 0;
// left: 0;
// width: 100%;
// height: 100%;
// text-shadow: 0 0 4px #000;
// color: white;
// text-align: center;
// font-size: 0.9rem;
// line-height: 1.5rem;
// }
// }
// }
// .p-preview {
// width: 100%;
// height: 100%;
// //background-image: url("https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png");
// @include k-img-bg();
// }
// }
//}
//
//.p-btn-delete {
// position: absolute;
// right: -0.5rem;
// top: -0.5rem;
// width: 2rem;
// height: 2rem;
// border: 0.2rem solid white;
// border-radius: 50%;
// font-size: 1.2rem;
// background-color: #fb781a;
// color: white;
// text-align: center;
//}
//
//.p-upload-progress-bg {
// position: absolute;
// width: 100%;
// height: 100%;
// display: flex;
// align-items: center;
// justify-content: center;
// & .i-text {
// position: absolute;
// text-align: center;
// color: white;
// text-shadow: 0 0 2px rgba(0, 0, 0, .85);
// }
// & .i-bg {
// position: absolute;
// left: 0;
// top: 0;
// height: 100%;
// background-color: #27b43f;
// border-radius: 0.5rem;
// }
//}
//
//
//:host ::ng-deep .ant-upload {
// display: block;
//}
import {Component, ElementRef, EventEmitter, HostListener, Input, OnChanges, OnDestroy, OnInit, Output, ViewChild} from '@angular/core'; import {
ApplicationRef,
ChangeDetectorRef,
Component,
ElementRef,
EventEmitter,
HostListener,
Input,
OnChanges,
OnDestroy,
OnInit,
Output,
ViewChild
} from '@angular/core';
import {Subject} from 'rxjs'; import {Subject} from 'rxjs';
import {debounceTime} from 'rxjs/operators'; import {debounceTime} from 'rxjs/operators';
import {EditorItem, HotZoneItem, Label, MySprite} from './Unit'; import {DragItem, EditorItem, HotZoneImg, HotZoneItem, HotZoneLabel, Label, MySprite, removeItemFromArr, ShapeRect, ShapeRectNew} from './Unit';
import TWEEN from '@tweenjs/tween.js'; import TWEEN from '@tweenjs/tween.js';
import {getMinScale} from '../../play/Unit';
import {tar} from 'compressing';
import {NzMessageService} from 'ng-zorro-antd';
@Component({ @Component({
...@@ -12,100 +28,145 @@ import TWEEN from '@tweenjs/tween.js'; ...@@ -12,100 +28,145 @@ import TWEEN from '@tweenjs/tween.js';
}) })
export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
@ViewChild('canvas', {static: true}) canvas: ElementRef;
@ViewChild('wrap', {static: true}) wrap: ElementRef;
_bgItem = null;
@Input() @Input()
set bgItem(v) { hotZoneItemArr = null;
this._bgItem = v;
this.init();
}
get bgItem() {
return this._bgItem;
}
@Input() @Input()
imgItemArr = null; hotZoneArr = null;
@Input() @Input()
hotZoneItemArr = null; isHasRect = true;
@Input()
isHasPic = true;
@Input()
isHasText = true;
@Input()
isHasAudio = true;
@Input()
isHasAnima = false;
@Input()
customTypeGroupArr; // [{name:string, rect:boolean, pic:boolean, text:boolean, audio:boolean, anima:boolean, animaNames:['name1', ..]}, ...]
@Input()
// hotZoneFontObj;
@Input()
isCopyData = false;
hotZoneFontObj;
// hotZoneFontObj = {
// size: 50,
// name: 'ahronbd-1',
// color: '#8f3758'
// }
@Input() @Input()
hotZoneArr = null; defaultItemType = 'text';
@Input()
hotZoneImgSize = 0;
@Output() @Output()
save = new EventEmitter(); save = new EventEmitter();
@ViewChild('canvas') canvas: ElementRef;
@ViewChild('wrap') wrap: ElementRef; saveDisabled = true;
// @HostListener('window:resize', ['$event'])
canvasWidth = 1280; canvasWidth = 1280;
canvasHeight = 720; canvasHeight = 720;
canvasBaseW = 1280; canvasBaseW = 1280;
// @HostListener('window:resize', ['$event'])
canvasBaseH = 720; canvasBaseH = 720;
mapScale = 1; mapScale = 1;
ctx; ctx;
mx; mx;
my; // 点击坐标 my; // 点击坐标
// 资源
// rawImages = new Map(res);
// 声音 // 声音
bgAudio = new Audio(); bgAudio = new Audio();
images = new Map(); images = new Map();
animationId: any; animationId: any;
// winResizeEventStream = new Subject();
// 资源
// rawImages = new Map(res);
winResizeEventStream = new Subject();
canvasLeft; canvasLeft;
canvasTop; canvasTop;
renderArr; renderArr;
imgArr = []; imgArr = [];
oldPos; oldPos;
radioValue;
curItem; curItem;
bg: MySprite; bg: MySprite;
changeSizeFlag = false; changeSizeFlag = false;
changeTopSizeFlag = false; changeTopSizeFlag = false;
changeRightSizeFlag = false; changeRightSizeFlag = false;
animaPanelVisible = false;
uploadUrl;
uploadData;
skeJsonData = {};
texJsonData = {};
texPngData = {};
animaName = '';
curDragonBoneIndex;
curDragonBoneGIdx;
pasteData = '';
isSkeJsonLoading = false;
isTexJsonLoading = false;
isTexPngLoading = false;
isAnimaSmall = false;
savePropertyArr = [
'id',
'gIdx',
'selectType',
'labelText',
'posX',
'posY',
'mathLabel',
]
constructor(private nzMessageService: NzMessageService, private appRef: ApplicationRef, private changeDetectorRef: ChangeDetectorRef) {
this.uploadUrl = (<any> window).courseware.uploadUrl();
this.uploadData = (<any> window).courseware.uploadData();
window['air'].getUploadCallback = (url, data) => {
this.uploadUrl = url;
this.uploadData = data;
};
}
_bgItem = null;
get bgItem() {
constructor() { return this._bgItem;
} }
@Input()
set bgItem(v) {
this._bgItem = v;
this.init();
}
onResize(event) { onResize(event) {
// this.winResizeEventStream.next(); this.winResizeEventStream.next();
} }
ngOnInit() { ngOnInit() {
this.initListener(); this.initListener();
// this.init(); // this.init();
this.update(); this.update();
this.refresh();
} }
ngOnDestroy() { ngOnDestroy() {
...@@ -118,13 +179,24 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { ...@@ -118,13 +179,24 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
} }
onBackgroundUploadSuccess(e) { onBackgroundUploadSuccess(e) {
console.log('e: ', e); console.log('e: ', e);
this.bgItem.url = e.url; this.bgItem.url = e.url;
this.refreshBackground(); this.refreshBackground();
} }
onItemImgUploadSuccess(e, item) {
item.pic_url = e.url;
this.loadHotZonePic(item.pic, e.url);
this.refresh();
}
onItemAudioUploadSuccess(e, item) {
item.audio_url = e.url;
this.refresh();
}
refreshBackground(callBack = null) { refreshBackground(callBack = null) {
if (!this.bg) { if (!this.bg) {
...@@ -132,8 +204,12 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { ...@@ -132,8 +204,12 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
this.renderArr.push(this.bg); this.renderArr.push(this.bg);
} }
if (!this.bgItem.url) {
this.bgItem.url = 'http://teach.cdn.ireadabc.com/8ebb1858564340ea0936b83e3280ad7d.jpg';
}
const bg = this.bg; const bg = this.bg;
if (this.bgItem.url) { // if (this.bgItem.url) {
bg.load(this.bgItem.url).then(() => { bg.load(this.bgItem.url).then(() => {
const rate1 = this.canvasWidth / bg.width; const rate1 = this.canvasWidth / bg.width;
...@@ -142,34 +218,67 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { ...@@ -142,34 +218,67 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
const rate = Math.min(rate1, rate2); const rate = Math.min(rate1, rate2);
bg.setScaleXY(rate); bg.setScaleXY(rate);
bg.x = this.canvasWidth / 2; bg.x = this.canvasWidth / 2;
bg.y = this.canvasHeight / 2; bg.y = this.canvasHeight / 2;
bg.removeChildren();
const bgBorder = new ShapeRectNew(this.ctx);
bgBorder.setSize(bg.width, bg.height, 0);
bgBorder.fillColor = '#ff0000';
bgBorder.fill = false;
bgBorder.stroke = true;
bgBorder.x = -bg.width / 2;
bgBorder.y = -bg.height / 2;
bgBorder.lineWidth = 0.5;
bg.addChild(bgBorder);
if (callBack) { if (callBack) {
callBack(); callBack();
} }
this.refresh();
}); });
} // }
} }
addBtnClick() { addBtnClick(data=null) {
// this.imgArr.push({}); // this.imgArr.push({});
// this.hotZoneArr.push({}); // this.hotZoneArr.push({});
const item = this.getHotZoneItem(); const item = this.getHotZoneItem(data);
this.hotZoneArr.push(item); this.hotZoneArr.push(item);
if (this.customTypeGroupArr) {
this.refreshCustomItem(item);
} else {
this.refreshItem(item);
}
this.refreshHotZoneId();
}
deleteBtnClick(index) {
const item = this.hotZoneArr.splice(index, 1)[0];
removeItemFromArr(this.renderArr, item.pic);
removeItemFromArr(this.renderArr, item.textLabel);
removeItemFromArr(this.renderArr, item.drag);
this.refreshHotZoneId(); this.refreshHotZoneId();
console.log('hotZoneArr:', this.hotZoneArr);
} }
onImgUploadSuccessByImg(e, img) { onImgUploadSuccessByImg(e, img) {
img.pic_url = e.url; img.pic_url = e.url;
this.refreshImage (img); this.refreshImage(img);
this.refresh();
} }
refreshImage(img) { refreshImage(img) {
...@@ -188,10 +297,11 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { ...@@ -188,10 +297,11 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
this.hotZoneArr[i].index = i; this.hotZoneArr[i].index = i;
if (this.hotZoneArr[i]) { if (this.hotZoneArr[i]) {
this.hotZoneArr[i].text = 'item-' + (i + 1); this.hotZoneArr[i].title = 'item-' + (i + 1);
} }
} }
this.refresh();
} }
...@@ -206,7 +316,7 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { ...@@ -206,7 +316,7 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
} }
getHotZoneItem( saveData = null) { getHotZoneItem(saveData = null) {
const itemW = 200; const itemW = 200;
...@@ -216,31 +326,229 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { ...@@ -216,31 +326,229 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
item.anchorX = 0.5; item.anchorX = 0.5;
item.anchorY = 0.5; item.anchorY = 0.5;
item.x = this.canvasWidth / 2; item.x = this.canvasWidth / 2;
item.y = this.canvasHeight / 2; item.y = this.canvasHeight / 2;
item.itemType = this.getDefaultItemType();
item.gIdx = '0';
item['id'] = this.createItemId() // new Date().getTime().toString();
item['data'] = saveData;
console.log('item.x: ', item.x);
if (saveData) { if (saveData) {
const saveRect = saveData.rect; const saveRect = saveData.rect;
item.scaleX = saveRect.width / item.width; item.scaleX = saveRect.width / item.width;
item.scaleY = saveRect.height / item.height; item.scaleY = saveRect.height / item.height;
item.x = saveRect.x + saveRect.width / 2 ; item.x = saveRect.x + saveRect.width / 2;
item.y = saveRect.y + saveRect.height / 2; item.y = saveRect.y + saveRect.height / 2;
item.gIdx = saveData.gIdx;
item['id'] = saveData.id;
item['skeJsonData'] = saveData.skeJsonData;
item['texJsonData'] = saveData.texJsonData;
item['texPngData'] = saveData.texPngData;
item['actionData_' + item.gIdx] = saveData['actionData_' + item.gIdx];
this.savePropertyArr.forEach((key) => {
if (saveData[key]) {
item[key] = saveData[key];
}
})
} }
console.log('item.x:~~ ', item.x);
item.showLineDash(); item.showLineDash();
// const pic = new HotZoneImg(this.ctx);
this.setItemPic(item, saveData);
this.setItemLabel(item, saveData);
this.setItemAnima(item, saveData);
this.setItemDrag(item, saveData);
return item; return item;
} }
setItemPic(item, saveData) {
console.log('in setItemPic ', saveData);
const pic = new EditorItem(this.ctx);
pic.visible = false;
item['pic'] = pic;
if (saveData) {
let picUrl = saveData.pic_url;
const actionData = saveData['actionData_' + item.gIdx];
if (actionData && actionData.type == 'pic') {
picUrl = actionData.pic_url;
}
console.log('saveData: ', saveData);
console.log('picUrl: ', picUrl);
if (picUrl) {
this.loadHotZonePic(pic, picUrl, saveData.imgScale);
}
}
pic.x = item.x;
pic.y = item.y;
this.renderArr.push(pic);
}
setItemDrag(item, saveData) {
console.log('in setItemDrag ', saveData);
const dragItem = new DragItem(this.ctx);
dragItem.init();
dragItem.item = item;
item['drag'] = dragItem;
dragItem.visible = false;
dragItem.x = item.x;
dragItem.y = item.y;
this.renderArr.push(dragItem);
if (saveData) {
if (saveData.dragDot) {
dragItem.x = saveData.dragDot.x / saveData.mapScale * this.mapScale;
dragItem.y = saveData.dragDot.y / saveData.mapScale * this.mapScale;
}
}
// console.log('item.itemType: ', item.itemType);
// let w = item.width;
// let h = item.height;
// if (saveData) {
// switch (saveData.itemType) {
// case 'rect':
// w = saveData.rect.width;
// h = saveData.rect.height;
// break;
// case 'pic':
// w = saveData.imgSizeW * saveData.imgScale;
// h = saveData.imgSizeH * saveData.imgScale;;
// break;
// case 'text':
// w = saveData.rect.width;
// h = saveData.rect.height;
// break;
// }
// }
// dragItem.setSize(w, h);
}
setItemAnima(item, saveData) {
console.log('in setItemAnima ', saveData);
// const pic = new EditorItem(this.ctx);
// pic.visible = false;
// item['pic'] = pic;
// if (saveData) {
// let picUrl = saveData.pic_url;
// const actionData = saveData['actionData_' + item.gIdx];
// if (actionData && actionData.type == 'pic') {
// picUrl = actionData.pic_url;
// }
// console.log('saveData: ', saveData);
// console.log('picUrl: ', picUrl);
// if (picUrl) {
// this.loadHotZonePic(pic, picUrl, saveData.imgScale);
// }
// }
// pic.x = item.x;
// pic.y = item.y;
// this.renderArr.push(pic);
}
setItemLabel(item, saveData) {
const textLabel = new HotZoneLabel(this.ctx);
if (this.hotZoneFontObj) {
textLabel.fontSize = this.hotZoneFontObj.size;
textLabel.fontName = this.hotZoneFontObj.name;
textLabel.fontColor = this.hotZoneFontObj.color;
}
textLabel.textAlign = 'center';
// textLabel.setOutline();
item['textLabel'] = textLabel;
textLabel.setScaleXY(this.mapScale);
if (saveData) {
if (saveData.text && this.hotZoneFontObj) {
textLabel.text = saveData.text
}
this.setActionFont(textLabel, saveData['actionData_' + item.gIdx]);
textLabel.refreshSize();
}
textLabel.x = item.x;
textLabel.y = item.y;
this.renderArr.push(textLabel);
}
setActionFont(textLabel, actionData) {
if (actionData && actionData.type == 'text') {
textLabel.text = actionData.text;
for (let i=0; i<actionData.changeOption.length; i++) {
const op = actionData.changeOption[i];
textLabel[op[0]] = op[1];
}
}
}
getDefaultItemType() {
if (this.customTypeGroupArr) {
const group = this.customTypeGroupArr[0];
if (group.rect) {
return 'rect';
}
if (group.pic) {
return 'pic';
}
if (group.text) {
return 'text';
}
} else {
return this.defaultItemType;
}
}
getPicItem(img, saveData = null) { getPicItem(img, saveData = null) {
const item = new EditorItem(this.ctx); const item = new EditorItem(this.ctx);
item.load(img.pic_url).then( img => { item.load(img.pic_url).then(img => {
let maxW, maxH; let maxW, maxH;
if (this.bg) { if (this.bg) {
...@@ -266,13 +574,15 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { ...@@ -266,13 +574,15 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
const saveRect = saveData.rect; const saveRect = saveData.rect;
item.setScaleXY(saveRect.width / item.width); item.setScaleXY(saveRect.width / item.width);
item.x = saveRect.x + saveRect.width / 2 ; item.x = saveRect.x + saveRect.width / 2;
item.y = saveRect.y + saveRect.height / 2; item.y = saveRect.y + saveRect.height / 2;
} else { } else {
item.showLineDash(); // item.showLineDash();
} }
item.showLineDash();
console.log('aaa');
}); });
return item; return item;
} }
...@@ -280,6 +590,7 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { ...@@ -280,6 +590,7 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
onAudioUploadSuccessByImg(e, img) { onAudioUploadSuccessByImg(e, img) {
img.audio_url = e.url; img.audio_url = e.url;
this.refresh();
} }
deleteItem(e, i) { deleteItem(e, i) {
...@@ -288,35 +599,148 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { ...@@ -288,35 +599,148 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
this.hotZoneArr.splice(i, 1); this.hotZoneArr.splice(i, 1);
this.refreshHotZoneId(); this.refreshHotZoneId();
this.refresh();
}
// radioChange(e, item) {
// item.itemType = e;
// this.refreshItem(item);
// this.refresh();
// // console.log(' in radioChange e: ', e);
// }
customRadioChange(e, item) {
console.log('in customRadioChange', e);
item.gIdx = -1;
setTimeout(() => {
item.gIdx = e;
this.refreshCustomItem(item);
this.refresh();
}, 1);
// const curGroup = this.customTypeGroupArr[e];
}
refreshCustomItem(item) {
this.hideHotZoneItem(item);
const group = this.customTypeGroupArr[item.gIdx];
if (!group) {
return;
}
if (group.text) {
this.showItemLabel(item);
}
if (group.rect) {
this.showItemRect(item, !group.isFixed);
}
if (group.pic && !group.anima) {
this.showItemPic(item);
}
if (group.action) {
if (group.action.type == 'pic') {
this.showItemPic(item);
}
if (group.action.type == 'text') {
this.showItemLabel(item);
}
if (group.action.type == 'anima') {
this.showItemRect(item);
}
}
item.drag.visible = group.drag;
item.setAnimaStyle(group.animaSmall)
}
showItemDrag(item) {
item.drag.visible = true;
// item.dragBody.visible = true;
// item.itemType = 'pic';
// this.showArrowTop(item)
}
showItemPic(item) {
item.pic.visible = true;
item.itemType = 'pic';
this.showArrowTop(item, true)
} }
showItemLabel(item) {
item.textLabel.visible = true;
item.itemType = 'text';
this.showArrowTop(item)
}
showItemRect(item, isShowArrowTop = true) {
item.visible = true;
item.itemType = 'rect';
this.showArrowTop(item, isShowArrowTop)
}
showArrowTop(item, isShowArrowTop = false) {
if (isShowArrowTop) {
item.arrowTop.visible = true;
item.arrowRight.visible = true;
} else {
item.arrowTop.visible = false;
item.arrowRight.visible = false;
}
}
hideHotZoneItem(item) {
item.visible = false;
item.pic.visible = false;
item.textLabel.visible = false;
}
refreshItem(item) {
switch (item.itemType) {
case 'rect':
this.setRectState(item);
break;
case 'pic':
this.setPicState(item);
break;
case 'text':
this.setTextState(item);
break;
default:
this.setNoneState(item);
}
}
init() { init() {
console.log('init');
this.initData(); this.initData();
this.initCtx(); this.initCtx();
this.initItem(); this.initItem();
} }
initItem() { initItem() {
this.changeDetectorRef.markForCheck();
this.changeDetectorRef.detectChanges();
if (!this.bgItem) { if (!this.bgItem) {
this.bgItem = {}; this.bgItem = {};
} else { } else {
this.refreshBackground(() => { this.refreshBackground(() => {
// if (!this.imgItemArr) {
// this.imgItemArr = [];
// } else {
// this.initImgArr();
// }
// console.log('aaaaa');
if (!this.hotZoneItemArr) { if (!this.hotZoneItemArr) {
this.hotZoneItemArr = []; this.hotZoneItemArr = [];
...@@ -327,6 +751,7 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { ...@@ -327,6 +751,7 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
}); });
} }
this.refresh();
} }
initHotZoneArr() { initHotZoneArr() {
...@@ -350,6 +775,7 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { ...@@ -350,6 +775,7 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
this.hotZoneArr = []; this.hotZoneArr = [];
const arr = this.hotZoneItemArr.concat(); const arr = this.hotZoneItemArr.concat();
console.log('this.hotZoneItemArr: ', this.hotZoneItemArr);
for (let i = 0; i < arr.length; i++) { for (let i = 0; i < arr.length; i++) {
const data = JSON.parse(JSON.stringify(arr[i])); const data = JSON.parse(JSON.stringify(arr[i]));
...@@ -367,59 +793,28 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { ...@@ -367,59 +793,28 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
// img['audio_url'] = arr[i].audio_url; // img['audio_url'] = arr[i].audio_url;
// this.imgArr.push(img); // this.imgArr.push(img);
const item = this.getHotZoneItem( data); const item = this.getHotZoneItem(data);
console.log('item: ', item); item.audio_url = data.audio_url;
this.hotZoneArr.push(item); item.pic_url = data.pic_url;
item.text = data.text;
} item.itemType = data.itemType;
this.refreshHotZoneId();
// this.refreshImageId();
}
if (this.customTypeGroupArr) {
this.refreshCustomItem(item);
initImgArr() {
console.log('this.imgItemArr: ', this.imgItemArr);
let curBgRect;
if (this.bg) {
curBgRect = this.bg.getBoundingBox();
} else { } else {
curBgRect = {x: 0, y: 0, width: this.canvasWidth, height: this.canvasHeight}; this.refreshItem(item);
}
let oldBgRect = this.bgItem.rect;
if (!oldBgRect) {
oldBgRect = curBgRect;
} }
const rate = curBgRect.width / oldBgRect.width;
console.log('rate: ', rate);
this.imgArr = []; console.log('1 item: ', item);
const arr = this.imgItemArr.concat(); this.hotZoneArr.push(item);
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; this.refreshHotZoneId();
data.rect.y *= rate;
data.rect.width *= rate;
data.rect.height *= rate;
data.rect.x += curBgRect.x; // this.refreshImageId();
data.rect.y += curBgRect.y;
img['picItem'] = this.getPicItem(img, data);
img['audio_url'] = arr[i].audio_url;
this.imgArr.push(img);
}
this.refreshImageId();
} }
...@@ -446,34 +841,59 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { ...@@ -446,34 +841,59 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
this.oldPos = {x: this.mx, y: this.my}; this.oldPos = {x: this.mx, y: this.my};
const arr = this.hotZoneArr;
for (let i = arr.length - 1; i >= 0 ; i--) { // 先检测拖拽点
const item = arr[i]; for (let i = this.hotZoneArr.length - 1; i >= 0; i--) {
if (item) { const item = this.hotZoneArr[i];
if (this.checkClickTarget(item)) {
if (item.lineDashFlag && this.checkClickTarget(item.arrow)) { if (item && item.drag && item.drag.visible) {
this.changeItemSize(item);
} else if (item.lineDashFlag && this.checkClickTarget(item.arrowTop)) { if (this.checkClickTarget(item.drag)) {
this.changeItemTopSize(item);
} else if (item.lineDashFlag && this.checkClickTarget(item.arrowRight)) { this.clickedDragPoint(item.drag);
this.changeItemRightSize(item);
} else {
this.changeCurItem(item);
}
return; return;
} }
} }
} }
// this.hideAllLineDash(); for (let i = this.hotZoneArr.length - 1; i >= 0; i--) {
const item = this.hotZoneArr[i];
console.log('mapDown item: ', item);
let callback;
let target;
switch (item.itemType) {
case 'rect':
target = item;
callback = this.clickedHotZoneRect.bind(this);
break;
case 'pic':
target = item.pic;
callback = this.clickedHotZonePic.bind(this);
break;
case 'text':
target = item.textLabel;
callback = this.clickedHotZoneText.bind(this);
break;
}
if (target && this.checkClickTarget(target)) {
callback(target);
return;
}
}
} }
mapMove(event) { mapMove(event) {
if (!this.curItem) { return; } if (!this.curItem) {
return;
}
if (this.changeSizeFlag) { if (this.changeSizeFlag) {
this.changeSize(); this.changeSize();
...@@ -490,12 +910,18 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { ...@@ -490,12 +910,18 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
const addY = this.my - this.oldPos.y; const addY = this.my - this.oldPos.y;
this.curItem.x += addX; this.curItem.x += addX;
this.curItem.y += addY; this.curItem.y += addY;
this.curItem.posX = this.curItem.x;
this.curItem.posY = this.curItem.y;
} }
this.oldPos = {x: this.mx, y: this.my}; this.oldPos = {x: this.mx, y: this.my};
// this.saveDisabled = false;
} }
mapUp(event) { mapUp(event=null) {
this.curItem = null; this.curItem = null;
this.changeSizeFlag = false; this.changeSizeFlag = false;
this.changeTopSizeFlag = false; this.changeTopSizeFlag = false;
...@@ -503,13 +929,11 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { ...@@ -503,13 +929,11 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
} }
changeSize() { changeSize() {
const rect = this.curItem.getBoundingBox(); const rect = this.curItem.getBoundingBox();
let lenW = ( this.mx - (rect.x + rect.width / 2) ) * 2; let lenW = (this.mx - (rect.x + rect.width / 2)) * 2;
let lenH = ( (rect.y + rect.height / 2) - this.my ) * 2; let lenH = ((rect.y + rect.height / 2) - this.my) * 2;
let minLen = 20; let minLen = 20;
...@@ -538,7 +962,7 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { ...@@ -538,7 +962,7 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
const rect = this.curItem.getBoundingBox(); const rect = this.curItem.getBoundingBox();
// let lenW = ( this.mx - (rect.x + rect.width / 2) ) * 2; // let lenW = ( this.mx - (rect.x + rect.width / 2) ) * 2;
let lenH = ( (rect.y + rect.height / 2) - this.my ) * 2; let lenH = ((rect.y + rect.height / 2) - this.my) * 2;
let minLen = 20; let minLen = 20;
...@@ -565,7 +989,7 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { ...@@ -565,7 +989,7 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
changeRightSize() { changeRightSize() {
const rect = this.curItem.getBoundingBox(); const rect = this.curItem.getBoundingBox();
let lenW = ( this.mx - (rect.x + rect.width / 2) ) * 2; let lenW = (this.mx - (rect.x + rect.width / 2)) * 2;
// let lenH = ( (rect.y + rect.height / 2) - this.my ) * 2; // let lenH = ( (rect.y + rect.height / 2) - this.my ) * 2;
let minLen = 20; let minLen = 20;
...@@ -596,10 +1020,13 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { ...@@ -596,10 +1020,13 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
changeCurItem(item) { changeCurItem(item) {
console.log(' in changeCurItem', item)
this.hideAllLineDash(); this.hideAllLineDash();
this.curItem = item; this.curItem = item;
this.curItem.showLineDash(); this.curItem.showLineDash();
} }
hideAllLineDash() { hideAllLineDash() {
...@@ -613,16 +1040,16 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { ...@@ -613,16 +1040,16 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
update() { update() {
if (!this.ctx) {
return;
}
this.animationId = window.requestAnimationFrame(this.update.bind(this)); this.animationId = window.requestAnimationFrame(this.update.bind(this));
// 清除画布内容 // 清除画布内容
this.ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight); this.ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight);
for (let i = 0; i < this.renderArr.length; i++) {
this.renderArr[i].update(this);
}
// for (let i = 0; i < this.imgArr.length; i++) { // for (let i = 0; i < this.imgArr.length; i++) {
// const picItem = this.imgArr[i].picItem; // const picItem = this.imgArr[i].picItem;
...@@ -631,9 +1058,18 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { ...@@ -631,9 +1058,18 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
// } // }
// } // }
for (let i = 0; i < this.renderArr.length; i++) {
this.renderArr[i].update(this);
}
this.updateArr(this.hotZoneArr); this.updateArr(this.hotZoneArr);
this.updatePos();
TWEEN.update(); TWEEN.update();
} }
...@@ -646,7 +1082,6 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { ...@@ -646,7 +1082,6 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
} }
renderAfterResize() { renderAfterResize() {
this.canvasWidth = this.wrap.nativeElement.clientWidth; this.canvasWidth = this.wrap.nativeElement.clientWidth;
this.canvasHeight = this.wrap.nativeElement.clientHeight; this.canvasHeight = this.wrap.nativeElement.clientHeight;
...@@ -655,11 +1090,11 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { ...@@ -655,11 +1090,11 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
initListener() { initListener() {
// this.winResizeEventStream this.winResizeEventStream
// .pipe(debounceTime(500)) .pipe(debounceTime(500))
// .subscribe(data => { .subscribe(data => {
// this.renderAfterResize(); this.renderAfterResize();
// }); });
if (this.IsPC()) { if (this.IsPC()) {
...@@ -742,7 +1177,9 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { ...@@ -742,7 +1177,9 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
checkClickTarget(target) { checkClickTarget(target) {
if (!target || !target.visible) {
return;
}
const rect = target.getBoundingBox(); const rect = target.getBoundingBox();
if (this.checkPointInRect(this.mx, this.my, rect)) { if (this.checkPointInRect(this.mx, this.my, rect)) {
return true; return true;
...@@ -761,51 +1198,580 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { ...@@ -761,51 +1198,580 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
saveClick() { saveClick() {
const sendData = this.getSendData();
this.save.emit(sendData);
}
getSendData() {
const bgItem = this.bgItem; const bgItem = this.bgItem;
if (this.bg) { if (this.bg) {
bgItem['rect'] = this.bg.getBoundingBox(); const rect = this.bg.getBoundingBox();
bgItem['rect'] = rect;
rect.x = Math.round(rect.x * 100) / 100;
rect.y = Math.round(rect.y * 100) / 100;
rect.width = Math.round(rect.width * 100) / 100;
rect.height = Math.round(rect.height * 100) / 100;
} else { } else {
bgItem['rect'] = {x: 0, y: 0, width: Math.round(this.canvasWidth * 100) / 100, height: Math.round(this.canvasHeight * 100) / 100}; bgItem['rect'] = {
x: 0,
y: 0,
width: Math.round(this.canvasWidth * 100) / 100,
height: Math.round(this.canvasHeight * 100) / 100
};
} }
// const imgItemArr = [];
// const imgArr = this.imgArr;
// for (let i = 0; i < imgArr.length; i++) {
//
// const imgItem = {
// id: imgArr[i].id,
// pic_url: imgArr[i].pic_url,
// audio_url: imgArr[i].audio_url,
// };
// if (imgArr[i].picItem) {
// imgItem['rect'] = imgArr[i].picItem.getBoundingBox();
// imgItem['rect'].x -= bgItem['rect'].x;
// imgItem['rect'].y -= bgItem['rect'].y;
// }
// imgItemArr.push(imgItem);
// }
const hotZoneItemArr = []; const hotZoneItemArr = [];
const hotZoneArr = this.hotZoneArr; const hotZoneArr = this.hotZoneArr;
for (let i = 0; i < hotZoneArr.length; i++) { for (let i = 0; i < hotZoneArr.length; i++) {
const hotZoneItem = { const hotZoneItem = {
id: hotZoneArr[i].id,
index: hotZoneArr[i].index, index: hotZoneArr[i].index,
pic_url: hotZoneArr[i].pic_url,
text: hotZoneArr[i].text,
audio_url: hotZoneArr[i].audio_url,
itemType: hotZoneArr[i].itemType,
fontScale: hotZoneArr[i].textLabel ? hotZoneArr[i].textLabel.scaleX : 1,
imgScale: hotZoneArr[i].pic ? hotZoneArr[i].pic.scaleX : 1,
imgSizeW: hotZoneArr[i].pic ? hotZoneArr[i].pic.width : 0,
imgSizeH: hotZoneArr[i].pic ? hotZoneArr[i].pic.height : 0,
mapScale: this.mapScale,
skeJsonData: hotZoneArr[i].skeJsonData,
texJsonData: hotZoneArr[i].texJsonData,
texPngData: hotZoneArr[i].texPngData,
dragDot: hotZoneArr[i].drag.getPosition(),
gIdx: hotZoneArr[i].gIdx,
}; };
this.savePropertyArr.forEach((key) => {
if (hotZoneArr[i][key]) {
hotZoneItem[key] = hotZoneArr[i][key];
}
})
hotZoneItem['actionData_' + hotZoneItem.gIdx] = hotZoneArr[i]['actionData_' + hotZoneArr[i].gIdx]
if (this.hotZoneFontObj) {
hotZoneItem['fontSize'] = this.hotZoneFontObj.size;
hotZoneItem['fontName'] = this.hotZoneFontObj.name;
hotZoneItem['ontColor'] = this.hotZoneFontObj.color;
}
if (hotZoneArr[i].itemType == 'pic') {
hotZoneItem['rect'] = hotZoneArr[i].pic.getBoundingBox();
} else if (hotZoneArr[i].itemType == 'text') {
hotZoneArr[i].textLabel.refreshSize();
hotZoneItem['rect'] = hotZoneArr[i].textLabel.getLabelRect();
// hotZoneItem['rect'].width = hotZoneItem['rect'].width / hotZoneArr[i].textLabel.scaleX;
// hotZoneItem['rect'].height = hotZoneArr[i].textLabel.height * hotZoneArr[i].textLabel.scaleY;
} else {
hotZoneItem['rect'] = hotZoneArr[i].getBoundingBox(); hotZoneItem['rect'] = hotZoneArr[i].getBoundingBox();
hotZoneItem['rect'].x = Math.round( (hotZoneItem['rect'].x - bgItem['rect'].x) * 100) / 100; }
hotZoneItem['rect'].y = Math.round( (hotZoneItem['rect'].y - bgItem['rect'].y) * 100) / 100; // hotZoneItem['rect'] = hotZoneArr[i].getBoundingBox();
hotZoneItem['rect'].width = Math.round( (hotZoneItem['rect'].width) * 100) / 100; hotZoneItem['rect'].x = Math.round((hotZoneItem['rect'].x - bgItem['rect'].x) * 100) / 100;
hotZoneItem['rect'].height = Math.round( (hotZoneItem['rect'].height) * 100) / 100; hotZoneItem['rect'].y = Math.round((hotZoneItem['rect'].y - bgItem['rect'].y) * 100) / 100;
hotZoneItem['rect'].width = Math.round((hotZoneItem['rect'].width) * 100) / 100;
hotZoneItem['rect'].height = Math.round((hotZoneItem['rect'].height) * 100) / 100;
hotZoneItemArr.push(hotZoneItem); hotZoneItemArr.push(hotZoneItem);
} }
console.log('hotZoneItemArr: ', hotZoneItemArr); console.log('hotZoneItemArr: ', hotZoneItemArr);
this.save.emit({bgItem, hotZoneItemArr}); return {bgItem, hotZoneItemArr};
} }
saveText(item) {
if (item.itemType == 'text') {
item.textLabel.text = item.text;
}
}
saveItemPos(item) {
console.log('item.posX: ', item.posX)
console.log('item.posY: ', item.posY)
item.x = Number(item.posX || 0)
item.y = Number(item.posY || 0)
// this.changeCurItem(item);
// this.curItem.x = item.posX || 0;
// this.curItem.y = item.posY || 0;
// this.mapUp();
}
onSaveCustomAction(e, item) {
const data = e;
item['actionData_' + item.gIdx] = data;
if (data.type == 'pic') {
let picUrl = data.pic_url;
if (picUrl) {
this.loadHotZonePic(item.pic, picUrl);
}
}
if (data.type == 'text') {
this.setActionFont(item.textLabel, data);
item.textLabel.refreshSize();
}
// if (data.type == 'anima') {
// this.setActionAnima(item.anima, data);
// }
// this.loadHotZonePic(item.pic, e.url);
this.refresh()
}
setActionAnima() {
}
setAnimaBtnClick(index) {
console.log('aaaa')
this.isAnimaSmall = false;
this.setCurDragonBone(index);
// this.curDragonBoneIndex = index;
// this.curDragonBoneGIdx = Number(this.hotZoneArr[index].gIdx);
// const {skeJsonData, texJsonData, texPngData} = this.hotZoneArr[index];
// this.skeJsonData = skeJsonData || {};
// this.texJsonData = texJsonData || {};
// this.texPngData = texPngData || {};
// this.animaPanelVisible = true;
// this.refresh();
}
setAnimaSmallBtnClick(index) {
console.log('bbb')
this.isAnimaSmall = true;
this.setCurDragonBone(index);
}
setCurDragonBone(index) {
this.curDragonBoneIndex = index;
this.curDragonBoneGIdx = Number(this.hotZoneArr[index].gIdx);
const {skeJsonData, texJsonData, texPngData} = this.hotZoneArr[index];
this.skeJsonData = skeJsonData || {};
this.texJsonData = texJsonData || {};
this.texPngData = texPngData || {};
this.animaPanelVisible = true;
this.refresh();
}
setItemSizeByAnima(jsonData, item) {
console.log('json: ', jsonData);
const request = new XMLHttpRequest();
//通过url获取文件,第二个选项是文件所在的具体地址
request.open('GET', jsonData.url, true);
request.send(null);
request.onreadystatechange = ()=> {
if (request.readyState === 4 && request.status === 200) {
var type = request.getResponseHeader('Content-Type');
if (type.indexOf("text") !== 1) {
//返回一个文件内容的对象
const data = JSON.parse(request.responseText);
console.log('request.responseText;', data)
const animaSize = data.armature[0].canvas;
item.width = animaSize.width;
item.height = animaSize.height;
// return request.responseText;
}
}
}
}
animaPanelCancel() {
this.animaPanelVisible = false;
this.refresh();
}
animaPanelOk() {
this.setItemDragonBoneData(this.hotZoneArr[this.curDragonBoneIndex]);
console.log('this.hotZoneArr: ', this.hotZoneArr);
this.animaPanelVisible = false;
if (this.isAnimaSmall) {
this.setItemSizeByAnima(this.skeJsonData, this.hotZoneArr[this.curDragonBoneIndex]);
}
this.refresh();
}
setItemDragonBoneData(item) {
item['skeJsonData'] = this.skeJsonData;
item['texJsonData'] = this.texJsonData;
item['texPngData'] = this.texPngData;
}
skeJsonHandleChange(e) {
console.log('e: ', e);
switch (e.type) {
case 'start':
this.isSkeJsonLoading = true;
break;
case 'success':
this.skeJsonData['url'] = e.file.response.url;
this.skeJsonData['name'] = e.file.name;
this.nzMessageService.success('上传成功');
this.isSkeJsonLoading = false;
break;
case 'progress':
break;
}
}
texJsonHandleChange(e) {
console.log('e: ', e);
switch (e.type) {
case 'start':
this.isTexJsonLoading = true;
break;
case 'success':
this.texJsonData['url'] = e.file.response.url;
this.texJsonData['name'] = e.file.name;
this.nzMessageService.success('上传成功');
this.isTexJsonLoading = false;
break;
case 'progress':
break;
}
}
texPngHandleChange(e) {
console.log('e: ', e);
switch (e.type) {
case 'start':
this.isTexPngLoading = true;
break;
case 'success':
this.texPngData['url'] = e.file.response.url;
this.texPngData['name'] = e.file.name;
this.nzMessageService.success('上传成功');
this.isTexPngLoading = false;
break;
case 'progress':
break;
}
}
copyItem(it) {
const {hotZoneItemArr} = this.getSendData();
let itemData;
hotZoneItemArr.forEach((data) => {
if (data.id == it.id) {
itemData = data;
}
})
let curBgRect;
if (this.bg) {
curBgRect = this.bg.getBoundingBox();
} else {
curBgRect = {x: 0, y: 0, width: this.canvasWidth, height: this.canvasHeight};
}
let oldBgRect = this.bgItem.rect;
if (!oldBgRect) {
oldBgRect = curBgRect;
}
const rate = curBgRect.width / oldBgRect.width;
console.log('rate: ', rate);
const data = itemData
data.rect.x *= rate;
data.rect.y *= rate;
data.rect.width *= rate;
data.rect.height *= rate;
data.rect.x += curBgRect.x;
data.rect.y += curBgRect.y;
const item = this.getHotZoneItem(data);
item.audio_url = data.audio_url;
item.pic_url = data.pic_url;
item.text = data.text;
item.itemType = data.itemType;
this.hotZoneArr.push(item);
if (this.customTypeGroupArr) {
this.refreshCustomItem(item);
} else {
this.refreshItem(item);
}
this.refreshHotZoneId();
item['id'] = this.createItemId();
}
createItemId() {
return new Date().getTime().toString();
}
copyHotZoneData() {
const {bgItem, hotZoneItemArr} = this.getSendData();
// const hotZoneItemArrNew = [];
// const tmpArr = JSON.parse(JSON.stringify(hotZoneItemArr));
// tmpArr.forEach((item) => {
// if (item.gIdx === '0') {
// hotZoneItemArr.push(item);
// }
// })
const jsonData = {
bgItem,
hotZoneItemArr,
isHasRect: this.isHasRect,
isHasPic: this.isHasPic,
isHasText: this.isHasText,
isHasAudio: this.isHasAudio,
isHasAnima: this.isHasAnima,
hotZoneFontObj: this.hotZoneFontObj,
defaultItemType: this.defaultItemType,
hotZoneImgSize: this.hotZoneImgSize,
};
const oInput = document.createElement('input');
oInput.value = JSON.stringify(jsonData);
document.body.appendChild(oInput);
oInput.select(); // 选择对象
document.execCommand('Copy'); // 执行浏览器复制命令
document.body.removeChild(oInput);
this.nzMessageService.success('复制成功');
// alert('复制成功');
}
importData() {
if (!this.pasteData) {
return;
}
try {
const data = JSON.parse(this.pasteData);
console.log('data:', data);
const {
bgItem,
hotZoneItemArr,
isHasRect,
isHasPic,
isHasText,
isHasAudio,
isHasAnima,
hotZoneFontObj,
defaultItemType,
hotZoneImgSize,
} = data;
this.hotZoneItemArr = hotZoneItemArr;
this.isHasRect = isHasRect;
this.isHasPic = isHasPic;
this.isHasText = isHasText;
this.isHasAudio = isHasAudio;
this.isHasAnima = isHasAnima;
this.hotZoneFontObj = hotZoneFontObj;
this.defaultItemType = defaultItemType;
this.hotZoneImgSize = hotZoneImgSize;
this.bgItem = bgItem;
this.pasteData = '';
} catch (e) {
console.log('err: ', e);
this.nzMessageService.error('导入失败');
}
}
private updatePos() {
this.hotZoneArr.forEach((item) => {
let x, y;
switch (item.itemType) {
case 'rect':
x = item.x;
y = item.y;
break;
case 'pic':
x = item.pic.x;
y = item.pic.y;
break;
case 'text':
x = item.textLabel.x;
y = item.textLabel.y;
break;
}
if (x != undefined && y != undefined) {
item.x = x;
item.y = y;
item.pic.x = x;
item.pic.y = y;
item.textLabel.x = x;
item.textLabel.y = y;
}
});
}
private setPicState(item: any) {
item.visible = false;
item.textLabel.visible = false;
item.pic.visible = true;
}
private setRectState(item: any) {
item.visible = true;
item.textLabel.visible = false;
item.pic.visible = false;
}
private setTextState(item: any) {
item.visible = false;
item.pic.visible = false;
item.textLabel.visible = true;
}
private setNoneState(item: any) {
item.visible = false;
item.pic.visible = false;
item.textLabel.visible = false;
}
private clickedHotZoneRect(item: any) {
if (this.checkClickTarget(item)) {
if (item.lineDashFlag && this.checkClickTarget(item.arrow)) {
this.changeItemSize(item);
} else if (item.lineDashFlag && this.checkClickTarget(item.arrowTop)) {
this.changeItemTopSize(item);
} else if (item.lineDashFlag && this.checkClickTarget(item.arrowRight)) {
this.changeItemRightSize(item);
} else {
this.changeCurItem(item);
}
return;
}
}
private clickedHotZonePic(item: any) {
if (this.checkClickTarget(item)) {
if (item.lineDashFlag && this.checkClickTarget(item.arrow)) {
this.changeItemSize(item);
} else if (item.lineDashFlag && this.checkClickTarget(item.arrowTop)) {
this.changeItemTopSize(item);
} else if (item.lineDashFlag && this.checkClickTarget(item.arrowRight)) {
this.changeItemRightSize(item);
} else {
this.changeCurItem(item);
}
this.curItem = item;
}
}
private clickedHotZoneText(item: any) {
if (this.checkClickTarget(item)) {
this.curItem = item;
}
}
clickedDragPoint(item) {
this.curItem = item;
}
private loadHotZonePic(pic: HotZoneImg, url, scale = null) {
let baseLen;
if (this.hotZoneImgSize) {
baseLen = this.hotZoneImgSize * this.mapScale;
}
pic.load(url).then(() => {
if (!scale) {
if (baseLen) {
scale = getMinScale(pic, baseLen);
} else {
scale = this.bg.scaleX;
}
}
pic.setScaleXY(scale);
});
}
closeAfterPanel() {
this.refresh();
}
/**
* 刷新 渲染页面
*/
refresh() {
setTimeout(() => {
this.appRef.tick();
}, 1);
}
} }
<div class="title-config"> <div class="title-config">
<div class="title-wrap"> <div class="title-wrap">
...@@ -7,9 +8,10 @@ ...@@ -7,9 +8,10 @@
<nz-select class="ml-1" style="width: 120px;" [(ngModel)]="__fontFamily" <nz-select class="ml-1" style="width: 120px;" [(ngModel)]="__fontFamily"
(ngModelChange)="onChangeFontFamily($event)" (ngModelChange)="onChangeFontFamily($event)"
nzPlaceHolder="Font Family" nzPlaceHolder="Font Family"
[nzDropdownMatchSelectWidth]="false" [nzDropdownMatchSelectWidth]="false">
> <nz-option [nzValue]="font" nzCustomContent [nzLabel]="font" *ngFor="let font of fontFamilyList">
<nz-option [nzValue]="font" [nzLabel]="font" *ngFor="let font of fontFamilyList"></nz-option> <span [ngStyle]="{'font-family': font}" >{{font}}</span>
</nz-option>
</nz-select> </nz-select>
<nz-select class="ml-1" style="width: 110px;" [(ngModel)]="__fontSize" <nz-select class="ml-1" style="width: 110px;" [(ngModel)]="__fontSize"
(ngModelChange)="onChangeFontSize()" (ngModelChange)="onChangeFontSize()"
...@@ -19,28 +21,33 @@ ...@@ -19,28 +21,33 @@
<div class="p-divider"></div> <div class="p-divider"></div>
<div class="i-tool-font-btn d-flex mr-2"> <div class="i-tool-font-btn d-flex mr-2">
<div class="position-relative fa-icon" (click)="onChangeBold()"> <div class="position-relative fa-icon" (click)="onChangeBold()">
<div class="fa fa-bold"></div> <!-- <div class="fa fa-bold"></div>-->
<fa-icon icon="bold"></fa-icon>
</div> </div>
</div> </div>
<div class="i-tool-font-btn d-flex mr-2"> <div class="i-tool-font-btn d-flex mr-2">
<div class="position-relative fa-icon" (click)="onChangeItalic()"> <div class="position-relative fa-icon" (click)="onChangeItalic()">
<div class="fa fa-italic"></div> <!-- <div class="fa fa-italic"></div>-->
<fa-icon icon="italic"></fa-icon>
</div> </div>
</div> </div>
<div class="i-tool-font-btn d-flex mr-2"> <div class="i-tool-font-btn d-flex mr-2">
<div class="position-relative fa-icon" (click)="onChangeUnderline()"> <div class="position-relative fa-icon" (click)="onChangeUnderline()">
<div class="fa fa-underline"></div> <!-- <div class="fa fa-underline"></div>-->
<fa-icon icon="underline"></fa-icon>
</div> </div>
</div> </div>
<div class="i-tool-font-btn d-flex"> <div class="i-tool-font-btn d-flex">
<div class="position-relative fa-icon" (click)="onChangeStrikethrough()"> <div class="position-relative fa-icon" (click)="onChangeStrikethrough()">
<div class="fa fa-strikethrough"></div> <!-- <div class="fa fa-strikethrough"></div>-->
<fa-icon icon="strikethrough"></fa-icon>
</div> </div>
</div> </div>
<div class="p-divider"></div> <div class="p-divider"></div>
<div class="i-tool-font-color d-flex"> <div class="i-tool-font-color d-flex">
<div class="position-relative i-left flex-fill" (click)="onChangeFontColor($event)"> <div class="position-relative i-left flex-fill" (click)="onChangeFontColor($event)">
<div class="fa fa-font"></div> <!-- <div class="fa fa-font"></div>-->
<fa-icon icon="palette"></fa-icon>
<div class="i-color" [style.background-color]="__fontColor"></div> <div class="i-color" [style.background-color]="__fontColor"></div>
</div> </div>
<div class="i-dropdown-menu" nzPlacement="bottom" <div class="i-dropdown-menu" nzPlacement="bottom"
...@@ -51,14 +58,14 @@ ...@@ -51,14 +58,14 @@
</div> </div>
<div class="p-divider"></div> <div class="p-divider"></div>
<div style="background: #fff;display: block;"> <div style="background: #fff;display: block;">
<div class="position-relative" (click)="onChangeStrikethrough()"> <div class="position-relative">
<app-audio-recorder [audioUrl]="titleObj && titleObj.audio_url" (audioUploaded)="titleAudioUploaded($event)"></app-audio-recorder> <app-audio-recorder [audioUrl]="titleObj && titleObj.audio_url" (audioUploaded)="titleAudioUploaded($event)"></app-audio-recorder>
</div> </div>
</div> </div>
</div> </div>
<div class="width-100 d-flex"> <div class="width-100 d-flex">
<iframe #titleEl frameborder="0" style="overflow: hidden;width: 100%; height:48px; margin: 0; padding: 0;"></iframe> <iframe #titleEl id="titleContentEgret" frameborder="0" style="overflow: hidden;width: 100%; height:48px; margin: 0; padding: 0;"></iframe>
</div> </div>
</div> </div>
...@@ -76,37 +83,11 @@ ...@@ -76,37 +83,11 @@
<ng-container *ngIf="withIcon">
<div class="row type-row">
课程类型:
<nz-radio-group [(ngModel)]="titleObj && titleObj.type" (ngModelChange)="typeChange($event)">
<label nz-radio nzValue="a">单数课</label>
<label nz-radio nzValue="b">双数课</label>
<label nz-radio nzValue="c">复习课</label>
</nz-radio-group>
</div>
</ng-container>
</div>
</div>
<ng-container *ngIf="withIcon">
<div class="title-icons">
<div class="icons-list">
<nz-checkbox-wrapper style="width: 100%;clear:both" (nzOnChange)="iconsChanges($event)">
<div [class]="'icon-item icon-'+i" *ngFor="let i of groupIconsCount[titleObj.type];">
<div class="img-box">
<nz-badge class="icon-badge" [nzCount]="titleObj && titleObj.icons && titleObj.icons.indexOf(i) + 1">
<img [src]="'assets/title-icons/'+titleObj.type+'/icon-'+i+'.png'" alt="">
</nz-badge>
</div>
<label nz-checkbox [nzValue]="i" [ngModel]="titleObj && titleObj.icons && titleObj.icons.indexOf(i) > -1"></label>
</div>
</nz-checkbox-wrapper>
</div>
</div>
</ng-container>
</div> </div>
@import '../../style/common_mixin'; @import '../../style/common_mixin.css';
.title-config { .title-config {
.letter-wrap{ .letter-wrap{
...@@ -11,39 +11,73 @@ ...@@ -11,39 +11,73 @@
.type-row{ .type-row{
margin: 0;padding-top: 1rem; margin: 0;padding-top: 1rem;
} }
.icon-item{
margin-right: 16px; }
float: left; @font-face
width: 45px; {
height: 75px; font-family: 'BRLNSDB';
display: flex; src: url("../../../assets/font/BRLNSDB.TTF") ;
justify-content: center; }
align-items: center;
position: relative; @font-face
.icon-badge{ {
position: absolute; font-family: 'BRLNSB';
top: 0; src: url("../../../assets/font/BRLNSB.TTF") ;
right: 0; }
}
.img-box{ @font-face
top: 0; {
position: absolute; font-family: 'BRLNSR';
width: 45px; src: url("../../../assets/font/BRLNSR.TTF") ;
height: 50px; }
display: flex;
justify-content: center; @font-face
align-items: center; {
img{ font-family: 'GOTHIC';
max-width: 100%; src: url("../../../assets/font/GOTHIC.TTF") ;
} }
}
label{ @font-face
position: absolute; {
bottom: 0; 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") ;
}
@mixin tool-btn { @mixin tool-btn {
border: 1px solid #ddd; border: 1px solid #ddd;
display: flex; display: flex;
...@@ -54,16 +88,37 @@ ...@@ -54,16 +88,37 @@
border-radius: 6px; border-radius: 6px;
color: #555; color: #555;
} }
.d-flex{
display: flex;
}
.p-title-box { .position-relative {
.p-title { position: relative;
}
.flex-fill {
-webkit-box-flex: 1;
flex: 1 1 auto;
justify-content: center;
display: flex;
}
.i-dropdown-menu{
width: 15px;
font-size: 10px;
border-left: 1px solid #ddd;
display: -webkit-box;
display: flex;
-webkit-box-align: center;
align-items: center;
flex: 0
}
.p-title-box .p-title {
font-size: 20px; font-size: 20px;
} }
input { .p-title-box input {
width: 300px; width: 300px;
margin-left: 10px; margin-left: 10px;
} }
}
.p-content { .p-content {
border: 1px solid #ddd; border: 1px solid #ddd;
...@@ -85,33 +140,31 @@ ...@@ -85,33 +140,31 @@
align-items: center; align-items: center;
border-bottom: 1px solid #ddd; border-bottom: 1px solid #ddd;
// save
.i-tool-save {
@include tool-btn(); }
// save
.i-tool-save {
//@include tool-btn();
color: white; color: white;
} }
.i-tool-save:disabled { .i-tool-save:disabled {
color: #555; color: #555;
} }
// font-size // font-size
.i-tool-font-size { .i-tool-font-size {
@include tool-btn(); //@include tool-btn();
width: 37px; width: 37px;
& > span { }
position: absolute; .i-tool-font-size:hover {
top: -5px;
right: 5px;
}
}
.i-tool-font-size:hover {
color: black; color: black;
border-color: #bbb; border-color: #bbb;
} }
// font-color // font-color
.i-tool-font-color, .i-tool-font-btn { .i-tool-font-color, .i-tool-font-btn {
border: 1px solid #ddd; border: 1px solid #ddd;
//padding: 3px 7px; //padding: 3px 7px;
border-radius: 6px; border-radius: 6px;
...@@ -155,20 +208,20 @@ ...@@ -155,20 +208,20 @@
transform: scale(0.6); transform: scale(0.6);
} }
} }
} }
.i-tool-font-btn{ .i-tool-font-btn{
width: 31px; width: 31px;
} }
.fa-icon{ .fa-icon{
width: 100%; width: 100%;
height: 100%; height: 100%;
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
cursor: pointer; cursor: pointer;
} }
// bg-color // bg-color
.i-tool-bg-color { .i-tool-bg-color {
@include tool-btn(); @include tool-btn();
padding: 0 9px; padding: 0 9px;
::ng-deep > span { ::ng-deep > span {
...@@ -183,17 +236,14 @@ ...@@ -183,17 +236,14 @@
background-color: white; background-color: white;
margin-left: 10px; margin-left: 10px;
} }
} }
// horizontal-center // horizontal-center
.i-tool-horizontal-center { .i-tool-horizontal-center {
@include tool-btn(); @include tool-btn();
width: 37px; width: 37px;
}
} }
.p-box { .p-box {
width: 1280px; width: 1280px;
height: 720px; height: 720px;
...@@ -203,9 +253,7 @@ ...@@ -203,9 +253,7 @@
overflow: hidden; overflow: hidden;
} }
.p-sentence {
@include k-no-select();
}
.p-animation-index-box { .p-animation-index-box {
.i-animation-index { .i-animation-index {
...@@ -278,7 +326,6 @@ ...@@ -278,7 +326,6 @@
::ng-deep .ant-radio-button-wrapper { ::ng-deep .ant-radio-button-wrapper {
padding: 0 10px; padding: 0 10px;
@include k-no-select();
} }
.i-toolbox { .i-toolbox {
...@@ -309,7 +356,6 @@ ...@@ -309,7 +356,6 @@
cursor: pointer; cursor: pointer;
text-align: left; text-align: left;
display: flex; display: flex;
@include k-no-select();
} }
.i-active { .i-active {
background-color: antiquewhite; background-color: antiquewhite;
......
import { import {
Component, Component,
ElementRef, ElementRef,
...@@ -10,6 +11,82 @@ import { ...@@ -10,6 +11,82 @@ import {
ViewChild ViewChild
} from '@angular/core'; } from '@angular/core';
const editorTpl = `<html lang="en"><head><meta charset="utf-8">
<meta name="viewport"
content="width=device-width,initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no"/>
<style>
@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") ;
}
html, body{
/*font-size: 30px;*/
}
body{
height:48px;
overflow: hidden;
margin: 0;
padding: 0 .5rem;
font-family: 'BRLNSB, BRLNSDB, BRLNSR, GOTHIC, GOTHICB, MMTextBook';
background: #FFF;
line-height: 48px;
}
</style>
</head>
<body>{{content}}</body>
</html>`;
@Component({ @Component({
selector: 'app-lesson-title-config', selector: 'app-lesson-title-config',
templateUrl: './lesson-title-config.component.html', templateUrl: './lesson-title-config.component.html',
...@@ -19,22 +96,45 @@ export class LessonTitleConfigComponent implements OnInit, OnChanges, OnDestroy, ...@@ -19,22 +96,45 @@ export class LessonTitleConfigComponent implements OnInit, OnChanges, OnDestroy,
fontFamilyList = [ fontFamilyList = [
'Arial', 'Arial',
'ARBLI' 'BRLNSB',
'BRLNSDB',
'BRLNSR',
'GOTHIC',
'GOTHICB',
// "GOTHICBI",
// "GOTHICI",
'MMTextBook',
// "MMTextBook-Bold",
// "MMTextBook-Italic",
// "MMTextBook-BoldItalic",
]; ];
colorList = [ colorList = [
'#111111', '#000000',
'#ffffff', '#ffffff',
'#595959', '#595959',
'#0075c2', '#0075c2',
'#c61c1e', '#c61c1e',
'#9cbc3a' '#9cbc3a',
'#008000',
'#FF0000',
'#D2691E',
]; ];
MIN_FONT_SIZE = 1; MIN_FONT_SIZE = 1;
MAX_FONT_SIZE = 7; MAX_FONT_SIZE = 7;
isShowFontColorPane = false; isShowFontColorPane = false;
isShowBGColorPane = false; isShowBGColorPane = false;
fontSizeRange: number[]; fontSizeRange = [
// {name: '1号', value: 9},
// {name: '2号', value: 13},
// {name: '3号', value: 16},
// {name: '4号', value: 18},
// {name: '5号', value: 24},
// {name: '6号', value: 32},
];
editorContent = ''; editorContent = '';
...@@ -45,25 +145,17 @@ export class LessonTitleConfigComponent implements OnInit, OnChanges, OnDestroy, ...@@ -45,25 +145,17 @@ export class LessonTitleConfigComponent implements OnInit, OnChanges, OnDestroy,
loopCnt = 0; loopCnt = 0;
maxLoops = 20; maxLoops = 20;
groupIconsCount = {
a: Array.from(Array(11).keys()), @ViewChild('titleEl', {static: true}) titleEl: ElementRef;
b: Array.from(Array(8).keys()),
c: Array.from(Array(8).keys()),
};
prevIcons = [];
prevType = '';
@ViewChild('titleEl') titleEl: ElementRef;
titleEW = null; titleEW = null;
@Input() @Input()
titleObj = { titleObj = {
type: 'a',
content: '', content: '',
icons: [],
audio_url: '' audio_url: ''
}; };
@Input()
withIcon = true;
@Output() @Output()
titleUpdated = new EventEmitter(); titleUpdated = new EventEmitter();
...@@ -84,16 +176,12 @@ export class LessonTitleConfigComponent implements OnInit, OnChanges, OnDestroy, ...@@ -84,16 +176,12 @@ export class LessonTitleConfigComponent implements OnInit, OnChanges, OnDestroy,
let defObj = this.titleObj; let defObj = this.titleObj;
if (!vars.titleObj.currentValue) { if (!vars.titleObj.currentValue) {
defObj = { defObj = {
type: 'a',
content: '', content: '',
icons: [],
audio_url: '' audio_url: ''
}; };
} else { } else {
defObj = vars.titleObj.currentValue; defObj = vars.titleObj.currentValue;
} }
this.titleObj.icons = defObj.icons || [];
this.titleObj.type = defObj.type || 'a';
this.titleObj.content = defObj.content || ''; this.titleObj.content = defObj.content || '';
this.titleObj.audio_url = defObj.audio_url || ''; this.titleObj.audio_url = defObj.audio_url || '';
this.titleEW.document.body.innerHTML = this.titleObj.content; this.titleEW.document.body.innerHTML = this.titleObj.content;
...@@ -102,33 +190,23 @@ export class LessonTitleConfigComponent implements OnInit, OnChanges, OnDestroy, ...@@ -102,33 +190,23 @@ export class LessonTitleConfigComponent implements OnInit, OnChanges, OnDestroy,
ngOnInit() { ngOnInit() {
if (!this.titleObj) { if (!this.titleObj) {
this.titleObj = { this.titleObj = {
type: 'a',
content: '', content: '',
icons: [],
audio_url: '' audio_url: ''
}; };
} }
this.titleObj.icons = this.titleObj.icons || [];
this.titleObj.type = this.titleObj.type || 'a';
this.titleObj.content = this.titleObj.content || ''; this.titleObj.content = this.titleObj.content || '';
this.titleObj.audio_url = this.titleObj.audio_url || ''; this.titleObj.audio_url = this.titleObj.audio_url || '';
this.editorContent = `<html lang="en"><head><meta charset="utf-8"> this.editorContent = editorTpl.replace('{{content}}', this.titleObj.content) ;
<meta name="viewport"
content="width=device-width,initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no"/>
</head>
<body style="height:48px;overflow: hidden;margin: 0;padding: 0 .5rem;background: #FFF;line-height: 48px;">
${this.titleObj.content}
</body>
</html>`;
this.titleEW = this.titleEl.nativeElement.contentWindow; this.titleEW = this.titleEl.nativeElement.contentWindow;
console.log('this.titleEW', this.titleEW);
const tdoc = this.titleEW.document; const tdoc = this.titleEW.document;
tdoc.designMode = "on"; tdoc.designMode = 'on';
tdoc.open('text/html', 'replace'); tdoc.open('text/html', 'replace');
tdoc.write(this.editorContent); tdoc.write(this.editorContent);
tdoc.close(); tdoc.close();
tdoc.addEventListener("keypress", this.keyPress, true); tdoc.addEventListener('keypress', this.keyPress, true);
tdoc.addEventListener("blur", () => { tdoc.addEventListener('blur', () => {
if (this.titleObj.content === this.titleEW.document.body.innerHTML.trim()) { if (this.titleObj.content === this.titleEW.document.body.innerHTML.trim()) {
return; return;
} }
...@@ -159,30 +237,7 @@ export class LessonTitleConfigComponent implements OnInit, OnChanges, OnDestroy, ...@@ -159,30 +237,7 @@ export class LessonTitleConfigComponent implements OnInit, OnChanges, OnDestroy,
ngOnDestroy(): void { ngOnDestroy(): void {
} }
iconsChanges(val) {
let a = this.titleObj.icons;
let b = val;
if (a.length > b.length) {
const diff = a.filter(x => !b.includes(x));
const ti = [...this.titleObj.icons];
for (let i = 0; i < diff.length; i++) {
const d = diff[i];
const idx = ti.indexOf(d);
ti.splice(idx, 1);
}
this.titleObj.icons = ti;
} else {
const diff = b.filter(x => !a.includes(x));
this.titleObj.icons = [...this.titleObj.icons, ...diff];
}
this.shouldSave();
}
typeChange(val) {
this.titleObj.icons = [];
this.shouldSave();
}
keyPress(evt) { keyPress(evt) {
try { try {
...@@ -195,9 +250,9 @@ export class LessonTitleConfigComponent implements OnInit, OnChanges, OnDestroy, ...@@ -195,9 +250,9 @@ export class LessonTitleConfigComponent implements OnInit, OnChanges, OnDestroy,
const key = String.fromCharCode(evt.charCode).toLowerCase(); const key = String.fromCharCode(evt.charCode).toLowerCase();
let cmd = ''; let cmd = '';
switch (key) { switch (key) {
case 'b': cmd = "bold"; break; case 'b': cmd = 'bold'; break;
case 'i': cmd = "italic"; break; case 'i': cmd = 'italic'; break;
case 'u': cmd = "underline"; break; case 'u': cmd = 'underline'; break;
} }
...@@ -214,10 +269,13 @@ export class LessonTitleConfigComponent implements OnInit, OnChanges, OnDestroy, ...@@ -214,10 +269,13 @@ export class LessonTitleConfigComponent implements OnInit, OnChanges, OnDestroy,
alert(e); alert(e);
} }
} }
execEditorCommand(command, option?: any) { execEditorCommand(command, option?: any) {
console.log('sssss');
try { try {
this.titleEW.focus(); this.titleEW.focus();
this.titleEW.document.execCommand(command, false, option); const result = this.titleEW.document.execCommand(command, false, option);
console.log(result);
this.loopCnt = 0; this.loopCnt = 0;
return false; return false;
...@@ -229,7 +287,7 @@ export class LessonTitleConfigComponent implements OnInit, OnChanges, OnDestroy, ...@@ -229,7 +287,7 @@ export class LessonTitleConfigComponent implements OnInit, OnChanges, OnDestroy,
}, 100); }, 100);
this.loopCnt += 1; this.loopCnt += 1;
} else { } else {
alert("Error executing command."); alert('Error executing command.');
} }
} }
} }
...@@ -242,7 +300,7 @@ export class LessonTitleConfigComponent implements OnInit, OnChanges, OnDestroy, ...@@ -242,7 +300,7 @@ export class LessonTitleConfigComponent implements OnInit, OnChanges, OnDestroy,
this.execEditorCommand('forecolor', this.__fontColor); this.execEditorCommand('forecolor', this.__fontColor);
} }
onChangeFontFamily(font) { onChangeFontFamily(font) {
this.execEditorCommand('fontname', font); this.execEditorCommand('fontName', font);
} }
onChangeFontSize(size?: any) { onChangeFontSize(size?: any) {
...@@ -272,9 +330,10 @@ export class LessonTitleConfigComponent implements OnInit, OnChanges, OnDestroy, ...@@ -272,9 +330,10 @@ export class LessonTitleConfigComponent implements OnInit, OnChanges, OnDestroy,
this.titleUpdated.emit(this.titleObj); this.titleUpdated.emit(this.titleObj);
} }
shouldSave = () => { shouldSave = () => {
console.log('title shouldSave'); console.log('title shouldSave', this.titleObj);
this.titleObj.content = this.titleEW.document.body.innerHTML.trim(); this.titleObj.content = this.titleEW.document.body.innerHTML.trim();
this.titleUpdated.emit(this.titleObj); this.titleUpdated.emit(this.titleObj);
} }
} }
@import '../../style/common_mixin'; @import '../../style/common_mixin.css';
.cmp-player-content-wrapper{ .cmp-player-content-wrapper{
max-height: 100%; max-height: 100%;
......
...@@ -18,7 +18,7 @@ import { ...@@ -18,7 +18,7 @@ import {
export class PlayerContentWrapperComponent implements OnInit, OnChanges, OnDestroy, AfterViewInit { export class PlayerContentWrapperComponent implements OnInit, OnChanges, OnDestroy, AfterViewInit {
@ViewChild('wrapperEl') wrapperEl: ElementRef; @ViewChild('wrapperEl', {static: true }) wrapperEl: ElementRef;
// // aspect ratio? // // aspect ratio?
@Input() ratio; @Input() ratio;
......
<div class="position-relative" (drop)="handle_drop($event)" (dragover)="handle_dragover($event)">
<button nz-button (click)="setAnimaBtnClick()" style=" border-radius: 0.5rem; border: 1px solid #ddd;" (dragover)="handle_dragover($event)">
<i nz-icon nzType="tool" nzTheme="outline"></i>
{{btnName}}
</button>
<!--配置龙骨面板-->
<nz-modal [(nzVisible)]="animaPanelVisible" (nzAfterClose)="closePanel()" nzTitle="配置资源文件"
(nzOnCancel)="animaPanelCancel()" (nzOnOk)="animaPanelOk()" nzOkText="保存">
<div class="anima-upload-btn">
<span style="margin-right: 10px">上传 ske_json 文件: </span>
<nz-upload [nzShowUploadList]="false" nzAccept="application/json" [nzAction]="uploadUrl" [nzData]="uploadData"
(nzChange)="skeJsonHandleChange($event)">
<button nz-button><i nz-icon nzType="upload"></i><span>Upload</span></button>
</nz-upload>
<i *ngIf="isSkeJsonLoading" style="margin-left: 10px;" nz-icon [nzType]="'loading'"></i>
<span *ngIf="skeJsonData && skeJsonData['name']" style="margin-left: 10px"><u> {{skeJsonData['name']}} </u></span>
</div>
<div class="anima-upload-btn">
<span style="margin-right: 10px">上传 tex_json 文件: </span>
<nz-upload [nzShowUploadList]="false" nzAccept="application/json" [nzAction]="uploadUrl" [nzData]="uploadData"
(nzChange)="texJsonHandleChange($event)">
<button nz-button><i nz-icon nzType="upload"></i><span>Upload</span></button>
</nz-upload>
<i *ngIf="isTexJsonLoading" style="margin-left: 10px;" nz-icon [nzType]="'loading'"></i>
<span *ngIf="texJsonData && texJsonData['name']" style="margin-left: 10px"><u> {{texJsonData['name']}} </u></span>
</div>
<div class="anima-upload-btn">
<span style="margin-right: 10px">上传 tex_png 文件: </span>
<nz-upload [nzShowUploadList]="false" nzAccept="image/*" [nzAction]="uploadUrl" [nzData]="uploadData"
(nzChange)="texPngHandleChange($event)">
<button nz-button><i nz-icon nzType="upload"></i><span>Upload</span></button>
</nz-upload>
<i *ngIf="isTexPngLoading" style="margin-left: 10px;" nz-icon [nzType]="'loading'"></i>
<span *ngIf="texPngData && texPngData['name']" style="margin-left: 10px"><u> {{texPngData['name']}} </u></span>
</div>
<div class="anima-upload-btn" *ngIf="animaNames && animaNames.length > 0">
提示:需包含动画: {{animaNames.toString()}}.
</div>
</nz-modal>
</div>
\ No newline at end of file
@import '../../style/common_mixin.css';
.p-image-uploader {
position: relative;
display: block;
width: 100%;
height: 0;
padding-bottom: 56.25%;
.p-box {
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
border: 2px dashed #ddd;
border-radius: 0.5rem;
background-color: #fafafa;
text-align: center;
color: #aaa;
.p-upload-icon {
text-align: center;
margin: auto;
.anticon-upload {
color: #888;
font-size: 5rem;
}
.p-progress-bar {
position: relative;
width: 20rem;
height: 1.5rem;
border: 1px solid #ccc;
border-radius: 1rem;
.p-progress-bg {
background-color: #1890ff;
border-radius: 1rem;
height: 100%;
}
.p-progress-value {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
text-shadow: 0 0 4px #000;
color: white;
text-align: center;
font-size: 0.9rem;
line-height: 1.5rem;
}
}
}
.p-preview {
width: 100%;
height: 100%;
background-size: contain;
background-repeat: no-repeat;
background-position: 50% 50%;
//background-image: url("https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png");
}
}
.d-flex{
display: flex;
}
}
.p-btn-delete {
position: absolute;
right: -0.5rem;
top: -0.5rem;
width: 2rem;
height: 2rem;
border: 0.2rem solid white;
border-radius: 50%;
font-size: 1.2rem;
background-color: #fb781a;
color: white;
text-align: center;
}
.p-upload-progress-bg {
position: absolute;
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
& .i-text {
position: absolute;
text-align: center;
color: white;
text-shadow: 0 0 2px rgba(0, 0, 0, .85);
}
& .i-bg {
position: absolute;
left: 0;
top: 0;
height: 100%;
background-color: #27b43f;
border-radius: 0.5rem;
}
}
.anima-upload-btn {
padding: 10px;
}
:host ::ng-deep .ant-upload {
display: block;
}
import {ApplicationRef, Component, EventEmitter, Input, OnChanges, OnDestroy, Output} from '@angular/core';
import { NzMessageService, UploadXHRArgs, UploadFile } from 'ng-zorro-antd';
@Component({
selector: 'app-upload-dragon-bone',
templateUrl: './upload-dragon-bone.component.html',
styleUrls: ['./upload-dragon-bone.component.scss']
})
export class UploadDragonBoneComponent implements OnDestroy, OnChanges {
uploading = false;
progress = 0;
@Input()
btnName = '配置龙骨动画';
@Input()
animaNames = [];
@Input()
skeJsonData = {};
@Input()
texJsonData = {};
@Input()
texPngData = {};
@Output()
save = new EventEmitter();
@Output()
refreshEmitter = new EventEmitter();
// @Input()
// picUrl;
// @Input()
// canDelete = false;
// @Output()
// imageUploaded = new EventEmitter();
// @Output()
// imageUploadFailure = new EventEmitter();
// @Output()
// delete = new EventEmitter();
// @Input()
// picItem = null;
// @Input()
// iconSize = 2;
// @Input()
// TIP = 'Click here to upload image';
// @Input()
// disableUpload = false;
uploadUrl;
uploadData;
animaPanelVisible = false;
isSkeJsonLoading = false;
isTexJsonLoading = false;
isTexPngLoading = false;
constructor(private appRef: ApplicationRef, private nzMessageService: NzMessageService) {
this.uploadUrl = (<any> window).courseware.uploadUrl();
this.uploadData = (<any> window).courseware.uploadData();
window['air'].getUploadCallback = (url, data) => {
this.uploadUrl = url;
this.uploadData = data;
};
}
ngOnChanges() {
}
setAnimaBtnClick() {
this.animaPanelVisible = true;
this.refresh();
}
animaPanelCancel() {
this.animaPanelVisible = false;
this.refresh();
}
animaPanelOk() {
this.sendItemDragonBoneData();
this.animaPanelVisible = false;
this.refresh();
}
sendItemDragonBoneData() {
const data = {};
data['skeJsonData'] = this.skeJsonData;
data['texJsonData'] = this.texJsonData;
data['texPngData'] = this.texPngData;
this.save.emit(data);
}
skeJsonHandleChange(e) {
console.log('e: ', e);
switch (e.type) {
case 'start':
this.isSkeJsonLoading = true;
break;
case 'success':
this.skeJsonData['url'] = e.file.response.url;
this.skeJsonData['name'] = e.file.name;
this.nzMessageService.success('上传成功');
this.isSkeJsonLoading = false;
break;
case 'progress':
break;
}
}
texJsonHandleChange(e) {
console.log('e: ', e);
switch (e.type) {
case 'start':
this.isTexJsonLoading = true;
break;
case 'success':
this.texJsonData['url'] = e.file.response.url;
this.texJsonData['name'] = e.file.name;
this.nzMessageService.success('上传成功');
this.isTexJsonLoading = false;
break;
case 'progress':
break;
}
}
texPngHandleChange(e) {
console.log('e: ', e);
switch (e.type) {
case 'start':
this.isTexPngLoading = true;
break;
case 'success':
this.texPngData['url'] = e.file.response.url;
this.texPngData['name'] = e.file.name;
this.nzMessageService.success('上传成功');
this.isTexPngLoading = false;
break;
case 'progress':
break;
}
}
/**
* 刷新 渲染页面
*/
refresh() {
// this.refreshEmitter.emit();
setTimeout(() => {
this.appRef.tick();
}, 1);
}
closePanel() {
console.log(' in closePanel ');
this.refresh();
}
ngOnDestroy() {
}
linkInputed (ske, tex, png) {
this.skeJsonData["url"] = ske.url;
this.skeJsonData["name"] = ske.name;
this.texJsonData["url"] = tex.url;
this.texJsonData["name"] = tex.name;
this.texPngData["url"] = png.url;
this.texPngData["name"] = png.name;
this.animaPanelOk();
}
handle_dragover(e) {
e.preventDefault();
}
handle_drop(e) {
e.preventDefault();
const dt = e.dataTransfer.getData("text/plain");
console.log("handle_drop===", dt);
if (!dt) {
return;
}
try {
const {ske, tex, png} = JSON.parse(dt);
if (!ske || !tex || !png ||
ske.url.indexOf("teach")<0 || ske.url.indexOf("cdn")<0 || ske.url.indexOf(".json")<0 ||
tex.url.indexOf("teach")<0 || tex.url.indexOf("cdn")<0 || tex.url.indexOf(".json")<0 ||
png.url.indexOf("teach")<0 || png.url.indexOf("cdn")<0 || png.url.indexOf(".png")<0 ||
!ske.name || !tex.name || !png.name
) {
console.warn("handle_drop拖拽在线骨骼动画传递参数不合法,应该是{ske:{url:'', name:''},tex:{url:'', name:''},png:{url:'', name:''}}");
return;
}
this.linkInputed(ske, tex, png);
} catch (error) {
console.warn("handle_drop拖拽在线骨骼动画传递参数不合法,应该是{ske:{url:'', name:''},tex:{url:'', name:''},png:{url:'', name:''}}");
}
}
}
<div class="position-relative"> <div class="position-relative" (drop)="handle_drop($event)" (dragover)="handle_dragover($event)">
<nz-upload class="p-image-uploader" [nzDisabled]="disableUpload" <nz-upload class="p-image-uploader" [nzDisabled]="disableUpload"
[nzShowUploadList]="false" [nzShowUploadList]="false"
nzAccept = "image/*" nzAccept = "image/*"
[nzAction]="uploadUrl" [nzAction]="uploadUrl"
[nzData]="uploadData" [nzData]="uploadData"
(nzChange)="handleChange($event)"> (nzChange)="handleChange($event)"
>
<!--[nzBeforeUpload]="customUpload">--> <!--[nzBeforeUpload]="customUpload">-->
<div class="p-box d-flex align-items-center"> <div class="p-box d-flex align-items-center">
<div class="p-upload-icon" *ngIf="!picUrl && !uploading"> <div class="p-upload-icon" *ngIf="!picUrl && !uploading">
<i nz-icon type="cloud-upload" theme="outline" [style.font-size]="iconSize + 'em'"></i> <i nz-icon nzType="cloud-upload" nzTheme="outline" [style.font-size]="iconSize + 'em'"></i>
<div class="m-3"></div> <div class="m-3"></div>
<span>{{TIP}}</span> <span>{{TIP}}</span>
<!--<div class="mt-5 p-progress-bar" *ngIf="uploading">--> <!--<div class="mt-5 p-progress-bar" *ngIf="uploading">-->
...@@ -19,7 +21,7 @@ ...@@ -19,7 +21,7 @@
<div class="p-upload-progress-bg" *ngIf="uploading"> <div class="p-upload-progress-bg" *ngIf="uploading">
<div class="i-bg" [style.width]="progress+'%'"></div> <div class="i-bg" [style.width]="progress+'%'"></div>
<div class="i-text"> <div class="i-text">
<fa name="cloud-upload"></fa> <fa-icon icon="cloud-upload-alt"></fa-icon>
Uploading... Uploading...
</div> </div>
</div> </div>
...@@ -32,6 +34,6 @@ ...@@ -32,6 +34,6 @@
nz-popconfirm nzTitle="Are you sure ?" nz-popconfirm nzTitle="Are you sure ?"
(nzOnConfirm)="onDelete()" (nzOnConfirm)="onDelete()"
> >
<i nz-icon type="close" theme="outline"></i> <i nz-icon nzType="close" nzTheme="outline"></i>
</div> </div>
</div> </div>
@import '../../style/common_mixin'; @import '../../style/common_mixin.css';
.p-image-uploader { .p-image-uploader {
position: relative; position: relative;
...@@ -52,10 +52,15 @@ ...@@ -52,10 +52,15 @@
.p-preview { .p-preview {
width: 100%; width: 100%;
height: 100%; height: 100%;
background-size: contain;
background-repeat: no-repeat;
background-position: 50% 50%;
//background-image: url("https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png"); //background-image: url("https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png");
@include k-img-bg();
} }
} }
.d-flex{
display: flex;
}
} }
.p-btn-delete { .p-btn-delete {
......
...@@ -29,10 +29,19 @@ export class UploadImageWithPreviewComponent implements OnDestroy, OnChanges { ...@@ -29,10 +29,19 @@ export class UploadImageWithPreviewComponent implements OnDestroy, OnChanges {
@Input() @Input()
disableUpload = false; disableUpload = false;
uploadUrl = (<any> window).courseware.uploadUrl(); uploadUrl;
uploadData = (<any> window).courseware.uploadData(); uploadData;
constructor(private nzMessageService: NzMessageService) { constructor(private nzMessageService: NzMessageService) {
this.uploadUrl = (<any> window).courseware.uploadUrl();
this.uploadData = (<any> window).courseware.uploadData();
window['air'].getUploadCallback = (url, data) => {
this.uploadUrl = url;
this.uploadData = data;
};
} }
ngOnChanges() { ngOnChanges() {
if (!this.picItem) { if (!this.picItem) {
...@@ -146,4 +155,39 @@ export class UploadImageWithPreviewComponent implements OnDestroy, OnChanges { ...@@ -146,4 +155,39 @@ export class UploadImageWithPreviewComponent implements OnDestroy, OnChanges {
ngOnDestroy() { ngOnDestroy() {
} }
linkInputed (url) {
const file = {
response: {url}
};
const img = new Image();
img.addEventListener('load', () => {
const height = img.naturalHeight;
const width = img.naturalWidth;
file['height'] = height;
file['width'] = width;
img.remove();
this.imageUploaded.emit(file.response);
});
img.src = url;
this.picUrl = url;
}
handle_dragover(e) {
e.preventDefault();
}
handle_drop(e) {
const dt = e.dataTransfer.getData("text/plain");
console.log("handle_drop===", dt);
if (!dt || dt.indexOf("teach")<0 || dt.indexOf("cdn")<0) {
return;
}
const white = [".jpg", ".jpeg", ".png", ".bmp", ".JPG", ".JPEG", ".PNG", ".BMP"];
if (!white.includes(dt.substr(dt.lastIndexOf(".")))) {
return;
}
this.linkInputed(dt);
}
} }
<div class="p-video-box" (drop)="handle_drop($event)" (dragover)="handle_dragover($event)">
<div class="up-video" style="display: flex;"> <div class="up-video" style="display: flex;">
<!--<nz-upload class="" [nzDisabled]="!showUploadBtn"--> <!--<nz-upload class="" [nzDisabled]="!showUploadBtn"-->
<!--[nzShowUploadList]="false"--> <!--[nzShowUploadList]="false"-->
<!--[nzBeforeUpload]="beforeUpload"--> <!--[nzBeforeUpload]="beforeUpload"-->
<!--nzAccept = ".mp4"--> <!--nzAccept = ".mp4"-->
<!--style="margin-right: 1rem">--> <!--style="margin-right: 1rem">-->
<nz-upload class="p-image-uploader" [nzDisabled]="uploading" <nz-upload class="p-image-uploader" [nzDisabled]="uploading" [nzShowUploadList]="false" nzAccept=".mp4"
[nzShowUploadList]="false" [nzAction]="uploadUrl" [nzData]="uploadData" (nzChange)="handleChange($event)" style="margin-right: 1rem">
nzAccept = ".mp4"
[nzAction]="uploadUrl"
[nzData]="uploadData"
(nzChange)="handleChange($event)"
style="margin-right: 1rem">
<button type="button" nz-button nzType="default" *ngIf="showUploadBtn" [disabled]="uploading" <button type="button" nz-button nzType="default" *ngIf="showUploadBtn" [disabled]="uploading"
[nzLoading]="uploading" > [nzLoading]="uploading">
<i nz-icon type="plus" theme="outline"></i> <i nz-icon nzType="plus" nzTheme="outline"></i>
<span>{{ uploading ? 'Uploading' : 'Select Video' }}</span> <span>{{ uploading ? 'Uploading' : 'Select Video' }}</span>
<!--<span>Select Video</span>--> <!--<span>Select Video</span>-->
</button> </button>
...@@ -55,10 +49,10 @@ ...@@ -55,10 +49,10 @@
--> -->
</div> </div>
<div class="p-box d-flex align-items-center p-video-uploader" style="top: 20px;"> <div class="p-box d-flex align-items-center p-video-uploader">
<div class="p-upload-icon" *ngIf="!showUploadBtn && !videoUrl && !uploading"> <div class="p-upload-icon" *ngIf="!showUploadBtn && !videoUrl && !uploading">
<i nz-icon type="upload" theme="outline"></i> <i nz-icon nzType="upload" nzTheme="outline"></i>
<div class="m-3"></div> <div class="m-3"></div>
<span>Click here to upload video</span> <span>Click here to upload video</span>
<div class="mt-5 p-progress-bar" *ngIf="uploading"> <div class="mt-5 p-progress-bar" *ngIf="uploading">
...@@ -66,30 +60,26 @@ ...@@ -66,30 +60,26 @@
<div class="p-progress-value">{{progress}}%</div> <div class="p-progress-value">{{progress}}%</div>
</div> </div>
</div> </div>
<div class="p-upload-progress-bg dddd " *ngIf="uploading" <div class="p-upload-progress-bg dddd " *ngIf="uploading" [ngClass]="{'smart-bar': showUploadBtn}">
[ngClass]="{'smart-bar': showUploadBtn}" >
<div class="i-bg" [style.width]="progress+'%'"></div> <div class="i-bg" [style.width]="progress+'%'"></div>
<div class="i-text"> <div class="i-text">
<fa name="cloud-upload"></fa> <fa-icon icon="cloud-upload-alt"></fa-icon>
Uploading... Uploading...
</div> </div>
</div> </div>
<div class="p-upload-check-bg" *ngIf="checking"> <div class="p-upload-check-bg" *ngIf="checking">
<div class="i-bg" [style.width]="progress+'%'"></div> <div class="i-bg" [style.width]="progress+'%'"></div>
<div class="i-text"> <div class="i-text">
<fa name="cloud-upload"></fa> <fa-icon icon="cloud-upload-alt"></fa-icon>
<i nz-icon type="loading" theme="outline"></i>Checking... <i nz-icon nzType="loading" nzTheme="outline"></i>Checking...
</div> </div>
</div> </div>
<div class="p-preview" *ngIf="!showUploadBtn && !uploading && videoUrl " > <div class="p-preview" *ngIf="!uploading && videoUrl ">
<!--<video crossorigin="anonymous" [src]="videoUrl" controls #videoNode></video>--> <!--<video crossorigin="anonymous" [src]="videoUrl" controls #videoNode></video>-->
<video [src]="safeVideoUrl(videoUrl)" controls #videoNode (loadedmetadata)="videoLoadedMetaData()"></video> <video [src]="safeVideoUrl(videoUrl)" controls #videoNode></video>
</div>
</div>
<div [style.display]="!checkVideoExists?'none':''">
<span><i nz-icon nzType="loading" nzTheme="outline"></i> checking file to upload</span>
</div> </div>
</div> </div>
\ No newline at end of file
<div [style.display]="!checkVideoExists?'none':''">
<span><i nz-icon type="loading" theme="outline"></i> checking file to upload</span>
</div>
@import '../../style/common_mixin'; @import '../../style/common_mixin.css';
/*.p-video-box{
bottom: 0;
border: 2px dashed #ddd;
border-radius: 0.5rem;
background-color: #fafafa;
text-align: center;
color: #aaa;
padding-top: 56.25%;
//font-size: 4rem;
position: relative;
.p-upload-icon{
left: 50%;
position: absolute;
top: 50%;
transform: translate(-50% ,-50%);
}
}*/
.p-video-uploader { .p-video-uploader {
position: relative; position: relative;
display: block; display: block;
...@@ -17,25 +33,33 @@ ...@@ -17,25 +33,33 @@
background-color: #fafafa; background-color: #fafafa;
text-align: center; text-align: center;
color: #aaa; color: #aaa;
.p-upload-icon {
}
}
.p-upload-icon {
text-align: center; text-align: center;
margin: auto; margin: auto;
.anticon-upload {
}
.p-upload-icon .anticon-upload {
color: #888; color: #888;
font-size: 5rem; font-size: 5rem;
} }
.p-progress-bar { p-progress-bar {
position: relative; position: relative;
width: 20rem; width: 20rem;
height: 1.5rem; height: 1.5rem;
border: 1px solid #ccc; border: 1px solid #ccc;
border-radius: 1rem; border-radius: 1rem;
.p-progress-bg {
}
.p-progress-bar .p-progress-bg {
background-color: #1890ff; background-color: #1890ff;
border-radius: 1rem; border-radius: 1rem;
height: 100%; height: 100%;
} }
.p-progress-value { .p-progress-bar .p-progress-value {
position: absolute; position: absolute;
top: 0; top: 0;
left: 0; left: 0;
...@@ -46,21 +70,19 @@ ...@@ -46,21 +70,19 @@
text-align: center; text-align: center;
font-size: 0.9rem; font-size: 0.9rem;
line-height: 1.5rem; line-height: 1.5rem;
} }
} .p-preview {
}
.p-preview {
width: 100%; width: 100%;
height: 100%; height: 100%;
//background-image: url("https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png"); //background-image: url("https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png");
video{
}
.p-preview video{
max-height: 100%; max-height: 100%;
max-width: 100%; max-width: 100%;
position: absolute;
display: flex;
} }
}
}
}
.p-btn-delete { .p-btn-delete {
position: absolute; position: absolute;
right: -0.5rem; right: -0.5rem;
......
import {Component, ElementRef, EventEmitter, Input, OnChanges, OnDestroy, Output, SecurityContext, ViewChild} from '@angular/core'; import {Component, ElementRef, EventEmitter, Input, OnChanges, OnDestroy, Output, SecurityContext, ViewChild} from '@angular/core';
import {NzMessageService, UploadFile} from 'ng-zorro-antd'; import {NzMessageService, UploadChangeParam, UploadFile, UploadFileStatus} from 'ng-zorro-antd';
import {DomSanitizer, SafeResourceUrl} from '@angular/platform-browser'; import {DomSanitizer, SafeResourceUrl} from '@angular/platform-browser';
...@@ -24,7 +24,7 @@ export class UploadVideoComponent implements OnChanges, OnDestroy { ...@@ -24,7 +24,7 @@ export class UploadVideoComponent implements OnChanges, OnDestroy {
@Input() @Input()
videoUrl = ''; videoUrl = '';
@ViewChild('videoNode') @ViewChild('videoNode', {static: true })
videoNode: ElementRef; videoNode: ElementRef;
...@@ -47,8 +47,8 @@ export class UploadVideoComponent implements OnChanges, OnDestroy { ...@@ -47,8 +47,8 @@ export class UploadVideoComponent implements OnChanges, OnDestroy {
item: any; item: any;
// videoItem = null; // videoItem = null;
uploadUrl = (<any> window).courseware.uploadUrl(); uploadUrl;
uploadData = (<any> window).courseware.uploadData(); uploadData;
constructor(private nzMessageService: NzMessageService, constructor(private nzMessageService: NzMessageService,
private sanitization: DomSanitizer private sanitization: DomSanitizer
...@@ -58,6 +58,16 @@ export class UploadVideoComponent implements OnChanges, OnDestroy { ...@@ -58,6 +58,16 @@ export class UploadVideoComponent implements OnChanges, OnDestroy {
this.uploading = false; this.uploading = false;
this.videoFile = null; this.videoFile = null;
this.uploadUrl = (<any> window).courseware.uploadUrl();
this.uploadData = (<any> window).courseware.uploadData();
window['air'].getUploadCallback = (url, data) => {
this.uploadUrl = url;
this.uploadData = data;
};
} }
ngOnChanges() { ngOnChanges() {
// if (!this.videoFile || this.showUploadBtn) { // if (!this.videoFile || this.showUploadBtn) {
...@@ -70,52 +80,70 @@ export class UploadVideoComponent implements OnChanges, OnDestroy { ...@@ -70,52 +80,70 @@ export class UploadVideoComponent implements OnChanges, OnDestroy {
URL.revokeObjectURL(this.videoUrl); URL.revokeObjectURL(this.videoUrl);
} }
safeVideoUrl(url) { httpHeadCall(requsetUrl: string, callback) {
console.log(url) let xhr = new XMLHttpRequest();
return this.sanitization.bypassSecurityTrustResourceUrl(url); // `${url}`; console.log("Status: Send Post Request to " + requsetUrl);
try {
xhr.onreadystatechange = () => {
try {
console.log('xhr.readyState: ', xhr.readyState);
if (xhr.readyState == 4) {
if ((xhr.status >= 200 && xhr.status < 400)) {
callback(true);
} else {
callback(false);
}
} }
videoLoadedMetaData() {
} catch (e) {
console.log(e)
}
};
xhr.open("HEAD", requsetUrl, true);
xhr.send();
xhr.timeout = 15000;
xhr.onerror = (e) => {
callback(false);
};
xhr.ontimeout = (e) => {
callback(false);
};
} catch (e) {
console.log("Send Get Request error: ", e)
}
} }
safeVideoUrl(url) {
const _url = url.replace("_l.", ".");
return this.sanitization.bypassSecurityTrustResourceUrl(_url); // `${url}`;
}
videoLoadedMetaData() {
handleChange(info: { type: string, file: UploadFile, event: any }): void { }
console.log('info:' , info);
handleChange(info: UploadChangeParam): void {
switch (info.type) { switch (info.type) {
case 'start': case 'start':
// this.beforeUpload(info.file);
if (!this.checkSelectFile(info.file)) { if (!this.checkSelectFile(info.file)) {
return; return;
} }
this.uploading = true; this.uploading = true;
this.progress = 0; this.progress = 0;
break; break;
case 'success': case 'success':
let url = info.file.response.url;
url = url.substring(0, url.lastIndexOf(".")) + "_l.mp4";
info.file.response.url = url;
this.uploadSuccess(info.file); this.uploadSuccess(info.file);
// this.beforeUpload(info.file);
// this.uploadSuccess(info.file);
break; break;
case 'progress': case 'progress':
this.progress = parseInt(info.event.percent, 10); this.progress = info.event.percent;
this.doProgress(this.progress); this.doProgress(this.progress);
break; break;
} }
} }
checkSelectFile(file) { checkSelectFile(file) {
if (!file.lastModified) { if (!file.lastModified) {
return false; return false;
...@@ -152,9 +180,9 @@ export class UploadVideoComponent implements OnChanges, OnDestroy { ...@@ -152,9 +180,9 @@ export class UploadVideoComponent implements OnChanges, OnDestroy {
if (duration) { if (duration) {
duration = duration * 1000; duration = duration * 1000;
} }
file['height'] = height; file.height = height;
file['width'] = width; file.width = width;
file['duration'] = duration; file.duration = duration;
vid.preload = 'none'; vid.preload = 'none';
vid.src = ''; vid.src = '';
vid.remove(); vid.remove();
...@@ -197,5 +225,55 @@ export class UploadVideoComponent implements OnChanges, OnDestroy { ...@@ -197,5 +225,55 @@ export class UploadVideoComponent implements OnChanges, OnDestroy {
// console.log(Math.floor(p * 100)); // console.log(Math.floor(p * 100));
this.progress = Math.floor(p * 100); this.progress = Math.floor(p * 100);
} }
linkInputed (url, name) {
const file = {
response: {url}
};
const vid = document.createElement('video');
vid.addEventListener('loadedmetadata', () => {
const height = vid.videoHeight;
const width = vid.videoWidth;
let duration = vid.duration;
if (duration) {
duration = duration * 1000;
}
file["height"] = height;
file["width"] = width;
file["duration"] = duration;
vid.preload = 'none';
vid.src = '';
vid.remove();
this.videoUploaded.emit(file.response);
});
vid.src = file.response.url;
this.videoUrl = url;
}
handle_dragover(e) {
e.preventDefault();
}
handle_drop(e) {
const dt = e.dataTransfer.getData("text/plain");
console.log("handle_drop===", dt);
if (!dt) {
return;
}
try {
const {url, name} = JSON.parse(dt);
if (url.indexOf("teach")<0 || url.indexOf("cdn")<0) {
return;
}
const white = [".mp4"];
if (!white.includes(url.substr(url.lastIndexOf(".")))) {
return;
}
this.linkInputed(url, name);
} catch (error) {
console.warn("handle_drop拖拽在线视频传递参数不合法,应该是{url:'', name:''}");
}
}
} }
import { ApplicationRef, ChangeDetectorRef, ElementRef, ViewChild } from "@angular/core";
export class ComponentBase {
// 储存数据用
saveKey = "";
// 储存对象
item: any = {};
ngOnChanges() { }
ngOnDestroy() { }
constructor(private appRef: ApplicationRef, private changeDetectorRef: ChangeDetectorRef) { }
ngOnInit() {
// 获取存储的数据
(<any>window).courseware.getData((data) => {
if (data) {
this.item = data;
if (!this.item.returnType) {
this.item.returnType = '0'
}
this.itemStr = JSON.stringify(this.item, null, 4).trim();
}
this.init();
this.changeDetectorRef.markForCheck();
this.changeDetectorRef.detectChanges();
this.refresh();
}, this.saveKey);
}
@ViewChild("itemTextarea", { static: true }) itemTextarea: ElementRef;
copyData() {
this.itemTextarea.nativeElement.select();
document.execCommand("copy");
}
/**
* 储存图片数据
* @param e
*/
// onAssetUploadSuccess(e: any, ...key: Array<string>) {
// let item = this.item;
// for (let i = 0; i < key.length; i++) {
// if (i + 1 == key.length) {
// if (key[i] == "audio") {
// let sp = e.url.split(".mp3");
// let u = sp[0] + "_l.mp3";
// item[key[i]] = u;
// item["audioName"] = e.name || "";
// } else {
// item[key[i]] = e.url;
// }
// this.save();
// return;
// }
// item = item[key[i]];
// }
// }
/**
* 储存图片数据
* @param e
*/
onImageUploadSuccess(e, key, it = this.item) {
it[key] = e.url;
this.save();
}
/**
* 储存音频数据
* @param e
*/
onAudioUploadSuccess(e, key, it = this.item) {
let url = e.url;
it[key] = url;
it[`${key}Name`] = e.name || "";
this.save();
}
save() {
(<any>window).courseware.setData(this.item, null, this.saveKey);
this.itemStr = JSON.stringify(this.item, null, 4).trim();
this.refresh();
console.log('this.item = ' + JSON.stringify(this.item));
}
itemStr = "";
load() {
this.itemStr = this.itemTextarea.nativeElement.value;
if (this.isJSON(this.itemStr)) {
this.item = JSON.parse(this.itemStr);
this.init();
this.changeDetectorRef.markForCheck();
this.changeDetectorRef.detectChanges();
this.refresh();
}
}
isJSON(str) {
if (typeof str == 'string') {
try {
var obj = JSON.parse(str);
if (typeof obj == 'object' && obj) {
return true;
}
return false;
} catch (e) {
return false;
}
}
return false;
}
/**
* 刷新 渲染页面
*/
refresh() {
setTimeout(() => {
this.appRef.tick();
}, 1);
}
init() { }
}
import TWEEN from '@tweenjs/tween.js'; import TWEEN from '@tweenjs/tween.js';
import {del} from 'selenium-webdriver/http';
import construct = Reflect.construct;
interface AirWindow extends Window {
air: any;
curCtx: any;
}
declare let window: AirWindow;
class Sprite { class Sprite {
x = 0; x = 0;
...@@ -16,7 +19,7 @@ class Sprite { ...@@ -16,7 +19,7 @@ class Sprite {
constructor(ctx = null) { constructor(ctx = null) {
if (!ctx) { if (!ctx) {
this.ctx = window['curCtx']; this.ctx = window.curCtx;
} else { } else {
this.ctx = ctx; this.ctx = ctx;
} }
...@@ -67,7 +70,7 @@ export class MySprite extends Sprite { ...@@ -67,7 +70,7 @@ export class MySprite extends Sprite {
_z = 0; _z = 0;
init(imgObj = null, anchorX:number = 0.5, anchorY:number = 0.5) { init(imgObj = null, anchorX: number = 0.5, anchorY: number = 0.5) {
if (imgObj) { if (imgObj) {
...@@ -159,6 +162,7 @@ export class MySprite extends Sprite { ...@@ -159,6 +162,7 @@ export class MySprite extends Sprite {
if (this._shadowFlag) { if (this._shadowFlag) {
this.ctx.shadowOffsetX = this._shadowOffsetX; this.ctx.shadowOffsetX = this._shadowOffsetX;
this.ctx.shadowOffsetY = this._shadowOffsetY; this.ctx.shadowOffsetY = this._shadowOffsetY;
this.ctx.shadowBlur = this._shadowBlur; this.ctx.shadowBlur = this._shadowBlur;
...@@ -176,22 +180,21 @@ export class MySprite extends Sprite { ...@@ -176,22 +180,21 @@ export class MySprite extends Sprite {
} }
} }
updateChildren() { updateChildren() {
if (this.children.length <= 0) { return; } if (this.children.length <= 0) { return; }
for (let i = 0; i < this.children.length; i++) { for (const child of this.children) {
if (child === this) {
if (this.children[i] === this) {
if (this.visible) { if (this.visible) {
this.drawSelf(); this.drawSelf();
} }
} else { } else {
child.update();
this.children[i].update();
} }
} }
} }
...@@ -238,7 +241,7 @@ export class MySprite extends Sprite { ...@@ -238,7 +241,7 @@ export class MySprite extends Sprite {
removeChildren() { removeChildren() {
for (let i = 0; i < this.children.length; i++) { for (let i = 0; i < this.children.length; i++) {
if (this.children[i]) { if (this.children[i]) {
if (this.children[i] != this) { if (this.children[i] !== this) {
this.children.splice(i, 1); this.children.splice(i, 1);
i --; i --;
} }
...@@ -247,9 +250,9 @@ export class MySprite extends Sprite { ...@@ -247,9 +250,9 @@ export class MySprite extends Sprite {
} }
_changeChildAlpha(alpha) { _changeChildAlpha(alpha) {
for (let i = 0; i < this.children.length; i++) { for (const child of this.children) {
if (this.children[i] != this) { if (child !== this) {
this.children[i].alpha = alpha; child.alpha = alpha;
} }
} }
} }
...@@ -360,7 +363,7 @@ export class ColorSpr extends MySprite { ...@@ -360,7 +363,7 @@ export class ColorSpr extends MySprite {
g = 0; g = 0;
b = 0; b = 0;
createGSCanvas(){ createGSCanvas() {
if (!this.img) { if (!this.img) {
return; return;
...@@ -375,8 +378,8 @@ export class ColorSpr extends MySprite { ...@@ -375,8 +378,8 @@ export class ColorSpr extends MySprite {
const c = this.ctx.getImageData(rect.x, rect.y, rect.width, rect.height); const c = this.ctx.getImageData(rect.x, rect.y, rect.width, rect.height);
for( let i = 0; i < c.height; i++){ for ( let i = 0; i < c.height; i++) {
for( let j = 0; j < c.width; j++){ for ( let j = 0; j < c.width; j++) {
const x = (i * 4) * c.width + ( j * 4 ); const x = (i * 4) * c.width + ( j * 4 );
const r = c.data[x]; const r = c.data[x];
...@@ -410,7 +413,7 @@ export class GrayscaleSpr extends MySprite { ...@@ -410,7 +413,7 @@ export class GrayscaleSpr extends MySprite {
grayScale = 120; grayScale = 120;
createGSCanvas(){ createGSCanvas() {
if (!this.img) { if (!this.img) {
return; return;
...@@ -421,8 +424,8 @@ export class GrayscaleSpr extends MySprite { ...@@ -421,8 +424,8 @@ export class GrayscaleSpr extends MySprite {
const rect = this.getBoundingBox(); const rect = this.getBoundingBox();
const c = this.ctx.getImageData(rect.x, rect.y, rect.width, rect.height); const c = this.ctx.getImageData(rect.x, rect.y, rect.width, rect.height);
for( let i = 0; i < c.height; i++){ for ( let i = 0; i < c.height; i++) {
for( let j = 0; j < c.width; j++){ for ( let j = 0; j < c.width; j++) {
const x = (i * 4) * c.width + ( j * 4 ); const x = (i * 4) * c.width + ( j * 4 );
const r = c.data[x]; const r = c.data[x];
...@@ -465,10 +468,10 @@ export class BitMapLabel extends MySprite { ...@@ -465,10 +468,10 @@ export class BitMapLabel extends MySprite {
const tmpArr = text.split(''); const tmpArr = text.split('');
let totalW = 0; let totalW = 0;
let h = 0; let h = 0;
for (let i = 0; i < tmpArr.length; i++) { for (const tmp of tmpArr) {
const label = new MySprite(this.ctx); const label = new MySprite(this.ctx);
label.init(data[tmpArr[i]], 0); label.init(data[tmp], 0);
this.addChild(label); this.addChild(label);
labelArr.push(label); labelArr.push(label);
...@@ -481,9 +484,9 @@ export class BitMapLabel extends MySprite { ...@@ -481,9 +484,9 @@ export class BitMapLabel extends MySprite {
this.height = h; this.height = h;
let offX = -totalW / 2; let offX = -totalW / 2;
for (let i = 0; i < labelArr.length; i++) { for (const label of labelArr) {
labelArr[i].x = offX; label.x = offX;
offX += labelArr[i].width; offX += label.width;
} }
this.labelArr = labelArr; this.labelArr = labelArr;
...@@ -496,22 +499,22 @@ export class BitMapLabel extends MySprite { ...@@ -496,22 +499,22 @@ export class BitMapLabel extends MySprite {
export class Label extends MySprite { export class Label extends MySprite {
text: String; text: string;
// fontSize:String = '40px'; // fontSize:String = '40px';
fontName: String = 'Verdana'; fontName = 'Verdana';
textAlign: String = 'left'; textAlign = 'left';
fontSize = 40; fontSize = 40;
fontColor = '#000000'; fontColor = '#000000';
fontWeight = 900; fontWeight = 900;
maxWidth; _maxWidth;
outline = 0; outline = 0;
outlineColor = '#ffffff'; outlineColor = '#ffffff';
_shadowFlag = false; // _shadowFlag = false;
_shadowColor; // _shadowColor;
_shadowOffsetX; // _shadowOffsetX;
_shadowOffsetY; // _shadowOffsetY;
_shadowBlur; // _shadowBlur;
_outlineFlag = false; _outlineFlag = false;
_outLineWidth; _outLineWidth;
...@@ -542,7 +545,7 @@ export class Label extends MySprite { ...@@ -542,7 +545,7 @@ export class Label extends MySprite {
setMaxSize(w) { setMaxSize(w) {
this.maxWidth = w; this._maxWidth = w;
this.refreshSize(); this.refreshSize();
if (this.width >= w) { if (this.width >= w) {
this.scaleX *= w / this.width; this.scaleX *= w / this.width;
...@@ -561,7 +564,7 @@ export class Label extends MySprite { ...@@ -561,7 +564,7 @@ export class Label extends MySprite {
const tween = new TWEEN.Tween(this) const tween = new TWEEN.Tween(this)
.to({ alpha: 1 }, 800) .to({ alpha: 1 }, 800)
// .easing(TWEEN.Easing.Quadratic.Out) // Use an easing function to make the animation smooth. // .easing(TWEEN.Easing.Quadratic.Out) // Use an easing function to make the animation smooth.
.onComplete(function() { .onComplete(() => {
if (callBack) { if (callBack) {
callBack(); callBack();
} }
...@@ -569,16 +572,16 @@ export class Label extends MySprite { ...@@ -569,16 +572,16 @@ export class Label extends MySprite {
.start(); // Start the tween immediately. .start(); // Start the tween immediately.
} }
setShadow(offX = 2, offY = 2, blur = 2, color = 'rgba(0, 0, 0, 0.2)') { // setShadow(offX = 0, offY = 2, blur = 2, color = 'rgba(0, 0, 0, 0.2)') {
//
this._shadowFlag = true; // this._shadowFlag = true;
this._shadowColor = color; // this._shadowColor = color;
// 将阴影向右移动15px,向上移动10px // // 将阴影向右移动15px,向上移动10px
this._shadowOffsetX = 5; // this._shadowOffsetX = 5;
this._shadowOffsetY = 5; // this._shadowOffsetY = 5;
// 轻微模糊阴影 // // 轻微模糊阴影
this._shadowBlur = 5; // this._shadowBlur = 5;
} // }
setOutline(width = 5, color = '#ffffff') { setOutline(width = 5, color = '#ffffff') {
...@@ -647,11 +650,10 @@ export class RichTextOld extends Label { ...@@ -647,11 +650,10 @@ export class RichTextOld extends Label {
textArr = []; textArr = [];
fontSize = 40; fontSize = 40;
setText(text:string, words) { setText(text: string, words) {
let newText = text; let newText = text;
for (let i = 0; i < words.length; i++) { for (const word of words) {
const word = words[i];
const re = new RegExp(word, 'g'); const re = new RegExp(word, 'g');
newText = newText.replace( re, `#${word}#`); newText = newText.replace( re, `#${word}#`);
...@@ -674,8 +676,8 @@ export class RichTextOld extends Label { ...@@ -674,8 +676,8 @@ export class RichTextOld extends Label {
this.ctx.fontWeight = this.fontWeight; this.ctx.fontWeight = this.fontWeight;
let curX = 0; let curX = 0;
for (let i = 0; i < this.textArr.length; i++) { for (const text of this.textArr) {
const w = this.ctx.measureText(this.textArr[i]).width; const w = this.ctx.measureText(text).width;
curX += w; curX += w;
} }
...@@ -697,7 +699,7 @@ export class RichTextOld extends Label { ...@@ -697,7 +699,7 @@ export class RichTextOld extends Label {
const tween = new TWEEN.Tween(this) const tween = new TWEEN.Tween(this)
.to({ alpha: 1 }, 800) .to({ alpha: 1 }, 800)
// .easing(TWEEN.Easing.Quadratic.Out) // Use an easing function to make the animation smooth. // .easing(TWEEN.Easing.Quadratic.Out) // Use an easing function to make the animation smooth.
.onComplete(function() { .onComplete(() => {
if (callBack) { if (callBack) {
callBack(); callBack();
} }
...@@ -733,7 +735,7 @@ export class RichTextOld extends Label { ...@@ -733,7 +735,7 @@ export class RichTextOld extends Label {
const w = this.ctx.measureText(this.textArr[i]).width; const w = this.ctx.measureText(this.textArr[i]).width;
if ((i + 1) % 2 == 0) { if ((i + 1) % 2 === 0) {
this.ctx.fillStyle = '#c8171e'; this.ctx.fillStyle = '#c8171e';
} else { } else {
this.ctx.fillStyle = '#000000'; this.ctx.fillStyle = '#000000';
...@@ -758,7 +760,7 @@ export class RichText extends Label { ...@@ -758,7 +760,7 @@ export class RichText extends Label {
disH = 30; disH = 30;
constructor(ctx) { constructor(ctx?: any) {
super(ctx); super(ctx);
// this.dataArr = dataArr; // this.dataArr = dataArr;
...@@ -792,12 +794,12 @@ export class RichText extends Label { ...@@ -792,12 +794,12 @@ export class RichText extends Label {
for (let a = 0; a < chr.length; a++) { for (const c of chr) {
if (this.ctx.measureText(temp).width < w && this.ctx.measureText(temp + (chr[a])).width <= w) { if (this.ctx.measureText(temp).width < w && this.ctx.measureText(temp + (c)).width <= w) {
temp += ' ' + chr[a]; temp += ' ' + c;
} else { } else {
row.push(temp); row.push(temp);
temp = ' ' + chr[a]; temp = ' ' + c;
} }
} }
row.push(temp); row.push(temp);
...@@ -837,6 +839,40 @@ export class RichText extends Label { ...@@ -837,6 +839,40 @@ 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 { export class ShapeRect extends MySprite {
...@@ -895,7 +931,83 @@ export class ShapeCircle extends MySprite { ...@@ -895,7 +931,83 @@ export class ShapeCircle extends MySprite {
} }
} }
export class ShapeRectNew extends MySprite {
radius = 0;
fillColor = '#ffffff';
strokeColor = '#000000';
fill = true;
stroke = false;
lineWidth = 1;
setSize(w, h, r) {
this.width = w;
this.height = h;
this.radius = r;
}
setOutLine(color, lineWidth) {
this.stroke = true;
this.strokeColor = color;
this.lineWidth = lineWidth;
}
drawShape() {
const ctx = this.ctx;
const width = this.width;
const height = this.height;
const radius = this.radius;
ctx.save();
ctx.beginPath(0);
// 从右下角顺时针绘制,弧度从0到1/2PI
ctx.arc(width - radius, height - radius, radius, 0, Math.PI / 2);
// 矩形下边线
ctx.lineTo(radius, height);
// 左下角圆弧,弧度从1/2PI到PI
ctx.arc(radius, height - radius, radius, Math.PI / 2, Math.PI);
// 矩形左边线
ctx.lineTo(0, radius);
// 左上角圆弧,弧度从PI到3/2PI
ctx.arc(radius, radius, radius, Math.PI, Math.PI * 3 / 2);
// 上边线
ctx.lineTo(width - radius, 0);
// 右上角圆弧
ctx.arc(width - radius, radius, radius, Math.PI * 3 / 2, Math.PI * 2);
// 右边线
ctx.lineTo(width, height - radius);
ctx.closePath();
if (this.fill) {
ctx.fillStyle = this.fillColor;
ctx.fill();
}
if (this.stroke) {
ctx.lineWidth = this.lineWidth;
ctx.strokeStyle = this.strokeColor;
ctx.stroke();
}
ctx.restore();
}
drawSelf() {
super.drawSelf();
this.drawShape();
}
}
export class MyAnimation extends MySprite { export class MyAnimation extends MySprite {
...@@ -942,13 +1054,13 @@ export class MyAnimation extends MySprite { ...@@ -942,13 +1054,13 @@ export class MyAnimation extends MySprite {
this.frameArr[this.frameIndex].visible = true; this.frameArr[this.frameIndex].visible = true;
} }
_refreshSize(img) { _refreshSize(img: any) {
if (this.width < img['width']) { if (this.width < img.width) {
this.width = img['width']; this.width = img.width;
} }
if (this.height < img['height']) { if (this.height < img.height) {
this.height = img['height']; this.height = img.height;
} }
} }
...@@ -977,14 +1089,14 @@ export class MyAnimation extends MySprite { ...@@ -977,14 +1089,14 @@ export class MyAnimation extends MySprite {
} }
showAllFrame() { showAllFrame() {
for (let i = 0; i < this.frameArr.length; i++) { for (const frame of this.frameArr ) {
this.frameArr[i].alpha = 1; frame.alpha = 1;
} }
} }
hideAllFrame() { hideAllFrame() {
for (let i = 0; i < this.frameArr.length; i++) { for (const frame of this.frameArr) {
this.frameArr[i].alpha = 0; frame.alpha = 0;
} }
} }
...@@ -1156,7 +1268,7 @@ export function endShow(item, s = 1) { ...@@ -1156,7 +1268,7 @@ export function endShow(item, s = 1) {
const tween = new TWEEN.Tween(item) const tween = new TWEEN.Tween(item)
.to({ alpha: 1, scaleX: s, scaleY: s }, 800) .to({ alpha: 1, scaleX: s, scaleY: s }, 800)
.easing(TWEEN.Easing.Elastic.Out) // Use an easing function to make the animation smooth. .easing(TWEEN.Easing.Elastic.Out) // Use an easing function to make the animation smooth.
.onComplete(function() { .onComplete(() => {
}) })
.start(); .start();
...@@ -1164,14 +1276,14 @@ export function endShow(item, s = 1) { ...@@ -1164,14 +1276,14 @@ export function endShow(item, s = 1) {
export function hideItem(item, time = 0.8, callBack = null, easing = null) { export function hideItem(item, time = 0.8, callBack = null, easing = null) {
if (item.alpha == 0) { if (item.alpha === 0) {
return; return;
} }
const tween = new TWEEN.Tween(item) const tween = new TWEEN.Tween(item)
.to({alpha: 0}, time * 1000) .to({alpha: 0}, time * 1000)
// .easing(TWEEN.Easing.Quadratic.Out) // Use an easing function to make the animation smooth. // .easing(TWEEN.Easing.Quadratic.Out) // Use an easing function to make the animation smooth.
.onComplete(function () { .onComplete(() => {
if (callBack) { if (callBack) {
callBack(); callBack();
} }
...@@ -1187,7 +1299,7 @@ export function hideItem(item, time = 0.8, callBack = null, easing = null) { ...@@ -1187,7 +1299,7 @@ export function hideItem(item, time = 0.8, callBack = null, easing = null) {
export function showItem(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) { if (callBack) {
callBack(); callBack();
} }
...@@ -1198,7 +1310,7 @@ export function showItem(item, time = 0.8, callBack = null, easing = null) { ...@@ -1198,7 +1310,7 @@ export function showItem(item, time = 0.8, callBack = null, easing = null) {
const tween = new TWEEN.Tween(item) const tween = new TWEEN.Tween(item)
.to({alpha: 1}, time * 1000) .to({alpha: 1}, time * 1000)
// .easing(TWEEN.Easing.Quadratic.Out) // Use an easing function to make the animation smooth. // .easing(TWEEN.Easing.Quadratic.Out) // Use an easing function to make the animation smooth.
.onComplete(function () { .onComplete(() => {
if (callBack) { if (callBack) {
callBack(); callBack();
} }
...@@ -1216,9 +1328,9 @@ export function alphaItem(item, alpha, time = 0.8, callBack = null, easing = nul ...@@ -1216,9 +1328,9 @@ export function alphaItem(item, alpha, time = 0.8, callBack = null, easing = nul
const tween = new TWEEN.Tween(item) const tween = new TWEEN.Tween(item)
.to({alpha: alpha}, time * 1000) .to({alpha}, time * 1000)
// .easing(TWEEN.Easing.Quadratic.Out) // Use an easing function to make the animation smooth. // .easing(TWEEN.Easing.Quadratic.Out) // Use an easing function to make the animation smooth.
.onComplete(function () { .onComplete(() => {
if (callBack) { if (callBack) {
callBack(); callBack();
} }
...@@ -1238,7 +1350,7 @@ export function showStar(item, time = 0.8, callBack = null, easing = null) { ...@@ -1238,7 +1350,7 @@ export function showStar(item, time = 0.8, callBack = null, easing = null) {
const tween = new TWEEN.Tween(item) const tween = new TWEEN.Tween(item)
.to({alpha: 1, scale: 1}, time * 1000) .to({alpha: 1, scale: 1}, time * 1000)
// .easing(TWEEN.Easing.Quadratic.Out) // Use an easing function to make the animation smooth. // .easing(TWEEN.Easing.Quadratic.Out) // Use an easing function to make the animation smooth.
.onComplete(function () { .onComplete(() => {
if (callBack) { if (callBack) {
callBack(); callBack();
} }
...@@ -1294,22 +1406,22 @@ export function getAngleByPos(px, py, mx, my) { ...@@ -1294,22 +1406,22 @@ export function getAngleByPos(px, py, mx, my) {
const radina = Math.acos(cos); // 用反三角函数求弧度 const radina = Math.acos(cos); // 用反三角函数求弧度
let angle = Math.floor(180 / (Math.PI / radina) * 100) / 100; // 将弧度转换成角度 let angle = Math.floor(180 / (Math.PI / radina) * 100) / 100; // 将弧度转换成角度
if(mx > px && my > py) {// 鼠标在第四象限 if (mx > px && my > py) {// 鼠标在第四象限
angle = 180 - angle; angle = 180 - angle;
} }
if(mx === px && my > py) {// 鼠标在y轴负方向上 if (mx === px && my > py) {// 鼠标在y轴负方向上
angle = 180; angle = 180;
} }
if(mx > px && my === py) {// 鼠标在x轴正方向上 if (mx > px && my === py) {// 鼠标在x轴正方向上
angle = 90; angle = 90;
} }
if(mx < px && my > py) {// 鼠标在第三象限 if (mx < px && my > py) {// 鼠标在第三象限
angle = 180 + angle; angle = 180 + angle;
} }
if(mx < px && my === py) {// 鼠标在x轴负方向 if (mx < px && my === py) {// 鼠标在x轴负方向
angle = 270; angle = 270;
} }
if(mx < px && my < py) {// 鼠标在第二象限 if (mx < px && my < py) {// 鼠标在第二象限
angle = 360 - angle; angle = 360 - angle;
} }
...@@ -1321,7 +1433,7 @@ export function getAngleByPos(px, py, mx, my) { ...@@ -1321,7 +1433,7 @@ export function getAngleByPos(px, py, mx, my) {
export function removeItemFromArr(arr, item) { export function removeItemFromArr(arr, item) {
const index = arr.indexOf(item); const index = arr.indexOf(item);
if (index != -1) { if (index !== -1) {
arr.splice(index, 1); arr.splice(index, 1);
} }
} }
...@@ -1331,7 +1443,7 @@ export function removeItemFromArr(arr, item) { ...@@ -1331,7 +1443,7 @@ export function removeItemFromArr(arr, item) {
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); const r = getPosDistance(item.x, item.y, x0, y0);
let a = getAngleByPos(item.x, item.y, x0, y0); let a = getAngleByPos(item.x, item.y, x0, y0);
...@@ -1396,18 +1508,20 @@ export function formatTime(fmt, date) { ...@@ -1396,18 +1508,20 @@ export function formatTime(fmt, date) {
// "yyyy-MM-dd HH:mm:ss"; // "yyyy-MM-dd HH:mm:ss";
const o = { const o = {
"M+": date.getMonth() + 1, // 月份 'M+': date.getMonth() + 1, // 月份
"d+": date.getDate(), // 日 'd+': date.getDate(), // 日
"h+": date.getHours(), // 小时 'h+': date.getHours(), // 小时
"m+": date.getMinutes(), // 分 'm+': date.getMinutes(), // 分
"s+": date.getSeconds(), // 秒 's+': date.getSeconds(), // 秒
"q+": Math.floor((date.getMonth() + 3) / 3), // 季度 'q+': Math.floor((date.getMonth() + 3) / 3), // 季度
"S": date.getMilliseconds() // 毫秒 S: date.getMilliseconds() // 毫秒
}; };
if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (date.getFullYear() + "").substr(4 - RegExp.$1.length)); if (/(y+)/.test(fmt)) { fmt = fmt.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length)); }
for (var k in o) for (const k in o) {
if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) if (new RegExp('(' + k + ')').test(fmt)) { fmt = fmt.replace(RegExp.$1, (RegExp.$1.length === 1)
? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length))); ? (o[k]) : (('00' + o[k]).substr(('' + o[k]).length)));
}
}
return fmt; return fmt;
} }
...@@ -1459,9 +1573,9 @@ export function jelly(item, time = 0.7) { ...@@ -1459,9 +1573,9 @@ export function jelly(item, time = 0.7) {
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 ++) { for (let i = 0; i < num; i ++) {
const particle = new MySprite(); const particle = new MySprite();
...@@ -1473,8 +1587,8 @@ export function showPopParticle(img, pos, parent) { ...@@ -1473,8 +1587,8 @@ export function showPopParticle(img, pos, parent) {
const randomR = 360 * Math.random(); const randomR = 360 * Math.random();
particle.rotation = randomR; particle.rotation = randomR;
const randomS = 0.5 + Math.random() * 0.5; const randomS = 0.3 + Math.random() * 0.7;
particle.setScaleXY(randomS); particle.setScaleXY(randomS * 0.3);
const randomX = Math.random() * 20 - 10; const randomX = Math.random() * 20 - 10;
particle.x += randomX; particle.x += randomX;
...@@ -1482,16 +1596,32 @@ export function showPopParticle(img, pos, parent) { ...@@ -1482,16 +1596,32 @@ export function showPopParticle(img, pos, parent) {
const randomY = Math.random() * 20 - 10; const randomY = Math.random() * 20 - 10;
particle.y += randomY; particle.y += randomY;
const randomL = 40 + Math.random() * 40; const randomL = minLen + Math.random() * (maxLen - minLen);
const randomA = 360 * Math.random(); const randomA = 360 * Math.random();
const randomT = getPosByAngle(randomA, randomL); const randomT = getPosByAngle(randomA, randomL);
moveItem(particle, particle.x + randomT.x, particle.y + randomT.y, 0.4, () => { moveItem(particle, particle.x + randomT.x, particle.y + randomT.y, showTime, () => {
}, TWEEN.Easing.Exponential.Out); }, TWEEN.Easing.Exponential.Out);
scaleItem(particle, 0, 0.6, () => { // scaleItem(particle, 0, 0.6, () => {
//
// });
scaleItem(particle, randomS, 0.6, () => {
}, TWEEN.Easing.Exponential.Out);
setTimeout(() => {
hideItem(particle, 0.4, () => {
}, TWEEN.Easing.Cubic.In);
}, showTime * 0.5 * 1000);
});
} }
} }
...@@ -1533,7 +1663,7 @@ export function shake(item, time = 0.5, callback = null, rate = 1) { ...@@ -1533,7 +1663,7 @@ export function shake(item, time = 0.5, callback = null, rate = 1) {
}; };
const move1 = () => { const move1 = () => {
moveItem(item, baseX + offX, baseY + offY, time / 8, () => { moveItem(item, baseX + offX, baseY + offY, time / 7.5, () => {
move2(); move2();
}, easing); }, easing);
}; };
...@@ -1544,244 +1674,3 @@ export function shake(item, time = 0.5, callback = null, rate = 1) { ...@@ -1544,244 +1674,3 @@ export function shake(item, time = 0.5, callback = null, rate = 1) {
// --------------- custom class -------------------- // --------------- custom class --------------------
export class Cow extends MyAnimation {
idleFrameArr;
eatFrameArr;
likeFrameArr;
angryFrameArr;
happyFrameArr;
bubble1;
bubble2;
idle() {
this.setStyle('idle');
this.loop = true;
this.play();
this.showBubble();
}
eat() {
this.setStyle('eat');
this.loop = false;
this.playEndFunc = () => {
this.idle();
};
this.hideBubble();
}
angry() {
this.setStyle('angry');
this.loop = false;
this.playEndFunc = () => {
this.idle();
};
this.hideBubble();
}
like() {
this.setStyle('like');
this.loop = true;
this.hideBubble();
}
happy() {
this.setStyle('happy');
this.loop = true;
this.hideBubble();
}
setBubble(b1, b2, item) {
const bubble = new MySprite();
bubble.init(b1);
bubble.x = -65;
bubble.y = -120;
this.addChild(bubble);
bubble.visible = false;
this.bubble1 = bubble;
const bubble2 = new MySprite();
bubble2.init(b2);
bubble2.x = -100;
bubble2.y = -210;
this.addChild(bubble2);
bubble2.visible = false;
this.bubble2 = bubble2;
// const maxH = 150;
// const shapeRect = new ShapeRect();
// shapeRect.setSize(160, 120);
// shapeRect.alpha = 0.3;
// shapeRect.init();
// bubble2.addChild(shapeRect);
bubble2.addChild(item);
}
showBubble() {
const bubble1 = this.bubble1;
const bubble2 = this.bubble2;
bubble1.visible = true;
bubble2.visible = true;
bubble1.setScaleXY(0);
bubble2.setScaleXY(0);
scaleItem(bubble1, 1, 0.2, () => {
}, TWEEN.Easing.Quadratic.Out);
setTimeout(() => {
scaleItem(bubble2, 1, 0.6, null, TWEEN.Easing.Quadratic.Out);
}, 0.2 * 1000);
}
hideBubble() {
this.bubble1.visible = false;
this.bubble2.visible = false;
}
setStyle(key) {
this.delayPerUnit = 0.15;
switch (key) {
case 'idle':
this.frameArr = this.idleFrameArr.concat();
break;
case 'eat':
this.delayPerUnit = 0.115;
this.frameArr = this.eatFrameArr.concat();
break;
case 'angry':
this.frameArr = this.angryFrameArr.concat();
this.delayPerUnit = 0.165;
break;
case 'happy':
this.frameArr = this.happyFrameArr.concat();
break;
case 'like':
this.frameArr = this.likeFrameArr.concat();
break;
}
this.frameIndex = 0;
this.setArrVisible(this.idleFrameArr);
this.setArrVisible(this.eatFrameArr);
this.setArrVisible(this.likeFrameArr);
this.setArrVisible(this.angryFrameArr);
this.setArrVisible(this.happyFrameArr);
this.frameArr[this.frameIndex].visible = true;
}
setArrVisible(arr) {
if (arr) {
for (let i = 0; i < arr.length; i ++) {
arr[i].visible = false;
}
}
}
addIdleFrame(img) {
if (!this.idleFrameArr) {
this.idleFrameArr = [];
}
const spr = new MySprite(this.ctx);
spr.init(img);
this._refreshSize(img);
spr.visible = false;
this.addChild(spr);
this.idleFrameArr.push(spr);
}
addEatFrame(img) {
if (!this.eatFrameArr) {
this.eatFrameArr = [];
}
const spr = new MySprite(this.ctx);
spr.init(img);
this._refreshSize(img);
spr.visible = false;
this.addChild(spr);
this.eatFrameArr.push(spr);
}
addLikeFrame(img) {
if (!this.likeFrameArr) {
this.likeFrameArr = [];
}
const spr = new MySprite(this.ctx);
spr.init(img);
this._refreshSize(img);
spr.visible = false;
this.addChild(spr);
this.likeFrameArr.push(spr);
}
addAngryFrame(img) {
if (!this.angryFrameArr) {
this.angryFrameArr = [];
}
const spr = new MySprite(this.ctx);
spr.init(img);
this._refreshSize(img);
spr.visible = false;
this.addChild(spr);
this.angryFrameArr.push(spr);
}
addHappyFrame(img) {
if (!this.happyFrameArr) {
this.happyFrameArr = [];
}
const spr = new MySprite(this.ctx);
spr.init(img);
this._refreshSize(img);
spr.visible = false;
this.addChild(spr);
this.happyFrameArr.push(spr);
}
}
.game-container { .game-container {
width: 100%; width: 100%;
height: 100%; height: 100%;
//background-image: url("/assets/listen-read-circle/bg.jpg");
background: #ffffff; background: #ffffff;
background-repeat: no-repeat;
background-size: cover; background-size: cover;
} }
...@@ -19,11 +17,3 @@ ...@@ -19,11 +17,3 @@
src: url("../../assets/font/BRLNSDB.TTF") ; src: url("../../assets/font/BRLNSDB.TTF") ;
} }
//
//
//@font-face
//{
// font-family: 'RoundedBold';
// src: url("../../assets/font/ArialRoundedBold.otf") ;
//}
import {Component, ElementRef, ViewChild, OnInit, Input, OnDestroy, HostListener} from '@angular/core'; import {Component, ElementRef, ViewChild, OnInit, Input, OnDestroy, HostListener} from '@angular/core';
import { import {
getAngleByPos,
MySprite,
getPosByAngle,
Label, Label,
MyAnimation, MySprite, tweenChange,
moveItem,
randomSortByArr,
scaleItem,
rotateItem,
tweenChange,
hideItem,
showItem,
BitMapLabel,
ColorSpr,
removeItemFromArr,
ShapeRect,
alphaItem,
circleMove,
ShapeCircle,
delayCall,
RichText,
getMinScale,
getPosDistance, jelly, showPopParticle, shake, Cow, formatTime
} from './Unit'; } from './Unit';
import {res, resAudio} from './resources'; import {res, resAudio} from './resources';
import {Subject} from 'rxjs'; import {Subject} from 'rxjs';
import {debounceTime} from 'rxjs/operators'; import {debounceTime} from 'rxjs/operators';
import * as _ from 'lodash';
import TWEEN from '@tweenjs/tween.js'; import TWEEN from '@tweenjs/tween.js';
import {del} from 'selenium-webdriver/http';
import {text} from "@angular/core/src/render3";
...@@ -41,2380 +18,134 @@ import {text} from "@angular/core/src/render3"; ...@@ -41,2380 +18,134 @@ import {text} from "@angular/core/src/render3";
@Component({ @Component({
selector: 'app-play', selector: 'app-play',
templateUrl: './play.component.html', templateUrl: './play.component.html',
styleUrls: ['./play.component.scss'] styleUrls: ['./play.component.css']
}) })
export class PlayComponent implements OnInit, OnDestroy { export class PlayComponent implements OnInit, OnDestroy {
// 数据
_data;
@Input()
set data(data) {
this._data = data;
}
get data() {
return this._data;
}
@Input()
sid;
@ViewChild('canvas') canvas: ElementRef; @ViewChild('canvas', {static: true }) canvas: ElementRef;
@ViewChild('wrap') wrap: ElementRef; @ViewChild('wrap', {static: true }) wrap: ElementRef;
canvasWidth = 1280;
canvasHeight = 720;
canvasBaseW = 1280; // 数据
canvasBaseH = 720; data;
ctx; ctx;
fps = 0;
frametime = 0; // 上一帧动画的时间, 两帧时间差
canvasWidth = 1280; // canvas实际宽度
canvasHeight = 720; // canvas实际高度
mx; canvasBaseW = 1280; // canvas 资源预设宽度
my; // 点击坐标 canvasBaseH = 720; // canvas 资源预设高度
mx; // 点击x坐标
my; // 点击y坐标
// 资源 // 资源
rawImages = new Map(res); rawImages = new Map(res);
rawAudios = new Map(resAudio); rawAudios = new Map(resAudio);
// 声音
bgAudio = new Audio();
successAudio = new Audio();
wrongAudio = new Audio();
rightAudio = new Audio();
titleAudio = new Audio();
images = new Map(); images = new Map();
animationId: any; animationId: any;
winResizeEventStream = new Subject(); winResizeEventStream = new Subject();
audioObj = {}; audioObj = {};
renderArr; renderArr;
mapScale = 1; mapScale = 1;
canvasLeft; canvasLeft;
canvasTop; canvasTop;
saveKey = 'test_0011';
canTouch = true;
KEY = 'dfzx_zx_image';
// -----
picArr;
itemArrA;
itemArrB;
curItem;
linkIdArr;
petalTime;
optionArr;
cowScale;
grassArr;
curGrass;
downFlag = true;
cowArr;
timeLabel;
clockUpdateFlag;
clock1Bg;
btnRestar;
restartBtn;
clock2Bg;
curCow;
pageLabel;
leftBtn;
rightBtn;
curPicBg;
bgLayer;
curPageIndex;
curAudio;
itemBgArr;
ballArr;
lightIndex = 0;
grouoLightIndex = 0;
curLight;
goBtn;
wheel;
arrow;
lightDelayTime = 0;
questionBg;
answerLabelArr;
questionLabel;
questionLabel2;
questionPicRect;
textBgArr;
picBgArr;
answerPicArr;
idArr;
answerTypeArr = ['A', 'B', 'C', 'D'];
answerTitleArr;
lightDelayId;
rightFlag;
ballGroupArr;
animaStopRun;
animaNewStopRun;
hotZoneArr;
picRect;
closeBtn;
itemBg;
curSong;
oldFrameColorId;
curCard;
bottomCard;
picW = 370;
picH = 260;
mask;
ball;
stick;
robot;
pageW = 840;
page1;
page2;
arm1;
arm2;
centerPageArr;
pageOffX = 100;
curPic;
roleArr;
picIndex = 0;
curData;
bgTop;
topImg;
curWordArr;
wordMoveFlag;
maxScore;
bottomY;
leftScore;
rightScore;
leftScoreLabel;
rightScoreLabel;
addScoreNum = 20;
leftWin;
rightWin;
startPageArr = [];
bgArr;
rightArr;
title;
startBtn; btnLeft;
starArr; btnRight;
pic1;
wand; pic2;
light;
replayBtn;
endPageArr;
gameEndFlag;
showPetalFlag;
bg;
canTouch = true;
curPic;
@HostListener('window:resize', ['$event']) @HostListener('window:resize', ['$event'])
onResize(event) { onResize(event) {
this.winResizeEventStream.next(); this.winResizeEventStream.next();
} }
ngOnInit() { ngOnInit() {
this.data = {};
// 获取数据
const getData = (<any> window).courseware.getData; const getData = (<any> window).courseware.getData;
getData((data) => { getData((data) => {
if (data && typeof data == 'object') { if (data && typeof data == 'object') {
this.data = data; this.data = data;
} else {
this.data = {};
} }
// console.log('data:' , data);
console.log('data:' , data); // 初始化 各事件监听
if (!this.data.contentObj) { this.initListener();
this.data.contentObj = {};
}
// 若无数据 则为预览模式 需要填充一些默认数据用来显示
this.initDefaultData(); this.initDefaultData();
// 初始化 音频资源
this.initAudio(); this.initAudio();
// 初始化 图片资源
this.initImg(); this.initImg();
this.initListener(); // 开始预加载资源
this.load();
}, this.KEY);
//
// // this.initAudio();
// this.initImg();
// this.initListener();
}
initDefaultData() {
let picArr = this.data.contentObj.picArr;
// console.log('picArr: ', picArr);
if (!picArr || picArr.length == 0) {
const picArr = [];
for (let i = 0; i < 2; i++) {
picArr.push({
'pic_url': 'assets/play/default/pic.jpg',
'audio_url': 'assets/play/default/audio.mp3'
});
}
this.data.contentObj.picArr = picArr;
}
}
ngOnDestroy() {
window['curCtx'] = null;
window.cancelAnimationFrame(this.animationId);
this.bgAudio.pause();
this.gameEndFlag = true;
clearTimeout(this.lightDelayId);
}
initData() {
this.canvasWidth = this.wrap.nativeElement.clientWidth;
this.canvasHeight = this.wrap.nativeElement.clientHeight;
this.canvas.nativeElement.width = this.wrap.nativeElement.clientWidth;
this.canvas.nativeElement.height = this.wrap.nativeElement.clientHeight;
const sx = this.canvasWidth / this.canvasBaseW;
const sy = this.canvasHeight / this.canvasBaseH;
const s = Math.min(sx, sy);
this.mapScale = s;
// this.mapScale = this.canvasWidth / this.canvasBaseW;
// this.mapScale = this.canvasHeight / this.canvasBaseH;
this.renderArr = [];
console.log(' in initData', this.data);
this.canTouch = true;
this.curPageIndex = 0;
// this.downFlag = false;
this.endPageArr = [];
// this.clockUpdateFlag = false;
if (!this.data.contentObj.picArr) {
this.data.contentObj.picArr = [];
}
this.picArr = this.data.contentObj.picArr;
// this.optionArr = this.data.contentObj.optionArr;
// this.optionArr = randomSortByArr(this.optionArr);
this.curGrass = null;
this.curCow = null;
// this.picArr = randomSortByArr(this.picArr);
//
// // this.picArr = randomSortByArr(this.picArr);
this.picIndex = 0;
}
initAudio() {
const contentObj = this.data.contentObj;
if (!contentObj) { return; }
// const addAudio = (key) => {
// const audioUrl = contentObj[key];
// if (audioUrl) {
// const audio = new Audio();
// audio.src = audioUrl;
// audio.load();
// this.audioObj[key] = audio;
// }
// }
//
// for (let i = 0; i < 4; i ++) {
// const key = i + '_audio_url';
// addAudio(key);
// }
//
// addAudio('audio_url');
//
const addUrlToAudioObj = (audioUrl) => {
if (audioUrl) {
// console.log('audioUrl:', audioUrl);
const audio = new Audio();
audio.src = audioUrl;
audio.load();
this.audioObj[audioUrl] = audio;
}
};
let arr = contentObj.picArr;
if (arr) {
// console.log('arr: ', arr);
for (let i = 0; i < arr.length; i++) {
addUrlToAudioObj(arr[i].audio_url);
}
}
}, this.saveKey);
const audioObj = this.audioObj;
const addOneAudio = (key, url, vlomue = 1, loop = false, callback = null) => {
const audio = new Audio();
audio.src = url;
audio.load();
audio.loop = loop;
audio.volume = vlomue;
audioObj[key] = audio;
if (callback) {
audio.onended = () => {
callback();
};
}
};
addOneAudio('click', this.rawAudios.get('click'), 0.3);
// addOneAudio('angry', this.rawAudios.get('angry'), 1);
// addOneAudio('cow_start', this.rawAudios.get('cow_start'), 1);
// addOneAudio('eat', this.rawAudios.get('eat'), 1);
// addOneAudio('grass', this.rawAudios.get('grass'), 1);
// addOneAudio('happy', this.rawAudios.get('happy'), 1);
// addOneAudio('right', this.rawAudios.get('right'), 1);
// addOneAudio('wrong', this.rawAudios.get('wrong'), 1);
//
// const titleUrl = this.data.contentObj.title_audio_url;
// if (titleUrl) {
//
// this.titleAudio.src = titleUrl;
// this.titleAudio.load();
// }
// this.bgAudio.src = 'assets/bat-mail/music/bg.mp3';
// this.bgAudio.load();
// this.bgAudio.loop = true;
// this.bgAudio.volume = 0.5;
//
// this.wrongAudio.src = 'assets/common/music/wrong.mp3';
// this.wrongAudio.load();
//
// this.rightAudio.src = 'assets/common/music/right.mp3';
// this.rightAudio.load();
//
// this.successAudio.src = 'assets/magic-hat/music/finish.mp3';
// this.successAudio.load();
//
// this.successAudio.onended = () => {
// // this.showSuccessAudio();
// };
}
initImg() {
const contentObj = this.data.contentObj;
if (contentObj) {
const addPicUrl = (url) => {
if (url) {
this.rawImages.set(url, url);
}
};
let arr = this.data.contentObj.picArr;
if (arr) {
for (let i = 0; i < arr.length; i++) {
addPicUrl( arr[i].pic_url);
}
}
}
// this.initFontImg();
// 预加载资源
this.loadResources().then(() => {
// this.setfontData();
window['air'].hideAirClassLoading(this.KEY, this.data);
this.init();
this.update();
});
}
initFontImg() {
// const fontbaseUrlW = 'assets/mechanical/letter/';
// const fontDataW = {};
//
// let num = 97;
// for (let i = 0; i < 26; i++) {
//
// const key = String.fromCharCode(num + i); // 'a'
// const url = fontbaseUrlW + key + '.png';
//
// this.rawImages.set(url, url);
// fontDataW[key] = url;
// }
//
//
// this.fontDataW = fontDataW;
}
setfontData() {
// for (let key in this.fontDataW) {
// this.fontDataW[key] = this.images.get(this.fontDataW[key]);
// }
}
init() {
this.initData();
this.initCtx();
this.initView();
}
initCtx() {
this.ctx = this.canvas.nativeElement.getContext('2d');
this.canvas.nativeElement.width = this.canvasWidth;
this.canvas.nativeElement.height = this.canvasHeight;
window['curCtx'] = this.ctx;
// console.log('this.ctx.canvas w: ', this.ctx.canvas.width);
// console.log('this.ctx.canvas h: ', this.ctx.canvas.height);
}
initView() {
this.initBg();
this.initPic();
this.initBottomRight();
this.refreshPageLabel();
// this.initClock();
// this.initCow();
// this.initItem();
// this.initGrass();
// this.showClock2();
}
initBottomRight() {
const px = this.canvasWidth - 100 * this.mapScale;
const py = this.canvasHeight - 50 * this.mapScale;
const offX = 40 * this.mapScale;
const leftBtn = new MySprite();
leftBtn.init(this.images.get('btn_left'));
leftBtn.setScaleXY(this.mapScale);
leftBtn.x = px - offX;
leftBtn.y = py;
const rightBtn = new MySprite();
rightBtn.init(this.images.get('btn_right'));
rightBtn.setScaleXY(this.mapScale);
rightBtn.x = px + offX;
rightBtn.y = py;
this.renderArr.push(leftBtn);
this.renderArr.push(rightBtn);
const textBg = new MySprite();
textBg.init(this.images.get('text_bg'));
textBg.setScaleXY(this.mapScale);
textBg.x = px;
textBg.y = py - 65 * this.mapScale;
this.renderArr.push(textBg);
const label = new Label();
label.text = '0 / 0';
label.fontName = 'BRLNSDB';
label.fontSize = 24;
label.fontColor = '#ffffff';
label.textAlign = 'center';
label.setMaxSize( textBg.width * textBg.scaleX * 0.9 );
textBg.addChild(label);
this.leftBtn = leftBtn;
this.rightBtn = rightBtn;
this.pageLabel = label;
if (this.picArr.length <= 1) {
this.leftBtn.visible = false;
this.rightBtn.visible = false;
textBg.visible = false;
} }
}
refreshPageLabel() {
const label = this.pageLabel;
label.text = (this.curPageIndex + 1) + ' / ' + this.picArr.length;
this.showAudio();
}
showAudio() {
const data = this.picArr[this.curPageIndex];
const audio = this.audioObj[data.audio_url];
if (audio) {
audio.play();
this.curAudio = audio;
}
}
initCow() {
this.cowArr = [];
const edgeW = 50 * this.mapScale;
let itemW = 377 * this.mapScale * 0.9;
let disW = (this.canvasWidth - edgeW * 2 - itemW * 3) / 2;
let offX = this.canvasWidth / 2 - (itemW + disW) / 2 * (this.picArr.length - 1);
console.log('disW:' , disW);
if (this.picArr.length >= 4) {
const itemRate = 10;
const disWRate = 1;
const tmp = (this.canvasWidth - edgeW * 2) / (itemRate * this.picArr.length + disWRate * (this.picArr.length - 1));
itemW = itemRate * tmp;
disW = disWRate * tmp;
offX = edgeW + itemW / 2;
}
this.cowScale = itemW / 377;
for (let i = 0; i < this.picArr.length; i++) {
const data = this.picArr[i];
const cow = new Cow();
cow.init();
cow.setScaleXY(itemW / 377);
cow.x = offX + i * (itemW + disW);
cow.y = this.canvasHeight / 2 + 140 * this.mapScale - itemW / 2;
cow.width = 377;
cow.height = 377;
cow['id'] = i;
cow['baseX'] = cow.x;
cow['baseY'] = cow.y;
cow['data'] = data;
cow['offX'] = -70 * cow.scaleX;
cow['offY'] = 70 * cow.scaleY;
const url = this.rawAudios.get('cow_start');
const audio = new Audio();
audio.src = url.toString();
audio.load();
audio.volume = 0.2;
cow['audio'] = audio;
let item;
if (data.pic_url) {
item = new MySprite();
item.init(this.images.get(data.pic_url));
item.setScaleXY(getMinScale(item, 130));
} else {
item = new Label();
item.text = data.text;
item.fontName = 'BRLNSDB';
item.fontSize = 72;
item.fontColor = '#fe5e22';
item.textAlign = 'center';
item.setMaxSize(160);
}
cow.setBubble(this.images.get('bubble_small'), this.images.get('bubble_big'), item);
for (let j = 0; j < 12; j++) {
const key = 'idle_' + (j + 1);
cow.addIdleFrame(this.images.get(key));
}
for (let j = 0; j < 12; j++) {
const key = 'eat_' + (j + 1);
cow.addEatFrame(this.images.get(key));
}
for (let j = 0; j < 6; j++) {
const key = 'angry_' + (j + 1);
cow.addAngryFrame(this.images.get(key));
}
for (let j = 0; j < 4; j++) {
const key = 'happy_' + (j + 1);
cow.addHappyFrame(this.images.get(key));
}
for (let j = 0; j < 6; j++) {
const key = 'like_' + (j + 1);
cow.addLikeFrame(this.images.get(key));
}
cow.setStyle('idle');
this.renderArr.push(cow);
this.cowArr.push(cow);
cow.delayPerUnit = 0.15;
cow.loop = true;
// cow.play();
cow.y = -cow.height * cow.scaleY;
setTimeout(() => {
moveItem(cow, cow['baseX'], cow['baseY'], 1.2, () => {
cow.idle();
}, TWEEN.Easing.Bounce.Out);
setTimeout(() => {
cow['audio'].play();
}, 440);
}, Math.random() * 0.5 * 1000);
}
setTimeout(() => {
this.initGrass();
}, (0.3 + 1.2) * 1000);
}
initPic() {
for (let i = 0; i < this.picArr.length; i++) {
const data = this.picArr[i];
const pic = new MySprite();
pic.init(this.images.get(data.pic_url));
// pic.x = this.canvasWidth / 2;
// pic.y = this.canvasHeight / 2;
const maxW = this.canvasWidth * 0.9;
const maxH = this.canvasHeight * 0.9;
const sx = maxW / pic.width;
const sy = maxH / pic.height;
const s = Math.min(sx, sy);
pic.setScaleXY(s);
// pic.setRadius(50 * this.mapScale);
const picBg = new ShapeRect();
picBg.setSize(pic.width * pic.scaleX, pic.height * pic.scaleY);
picBg.x = this.canvasWidth / 2 + this.canvasWidth * i;
picBg.y = this.canvasHeight / 2;
picBg.init();
picBg.fillColor = '#ffffff';
// picBg.setRadius(50 * this.mapScale);
picBg.setShadow(0, 10, 20, 'rgba(0,0,0,0.3)');
// picBg.alpha = 0;
// this.renderArr.push(picBg);
// this.renderArr.push(picShadow);
picBg.addChild(pic);
this.bgLayer.addChild(picBg);
}
}
initGrass() {
this.grassArr = [];
// this.optionArr = this.optionArr.concat(this.optionArr);
const rect = new ShapeRect();
rect.setSize(this.canvasWidth, this.canvasHeight / 3);
rect.alpha = 0.3;
rect.y = this.canvasHeight - rect.height;
// this.renderArr.push(rect);
const scale = this.cowScale;
const grassW = 231 * scale;
const grassH = 148 * scale * 0.8;
const num = this.optionArr.length;
const disW = 0 * this.mapScale;
const maxRowNum = Math.floor(this.canvasWidth / (grassW + disW));
let offX = this.canvasWidth / 2 - (num - 1) * (grassW + disW) / 2 - grassW / 4;
if (num > maxRowNum) {
offX = this.canvasWidth / 2 - (maxRowNum - 1) * (grassW + disW) / 2 - grassW / 4;
}
let offY = this.canvasHeight - grassH / 2;
console.log('maxRowNum: ', maxRowNum);
for (let i = 0; i < this.optionArr.length; i++) {
const data = this.optionArr[i];
// console.log('option data: ', data);
const grass = new MySprite(this.ctx);
grass.init(this.images.get('grass'));
grass.setScaleXY(scale);
grass['type'] = data.type;
grass['data'] = data;
const light = new MySprite();
light.init(this.images.get('grass_light'));
light.visible = false;
grass.addChild(light);
grass['light'] = light;
const url = this.rawAudios.get('grass');
const audio = new Audio();
audio.src = url.toString();
audio.load();
audio.volume = 0.2;
grass['audio'] = audio;
if (data.pic_url) {
// const w = 150;
// const h = 50;
const w = 80;
const h = 80;
const pic = new MySprite();
pic.init(this.images.get(data.pic_url));
pic.setScaleXY(getMinScale(pic, w));
pic.x = 15;
pic.y = -3;
// const pic = new ShapeRect();
// pic.alpha = 0.3;
// pic.setSize(w, h);
// // pic.x = -w / 2 + 6;
// // pic.y = -h / 2 - 3.5;
// pic.x = -w / 2 + 15;
// pic.y = -h / 2 - 3;
grass.addChild(pic);
} else {
const label = new Label();
label.text = data.text;
label.fontName = 'BRLNSDB';
label.fontColor = '#ffffff';
label.fontSize = 48;
label.textAlign = 'center';
label.setMaxSize(140);
label.x = 6;
label.y = -2.5;
grass.addChild(label);
}
const tmpNum = Math.floor(i / maxRowNum);
grass.x = offX + (i % maxRowNum) * (grassW + disW) + tmpNum % 2 * grassW / 2;
grass.y = offY - (tmpNum) * grassH;
grass['baseX'] = grass.x;
grass['baseY'] = grass.y;
this.grassArr.push(grass);
this.renderArr.push(grass);
grass['baseS'] = grass.scaleX;
grass.setScaleXY(0);
setTimeout(() => {
scaleItem(grass, grass['baseS'], 1 + Math.random() * 0.5, null, TWEEN.Easing.Elastic.Out);
grass['audio'].play();
}, 500 * Math.random());
setTimeout(() => {
this.canTouch = true;
this.showTime();
}, 1300);
}
}
showTime() {
this.timeLabel.date = new Date();
this.clockUpdateFlag = true;
}
initItem() {
const picArr = this.picArr;
let itemW, edgeW, disW, disH, offX, offY;
if (picArr.length <= 6) {
itemW = 215 * this.mapScale;
edgeW = 10 * this.mapScale;
disW = (this.canvasWidth - itemW * 6 - edgeW * 2) / 5;
disH = 300 * this.mapScale;
offX = this.canvasWidth / 2 - (picArr.length - 1) * (itemW + disW) / 2;
offY = this.canvasHeight / 2 - disH / 2 + 70 * this.mapScale;
} else {
// itemW = 215 * this.mapScale;
const rate = 10; // 距离与图片比例 10:1
edgeW = 10 * this.mapScale;
itemW = (this.canvasWidth - edgeW / 2) / (picArr.length * rate + picArr.length + 1) * rate;
disW = itemW / rate;
disH = 300 * this.mapScale;
offX = this.canvasWidth / 2 - (picArr.length - 1) * (itemW + disW) / 2;
offY = this.canvasHeight / 2 - disH / 2 + 70 * this.mapScale;
}
const tmpS = itemW / 215;
const rectW = 157 * tmpS;
let dataArrA = [];
let dataArrB = [];
for (let i = 0; i < picArr.length; i ++) {
const picData = picArr[i];
let tmpData = {};
tmpData['id'] = i;
tmpData['text'] = picData.a_text;
tmpData['pic_url'] = picData.a_pic_url;
tmpData['audio_url'] = picData.a_audio_url;
dataArrA.push(tmpData);
tmpData = {};
tmpData['id'] = i;
tmpData['text'] = picData.b_text;
tmpData['pic_url'] = picData.b_pic_url;
tmpData['audio_url'] = picData.b_audio_url;
dataArrB.push(tmpData);
}
dataArrA = randomSortByArr(dataArrA);
dataArrB = randomSortByArr(dataArrB);
// this.itemArrA = itemArrA;
// this.itemArrB = itemArrB;
this.itemArrA = [];
this.itemArrB = [];
for (let i = 0; i < picArr.length; i ++) {
const dataA = dataArrA[i];
let itemBg = new MySprite();
itemBg.init(this.images.get('item_bg'));
itemBg.setScaleXY(itemW / itemBg.width);
itemBg.x = offX + i * (itemW + disW);
itemBg.y = offY;
let bgRect = new ShapeRect();
// bgRect.setSize(rectW, rectW);
bgRect.setSize(157, 157);
bgRect.init();
// bgRect.x = itemBg.x;
// bgRect.y = itemBg.y;
bgRect.fillColor = '#ffffff';
itemBg.addChild(bgRect, -1);
// this.renderArr.push(bgRect);
if (dataA.pic_url) {
let pic = new MySprite();
pic.init(this.images.get(dataA.pic_url));
pic.setScaleXY(getMinScale(pic, bgRect.width - 2));
bgRect.addChild(pic);
} else {
const label = new Label();
label.text = dataA.text;
label.fontName = 'BRLNSDB';
label.textAlign = 'center';
label.fontSize = 64;
label.setMaxSize(bgRect.width - 20);
bgRect.addChild(label);
}
let dot = new MySprite();
dot.init(this.images.get('dot'));
dot.y = itemBg.height / 2 - 25;
dot.visible = false;
itemBg.addChild(dot);
itemBg['dot'] = dot;
itemBg['type'] = 'A';
itemBg['data'] = dataA;
this.renderArr.push(itemBg);
this.itemArrA.push(itemBg);
const dataB = dataArrB[i];
itemBg = new MySprite();
itemBg.init(this.images.get('item_bg'));
itemBg.setScaleXY(itemW / itemBg.width);
itemBg.x = offX + i * (itemW + disW);
itemBg.y = offY + disH;
bgRect = new ShapeRect();
// bgRect.setSize(rectW, rectW);
bgRect.setSize(157, 157);
bgRect.init();
// bgRect.x = itemBg.x;
// bgRect.y = itemBg.y;
bgRect.fillColor = '#ffffff';
itemBg.addChild(bgRect, -1);
// this.renderArr.push(bgRect);
if (dataB.pic_url) {
let pic = new MySprite();
pic.init(this.images.get(dataB.pic_url));
pic.setScaleXY(getMinScale(pic, bgRect.width - 2));
bgRect.addChild(pic);
} else {
const label = new Label();
label.text = dataB.text;
label.fontName = 'BRLNSDB';
label.textAlign = 'center';
label.fontSize = 64;
label.setMaxSize(bgRect.width - 20);
bgRect.addChild(label);
}
dot = new MySprite();
dot.init(this.images.get('dot'));
dot.y = -itemBg.height / 2 + 25;
dot.visible = false;
itemBg.addChild(dot);
itemBg['dot'] = dot;
itemBg['type'] = 'B';
itemBg['data'] = dataB;
this.renderArr.push(itemBg);
this.itemArrB.push(itemBg);
}
}
showStartAnima() {
const go = new MySprite(this.ctx);
go.init(this.images.get('go'));
go.setScaleXY(this.mapScale);
go.x = this.canvasWidth + go.width * go.scaleX;
go.y = this.canvasHeight - go.height / 2 * go.scaleY - 30 * this.mapScale;
this.renderArr.push(go);
this.goBtn = go;
const targetX = this.canvasWidth - go.width / 2 * go.scaleX - 30 * this.mapScale;
moveItem(go, targetX, go.y, 0.7, () => {
}, TWEEN.Easing.Cubic.Out);
this.playAudio('enter');
}
initLightAnima() {
clearTimeout(this.lightDelayId);
if (this.animaStopRun) {
return;
}
const delayTime = this.lightDelayTime;
// delayCall(delayTime, () => {
this.lightDelayId = setTimeout(() => {
if (this.animaStopRun) {
return;
}
if (this.curLight) {
hideItem(this.curLight, 0.02, null, TWEEN.Easing.Cubic.Out);
}
this.curLight = this.ballArr[this.lightIndex].light;
showItem(this.curLight, 0.02, () => {
this.initLightAnima();
}, TWEEN.Easing.Cubic.Out);
this.lightIndex--;
if (this.lightIndex < 0) {
this.lightIndex = this.ballArr.length - 1;
}
// });
}, delayTime * 1000);
}
initLightAnimaNew() {
// console.log(' in initLightAnimaNew');
clearTimeout(this.lightDelayId);
if (this.animaNewStopRun) {
return;
}
const delayTime = this.lightDelayTime;
// delayCall(delayTime, () => {
this.lightDelayId = setTimeout(() => {
// if (this.curLight) {
// hideItem(this.curLight, 0.02, null, TWEEN.Easing.Cubic.Out);
// }
//
if (this.animaNewStopRun) {
return;
}
this.lightDelayTime = 1;
for (let i = 0; i < this.ballGroupArr.length; i++) {
if (i != this.grouoLightIndex) {
const arr = this.ballGroupArr[i].arr;
for (let j = 0; j < arr.length; j++) {
hideItem(arr[j], 0.02);
}
}
}
// this.curLight = this.ballArr[this.lightIndex].light;
const lightArr = this.ballGroupArr[this.grouoLightIndex].arr;
for (let i = 0; i < lightArr.length; i++) {
if (i == lightArr.length - 1) {
showItem(lightArr[i], 0.02, () => {
this.initLightAnimaNew();
}, TWEEN.Easing.Cubic.Out);
} else {
showItem(lightArr[i], 0.02, () => {
}, TWEEN.Easing.Cubic.Out);
}
}
// showItem(this.curLight, 0.02, () => {
// this.initLightAnima();
// }, TWEEN.Easing.Cubic.Out);
this.grouoLightIndex--;
if (this.grouoLightIndex < 0) {
this.grouoLightIndex = this.ballGroupArr.length - 1;
}
// this.lightIndex--;
// if (this.lightIndex < 0) {
// this.lightIndex = this.ballArr.length - 1;
// }
// });
}, delayTime * 1000);
}
initQuestionWindow() {
const mask = new ShapeRect(this.ctx);
mask.setSize(this.canvasWidth, this.canvasHeight);
mask.fillColor = '#000000';
mask.alpha = 0.7;
mask.visible = false;
this.mask = mask;
const bg = new MySprite(this.ctx);
bg.init(this.images.get('question_bg'));
bg.setScaleXY(this.mapScale);
bg.x = this.canvasWidth / 2;
bg.y = this.canvasHeight / 2;
mask.addChild(bg);
this.questionBg = bg;
const w = 1020;
const h = 230;
const w2 = 740;
const labelRect1 = new ShapeRect(this.ctx);
labelRect1.setSize(w2, h);
labelRect1.alpha = 0;
labelRect1.x = -bg.width / 2 + 75;
labelRect1.y = -bg.height / 2 + 60;
bg.addChild(labelRect1);
const richText = new RichText(this.ctx);
richText.text = '';
richText.disH = 0;
richText.fontName = 'RoundedBold';
richText.width = w2;
richText.x = labelRect1.x; // + labelRect1.width / 2;
richText.y = labelRect1.y + labelRect1.height / 2 - richText.fontSize / 2;
richText.fontSize = 48;
bg.addChild(richText);
this.questionLabel = richText;
const picRect = new ShapeRect(this.ctx);
picRect.setSize(h, h);
picRect.alpha = 0;
picRect.x = labelRect1.x + w - picRect.width;
picRect.y = labelRect1.y;
bg.addChild(picRect);
this.questionPicRect = picRect;
// const labelRect2 = new ShapeRect(this.ctx);
// labelRect2.setSize(w, h);
// labelRect2.alpha = 0.3;
// labelRect2.x = labelRect1.x;
// labelRect2.y = labelRect1.y;
// bg.addChild(labelRect2);
const richText2 = new RichText(this.ctx);
richText2.text = '';
richText2.disH = 0;
richText2.fontName = 'RoundedBold';
richText2.width = w;
richText2.x = labelRect1.x; // + labelRect1.width / 2;
richText2.y = labelRect1.y + labelRect1.height / 2 - richText.fontSize / 2;
richText2.fontSize = 48;
bg.addChild(richText2);
this.questionLabel2 = richText2;
const textBgH = 81;
const disH = 5;
const offX = labelRect1.x;
const offY = labelRect1.y + labelRect1.height + textBgH / 2 + 15;
this.textBgArr = [];
this.answerLabelArr = [];
const keyArr = ['a', 'b', 'c', 'd'];
for (let i = 0; i < 4; i++) {
const key = 'text_bg_' + keyArr[i];
const textBg = new MySprite(this.ctx);
textBg.init(this.images.get(key));
textBg.x = offX + textBg.width / 2;
textBg.y = offY + i * (textBgH + disH);
bg.addChild(textBg, 2);
this.textBgArr.push(textBg);
const label = new Label(this.ctx);
label.fontName = 'RoundedBold';
label.text = 'aaaaaaaa';
label.fontColor = '#000000';
// label.textAlign = 'center';
label.fontSize = 50;
label.setMaxSize(textBg.width - 230);
label.refreshSize();
label.x = -textBg.width / 2 + 90;
textBg.addChild(label);
const rightBg = new MySprite(this.ctx);
rightBg.init(this.images.get('text_right'));
rightBg.x = textBg.x;
rightBg.y = textBg.y;
bg.addChild(rightBg, 1);
rightBg.visible = false;
textBg['rightBg'] = rightBg;
const wrongBg = new MySprite(this.ctx);
wrongBg.init(this.images.get('text_wrong'));
wrongBg.x = textBg.x;
wrongBg.y = textBg.y;
bg.addChild(wrongBg, 1);
wrongBg.visible = false;
textBg['wrongBg'] = wrongBg;
this.answerLabelArr.push(label);
}
this.picBgArr = [];
this.answerTitleArr = [];
const picBgW = 236;
const disW = (w - picBgW * 4) / 3;
for (let i = 0; i < 4; i ++) {
const key = 'pic_bg_' + keyArr[i];
const picBg = new MySprite(this.ctx);
picBg.init(this.images.get(key));
picBg.x = offX + picBg.width / 2 + i * (picBgW + disW);
picBg.y = offY + picBg.height / 2 - textBgH / 2;
bg.addChild(picBg);
this.picBgArr.push(picBg);
const rightBg = new MySprite(this.ctx);
rightBg.init(this.images.get('pic_right'));
rightBg.x = picBg.x;
rightBg.y = picBg.y;
bg.addChild(rightBg, 1);
rightBg.visible = false;
picBg['rightBg'] = rightBg;
const wrongBg = new MySprite(this.ctx);
wrongBg.init(this.images.get('pic_wrong'));
wrongBg.x = picBg.x;
wrongBg.y = picBg.y;
bg.addChild(wrongBg, 1);
wrongBg.visible = false;
picBg['wrongBg'] = wrongBg;
const textKey = 'text_' + keyArr[i];
const title = new MySprite(this.ctx);
title.init(this.images.get(textKey));
title.x = picBg.x;
title.y = picBg.y - picBg.height / 2 + 39;
bg.addChild(title);
this.answerTitleArr.push(title);
}
this.hideArr(this.textBgArr);
const closeBtn = new MySprite(this.ctx);
closeBtn.init(this.images.get('close_btn'));
bg.addChild(closeBtn);
closeBtn.x = bg.width / 2 - 25;
closeBtn.y = -bg.height / 2 + 50;
this.closeBtn = closeBtn;
}
initItemView() {
}
initHotZone() {
let curBgRect;
if (this.bg) {
curBgRect = this.bg.getBoundingBox();
}
let oldBgRect = this.data.contentObj.bgItem.rect;
if (!oldBgRect) {
oldBgRect = curBgRect;
}
const rate = curBgRect.width / oldBgRect.width;
// this.imgArr = [];
// const arr = this.data.contentObj.imgItemArr;
this.hotZoneArr = [];
const arr = this.data.contentObj.hotZoneItemArr;
if (!arr) return;
for (let i = 0; i < arr.length; i++) {
const data = JSON.parse(JSON.stringify(arr[i]));
// const img = {pic_url: data.pic_url};
data.rect.x *= rate;
data.rect.y *= rate;
data.rect.width *= rate;
data.rect.height *= rate;
data.rect.x += curBgRect.x;
data.rect.y += curBgRect.y;
const hotZone = this.getHotZoneItem(data);
hotZone.alpha = 0;
this.hotZoneArr.push(hotZone);
// hotZone['audio'] = this.audioObj[data.audio_url];
// this.imgArr.push(img);
}
//
//
// const hotZoneItemArr = this.data.contentObj.hotZoneItemArr;
// if (!hotZoneItemArr) {
// return;
// }
//
// if (!this.bg) {
// return;
// }
//
// const bgRect = this.bg.getBoundingBox();
// const bgItem = this.data.contentObj.bgItem;
//
// const rate = bgRect.width / bgItem.rect.width;
//
//
// for (let i = 0; i < hotZoneItemArr.length; i++) {
//
// const tmpData = hotZoneItemArr[i];
// const shapeRect = new ShapeRect(this.ctx);
// shapeRect.anchorX = 0;
// shapeRect.anchorY = 0;
// shapeRect.setSize(tmpData.rect.width, tmpData.rect.height);
// shapeRect.setScaleXY(this.bg.scaleX);
// shapeRect.x = (bgItem.rect.x - bgRect.x + tmpData.rect.x ) / rate;
// shapeRect.y = (bgItem.rect.y - bgRect.y + tmpData.rect.y ) / rate;
//
// // shapeRect.x = tmpData.rect.x - this.bg.width / 2;
// // shapeRect.y = tmpData.rect.y - this.bg.height / 2;
// // this.bg.addChild(shapeRect);
//
// this.renderArr.push(shapeRect);
// }
}
getHotZoneItem(data) {
const saveRect = data.rect;
const item = new ShapeRect(this.ctx);
item.setSize(saveRect.width, saveRect.height);
item.x = saveRect.x ;
item.y = saveRect.y ;
item['data'] = data;
this.renderArr.push(item);
// console.log('data: ', data);
return item;
}
getFrameColor() {
let arr = ['1', '2', '3'];
if (this.oldFrameColorId) {
removeItemFromArr(arr, this.oldFrameColorId);
}
arr = randomSortByArr(arr);
const colorId = arr[0];
this.oldFrameColorId = colorId;
return 'frame_' + colorId;
}
addPic(card) {
const curData = this.picArr[this.picIndex];
const w = 340;
const h = 340;
const pic = new MySprite(this.ctx);
pic.init(this.images.get(curData.pic_url));
const sx = w / pic.width;
const sy = h / pic.height;
const s = Math.min(sx, sy);
pic.setScaleXY(s);
pic.x = 5;
card.addChild(pic);
card.data = curData;
this.picIndex ++;
if (this.picIndex >= this.picArr.length) {
this.picIndex = 0;
}
}
initRobot() {
const robot = new MySprite(this.ctx);
robot.init(this.images.get('robot'));
robot.setScaleXY(this.mapScale);
robot.x = this.canvasWidth / 2 - 50 * this.mapScale;
robot.y = this.canvasHeight / 2 + 50 * this.mapScale;
this.renderArr.push(robot);
this.robot = robot;
const stick = new MySprite(this.ctx);
stick.init(this.images.get('stick'));
stick.anchorY = 0.95;
stick.x = robot.width / 2 + stick.width / 2 - 5;
stick.y = -25;
robot.addChild(stick);
this.stick = stick;
const ball = new MySprite(this.ctx);
ball.init(this.images.get('ball'));
ball.x = stick.x;
ball.y = stick.y - stick.height;
robot.addChild(ball);
this.ball = ball;
const mask = new MySprite(this.ctx);
mask.init(this.images.get('mask'));
mask.x = 31;
mask.y = 2;
robot.addChild(mask);
this.mask = mask;
// const w = 800;
// const h = 260;
// const rect = new ShapeRect(this.ctx);
// rect.setSize(w, h);
// rect.anchorX = 0.5;
// rect.anchorY = 0.5;
// mask.addChild(rect);
}
initBg() {
this.bgArr = [];
const bg = new MySprite();
bg.init(this.images.get('bg'));
bg.x = this.canvasWidth / 2;
bg.y = this.canvasHeight / 2;
const sx = this.canvasWidth / bg.width;
const sy = this.canvasHeight / bg.height;
const s = Math.max(sx, sy);
bg.setScaleXY(s);
this.renderArr.push(bg);
this.bgLayer = new MySprite();
this.renderArr.push(this.bgLayer);
}
initClock() {
const clock1Bg = new MySprite();
clock1Bg.init(this.images.get('clock_1_bg'));
clock1Bg.setScaleXY(this.mapScale);
clock1Bg.x = this.canvasWidth / 2;
clock1Bg.y = clock1Bg.height / 2 * clock1Bg.scaleY;
this.clock1Bg = clock1Bg;
clock1Bg['baseX'] = clock1Bg.x;
clock1Bg['baseY'] = clock1Bg.y;
this.renderArr.push(clock1Bg);
const clock1 = new MySprite();
clock1.init(this.images.get('clock_1'));
clock1.x = - clock1Bg.width / 4;
clock1.y = -5;
clock1Bg.addChild(clock1);
const label = new Label();
label.text = '00:00';
label.fontColor = '#73ce24';
label.fontSize = 32;
label.fontName = 'BRLNSDB';
// label.textAlign = 'center';
label.x = -20;
label.y = -9;
label.setMaxSize(100);
clock1Bg.addChild(label);
label['data'] =
this.timeLabel = label;
clock1Bg.y = -clock1Bg.height / 2 * clock1Bg.scaleY;
moveItem(clock1Bg, clock1Bg.x, clock1Bg.height / 2 * clock1Bg.scaleY, 0.5, () => {
this.initCow();
}, TWEEN.Easing.Cubic.Out);
}
cowLeave() {
this.playAudio('happy');
for (let i = 0; i < this.cowArr.length; i++) {
const cow = this.cowArr[i];
cow.happy();
let px = cow.x - this.canvasWidth / 3 * 2;
if (cow.x > this.canvasWidth / 2) {
px = cow.x + this.canvasWidth / 3 * 2;
cow.scaleX *= -1;
};
moveItem(cow, px, cow.y, 2, () => {
}, TWEEN.Easing.Sinusoidal.In);
}
setTimeout(() => {
this.showClock2();
}, 2000);
this.hideClock1();
}
hideClock1() {
const clock1Bg = this.clock1Bg;
moveItem(clock1Bg, clock1Bg.x, -clock1Bg.height / 2 * clock1Bg.scaleY, 1, () => {
// this.showClock2();
}, TWEEN.Easing.Cubic.In);
}
showClock2() {
const clock2Bg = new MySprite();
clock2Bg.init(this.images.get('clock_2_bg'));
clock2Bg.setScaleXY(this.mapScale);
clock2Bg.x = this.canvasWidth / 2;
clock2Bg.y = -clock2Bg.height / 2 * clock2Bg.scaleY;
this.renderArr.push(clock2Bg);
const clock2 = new MySprite();
clock2.init(this.images.get('clock_2'));
clock2.setScaleXY(this.mapScale);
clock2.x = -clock2Bg.width / 4;
clock2.y = 130;
clock2Bg.addChild(clock2);
const label = new Label();
label.text = this.timeLabel.text;
label.fontName = 'BRLNSDB';
label.fontSize = 64;
label.fontColor = '#ff8300';
label.x = -40;
label.y = clock2.y;
clock2Bg.addChild(label);
this.clock2Bg = clock2Bg;
const move1 = () => {
moveItem(clock2Bg, clock2Bg.x, (clock2Bg.height / 2 - 160) * clock2Bg.scaleY, 1.7, () => {
// move2();
}, TWEEN.Easing.Elastic.Out);
};
// const move2 = () => {
// moveItem(clock2Bg, clock2Bg.x, (clock2Bg.height / 2 - 50) * clock2Bg.scaleY , 0.5, () => {
//
// }, TWEEN.Easing.Cubic.In);
// };
move1();
setTimeout(() => {
this.showRestartBtn();
}, 300);
}
showRestartBtn() {
const btn = new MySprite();
btn.init(this.images.get('btn_restart'));
btn.setScaleXY(this.mapScale);
btn.x = this.canvasWidth + btn.width / 2 * btn.scaleX;
btn.y = this.canvasHeight - btn.height / 2 * btn.scaleY;
this.renderArr.push(btn);
btn.visible = true;
moveItem(btn, this.canvasWidth - (btn.width / 2 + 50) * btn.scaleX, btn.y, 0.5, () => {
this.canTouch = true
}, TWEEN.Easing.Cubic.Out);
this.restartBtn = btn;
}
initStartPage() {
this.starArr = [];
const maskLayer = new ShapeRect(this.ctx);
maskLayer.init(this.images.get(''));
maskLayer.setSize(this.canvasWidth, this.canvasHeight);
maskLayer.x = this.canvasWidth / 2;
maskLayer.y = this.canvasHeight / 2;
maskLayer.fillColor = '#000000';
maskLayer.alpha = 0.8;
this.startPageArr.push(maskLayer);
const startBtn = new MySprite(this.ctx);
startBtn.init(this.images.get('start_btn'));
startBtn.x = this.canvasWidth / 2;
startBtn.y = this.canvasHeight / 5 * 3;
startBtn.setScaleXY(this.mapScale);
this.startPageArr.push(startBtn);
this.startBtn = startBtn;
}
initEndPage() {
const maskLayer = new ShapeRect(this.ctx);
maskLayer.init(this.images.get(''));
maskLayer.setSize(this.canvasWidth, this.canvasHeight);
maskLayer.x = this.canvasWidth / 2;
maskLayer.y = this.canvasHeight / 2;
maskLayer.fillColor = '#000000';
maskLayer.alpha = 0.8;
this.endPageArr.push(maskLayer);
const leftWin = new MySprite(this.ctx);
leftWin.init(this.images.get('left_win'));
leftWin.x = this.canvasWidth / 2;
leftWin.y = this.canvasHeight / 2.5;
leftWin.setScaleXY(this.mapScale);
this.endPageArr.push(leftWin);
const rightWin = new MySprite(this.ctx);
rightWin.init(this.images.get('right_win'));
rightWin.x = this.canvasWidth / 2;
rightWin.y = this.canvasHeight / 2.5;
rightWin.setScaleXY(this.mapScale);
this.endPageArr.push(rightWin);
this.leftWin = leftWin;
this.rightWin = rightWin;
// const light = new MySprite(this.ctx);
// light.init(this.images.get('light_png'));
// light.x = this.canvasWidth / 2;
// light.y = this.canvasHeight / 5 * 2;
// light.setScaleXY(this.mapScale);
// this.endPageArr.push(light);
// this.light = light;
//
// const hand = new MySprite(this.ctx);
// hand.init(this.images.get('hand_png'));
// hand.x = this.canvasWidth / 2;
// hand.y = light.y;
// hand.setScaleXY(this.mapScale);
// this.endPageArr.push(hand);
// this.hand = hand;
const replayBtn = new MySprite(this.ctx);
replayBtn.init(this.images.get('replay_btn'));
replayBtn.x = this.canvasWidth / 2;
replayBtn.y = this.canvasHeight / 5 * 3.5;
replayBtn.setScaleXY(this.mapScale);
this.endPageArr.push(replayBtn);
this.replayBtn = replayBtn;
this.hideArr(this.endPageArr);
// const lightAction = () => {
// light.rotation = 0;
// rotateItem(light, 360, 10, () => {
// lightAction();
// });
// };
//
// lightAction();
}
initScore() {
const addLabelShadow = (label) => {
const labelShadow = new Label(this.ctx);
labelShadow.init();
labelShadow.text = label.text;
labelShadow.fontSize = label.fontSize;
labelShadow.fontName = label.fontName;
labelShadow.fontColor = '#e4688f';
labelShadow.textAlign = 'center';
labelShadow.y = 3;
labelShadow.setShadow(0, 2, 2, 'rgba(154, 23, 58, 0.5)');
label.addChild(labelShadow, -1);
label.shadowLabel = labelShadow;
};
const labelLeft = new Label(this.ctx);
labelLeft.init();
labelLeft.text = '0';
labelLeft.fontSize = 60;
labelLeft.fontName = 'BRLNSDB';
labelLeft.fontColor = '#fef9ff';
labelLeft.textAlign = 'center';
labelLeft.x = - this.bgTop.width / 4;
labelLeft.y = this.bgTop.height / 5;
labelLeft.refreshSize();
addLabelShadow(labelLeft);
this.bgTop.addChild(labelLeft);
this.leftScoreLabel = labelLeft;
const labelRight = new Label(this.ctx);
labelRight.init();
labelRight.text = '0';
labelRight.fontSize = 60;
labelRight.fontName = 'BRLNSDB';
labelRight.fontColor = '#fef9ff';
labelRight.textAlign = 'center';
labelRight.x = this.bgTop.width / 4;
labelRight.y = this.bgTop.height / 5;
labelRight.refreshSize();
addLabelShadow(labelRight);
this.bgTop.addChild(labelRight);
this.rightScoreLabel = labelRight;
// console.log('label.width: ', label.width);
}
showEndPage() {
this.showArr(this.endPageArr);
this.canTouch = true;
this.gameEndFlag = true;
this.showEndPatal();
this.successAudio.play();
if (this.leftScore >= this.maxScore) {
this.rightWin.visible = false;
} else {
this.leftWin.visible = false;
}
}
showEndPatal() {
this.endPageArr = [];
this.showPetalFlag = true;
this.addPetal();
}
addPetal() {
if (!this.showPetalFlag) {
return;
}
const petal = this.getPetal();
this.endPageArr.push(petal);
moveItem(petal, petal.x, this.canvasHeight + petal.height * petal.scaleY, petal['time'], () => {
removeItemFromArr(this.endPageArr, petal);
});
rotateItem(petal, petal['tr'], petal['time']);
setTimeout(() => {
this.addPetal();
}, 200);
// this.petalTime += 5;
}
getPetal() {
const petal = new MySprite(this.ctx);
const id = Math.ceil( Math.random() * 3 );
petal.init(this.images.get('petal_' + id));
const randomS = (Math.random() * 0.4 + 0.6) * this.mapScale;
petal.setScaleXY(randomS);
const randomR = Math.random() * 360;
petal.rotation = randomR;
const randomX = Math.random() * this.canvasWidth;
petal.x = randomX;
petal.y = -petal.height / 2 * petal.scaleY;
const randomT = 2 + Math.random() * 5;
petal['time'] = randomT;
let randomTR = 360 * Math.random(); // - 180;
if (Math.random() < 0.5) { randomTR *= -1; }
petal['tr'] = randomTR;
return petal;
}
gameEnd() {
// this.showEndPage();
this.cowLeave();
this.clockUpdateFlag = false;
console.log('gameEnd');
// this.canTouch = true;
this.petalTime = 0;
// this.playAudio('finish');
this.showEndPatal();
// setTimeout(() => {
// this.showPetalFlag = false;
// }, 5000);
}
mapDown(event) {
if (!this.canTouch) {
return;
}
if (this.checkClickTarget(this.leftBtn)) {
this.lastPageClick();
return;
}
if (this.checkClickTarget(this.rightBtn)) {
this.nextPageClick();
return;
}
}
mapMove(event) {
}
mapUp(event) {
}
nextPageClick() {
console.log(' in leftBtnClick');
if (this.curPageIndex >= this.picArr.length - 1) {
return;
}
this.curPageIndex ++;
this.changePageByIndex();
}
lastPageClick() {
console.log(' in rightBtnClick');
if (this.curPageIndex <= 0) {
return;
}
this.curPageIndex --;
this.changePageByIndex();
}
changePageByIndex() {
console.log(' in changePageByIndex');
this.canTouch = false;
if (this.curAudio) {
this.curAudio.pause();
this.curAudio.currentTime = 0;
}
// this.changePlayBtnStyle(this.BTN_TYPE_PLAY);
moveItem(this.bgLayer, -this.curPageIndex * this.canvasWidth, 0, 1, () => {
this.canTouch = true;
this.refreshPageLabel();
// this.resetCurData();
}, TWEEN.Easing.Cubic.Out);
this.playAudio('click', true);
}
checkOnCow() {
const arr = [];
for (let i = 0; i < this.cowArr.length; i++) {
if (this.checkPointInRect(this.mx, this.my, this.cowArr[i].getBoundingBox())) {
arr.push({
dis: getPosDistance(this.mx, this.my, this.cowArr[i].x, this.cowArr[i].y),
item: this.cowArr[i]
});
}
}
if (arr[0]) {
this.checkCowEat(arr[0].item);
} else {
this.grassResetPos();
}
// if (arr.length > 0) {
//
// arr.sort((a, b) => {
// return b.dis - a.dis;
// });
// }
console.log('arr: ', arr);
}
grassResetPos() {
if (this.curGrass) {
this.canTouch = false;
moveItem(this.curGrass, this.curGrass.baseX, this.curGrass.baseY, 0.3, () => {
this.canTouch = true;
}, TWEEN.Easing.Cubic.Out);
// this.curGrass.x = this.curGrass.baseX;
// this.curGrass.y = this.curGrass.baseY;
}
}
checkCowEat(cow) {
console.log('eat');
if (Number(this.curGrass.type) == Number(cow.id)) {
this.playAudio('eat', true);
cow.eat();
removeItemFromArr(this.grassArr, this.curGrass);
removeItemFromArr(this.renderArr, this.curGrass);
this.checkGameEnd();
this.curGrass = null;
} else {
this.playAudio('angry');
cow.angry();
this.grassResetPos();
}
}
checkCowEatClick(cow) {
console.log(' in checkCowEatClick');
this.curCow = cow;
if (Number(this.curGrass.type) == Number(cow.id)) {
cow.like();
} else {
this.playAudio('angry');
cow.angry();
}
this.canTouch = false;
moveItem(this.curGrass, cow.x + cow.offX, cow.y + cow.offY, 0.3, () => {
this.canTouch = true;
if (Number(this.curGrass.type) == Number(cow.id)) {
this.playAudio('eat', true);
cow.eat();
removeItemFromArr(this.grassArr, this.curGrass);
removeItemFromArr(this.renderArr, this.curGrass);
this.checkGameEnd();
this.curGrass = null;
} else {
this.grassResetPos();
}
}, TWEEN.Easing.Cubic.Out);
}
clickGrass(grass) {
console.log('in click grass data', grass.data);
grass.light.visible = true;
this.curGrass = grass;
if (grass.data.audio_url) {
this.playAudio(grass.data.audio_url);
} else {
this.playAudio('grass');
}
removeItemFromArr(this.renderArr, grass);
this.renderArr.push(grass);
}
checkGameEnd() {
if (this.grassArr.length > 0) {
return;
}
this.canTouch = false;
setTimeout(() => {
this.gameEnd();
}, 2000);
}
clickRestart() {
const clock2Bg = this.clock2Bg;
const move1 = () => {
moveItem(clock2Bg, clock2Bg.x, clock2Bg.height / 3 * 2 / 2 * clock2Bg.scaleY, 0.4, () => {
move2();
}, TWEEN.Easing.Quadratic.InOut);
};
const move2 = () => {
moveItem(clock2Bg, clock2Bg.x, -clock2Bg.height / 2 * clock2Bg.scaleY, 0.8, () => {
this.restartBtn.visible = false;
this.init();
}, TWEEN.Easing.Quadratic.InOut);
};
move1();
moveItem(this.restartBtn, this.canvasWidth + this.restartBtn.width / 2 * this.restartBtn.scaleX,
this.restartBtn.y, 0.6, () => {
}, TWEEN.Easing.Quadratic.Out);
this.showPetalFlag = false;
for (let i = 0; i < this.endPageArr.length; i++) {
hideItem(this.endPageArr[i], 0.8);
}
}
updateClock() {
if (!this.clockUpdateFlag) {
return;
}
const curDate = new Date();
const oldDate = this.timeLabel.date;
curDate.setTime(curDate.getTime() - oldDate.getTime());
const time = formatTime('mm:ss', curDate); ngOnDestroy() {
this.timeLabel.text = time; window['curCtx'] = null;
window.cancelAnimationFrame(this.animationId);
} }
update() { load() {
// 预加载资源
this.loadResources().then(() => {
window["air"].hideAirClassLoading(this.saveKey, this.data);
this.init();
this.update();
});
}
this.animationId = window.requestAnimationFrame(this.update.bind(this));
// 清除画布内容
this.ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight);
init() {
TWEEN.update(); this.initCtx();
this.initData();
this.initView();
}
initCtx() {
this.canvasWidth = this.wrap.nativeElement.clientWidth;
this.canvasHeight = this.wrap.nativeElement.clientHeight;
this.canvas.nativeElement.width = this.wrap.nativeElement.clientWidth;
this.canvas.nativeElement.height = this.wrap.nativeElement.clientHeight;
// this.updateWordArr(); this.ctx = this.canvas.nativeElement.getContext('2d');
this.canvas.nativeElement.width = this.canvasWidth;
this.canvas.nativeElement.height = this.canvasHeight;
// this.updateArr(this.bgArr); window['curCtx'] = this.ctx;
this.updateArr(this.renderArr); }
// this.updateArr(this.endPageArr);
// this.updateClock();
}
updateItem(item) { updateItem(item) {
...@@ -2436,6 +167,8 @@ export class PlayComponent implements OnInit, OnDestroy { ...@@ -2436,6 +167,8 @@ export class PlayComponent implements OnInit, OnDestroy {
initListener() { initListener() {
this.winResizeEventStream this.winResizeEventStream
...@@ -2469,7 +202,6 @@ export class PlayComponent implements OnInit, OnDestroy { ...@@ -2469,7 +202,6 @@ export class PlayComponent implements OnInit, OnDestroy {
// --------------------------------------------- // ---------------------------------------------
let firstTouch = true; let firstTouch = true;
const touchDownFunc = (e) => { const touchDownFunc = (e) => {
...@@ -2477,7 +209,6 @@ export class PlayComponent implements OnInit, OnDestroy { ...@@ -2477,7 +209,6 @@ export class PlayComponent implements OnInit, OnDestroy {
firstTouch = false; firstTouch = false;
removeMouseListener(); removeMouseListener();
} }
console.log('touch down');
setMxMyByTouch(e); setMxMyByTouch(e);
this.mapDown(e); this.mapDown(e);
}; };
...@@ -2495,7 +226,6 @@ export class PlayComponent implements OnInit, OnDestroy { ...@@ -2495,7 +226,6 @@ export class PlayComponent implements OnInit, OnDestroy {
firstTouch = false; firstTouch = false;
removeTouchListener(); removeTouchListener();
} }
console.log('mouse down');
setMxMyByMouse(e); setMxMyByMouse(e);
this.mapDown(e); this.mapDown(e);
}; };
...@@ -2535,93 +265,8 @@ export class PlayComponent implements OnInit, OnDestroy { ...@@ -2535,93 +265,8 @@ export class PlayComponent implements OnInit, OnDestroy {
element.removeEventListener('mouseup', mouseUpFunc); element.removeEventListener('mouseup', mouseUpFunc);
}; };
addMouseListener(); addMouseListener();
addTouchListener(); addTouchListener();
// if (this.IsPC()) {
//
// this.canvas.nativeElement.addEventListener('mousedown', (event) => {
//
// setMxMyByMouse(event);
// this.mapDown(event);
// });
//
// this.canvas.nativeElement.addEventListener('mousemove', (event) => {
//
// setMxMyByMouse(event);
// this.mapMove(event);
// });
//
// this.canvas.nativeElement.addEventListener('mouseup', (event) => {
//
// setMxMyByMouse(event);
// this.mapUp(event);
// });
//
//
// const setMxMyByMouse = (event) => {
//
// this.mx = event.offsetX;
// this.my = event.offsetY;
// };
//
//
//
// } else {
//
// this.canvas.nativeElement.addEventListener('touchstart', (event) => {
//
// setMxMyByTouch(event);
// this.mapDown(event);
// });
//
// this.canvas.nativeElement.addEventListener('touchmove', (event) => {
// setMxMyByTouch(event);
// this.mapMove(event);
// });
//
// this.canvas.nativeElement.addEventListener('touchend', (event) => {
// setMxMyByTouch(event);
// this.mapUp(event);
// });
//
// this.canvas.nativeElement.addEventListener('touchcancel', (event) => {
// setMxMyByTouch(event);
// this.mapUp(event);
// });
//
//
// const setMxMyByTouch = (event) => {
//
// // console.log('in 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;
// };
// }
} }
...@@ -2645,43 +290,6 @@ export class PlayComponent implements OnInit, OnDestroy { ...@@ -2645,43 +290,6 @@ export class PlayComponent implements OnInit, OnDestroy {
showArr(arr) {
if (!arr) {
return;
}
for (let i = 0; i < arr.length; i++) {
arr[i].visible = true;
}
}
hideArr(arr) {
if (!arr) {
return;
}
for (let i = 0; i < arr.length; i++) {
arr[i].visible = false;
}
}
IsPC() {
if (window['ELECTRON']) {
return false; // 封装客户端标记
}
if (document.body.ontouchmove !== undefined && document.body.ontouchmove !== undefined) {
return false;
} else {
return true;
}
}
loadResources() { loadResources() {
const pr = []; const pr = [];
this.rawImages.forEach((value, key) => {// 预加载图片 this.rawImages.forEach((value, key) => {// 预加载图片
...@@ -2695,7 +303,7 @@ export class PlayComponent implements OnInit, OnDestroy { ...@@ -2695,7 +303,7 @@ export class PlayComponent implements OnInit, OnDestroy {
pr.push(p); pr.push(p);
}); });
this.rawAudios.forEach((value, key) => {// 预加载图片 this.rawAudios.forEach((value, key) => {// 预加载音频
const a = this.preloadAudio(value) const a = this.preloadAudio(value)
.then(() => { .then(() => {
...@@ -2741,6 +349,8 @@ export class PlayComponent implements OnInit, OnDestroy { ...@@ -2741,6 +349,8 @@ export class PlayComponent implements OnInit, OnDestroy {
checkClickTarget(target) { checkClickTarget(target) {
const rect = target.getBoundingBox(); const rect = target.getBoundingBox();
...@@ -2773,22 +383,297 @@ export class PlayComponent implements OnInit, OnDestroy { ...@@ -2773,22 +383,297 @@ export class PlayComponent implements OnInit, OnDestroy {
return false; return false;
} }
getPosByAngle(angle, len) {
const radian = angle * Math.PI / 180;
const x = Math.sin(radian) * len;
const y = Math.cos(radian) * len;
return {x, y};
addUrlToAudioObj(key, url = null, vlomue = 1, loop = false, callback = null) {
const audioObj = this.audioObj;
if (url == null) {
url = key;
}
this.rawAudios.set(key, url);
const audio = new Audio();
audio.src = url;
audio.load();
audio.loop = loop;
audio.volume = vlomue;
audioObj[key] = audio;
if (callback) {
audio.onended = () => {
callback();
};
}
}
addUrlToImages(url) {
this.rawImages.set(url, url);
}
// ======================================================编写区域==========================================================================
/**
* 添加默认数据 便于无数据时的展示
*/
initDefaultData() {
if (!this.data.pic_url) {
this.data.pic_url = 'assets/play/default/pic.jpg';
this.data.pic_url_2 = 'assets/play/default/pic.jpg';
}
}
/**
* 添加预加载图片
*/
initImg() {
this.addUrlToImages(this.data.pic_url);
this.addUrlToImages(this.data.pic_url_2);
}
/**
* 添加预加载音频
*/
initAudio() {
// 音频资源
this.addUrlToAudioObj(this.data.audio_url);
this.addUrlToAudioObj(this.data.audio_url_2);
// 音效
this.addUrlToAudioObj('click', this.rawAudios.get('click'), 0.3);
}
/**
* 初始化数据
*/
initData() {
const sx = this.canvasWidth / this.canvasBaseW;
const sy = this.canvasHeight / this.canvasBaseH;
const s = Math.min(sx, sy);
this.mapScale = s;
// this.mapScale = sx;
// this.mapScale = sy;
this.renderArr = [];
}
/**
* 初始化试图
*/
initView() {
this.initPic();
this.initBottomPart();
}
initBottomPart() {
const btnLeft = new MySprite();
btnLeft.init(this.images.get('btn_left'));
btnLeft.x = this.canvasWidth - 150 * this.mapScale;
btnLeft.y = this.canvasHeight - 100 * this.mapScale;
btnLeft.setScaleXY(this.mapScale);
this.renderArr.push(btnLeft);
this.btnLeft = btnLeft;
const btnRight = new MySprite();
btnRight.init(this.images.get('btn_right'));
btnRight.x = this.canvasWidth - 50 * this.mapScale;
btnRight.y = this.canvasHeight - 100 * this.mapScale;
btnRight.setScaleXY(this.mapScale);
this.renderArr.push(btnRight);
this.btnRight = btnRight;
}
initPic() {
const maxW = this.canvasWidth * 0.7;
const pic1 = new MySprite();
pic1.init(this.images.get(this.data.pic_url));
pic1.x = this.canvasWidth / 2;
pic1.y = this.canvasHeight / 2;
pic1.setScaleXY(maxW / pic1.width);
this.renderArr.push(pic1);
this.pic1 = pic1;
const label1 = new Label();
label1.text = this.data.text;
label1.textAlign = 'center';
label1.fontSize = 50;
label1.fontName = 'BRLNSDB';
label1.fontColor = '#ffffff';
pic1.addChild(label1);
const pic2 = new MySprite();
pic2.init(this.images.get(this.data.pic_url_2));
pic2.x = this.canvasWidth / 2 + this.canvasWidth;
pic2.y = this.canvasHeight / 2;
pic2.setScaleXY(maxW / pic2.width);
this.renderArr.push(pic2);
this.pic2 = pic2;
this.curPic = pic1;
}
btnLeftClicked() {
this.lastPage();
}
btnRightClicked() {
this.nextPage();
}
lastPage() {
if (this.curPic == this.pic1) {
return;
}
this.canTouch = false;
const moveLen = this.canvasWidth;
tweenChange(this.pic1, {x: this.pic1.x + moveLen}, 1);
tweenChange(this.pic2, {x: this.pic2.x + moveLen}, 1, () => {
this.canTouch = true;
this.curPic = this.pic1;
});
}
nextPage() {
if (this.curPic == this.pic2) {
return;
}
this.canTouch = false;
const moveLen = this.canvasWidth;
tweenChange(this.pic1, {x: this.pic1.x - moveLen}, 1);
tweenChange(this.pic2, {x: this.pic2.x - moveLen}, 1, () => {
this.canTouch = true;
this.curPic = this.pic2;
});
}
pic1Clicked() {
this.playAudio(this.data.audio_url);
}
pic2Clicked() {
this.playAudio(this.data.audio_url_2);
}
mapDown(event) {
if (!this.canTouch) {
return;
}
if ( this.checkClickTarget(this.btnLeft) ) {
this.btnLeftClicked();
return;
}
if ( this.checkClickTarget(this.btnRight) ) {
this.btnRightClicked();
return;
}
if ( this.checkClickTarget(this.pic1) ) {
this.pic1Clicked();
return;
}
if ( this.checkClickTarget(this.pic2) ) {
this.pic2Clicked();
return;
}
}
mapMove(event) {
}
mapUp(event) {
} }
getPosDistance(sx, sy, ex, ey) {
const _x = ex - sx;
const _y = ey - sy; update() {
const len = Math.sqrt( Math.pow(_x, 2) + Math.pow(_y, 2) );
return len; // ----------------------------------------------------------
this.animationId = window.requestAnimationFrame(this.update.bind(this));
// 清除画布内容
this.ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight);
// tween 更新动画
TWEEN.update();
// ----------------------------------------------------------
this.updateArr(this.renderArr);
} }
} }
const res = [ const res = [
['bg', "assets/play/bg.jpg"], // ['bg', "assets/play/bg.jpg"],
['btn_left', "assets/play/btn_left.png"], ['btn_left', "assets/play/btn_left.png"],
['btn_right', "assets/play/btn_right.png"], ['btn_right', "assets/play/btn_right.png"],
['text_bg', "assets/play/text_bg.png"], // ['text_bg', "assets/play/text_bg.png"],
]; ];
...@@ -15,16 +11,7 @@ const res = [ ...@@ -15,16 +11,7 @@ const res = [
const resAudio = [ const resAudio = [
['click', "assets/play/music/click.mp3"], ['click', "assets/play/music/click.mp3"],
// ['right', "assets/play/music/right.mp3"],
// ['wrong', "assets/play/music/wrong.mp3"],
// ['angry', "assets/play/music/angry.mp3"],
// ['cow_start', "assets/play/music/cow_start.mp3"],
// ['eat', "assets/play/music/eat.mp3"],
// ['happy', "assets/play/music/happy.mp3"],
// ['grass', "assets/play/music/grass.mp3"],
]; ];
......
/*
global css to mixin
*/
@mixin hide-overflow-text {
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
@mixin k-no-select {
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
@mixin k-img-bg {
background-repeat: no-repeat;
background-position: center;
background-size: contain;
}
.anticon{
vertical-align: .1em!important;
}
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
...@@ -4,13 +4,13 @@ ...@@ -4,13 +4,13 @@
<meta charset="utf-8"> <meta charset="utf-8">
<title>NgOne</title> <title>NgOne</title>
<base href="/"> <base href="/">
<!-- <meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">-->
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico"> <link rel="icon" type="image/x-icon" href="favicon.ico">
<script type="text/javascript" src="https://staging-teach.cdn.ireadabc.com/h5template/h5-static-lib/js/air.js"></script> <script type="text/javascript" src="https://staging-teach.cdn.ireadabc.com/h5template/h5-static-lib/js/air.js"></script>
</head> </head>
<body> <body>
<app-root></app-root> <app-root></app-root>
</body> </body>
</html> </html>
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>NgOne</title>
<base href="/">
<!-- <meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">-->
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico">
<script type="text/javascript" src="https://staging-teach.cdn.ireadabc.com/h5template/h5-static-lib/js/air.js"></script>
</head>
<body>
Hello World!!
</body>
</html>
/* You can add global styles to this file, and also import other style files */ /* 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
...@@ -2,7 +2,9 @@ ...@@ -2,7 +2,9 @@
"extends": "./tsconfig.json", "extends": "./tsconfig.json",
"compilerOptions": { "compilerOptions": {
"outDir": "./out-tsc/app", "outDir": "./out-tsc/app",
"types": [] "types": [
"node"
]
}, },
"files": [ "files": [
"src/main.ts", "src/main.ts",
......
...@@ -3,13 +3,9 @@ ...@@ -3,13 +3,9 @@
"version": 1, "version": 1,
"newProjectRoot": "projects", "newProjectRoot": "projects",
"projects": { "projects": {
"ng-one": { "ng-template-generator": {
"projectType": "application", "projectType": "application",
"schematics": { "schematics": {},
"@schematics/angular:component": {
"style": "scss"
}
},
"root": "", "root": "",
"sourceRoot": "src", "sourceRoot": "src",
"prefix": "app", "prefix": "app",
...@@ -17,39 +13,26 @@ ...@@ -17,39 +13,26 @@
"build": { "build": {
"builder": "@angular-devkit/build-angular:browser", "builder": "@angular-devkit/build-angular:browser",
"options": { "options": {
"outputPath": "dist", "outputPath": "dist/ng-template-generator",
"index": "src/index.html", "index": "src/index.html",
"main": "src/main.ts", "main": "src/main.ts",
"polyfills": "src/polyfills.ts", "polyfills": "src/polyfills.ts",
"tsConfig": "tsconfig.app.json", "tsConfig": "tsconfig.app.json",
"aot": false, "aot": true,
"assets": [ "assets": [
"src/favicon.ico", "src/favicon.ico",
"src/assets", "src/assets",
{ "glob": "**/*", "input": "src/assets/libs/service-worker/", "output": "/" },
{ {
"glob": "**/*", "glob": "**/*",
"input": "./node_modules/@ant-design/icons-angular/src/inline-svg/", "input": "./node_modules/@ant-design/icons-angular/src/inline-svg/",
"output": "/assets/" "output": "/assets/"
},
{
"glob": "**/*",
"input": "./dist/game/",
"output": "/assets/cocos/"
} }
], ],
"styles": [ "styles": [
"src/styles.scss",
"./node_modules/ng-zorro-antd/ng-zorro-antd.min.css", "./node_modules/ng-zorro-antd/ng-zorro-antd.min.css",
"./node_modules/font-awesome/css/font-awesome.css", "src/styles.css"
"./node_modules/bootstrap/dist/css/bootstrap.min.css",
"./node_modules/animate.css/animate.min.css"
], ],
"scripts": [ "scripts": []
"src/assets/libs/audio-recorder/lame.min.js",
"src/assets/libs/audio-recorder/worker.js",
"src/assets/libs/audio-recorder/recorder.js"
]
}, },
"configurations": { "configurations": {
"production": { "production": {
...@@ -64,28 +47,39 @@ ...@@ -64,28 +47,39 @@
"sourceMap": false, "sourceMap": false,
"extractCss": true, "extractCss": true,
"namedChunks": false, "namedChunks": false,
"aot": true,
"extractLicenses": true, "extractLicenses": true,
"vendorChunk": false, "vendorChunk": false,
"buildOptimizer": true "buildOptimizer": true,
"budgets": [
{
"type": "initial",
"maximumWarning": "2mb",
"maximumError": "5mb"
},
{
"type": "anyComponentStyle",
"maximumWarning": "6kb",
"maximumError": "10kb"
}
]
} }
} }
}, },
"serve": { "serve": {
"builder": "@angular-devkit/build-angular:dev-server", "builder": "@angular-devkit/build-angular:dev-server",
"options": { "options": {
"browserTarget": "ng-one:build" "browserTarget": "ng-template-generator:build"
}, },
"configurations": { "configurations": {
"production": { "production": {
"browserTarget": "ng-one:build:production" "browserTarget": "ng-template-generator:build:production"
} }
} }
}, },
"extract-i18n": { "extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n", "builder": "@angular-devkit/build-angular:extract-i18n",
"options": { "options": {
"browserTarget": "ng-one:build" "browserTarget": "ng-template-generator:build"
} }
}, },
"test": { "test": {
...@@ -100,7 +94,8 @@ ...@@ -100,7 +94,8 @@
"src/assets" "src/assets"
], ],
"styles": [ "styles": [
"src/styles.scss" "./node_modules/ng-zorro-antd/ng-zorro-antd.min.css",
"src/styles.css"
], ],
"scripts": [] "scripts": []
} }
...@@ -122,15 +117,19 @@ ...@@ -122,15 +117,19 @@
"builder": "@angular-devkit/build-angular:protractor", "builder": "@angular-devkit/build-angular:protractor",
"options": { "options": {
"protractorConfig": "e2e/protractor.conf.js", "protractorConfig": "e2e/protractor.conf.js",
"devServerTarget": "ng-one:serve" "devServerTarget": "ng-template-generator:serve"
}, },
"configurations": { "configurations": {
"production": { "production": {
"devServerTarget": "ng-one:serve:production" "devServerTarget": "ng-template-generator:serve:production"
}
} }
} }
} }
} }
}}, },
"defaultProject": "ng-one" "defaultProject": "ng-template-generator",
"cli": {
"analytics": "5f501d82-8f25-4817-a608-9ac70d1f1f70"
}
} }
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -4,72 +4,57 @@ ...@@ -4,72 +4,57 @@
"scripts": { "scripts": {
"start": "ng serve", "start": "ng serve",
"build": "ng build --build--optimizer --aot --base-href /JGT/v3/", "build": "ng build --build--optimizer --aot --base-href /JGT/v3/",
"publish": "node ./bin/publish.js" "publish": "node ./bin/publish.js",
"ng": "ng",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e"
}, },
"private": true, "private": true,
"dependencies": { "dependencies": {
"@angular/animations": "^7.2.10", "@angular/animations": "~9.0.2",
"@angular/cdk": "^7.2.2", "@angular/common": "~9.0.2",
"@angular/common": "^7.2.10", "@angular/compiler": "~9.0.2",
"@angular/compiler": "^7.2.10", "@angular/core": "~9.0.2",
"@angular/core": "^7.2.10", "@angular/forms": "~9.0.2",
"@angular/flex-layout": "^7.0.0-beta.24", "@angular/platform-browser": "~9.0.2",
"@angular/forms": "^7.2.10", "@angular/platform-browser-dynamic": "~9.0.2",
"@angular/http": "^7.2.10", "@angular/router": "~9.0.2",
"@angular/material": "^7.2.2", "@fortawesome/angular-fontawesome": "^0.6.0",
"@angular/platform-browser": "^7.2.10", "@fortawesome/fontawesome-svg-core": "^1.2.27",
"@angular/platform-browser-dynamic": "^7.2.10", "@fortawesome/free-regular-svg-icons": "^5.12.1",
"@angular/platform-server": "^7.2.10", "@fortawesome/free-solid-svg-icons": "^5.12.1",
"@angular/router": "^7.2.10", "@tweenjs/tween.js": "~18.5.0",
"@tweenjs/tween.js": "^17.3.0", "ali-oss": "^6.5.1",
"ali-oss": "^6.0.0",
"angular-cropperjs": "^1.0.1",
"angular2-draggable": "^2.1.9",
"angular2-fontawesome": "^5.2.1", "angular2-fontawesome": "^5.2.1",
"angularx-qrcode": "^1.5.3", "compressing": "^1.5.0",
"animate.css": "^3.7.0", "ng-zorro-antd": "^8.5.2",
"bootstrap": "^4.1.1", "node-sass": "^4.0.0",
"browser-image-compression": "^1.0.5", "rxjs": "~6.5.4",
"compressing": "^1.4.0",
"core-js": "^2.6.1",
"cropperjs": "1.4.1",
"css-element-queries": "^1.0.2",
"decimal.js": "^10.0.1",
"font-awesome": "^4.7.0",
"hammerjs": "^2.0.8",
"install": "^0.12.2",
"karma-cli": "^2.0.0",
"lodash": "^4.17.10",
"nedb": "^1.8.0",
"ng-lottie": "^0.3.1",
"ng-zorro-antd": "^7.2.0",
"npm": "^6.5.0",
"rxjs": "^6.3.3",
"rxjs-compat": "^6.3.3",
"rxjs-tslint": "^0.1.6",
"spark-md5": "^3.0.0", "spark-md5": "^3.0.0",
"webpack": "^4.28.2", "tslib": "^1.10.0",
"zone.js": "^0.8.26" "yarn": "^1.22.19",
"zone.js": "~0.10.2"
}, },
"devDependencies": { "devDependencies": {
"@angular-devkit/build-angular": "^0.11.4", "@angular-devkit/build-angular": "~0.900.3",
"@angular/cli": "^7.2.10", "@angular/cli": "~9.0.3",
"@angular/compiler-cli": "^7.2.10", "@angular/compiler-cli": "~9.0.2",
"@angular/language-service": "^7.2.10", "@angular/language-service": "~9.0.2",
"@types/jasmine": "^3.3.5", "@types/jasmine": "~3.5.0",
"@types/jasminewd2": "~2.0.3", "@types/jasminewd2": "~2.0.3",
"@types/node": "^10.12.18", "@types/node": "^12.11.1",
"codelyzer": "^4.5.0", "codelyzer": "^5.1.2",
"jasmine-core": "^3.3.0", "jasmine-core": "~3.5.0",
"jasmine-spec-reporter": "^4.2.1", "jasmine-spec-reporter": "~4.2.1",
"karma": "^3.1.4", "karma": "~4.3.0",
"karma-chrome-launcher": "^2.2.0", "karma-chrome-launcher": "~3.1.0",
"karma-coverage-istanbul-reporter": "~2.0.0", "karma-coverage-istanbul-reporter": "~2.1.0",
"karma-jasmine": "^2.0.1", "karma-jasmine": "~2.0.1",
"karma-jasmine-html-reporter": "^1.4.0", "karma-jasmine-html-reporter": "^1.4.2",
"protractor": "^5.4.2", "protractor": "~5.4.3",
"ts-node": "~5.0.1", "ts-node": "~8.3.0",
"tslint": "^5.12.0", "tslint": "~5.18.0",
"typescript": "3.1.1" "typescript": "~3.7.5"
} }
} }
...@@ -5,7 +5,7 @@ import { NgModule } from '@angular/core'; ...@@ -5,7 +5,7 @@ import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms'; import { FormsModule } from '@angular/forms';
import { HttpClientModule } from '@angular/common/http'; import { HttpClientModule } from '@angular/common/http';
import { NgZorroAntdModule, NZ_I18N, zh_CN } from 'ng-zorro-antd'; import { NgZorroAntdModule, NZ_I18N, zh_CN } from 'ng-zorro-antd';
import {Angular2FontawesomeModule} from 'angular2-fontawesome/angular2-fontawesome'; import {Angular2FontawesomeModule} from 'angular2-fontawesome';
import { AppComponent } from './app.component'; import { AppComponent } from './app.component';
import { FormComponent } from './form/form.component'; import { FormComponent } from './form/form.component';
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico"> <link rel="icon" type="image/x-icon" href="favicon.ico">
<script type="text/javascript" src="http://teach.cdn.ireadabc.com/h5template/h5-static-lib/js/air.js"></script> <script type="text/javascript" src="https://staging-teach.cdn.ireadabc.com/h5template/h5-static-lib/js/air.js"></script>
</head> </head>
<body> <body>
......
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