Commit ee277b5b authored by Li MingZhe's avatar Li MingZhe

feat: 首次体检

parent 9f3a2900
# ng-template-generator # ng-template-generator
angularjs技术框架下的H5互动模板框架脚手架,基于NG-ZORRO实现快速开发基于绘玩云的H5互动课件。 angularjs技术框架下的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/
点击“模板管理” 菜单,找到对应的模板卡片,点击“发布”按钮,在弹出的对话框中选中压缩包,然后点击“确定”,上传完成后,则发布就成功了
## 常见问题汇总
### 静态资源引用路径写法
css文件里面要带 .. , eg:
```
background-image: url("../../assets/playground-house/bg.jpg");
```
其他的文件(html、ts、resources.js)里路径要开头不带斜杠, eg:
```
src="assets/guess-read/btn.png"
```
### no such file or directory,
出现类似如:
```
Error: ENOENT: no such file or directory, open 'C:/publish/resources/xxxx/v1/index.html'
```
这样的代码时, 请确认新建模板的时候表单填写的“配置页面URL”与“展示页面URL” 填写的路径是否正确
### 已经发布的模板,制作课件时看不到
如果模板已经确认发布成功了,制作课件的时候却看不到这个模板,请编辑模板,查看模板类型是否选择为“课中模板”
### 有些模板上传图片或视频时,存在偶尔上传不上去的问题
此问题是因为有些异步的情况下 uploadUrl 获取不到导致的
在 constructor 或者 ngOnInit 方法里,一直轮询,直到获取到 uploadUrl
```
this.uploadUrl = (<any> window).courseware.uploadUrl();
this.uploadData = (<any> window).courseware.uploadData();
const fun = () => {
setTimeout(() => {
this.uploadUrl = (<any> window).courseware.uploadUrl();
this.uploadData = (<any> window).courseware.uploadData();
if(!this.uploadUrl){
fun();
}
}, 1000);
}
if(!this.uploadUrl){
fun();
}
```
### 模板编译CI不通过,报类似如下错误
```
ERROR in ./src/styles.scss Module build failed (from ./node_modules/mini-css-extract-plugin/dist/loader.js): ModuleBuildError: Module build failed (from ./node_modules/sass-loader/dist/cjs.js): Error: Node Sass version 5.0.0 is incompatible with ^4.0.0. at getSassImplementation
```
此情况属于老的模板遗留问题,需要在package.json里面锁一下node-sass的版本
```
"node-sass": "4.0.0"
```
\ No newline at end of file
...@@ -3,9 +3,13 @@ ...@@ -3,9 +3,13 @@
"version": 1, "version": 1,
"newProjectRoot": "projects", "newProjectRoot": "projects",
"projects": { "projects": {
"ng-template-generator": { "ng-one": {
"projectType": "application", "projectType": "application",
"schematics": {}, "schematics": {
"@schematics/angular:component": {
"style": "scss"
}
},
"root": "", "root": "",
"sourceRoot": "src", "sourceRoot": "src",
"prefix": "app", "prefix": "app",
...@@ -13,26 +17,39 @@ ...@@ -13,26 +17,39 @@
"build": { "build": {
"builder": "@angular-devkit/build-angular:browser", "builder": "@angular-devkit/build-angular:browser",
"options": { "options": {
"outputPath": "dist/ng-template-generator", "outputPath": "dist",
"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": true, "aot": false,
"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",
"src/styles.css" "./node_modules/font-awesome/css/font-awesome.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": {
...@@ -47,39 +64,28 @@ ...@@ -47,39 +64,28 @@
"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-template-generator:build" "browserTarget": "ng-one:build"
}, },
"configurations": { "configurations": {
"production": { "production": {
"browserTarget": "ng-template-generator:build:production" "browserTarget": "ng-one:build:production"
} }
} }
}, },
"extract-i18n": { "extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n", "builder": "@angular-devkit/build-angular:extract-i18n",
"options": { "options": {
"browserTarget": "ng-template-generator:build" "browserTarget": "ng-one:build"
} }
}, },
"test": { "test": {
...@@ -94,8 +100,7 @@ ...@@ -94,8 +100,7 @@
"src/assets" "src/assets"
], ],
"styles": [ "styles": [
"./node_modules/ng-zorro-antd/ng-zorro-antd.min.css", "src/styles.scss"
"src/styles.css"
], ],
"scripts": [] "scripts": []
} }
...@@ -117,16 +122,15 @@ ...@@ -117,16 +122,15 @@
"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-template-generator:serve" "devServerTarget": "ng-one:serve"
}, },
"configurations": { "configurations": {
"production": { "production": {
"devServerTarget": "ng-template-generator:serve:production" "devServerTarget": "ng-one:serve:production"
} }
} }
} }
} }
} }},
}, "defaultProject": "ng-one"
"defaultProject": "ng-template-generator" }
} \ No newline at end of file
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
* 运行 npm run publish T_01,T_02,T_03,T_04 命令来分别打包 T_01,T_02,T_03,T_04 这四个模板,注意逗号要用英文的 * 运行 npm run publish T_01,T_02,T_03,T_04 命令来分别打包 T_01,T_02,T_03,T_04 这四个模板,注意逗号要用英文的
* 运行 npm run publish all 命令来打包所有模板 * 运行 npm run publish all 命令来打包所有模板
*/ */
const spawn = require('child_process').spawn; const spawn = require('child_process').spawn;
const path = require("path"); const path = require("path");
const fs = require("fs"); const fs = require("fs");
...@@ -12,9 +12,9 @@ const os = require('os'); ...@@ -12,9 +12,9 @@ const os = require('os');
const compressing = require("compressing"); const compressing = require("compressing");
//Linux系统上'Linux' //Linux系统上'Linux'
//macOS 系统上'Darwin' //macOS 系统上'Darwin'
//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 = {
...@@ -44,9 +44,9 @@ const runSpawn = async function (){ ...@@ -44,9 +44,9 @@ 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/'] );
...@@ -57,7 +57,7 @@ const runSpawn = async function (){ ...@@ -57,7 +57,7 @@ const runSpawn = async function (){
ls.stdout.on('data', (data) => { ls.stdout.on('data', (data) => {
console.log(` ${data}`); console.log(` ${data}`);
}); });
ls.stderr.on('data', (data) => { ls.stderr.on('data', (data) => {
console.log(`stderr: ${data}`); console.log(`stderr: ${data}`);
reject(); reject();
...@@ -66,13 +66,13 @@ const runSpawn = async function (){ ...@@ -66,13 +66,13 @@ 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", pkg.name); let zippath = path.resolve(__dirname,"../dist");
//压缩包的存放目录 //压缩包的存放目录
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 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){
...@@ -84,16 +84,16 @@ const runSpawn = async function (){ ...@@ -84,16 +84,16 @@ const runSpawn = async function (){
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);
writeStream.on('close', () => { writeStream.on('close', () => {
console.log(`模板 ${pkg.name} 打包已完成!`); console.log(`模板 ${pkg.name} 打包已完成!`);
resolve(); resolve();
}) })
}); });
}); });
}); });
} }
// let projects = ""; // let projects = "";
...@@ -101,7 +101,7 @@ const runSpawn = async function (){ ...@@ -101,7 +101,7 @@ const runSpawn = async function (){
// console.log("缺少参数"); // console.log("缺少参数");
// return; // return;
// } // }
// projects = process.argv[2]; // projects = process.argv[2];
let exec = async function(){ let exec = async function(){
//压缩模板 //压缩模板
...@@ -110,5 +110,6 @@ let exec = async function(){ ...@@ -110,5 +110,6 @@ let exec = async function(){
exec(); 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.
{ {
"name": "ng-template-generator", "name": "ng-template-generator",
"version": "0.0.1", "version": "0.0.1",
"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": "~9.0.2", "@angular/animations": "^7.2.10",
"@angular/common": "~9.0.2", "@angular/cdk": "^7.2.2",
"@angular/compiler": "~9.0.2", "@angular/common": "^7.2.10",
"@angular/core": "~9.0.2", "@angular/compiler": "^7.2.10",
"@angular/forms": "~9.0.2", "@angular/core": "^7.2.10",
"@angular/platform-browser": "~9.0.2", "@angular/flex-layout": "^7.0.0-beta.24",
"@angular/platform-browser-dynamic": "~9.0.2", "@angular/forms": "^7.2.10",
"@angular/router": "~9.0.2", "@angular/http": "^7.2.10",
"@fortawesome/angular-fontawesome": "^0.6.0", "@angular/material": "^7.2.2",
"@fortawesome/fontawesome-svg-core": "^1.2.27", "@angular/platform-browser": "^7.2.10",
"@fortawesome/free-regular-svg-icons": "^5.12.1", "@angular/platform-browser-dynamic": "^7.2.10",
"@fortawesome/free-solid-svg-icons": "^5.12.1", "@angular/platform-server": "^7.2.10",
"@tweenjs/tween.js": "~18.5.0", "@angular/router": "^7.2.10",
"ali-oss": "^6.5.1", "@tweenjs/tween.js": "^17.3.0",
"compressing": "^1.5.0", "ali-oss": "^6.0.0",
"ng-zorro-antd": "^8.5.2", "angular-cropperjs": "^1.0.1",
"rxjs": "~6.5.4", "angular2-draggable": "^2.1.9",
"angular2-fontawesome": "^5.2.1",
"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",
"tslib": "^1.10.0", "webpack": "^4.28.2",
"zone.js": "~0.10.2", "zone.js": "^0.8.26"
"node-sass": "4.0.0"
}, },
"devDependencies": { "devDependencies": {
"@angular-devkit/build-angular": "~0.900.3", "@angular-devkit/build-angular": "^0.11.4",
"@angular/cli": "~9.0.3", "@angular/cli": "^7.2.10",
"@angular/compiler-cli": "~9.0.2", "@angular/compiler-cli": "^7.2.10",
"@angular/language-service": "~9.0.2", "@angular/language-service": "^7.2.10",
"@types/jasmine": "~3.5.0", "@types/jasmine": "^3.3.5",
"@types/jasminewd2": "~2.0.3", "@types/jasminewd2": "~2.0.3",
"@types/node": "^12.11.1", "@types/node": "^10.12.18",
"codelyzer": "^5.1.2", "codelyzer": "^4.5.0",
"jasmine-core": "~3.5.0", "jasmine-core": "^3.3.0",
"jasmine-spec-reporter": "~4.2.1", "jasmine-spec-reporter": "^4.2.1",
"karma": "~4.3.0", "karma": "^3.1.4",
"karma-chrome-launcher": "~3.1.0", "karma-chrome-launcher": "^2.2.0",
"karma-coverage-istanbul-reporter": "~2.1.0", "karma-coverage-istanbul-reporter": "~2.0.0",
"karma-jasmine": "~2.0.1", "karma-jasmine": "^2.0.1",
"karma-jasmine-html-reporter": "^1.4.2", "karma-jasmine-html-reporter": "^1.4.0",
"protractor": "~5.4.3", "protractor": "^5.4.2",
"ts-node": "~8.3.0", "ts-node": "~5.0.1",
"tslint": "~5.18.0", "tslint": "^5.12.0",
"typescript": "~3.7.5" "node-sass": "^4.0.0",
"typescript": "3.1.1"
} }
} }
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 = 'play';
constructor() { constructor() {
const tp = this.getQueryString('type'); let tp = this.getQueryString("type");
if (tp) { if (tp){
this.type = tp; this.type = tp;
} }
} }
......
import { BrowserModule } from '@angular/platform-browser';
import { NgModule, ErrorHandler } from '@angular/core';
import {MyErrorHandler} from './MyError';
import { AppComponent } from './app.component'; import { BrowserModule } from '@angular/platform-browser';
import { NgZorroAntdModule, NZ_I18N, zh_CN } from 'ng-zorro-antd'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
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 { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { NgZorroAntdModule, NZ_I18N, zh_CN } from 'ng-zorro-antd';
import {Angular2FontawesomeModule} from 'angular2-fontawesome/angular2-fontawesome';
import { AppComponent } from './app.component';
import { FormComponent } from './form/form.component';
import { PlayComponent } from "./play/play.component";
import { LessonTitleConfigComponent } from './common/lesson-title-config/lesson-title-config.component';
import { AudioRecorderComponent } from './common/audio-recorder/audio-recorder.component';
import { PlayerContentWrapperComponent } from './common/player-content-wrapper/player-content-wrapper.component';
/** 配置 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 {FormComponent} from './form/form.component'; import {UploadImageWithPreviewComponent} from "./common/upload-image-with-preview/upload-image-with-preview.component";
import {PlayComponent} from './play/play.component'; import {BackgroundImagePipe} from "./pipes/background-image.pipe";
import {LessonTitleConfigComponent} from './common/lesson-title-config/lesson-title-config.component'; import {UploadVideoComponent} from "./common/upload-video/upload-video.component";
import {BackgroundImagePipe} from './pipes/background-image.pipe'; import {ResourcePipe} from "./pipes/resource.pipe";
import {UploadImageWithPreviewComponent} from './common/upload-image-with-preview/upload-image-with-preview.component'; import {TimePipe} from "./pipes/time.pipe";
import {PlayerContentWrapperComponent} from './common/player-content-wrapper/player-content-wrapper.component'; import {CustomHotZoneComponent} from "./common/custom-hot-zone/custom-hot-zone.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';
registerLocaleData(zh); registerLocaleData(zh);
@NgModule({ @NgModule({
...@@ -42,24 +42,20 @@ registerLocaleData(zh); ...@@ -42,24 +42,20 @@ registerLocaleData(zh);
CustomHotZoneComponent, CustomHotZoneComponent,
PlayerContentWrapperComponent PlayerContentWrapperComponent
], ],
imports: [ imports: [
BrowserModule,
NgZorroAntdModule,
FormsModule, FormsModule,
HttpClientModule, HttpClientModule,
BrowserAnimationsModule, BrowserAnimationsModule,
FontAwesomeModule BrowserModule,
Angular2FontawesomeModule,
NgZorroAntdModule,
], ],
providers: [ /** 配置 ng-zorro-antd 国际化(文案 及 日期) **/
{provide: ErrorHandler, useClass: MyErrorHandler}, providers : [
{ 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) {
library.addIconPacks(fas, far);
}
}
<div class="d-flex"> <div class="d-flex">
<div class="p-btn-record d-flex"> <div class="p-btn-record d-flex">
<div class="btn-clear" style="cursor: pointer" (click)="onBtnClearAudio()" *ngIf="withRmBtn && (audioUrl || audioBlob)"> <div class="btn-clear" (click)="onBtnClearAudio()" *ngIf="withRmBtn && (audioUrl || audioBlob)">
<fa-icon icon="times"></fa-icon> <fa name="close"></fa>
</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-icon icon="microphone"></fa-icon> <fa name="microphone"></fa>
Record Audio Record Audio
</div> </div>
<nz-upload <nz-upload
[nzAccept] = "'.mp3'" [nzAccept] = "'.mp3'"
[nzShowUploadList]="false" [nzShowUploadList]="false"
[nzAction]="uploadUrl" [nzAction]="uploadUrl"
[nzData]="uploadData" [nzData]="uploadData"
(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-icon icon="upload"></fa-icon> <fa name="upload"></fa>
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-icon icon="cloud-upload-alt"></fa-icon> <fa name="cloud-upload"></fa>
Uploading... Uploading...
</div> </div>
</div> </div>
...@@ -35,14 +35,14 @@ ...@@ -35,14 +35,14 @@
<ng-template #truthyTemplate > <ng-template #truthyTemplate >
<div class="btn-delete" (click)="onBtnDeleteAudio()"> <div class="btn-delete" (click)="onBtnDeleteAudio()">
<fa-icon icon="close"></fa-icon> <fa name="close"></fa>
</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-icon icon="cog"></fa-icon> <fa name="cog"></fa>
</div> </div>
</ng-template> </ng-template>
...@@ -55,7 +55,7 @@ ...@@ -55,7 +55,7 @@
<nz-progress [nzPercent]="percent" [nzWidth]="30" [nzFormat]="progressText" <nz-progress [nzPercent]="percent" [nzWidth]="30" [nzFormat]="progressText"
nzType="circle"></nz-progress> nzType="circle"></nz-progress>
<div class="p-btn-play" [style.left]="isPlaying?'8px':''"> <div class="p-btn-play" [style.left]="isPlaying?'8px':''">
<fa-icon [icon]="playIcon"></fa-icon> <fa [name]="playIcon"></fa>
</div> </div>
</div> </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;
......
import {Component, EventEmitter, Input, OnDestroy, OnInit, Output, NgZone, OnChanges} from '@angular/core'; import {Component, EventEmitter, Input, OnDestroy, OnInit, Output, NgZone, OnChanges} from '@angular/core';
import {NzMessageService, NzNotificationService, UploadFile} from 'ng-zorro-antd'; import {NzMessageService, NzNotificationService, UploadFile} from 'ng-zorro-antd';
import {HttpClient, HttpEvent, HttpEventType, HttpRequest} from '@angular/common/http'; import {HttpClient, HttpEvent, HttpEventType, HttpRequest} from '@angular/common/http';
import {environment} from '../../../environments/environment'; import {environment} from '../../../environments/environment';
declare var Recorder; declare var Recorder;
...@@ -9,7 +9,7 @@ declare var Recorder; ...@@ -9,7 +9,7 @@ declare var Recorder;
selector: 'app-audio-recorder', selector: 'app-audio-recorder',
templateUrl: './audio-recorder.component.html', templateUrl: './audio-recorder.component.html',
styleUrls: ['./audio-recorder.component.scss'] styleUrls: ['./audio-recorder.component.scss']
}) })
export class AudioRecorderComponent implements OnInit, OnChanges, OnDestroy { export class AudioRecorderComponent implements OnInit, OnChanges, OnDestroy {
_audioUrl: string; _audioUrl: string;
audio = new Audio(); audio = new Audio();
...@@ -19,11 +19,10 @@ export class AudioRecorderComponent implements OnInit, OnChanges, OnDestroy { ...@@ -19,11 +19,10 @@ 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; uploadUrl = (<any>window).courseware.uploadUrl();
uploadData; uploadData = (<any>window).courseware.uploadData();
@Input() @Input()
needRemove = false; needRemove = false;
...@@ -33,7 +32,7 @@ export class AudioRecorderComponent implements OnInit, OnChanges, OnDestroy { ...@@ -33,7 +32,7 @@ export class AudioRecorderComponent implements OnInit, OnChanges, OnDestroy {
@Input() @Input()
set audioUrl(url) { set audioUrl(url) {
this._audioUrl = url; this._audioUrl = url
if (url) { if (url) {
this.audio.src = this._audioUrl; this.audio.src = this._audioUrl;
this.audio.load(); this.audio.load();
...@@ -53,15 +52,9 @@ export class AudioRecorderComponent implements OnInit, OnChanges, OnDestroy { ...@@ -53,15 +52,9 @@ export class AudioRecorderComponent implements OnInit, OnChanges, OnDestroy {
recorder: any; recorder: any;
audioBlob: any; audioBlob: any;
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;
};
} }
init() { init() {
...@@ -144,14 +137,13 @@ export class AudioRecorderComponent implements OnInit, OnChanges, OnDestroy { ...@@ -144,14 +137,13 @@ export class AudioRecorderComponent implements OnInit, OnChanges, OnDestroy {
} }
// 开始录音 // 开始录音
onBtnRecord = () => { onBtnRecord = () => {
} }
// 切换模式 // 切换模式
onBtnSwitchType() { onBtnSwitchType() {
} }
onBtnClearAudio() { onBtnClearAudio() {
this.audioUrl = null;
this.audioRemoved.emit(); this.audioRemoved.emit();
} }
...@@ -160,7 +152,7 @@ export class AudioRecorderComponent implements OnInit, OnChanges, OnDestroy { ...@@ -160,7 +152,7 @@ export class AudioRecorderComponent implements OnInit, OnChanges, OnDestroy {
this.audioRemoved.emit(); this.audioRemoved.emit();
} }
handleChange(info: { type: string, file: UploadFile, event: any }): void { handleChange(info: { type: string, file: UploadFile, event: any }): void {
switch (info.type) { switch (info.type) {
case 'start': case 'start':
this.isUploading = true; this.isUploading = true;
...@@ -193,19 +185,19 @@ export class AudioRecorderComponent implements OnInit, OnChanges, OnDestroy { ...@@ -193,19 +185,19 @@ export class AudioRecorderComponent implements OnInit, OnChanges, OnDestroy {
} }
return true; return true;
} }
beforeUpload = (file: File) => { beforeUpload = (file: File) => {
this.audioUrl = null; this.audioUrl = null;
if (!this.checkSelectFile(file)) { if (!this.checkSelectFile(file)) {
return false; return false;
} }
this.isUploading = true; this.isUploading = true;
this.progress = 0; this.progress = 0;
} }
uploadSuccess = (url) => { uploadSuccess = (url) => {
this.nzMessageService.info('Upload Success'); this.nzMessageService.info('Upload Success');
this.isUploading = false; this.isUploading = false;
this.audioUrl = url; this.audioUrl = url;
} }
uploadFailure = (err, file) => { uploadFailure = (err, file) => {
this.isUploading = false; this.isUploading = false;
......
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;
...@@ -17,12 +12,8 @@ class Sprite { ...@@ -17,12 +12,8 @@ class Sprite {
angle = 0; angle = 0;
ctx; ctx;
constructor(ctx = null) { constructor(ctx) {
if (!ctx) { this.ctx = ctx;
this.ctx = window.curCtx;
} else {
this.ctx = ctx;
}
} }
update($event) { update($event) {
this.draw(); this.draw();
...@@ -39,45 +30,25 @@ class Sprite { ...@@ -39,45 +30,25 @@ 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) {
...@@ -85,8 +56,6 @@ export class MySprite extends Sprite { ...@@ -85,8 +56,6 @@ 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;
...@@ -94,35 +63,11 @@ export class MySprite extends Sprite { ...@@ -94,35 +63,11 @@ 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 && this.childDepandVisible) { if (this.visible) {
return; this.draw();
} }
this.draw();
} }
draw() { draw() {
...@@ -133,8 +78,6 @@ export class MySprite extends Sprite { ...@@ -133,8 +78,6 @@ export class MySprite extends Sprite {
this.updateChildren(); this.updateChildren();
this.ctx.restore(); this.ctx.restore();
} }
drawInit() { drawInit() {
...@@ -147,73 +90,26 @@ export class MySprite extends Sprite { ...@@ -147,73 +90,26 @@ 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) {
this.ctx.drawImage(this.img, this._offX, this._offY);
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);
}
} }
} }
updateChildren() { updateChildren() {
if (this.children.length <= 0) { return; } if (this.children.length <= 0) { return; }
for (const child of this.children) { for (let i = 0; i < this.children.length; i++) {
if (child === this) {
if (this.visible) { if (this.children[i] === this) {
this.drawSelf();
} this.drawSelf();
} else { } else {
child.update();
this.children[i].update();
} }
} }
} }
...@@ -244,1728 +140,237 @@ export class MySprite extends Sprite { ...@@ -244,1728 +140,237 @@ 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);
if (index !== -1) { if (index !== -1) {
this.children.splice(index, 1); this.children.splice(index, 1);
} }
}
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) {
this._anchorX = value;
this.refreshAnchorOff();
}
get anchorX() {
return this._anchorX;
}
set anchorY(value) {
this._anchorY = value;
this.refreshAnchorOff();
}
get anchorY() {
return this._anchorY;
}
refreshAnchorOff() {
this._offX = -this._width * this.anchorX;
this._offY = -this._height * this.anchorY;
}
setScaleXY(value) {
this.scaleX = this.scaleY = value;
}
getBoundingBox() {
const getParentData = (item) => {
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;
}
return {px, py, sx, sy};
};
const data = getParentData(this);
const x = data.px + this._offX * Math.abs(data.sx);
const y = data.py + this._offY * Math.abs(data.sy);
const width = this.width * Math.abs(data.sx);
const height = this.height * Math.abs(data.sy);
return {x, y, width, height};
}
}
export class RoundSprite extends MySprite {
_newCtx;
init(imgObj = null, anchorX: number = 0.5, anchorY: number = 0.5) {
if (imgObj) {
this.img = imgObj;
this.width = this.img.width;
this.height = this.img.height;
}
this.anchorX = anchorX;
this.anchorY = anchorY;
const canvas = window['curCanvas'];
const w = canvas.nativeElement.width;
const h = canvas.nativeElement.height;
this._offCanvas = document.createElement('canvas');
this._offCanvas.width = w;
this._offCanvas.height = h;
this._offCtx = this._offCanvas.getContext('2d');
// this._newCtx = this.ctx;
// this.ctx = this._offCtx;
}
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();
}
if (this.img) {
this._offCtx.drawImage(this.img, 0, 0);
this.ctx.drawImage(this._offCanvas,this._offX, this._offX);
}
}
}
export class ColorSpr extends MySprite {
r = 0;
g = 0;
b = 0;
createGSCanvas() {
if (!this.img) {
return;
}
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];
c.data[x] = this.r;
c.data[x + 1] = this.g;
c.data[x + 2] = this.b;
// c.data[x] = c.data[x + 1] = c.data[x + 2] = (r + g + b) / 3 ;
// // c.data[x + 3] = 255;
}
}
this.ctx.putImageData(c, rect.x, rect.y, 0, 0, rect.width, rect.height);
}
drawSelf() {
super.drawSelf();
this.createGSCanvas();
}
}
export class GrayscaleSpr extends MySprite {
grayScale = 120;
createGSCanvas() {
if (!this.img) {
return;
}
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() {
super.drawSelf();
this.createGSCanvas();
}
}
export class BitMapLabel extends MySprite {
labelArr;
baseUrl;
setText(data, text) {
this.labelArr = [];
const labelArr = [];
const tmpArr = text.split('');
let totalW = 0;
let h = 0;
for (const tmp of tmpArr) {
const label = new MySprite(this.ctx);
label.init(data[tmp], 0);
this.addChild(label);
labelArr.push(label);
totalW += label.width;
h = label.height;
}
this.width = totalW;
this.height = h;
let offX = -totalW / 2;
for (const label of labelArr) {
label.x = offX;
offX += label.width;
}
this.labelArr = labelArr;
}
}
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();
}
get text(): string {
return this._text;
}
set text(value: string) {
this._text = value;
this.refreshSize();
}
refreshSize() {
this.ctx.save();
this.ctx.font = `${this.fontSize * this.scaleX}px ${this.fontName}`;
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; set anchorX(value) {
this._anchorX = value;
this.refreshAnchorOff();
} }
if (mx > px && my === py) {// 鼠标在x轴正方向上 get anchorX() {
angle = 90; return this._anchorX;
} }
if (mx < px && my > py) {// 鼠标在第三象限 set anchorY(value) {
angle = 180 + angle; this._anchorY = value;
this.refreshAnchorOff();
} }
if (mx < px && my === py) {// 鼠标在x轴负方向 get anchorY() {
angle = 270; return this._anchorY;
} }
if (mx < px && my < py) {// 鼠标在第二象限 refreshAnchorOff() {
angle = 360 - angle; this._offX = -this.width * this.anchorX;
this._offY = -this.height * this.anchorY;
} }
// console.log('angle: ', angle); setScaleXY(value) {
return angle; this.scaleX = this.scaleY = value;
}
} getBoundingBox() {
const x = this.x + this._offX * this.scaleX;
const y = this.y + this._offY * this.scaleY;
const width = this.width * this.scaleX;
const height = this.height * this.scaleY;
export function removeItemFromArr(arr, item) { return {x, y, width, height};
const index = arr.indexOf(item);
if (index !== -1) {
arr.splice(index, 1);
} }
} }
export class Item extends MySprite {
export function circleMove(item, x0, y0, time = 2, addR = 360, xPer = 1, yPer = 1, callBack = null, easing = null) { baseX;
const r = getPosDistance(item.x, item.y, x0, y0); move(targetY, callBack) {
let a = getAngleByPos(item.x, item.y, x0, y0);
a += 90;
const obj = {r, a};
item._circleAngle = a; const self = this;
const targetA = a + addR;
const tween = new TWEEN.Tween(item).to({_circleAngle: targetA}, time * 1000); const tween = new TWEEN.Tween(this)
.to({ y: targetY }, 2500)
.easing(TWEEN.Easing.Quintic.Out)
.onComplete(function() {
self.hide(callBack);
// if (callBack) {
// callBack();
// }
})
.start();
if (callBack) {
tween.onComplete(() => {
callBack();
});
}
if (easing) {
tween.easing(easing);
} }
tween.onUpdate( (item, progress) => { show(callBack = null) {
// 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();
}
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 function getPosDistance(sx, sy, ex, ey) { }
const _x = ex - sx; hide(callBack = null) {
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)
const tween = new TWEEN.Tween(this) .to({ alpha: 0 }, 800)
.delay(second * 1000) // .easing(TWEEN.Easing.Quadratic.Out) // Use an easing function to make the animation smooth.
.onComplete(() => { .onComplete(function() {
if (callback) { if (callBack) {
callback(); callBack();
} }
}) })
.start(); .start(); // Start the tween immediately.
} }
export function formatTime(fmt, date) { shake(id) {
// "yyyy-MM-dd HH:mm:ss";
const o = { if (!this.baseX) {
'M+': date.getMonth() + 1, // 月份 this.baseX = this.x;
'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;
}
const baseX = this.baseX;
const baseTime = 50;
const sequence = [
{target: {x: baseX + 40 * id}, time: baseTime - 25},
{target: {x: baseX - 20 * id}, time: baseTime},
{target: {x: baseX + 10 * id}, time: baseTime},
{target: {x: baseX - 5 * id}, time: baseTime},
{target: {x: baseX + 2 * id}, time: baseTime},
{target: {x: baseX - 1 * id}, time: baseTime},
{target: {x: baseX}, time: baseTime},
];
export function jelly(item, time = 0.7) {
const self = this;
if (item.jellyTween) { function runSequence() {
TWEEN.remove(item.jellyTween);
}
const t = time / 9; if (self['shakeTween']) {
const baseSX = item.scaleX; self['shakeTween'].stop();
const baseSY = item.scaleY; }
let index = 0;
const run = () => { const tween = new TWEEN.Tween(self);
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();
}
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;
}
}
export function showPopParticle(img, pos, parent, num = 20, minLen = 40, maxLen = 80, showTime = 0.4) { runSequence();
}
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(); drop(targetY, callBack = null) {
particle.rotation = randomR;
const randomS = 0.3 + Math.random() * 0.7; const self = this;
particle.setScaleXY(randomS * 0.3);
const randomX = Math.random() * 20 - 10; const time = Math.abs(targetY - this.y) * 2.4;
particle.x += randomX;
const randomY = Math.random() * 20 - 10; this.alpha = 1;
particle.y += randomY;
const randomL = minLen + Math.random() * (maxLen - minLen); const tween = new TWEEN.Tween(this)
const randomA = 360 * Math.random(); .to({ y: targetY }, time)
const randomT = getPosByAngle(randomA, randomL); .easing(TWEEN.Easing.Cubic.In)
moveItem(particle, particle.x + randomT.x, particle.y + randomT.y, showTime, () => { .onComplete(function() {
// self.hideItem(callBack);
if (callBack) {
callBack();
}
})
.start();
}, TWEEN.Easing.Exponential.Out); }
// scaleItem(particle, 0, 0.6, () => {
//
// });
scaleItem(particle, randomS, 0.6, () => { }
}, TWEEN.Easing.Exponential.Out);
setTimeout(() => { export class EndSpr extends MySprite {
hideItem(particle, 0.4, () => { show(s) {
}, TWEEN.Easing.Cubic.In); this.scaleX = this.scaleY = 0;
this.alpha = 0;
}, showTime * 0.5 * 1000); const tween = new TWEEN.Tween(this)
.to({ alpha: 1, scaleX: s, scaleY: s }, 800)
.easing(TWEEN.Easing.Elastic.Out) // Use an easing function to make the animation smooth.
.onComplete(function() {
})
.start(); // Start the tween immediately.
} }
} }
export function shake(item, time = 0.5, callback = null, rate = 1) { export class ShapeRect extends MySprite {
if (item.shakeTween) {
return;
}
item.shakeTween = true; fillColor = '#FF0000';
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;
setSize(w, h) {
this.width = w;
this.height = h;
const move4 = () => { console.log('w:', w);
moveItem(item, baseX, baseY, time / 4, () => { console.log('h:', h);
item.shakeTween = false; }
if (callback) {
callback();
}
}, easing);
};
const move3 = () => { drawShape() {
moveItem(item, baseX + offX / 4, baseY + offY / 4, time / 4, () => {
move4();
}, easing);
};
const move2 = () => { this.ctx.fillStyle = this.fillColor;
moveItem(item, baseX - offX / 4 * 3, baseY - offY / 4 * 3, time / 4, () => { this.ctx.fillRect(this._offX, this._offY, this.width, this.height);
move3();
}, easing);
};
const move1 = () => { }
moveItem(item, baseX + offX, baseY + offY, time / 7.5, () => {
move2();
}, easing);
};
move1();
drawSelf() {
super.drawSelf();
this.drawShape();
}
} }
// --------------- custom class --------------------
export class HotZoneItem extends MySprite { export class HotZoneItem extends MySprite {
lineDashFlag = false; lineDashFlag = false;
arrow: MySprite; arrow: MySprite;
label: Label; label: Label;
title; text;
arrowTop; arrowTop;
arrowRight; arrowRight;
audio_url;
pic_url;
text;
private _itemType;
private shapeRect: ShapeRect;
get itemType() {
return this._itemType;
}
set itemType(value) {
this._itemType = value;
}
setSize(w, h) { setSize(w, h) {
this.width = w; this.width = w;
this.height = h; this.height = h;
...@@ -1986,7 +391,7 @@ export class HotZoneItem extends MySprite { ...@@ -1986,7 +391,7 @@ export class HotZoneItem 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 = 40; this.label.fontSize = '40px';
this.label.textAlign = 'center'; this.label.textAlign = 'center';
this.addChild(this.label); this.addChild(this.label);
// this.label.scaleX = 1 / this.scaleX; // this.label.scaleX = 1 / this.scaleX;
...@@ -1998,8 +403,8 @@ export class HotZoneItem extends MySprite { ...@@ -1998,8 +403,8 @@ export class HotZoneItem extends MySprite {
if (text) { if (text) {
this.label.text = text; this.label.text = text;
} else if (this.title) { } else if (this.text) {
this.label.text = this.title; this.label.text = this.text;
} }
this.label.visible = true; this.label.visible = true;
...@@ -2127,86 +532,12 @@ export class HotZoneItem extends MySprite { ...@@ -2127,86 +532,12 @@ export class HotZoneItem extends MySprite {
} }
} }
export class HotZoneImg extends MySprite {
drawFrame() {
this.ctx.save();
const rect = this.getBoundingBox();
const w = rect.width;
const h = rect.height;
const x = rect.x + w / 2;
const y = rect.y + h / 2;
this.ctx.setLineDash([5, 5]);
this.ctx.lineWidth = 2;
this.ctx.strokeStyle = '#1bfff7';
this.ctx.beginPath();
this.ctx.moveTo( x - w / 2, y - h / 2);
this.ctx.lineTo(x + w / 2, y - h / 2);
this.ctx.lineTo(x + w / 2, y + h / 2);
this.ctx.lineTo(x - w / 2, y + h / 2);
this.ctx.lineTo(x - w / 2, y - h / 2);
// this.ctx.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();
}
}
export class EditorItem extends MySprite { export class EditorItem extends MySprite {
lineDashFlag = false; lineDashFlag = false;
arrow: MySprite; arrow: MySprite;
label: Label; label:Label;
text; text;
showLabel(text = null) { showLabel(text = null) {
...@@ -2215,7 +546,7 @@ export class EditorItem extends MySprite { ...@@ -2215,7 +546,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 = 50; this.label.fontSize = '50px';
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);
...@@ -2326,783 +657,109 @@ export class EditorItem extends MySprite { ...@@ -2326,783 +657,109 @@ export class EditorItem extends MySprite {
// export class Label extends MySprite {
//
// import TWEEN from '@tweenjs/tween.js'; text:String;
// fontSize:String = '40px';
// fontName:String = 'Verdana';
// class Sprite { textAlign:String = 'left';
// x = 0;
// y = 0;
// color = ''; constructor(ctx) {
// radius = 0; super(ctx);
// alive = false; this.init();
// margin = 0; }
// angle = 0;
// ctx; drawText() {
//
// constructor(ctx) { // console.log('in drawText', this.text);
// this.ctx = ctx;
// } if (!this.text) { return; }
// update($event) {
// this.draw(); this.ctx.font = `${this.fontSize} ${this.fontName}`;
// } this.ctx.textAlign = this.textAlign;
// draw() { 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);
//
// export class MySprite extends Sprite {
// }
// width = 0;
// height = 0;
// _anchorX = 0; drawSelf() {
// _anchorY = 0; super.drawSelf();
// _offX = 0; this.drawText();
// _offY = 0; }
// scaleX = 1;
// scaleY = 1; }
// alpha = 1;
// rotation = 0;
// visible = true;
// export function getPosByAngle(angle, len) {
// children = [this];
// const radian = angle * Math.PI / 180;
// img; const x = Math.sin(radian) * len;
// _z = 0; const y = Math.cos(radian) * len;
//
// return {x, y};
// init(imgObj = null, anchorX:number = 0.5, anchorY:number = 0.5) {
// }
// if (imgObj) {
// export function getAngleByPos(px, py, mx, my) {
// this.img = imgObj;
// // const _x = p2x - p1x;
// this.width = this.img.width; // const _y = p2y - p1y;
// this.height = this.img.height; // const tan = _y / _x;
// } //
// // const radina = Math.atan(tan); // 用反三角函数求弧度
// this.anchorX = anchorX; // const angle = Math.floor(180 / (Math.PI / radina)); //
// this.anchorY = anchorY; //
// } // console.log('r: ' , angle);
// // return angle;
// //
//
// update($event = null) {
// if (this.visible) {
// this.draw(); const x = Math.abs(px - mx);
// } const y = Math.abs(py - my);
// } // const x = Math.abs(mx - px);
// draw() { // const y = Math.abs(my - py);
// const z = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
// this.ctx.save(); const cos = y / z;
// const radina = Math.acos(cos); // 用反三角函数求弧度
// this.drawInit(); let angle = Math.floor(180 / (Math.PI / radina) * 100) / 100; // 将弧度转换成角度
//
// this.updateChildren(); if(mx > px && my > py) {// 鼠标在第四象限
// angle = 180 - angle;
// this.ctx.restore(); }
// }
// if(mx === px && my > py) {// 鼠标在y轴负方向上
// drawInit() { angle = 180;
// }
// this.ctx.translate(this.x, this.y);
// if(mx > px && my === py) {// 鼠标在x轴正方向上
// this.ctx.rotate(this.rotation * Math.PI / 180); angle = 90;
// }
// this.ctx.scale(this.scaleX, this.scaleY);
// if(mx < px && my > py) {// 鼠标在第三象限
// this.ctx.globalAlpha = this.alpha; angle = 180 + angle;
// }
// }
// if(mx < px && my === py) {// 鼠标在x轴负方向
// drawSelf() { angle = 270;
// if (this.img) { }
// this.ctx.drawImage(this.img, this._offX, this._offY);
// } if(mx < px && my < py) {// 鼠标在第二象限
// } angle = 360 - angle;
// }
// updateChildren() {
// // console.log('angle: ', angle);
// if (this.children.length <= 0) { return; } return angle;
//
// for (let i = 0; i < this.children.length; i++) { }
//
// if (this.children[i] === this) {
//
// this.drawSelf();
// } else {
//
// this.children[i].update();
// }
// }
// }
//
//
// load(url, anchorX = 0.5, anchorY = 0.5) {
//
// return new Promise((resolve, reject) => {
// const img = new Image();
// img.onload = () => resolve(img);
// img.onerror = reject;
// img.src = url;
// }).then(img => {
//
// this.init(img, anchorX, anchorY);
// return img;
// });
// }
//
// addChild(child, z = 1) {
// if (this.children.indexOf(child) === -1) {
// this.children.push(child);
// child._z = z;
// child.parent = this;
// }
//
// this.children.sort((a, b) => {
// return a._z - b._z;
// });
//
// }
// removeChild(child) {
// const index = this.children.indexOf(child);
// if (index !== -1) {
// this.children.splice(index, 1);
// }
// }
//
// set anchorX(value) {
// this._anchorX = value;
// this.refreshAnchorOff();
// }
// get anchorX() {
// return this._anchorX;
// }
// set anchorY(value) {
// this._anchorY = value;
// this.refreshAnchorOff();
// }
// get anchorY() {
// return this._anchorY;
// }
// refreshAnchorOff() {
// this._offX = -this.width * this.anchorX;
// this._offY = -this.height * this.anchorY;
// }
//
// setScaleXY(value) {
// this.scaleX = this.scaleY = value;
// }
//
// getBoundingBox() {
//
// const x = this.x + this._offX * this.scaleX;
// const y = this.y + this._offY * this.scaleY;
// const width = this.width * this.scaleX;
// const height = this.height * this.scaleY;
//
// return {x, y, width, height};
// }
//
// }
//
//
//
//
//
// export class Item extends MySprite {
//
// baseX;
//
// move(targetY, callBack) {
//
// const self = this;
//
// const tween = new TWEEN.Tween(this)
// .to({ y: targetY }, 2500)
// .easing(TWEEN.Easing.Quintic.Out)
// .onComplete(function() {
//
// self.hide(callBack);
// // if (callBack) {
// // callBack();
// // }
// })
// .start();
//
// }
//
// show(callBack = null) {
//
// const tween = new TWEEN.Tween(this)
// .to({ alpha: 1 }, 800)
// // .easing(TWEEN.Easing.Quadratic.Out) // Use an easing function to make the animation smooth.
// .onComplete(function() {
// if (callBack) {
// callBack();
// }
// })
// .start(); // Start the tween immediately.
//
// }
//
// hide(callBack = null) {
//
// const tween = new TWEEN.Tween(this)
// .to({ alpha: 0 }, 800)
// // .easing(TWEEN.Easing.Quadratic.Out) // Use an easing function to make the animation smooth.
// .onComplete(function() {
// if (callBack) {
// callBack();
// }
// })
// .start(); // Start the tween immediately.
// }
//
//
// shake(id) {
//
//
// if (!this.baseX) {
// this.baseX = this.x;
// }
//
// const baseX = this.baseX;
// const baseTime = 50;
// const sequence = [
// {target: {x: baseX + 40 * id}, time: baseTime - 25},
// {target: {x: baseX - 20 * id}, time: baseTime},
// {target: {x: baseX + 10 * id}, time: baseTime},
// {target: {x: baseX - 5 * id}, time: baseTime},
// {target: {x: baseX + 2 * id}, time: baseTime},
// {target: {x: baseX - 1 * id}, time: baseTime},
// {target: {x: baseX}, time: baseTime},
//
// ];
//
//
// const self = this;
//
// function runSequence() {
//
// if (self['shakeTween']) {
// self['shakeTween'].stop();
// }
//
// const tween = new TWEEN.Tween(self);
//
// if (sequence.length > 0) {
// // console.log('sequence.length: ', sequence.length);
// const action = sequence.shift();
// tween.to(action['target'], action['time']);
// tween.onComplete( () => {
// runSequence();
// });
// tween.start();
//
// self['shakeTween'] = tween;
// }
// }
//
// runSequence();
//
// }
//
//
//
// drop(targetY, callBack = null) {
//
// const self = this;
//
// const time = Math.abs(targetY - this.y) * 2.4;
//
// this.alpha = 1;
//
// const tween = new TWEEN.Tween(this)
// .to({ y: targetY }, time)
// .easing(TWEEN.Easing.Cubic.In)
// .onComplete(function() {
//
// // self.hideItem(callBack);
// if (callBack) {
// callBack();
// }
// })
// .start();
//
//
// }
//
//
// }
//
//
// export class EndSpr extends MySprite {
//
// show(s) {
//
// this.scaleX = this.scaleY = 0;
// this.alpha = 0;
//
// const tween = new TWEEN.Tween(this)
// .to({ alpha: 1, scaleX: s, scaleY: s }, 800)
// .easing(TWEEN.Easing.Elastic.Out) // Use an easing function to make the animation smooth.
// .onComplete(function() {
//
// })
// .start(); // Start the tween immediately.
//
// }
// }
//
//
//
// export class ShapeRect extends MySprite {
//
// fillColor = '#FF0000';
//
// setSize(w, h) {
// this.width = w;
// this.height = h;
//
// console.log('w:', w);
// console.log('h:', h);
// }
//
// drawShape() {
//
// this.ctx.fillStyle = this.fillColor;
// this.ctx.fillRect(this._offX, this._offY, this.width, this.height);
//
// }
//
//
// drawSelf() {
// super.drawSelf();
// this.drawShape();
// }
// }
//
//
// export class HotZoneItem extends MySprite {
//
//
// lineDashFlag = false;
// arrow: MySprite;
// label: Label;
// title;
//
// arrowTop;
// arrowRight;
//
// audio_url;
// pic_url;
// text;
// private _itemType;
// private shapeRect: ShapeRect;
//
// get itemType() {
// return this._itemType;
// }
// set itemType(value) {
// this._itemType = value;
// }
//
// setSize(w, h) {
// this.width = w;
// this.height = h;
//
//
// const rect = new ShapeRect(this.ctx);
// rect.x = -w / 2;
// rect.y = -h / 2;
// rect.setSize(w, h);
// rect.fillColor = '#ffffff';
// rect.alpha = 0.2;
// this.addChild(rect);
// }
//
// showLabel(text = null) {
//
//
// if (!this.label) {
// this.label = new Label(this.ctx);
// this.label.anchorY = 0;
// this.label.fontSize = '40px';
// this.label.textAlign = 'center';
// this.addChild(this.label);
// // this.label.scaleX = 1 / this.scaleX;
// // this.label.scaleY = 1 / this.scaleY;
//
// this.refreshLabelScale();
//
// }
//
// if (text) {
// this.label.text = text;
// } else if (this.title) {
// this.label.text = this.title;
// }
// this.label.visible = true;
//
// }
//
// hideLabel() {
// if (!this.label) { return; }
//
// this.label.visible = false;
// }
//
// refreshLabelScale() {
// if (this.scaleX == this.scaleY) {
// this.label.setScaleXY(1);
// }
//
// if (this.scaleX > this.scaleY) {
// this.label.scaleX = this.scaleY / this.scaleX;
// } else {
// this.label.scaleY = this.scaleX / this.scaleY;
// }
// }
//
// showLineDash() {
// this.lineDashFlag = true;
//
// if (this.arrow) {
// this.arrow.visible = true;
// } else {
// this.arrow = new MySprite(this.ctx);
// this.arrow.load('assets/common/arrow.png', 1, 0);
// this.arrow.setScaleXY(0.06);
//
// this.arrowTop = new MySprite(this.ctx);
// this.arrowTop.load('assets/common/arrow_top.png', 0.5, 0);
// this.arrowTop.setScaleXY(0.06);
//
// this.arrowRight = new MySprite(this.ctx);
// this.arrowRight.load('assets/common/arrow_right.png', 1, 0.5);
// this.arrowRight.setScaleXY(0.06);
// }
//
// this.showLabel();
// }
//
// hideLineDash() {
//
// this.lineDashFlag = false;
//
// if (this.arrow) {
// this.arrow.visible = false;
// }
//
// this.hideLabel();
// }
//
//
//
// drawArrow() {
// if (!this.arrow) { return; }
//
// const rect = this.getBoundingBox();
// this.arrow.x = rect.x + rect.width;
// this.arrow.y = rect.y;
//
// this.arrow.update();
//
//
// this.arrowTop.x = rect.x + rect.width / 2;
// this.arrowTop.y = rect.y;
// this.arrowTop.update();
//
// this.arrowRight.x = rect.x + rect.width;
// this.arrowRight.y = rect.y + rect.height / 2;
// this.arrowRight.update();
// }
//
// drawFrame() {
//
//
// this.ctx.save();
//
//
// const rect = this.getBoundingBox();
//
// const w = rect.width;
// const h = rect.height;
// const x = rect.x + w / 2;
// const y = rect.y + h / 2;
//
// this.ctx.setLineDash([5, 5]);
// this.ctx.lineWidth = 2;
// this.ctx.strokeStyle = '#1bfff7';
// // this.ctx.fillStyle = '#ffffff';
//
// this.ctx.beginPath();
//
// this.ctx.moveTo( x - w / 2, y - h / 2);
//
// this.ctx.lineTo(x + w / 2, y - h / 2);
//
// this.ctx.lineTo(x + w / 2, y + h / 2);
//
// this.ctx.lineTo(x - w / 2, y + h / 2);
//
// this.ctx.lineTo(x - w / 2, y - h / 2);
//
// // this.ctx.fill();
// this.ctx.stroke();
//
//
//
//
// this.ctx.restore();
//
// }
//
// draw() {
// super.draw();
//
// if (this.lineDashFlag) {
// this.drawFrame();
// this.drawArrow();
// }
// }
// }
//
//
// export class EditorItem extends MySprite {
//
// lineDashFlag = false;
// arrow: MySprite;
// label:Label;
// text;
//
// showLabel(text = null) {
//
//
// if (!this.label) {
// this.label = new Label(this.ctx);
// this.label.anchorY = 0;
// this.label.fontSize = '50px';
// this.label.textAlign = 'center';
// this.addChild(this.label);
// this.label.setScaleXY(1 / this.scaleX);
// }
//
// if (text) {
// this.label.text = text;
// } else if (this.text) {
// this.label.text = this.text;
// }
// this.label.visible = true;
//
// }
//
// hideLabel() {
// if (!this.label) { return; }
//
// this.label.visible = false;
// }
//
// showLineDash() {
// this.lineDashFlag = true;
//
// if (this.arrow) {
// this.arrow.visible = true;
// } else {
// this.arrow = new MySprite(this.ctx);
// this.arrow.load('assets/common/arrow.png', 1, 0);
// this.arrow.setScaleXY(0.06);
//
// }
//
// this.showLabel();
// }
//
// hideLineDash() {
//
// this.lineDashFlag = false;
//
// if (this.arrow) {
// this.arrow.visible = false;
// }
//
// this.hideLabel();
// }
//
//
//
// drawArrow() {
// if (!this.arrow) { return; }
//
// const rect = this.getBoundingBox();
// this.arrow.x = rect.x + rect.width;
// this.arrow.y = rect.y;
//
// this.arrow.update();
// }
//
// drawFrame() {
//
//
// this.ctx.save();
//
//
// const rect = this.getBoundingBox();
//
// const w = rect.width;
// const h = rect.height;
// const x = rect.x + w / 2;
// const y = rect.y + h / 2;
//
// this.ctx.setLineDash([5, 5]);
// this.ctx.lineWidth = 2;
// this.ctx.strokeStyle = '#1bfff7';
// // this.ctx.fillStyle = '#ffffff';
//
// this.ctx.beginPath();
//
// this.ctx.moveTo( x - w / 2, y - h / 2);
//
// this.ctx.lineTo(x + w / 2, y - h / 2);
//
// this.ctx.lineTo(x + w / 2, y + h / 2);
//
// this.ctx.lineTo(x - w / 2, y + h / 2);
//
// this.ctx.lineTo(x - w / 2, y - h / 2);
//
// // this.ctx.fill();
// this.ctx.stroke();
//
//
//
//
// this.ctx.restore();
//
// }
//
// draw() {
// super.draw();
//
// if (this.lineDashFlag) {
// this.drawFrame();
// this.drawArrow();
// }
// }
// }
//
//
//
// export class Label extends MySprite {
//
// text:String;
// fontSize:String = '40px';
// fontName:String = 'Verdana';
// textAlign:String = 'left';
//
//
// constructor(ctx) {
// super(ctx);
// this.init();
// }
//
// drawText() {
//
// // console.log('in drawText', this.text);
//
// if (!this.text) { return; }
//
// this.ctx.font = `${this.fontSize} ${this.fontName}`;
// this.ctx.textAlign = this.textAlign;
// this.ctx.textBaseline = 'middle';
// this.ctx.fontWeight = 900;
//
// this.ctx.lineWidth = 5;
// this.ctx.strokeStyle = '#ffffff';
// this.ctx.strokeText(this.text, 0, 0);
//
// this.ctx.fillStyle = '#000000';
// this.ctx.fillText(this.text, 0, 0);
//
//
// }
//
//
// drawSelf() {
// super.drawSelf();
// this.drawText();
// }
//
// }
//
//
//
// export function getPosByAngle(angle, len) {
//
// const radian = angle * Math.PI / 180;
// const x = Math.sin(radian) * len;
// const y = Math.cos(radian) * len;
//
// return {x, y};
//
// }
//
// export function getAngleByPos(px, py, mx, my) {
//
// // const _x = p2x - p1x;
// // const _y = p2y - p1y;
// // const tan = _y / _x;
// //
// // const radina = Math.atan(tan); // 用反三角函数求弧度
// // const angle = Math.floor(180 / (Math.PI / radina)); //
// //
// // console.log('r: ' , angle);
// // return angle;
// //
//
//
//
// const x = Math.abs(px - mx);
// const y = Math.abs(py - my);
// // const x = Math.abs(mx - px);
// // const y = Math.abs(my - py);
// const z = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
// const cos = y / z;
// const radina = Math.acos(cos); // 用反三角函数求弧度
// let angle = Math.floor(180 / (Math.PI / radina) * 100) / 100; // 将弧度转换成角度
//
// if(mx > px && my > py) {// 鼠标在第四象限
// angle = 180 - angle;
// }
//
// if(mx === px && my > py) {// 鼠标在y轴负方向上
// angle = 180;
// }
//
// if(mx > px && my === py) {// 鼠标在x轴正方向上
// angle = 90;
// }
//
// if(mx < px && my > py) {// 鼠标在第三象限
// angle = 180 + angle;
// }
//
// if(mx < px && my === py) {// 鼠标在x轴负方向
// angle = 270;
// }
//
// if(mx < px && my < py) {// 鼠标在第二象限
// angle = 360 - angle;
// }
//
// // console.log('angle: ', angle);
// return angle;
//
// }
<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">
...@@ -13,57 +16,45 @@ ...@@ -13,57 +16,45 @@
<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>
<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 nz-col nzSpan="5" nzOffset="1" class="img-box"
*ngFor="let it of hotZoneArr; let i = index" >
<div style=" height: 40px;">
<h5> item-{{i+1}}
<i style="margin-left: 20px; margin-top: 2px; float: right; cursor:pointer" (click)="deleteItem($event, i)"
nz-icon [nzTheme]="'twotone'" [nzType]="'close-circle'" [nzTwotoneColor]="'#ff0000'"></i>
</h5>
</div>
<div style="margin-top: -20px; margin-bottom: 5px">
<nz-radio-group [ngModel]="it.itemType" (ngModelChange)="radioChange($event, it)">
<label *ngIf="isHasRect" nz-radio nzValue="rect">矩形</label>
<label *ngIf="isHasPic" nz-radio nzValue="pic">图片</label>
<label *ngIf="isHasText" nz-radio nzValue="text">文本</label>
</nz-radio-group>
</div>
<div *ngIf="it.itemType == 'pic'"> <!--<div class="img-box-upload">-->
<app-upload-image-with-preview <!--<app-upload-image-with-preview-->
[picUrl]="it?.pic_url" <!--[picUrl]="it.pic_url"-->
(imageUploaded)="onItemImgUploadSuccess($event, it)"> <!--(imageUploaded)="onImgUploadSuccessByImg($event, it)">-->
</app-upload-image-with-preview> <!--</app-upload-image-with-preview>-->
</div> <!--</div>-->
<div *ngIf="it.itemType == 'text'">
<input type="text" nz-input [(ngModel)]="it.text" (blur)="saveText(it)">
</div>
<div style="width: 100%; margin-top: 5px;"> <!--<app-audio-recorder-->
<app-audio-recorder <!--[audioUrl]="it.audio_url ? it.audio_url : null "-->
[audioUrl]="it.audio_url" <!--(audioUploaded)="onAudioUploadSuccessByImg($event, it)"-->
(audioUploaded)="onItemAudioUploadSuccess($event, it)" <!--&gt;</app-audio-recorder>-->
></app-audio-recorder>
</div>
</div>
</div> </div>
<div nz-col nzSpan="5" nzOffset="1"> <div nz-col nzSpan="5" nzOffset="1">
<div class="bg-box"> <div class="bg-box">
...@@ -84,17 +75,15 @@ ...@@ -84,17 +75,15 @@
<div class="save-box"> <div class="save-box">
<button class="save-btn" nz-button nzType="primary" [nzSize]="'large'" nzShape="round" <button class="save-btn" nz-button nzType="primary" [nzSize]="'large'" nzShape="round"
(click)="saveClick()" > (click)="saveClick()">
<i nz-icon nzType="save"></i> <i nz-icon type="save"></i>
Save Save
</button> </button>
</div> </div>
</div>
<label style="opacity: 0; position: absolute; top: 0px; font-family: 'BRLNSR_1'">1</label> </div>
...@@ -87,13 +87,6 @@ h5 { ...@@ -87,13 +87,6 @@ h5 {
@font-face
{
font-family: 'BRLNSR_1';
src: url("/assets/font/BRLNSR_1.TTF") ;
}
......
import { import {Component, ElementRef, EventEmitter, HostListener, Input, OnChanges, OnDestroy, OnInit, Output, ViewChild} from '@angular/core';
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, HotZoneImg, HotZoneItem, HotZoneLabel, Label, MySprite, removeItemFromArr} from './Unit'; import {EditorItem, HotZoneItem, Label, MySprite} from './Unit';
import TWEEN from '@tweenjs/tween.js'; import TWEEN from '@tweenjs/tween.js';
import {getMinScale} from "../../play/Unit";
import {tar} from "compressing";
@Component({ @Component({
...@@ -26,85 +13,89 @@ import {tar} from "compressing"; ...@@ -26,85 +13,89 @@ import {tar} from "compressing";
export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
_bgItem = null;
@Input()
set bgItem(v) {
this._bgItem = v;
this.init();
}
get bgItem() {
return this._bgItem;
}
@Input() @Input()
imgItemArr = null; imgItemArr = null;
@Input() @Input()
hotZoneItemArr = null; hotZoneItemArr = null;
@Input() @Input()
hotZoneArr = null; hotZoneArr = null;
@Output()
save = new EventEmitter();
@ViewChild('canvas', {static: true}) canvas: ElementRef;
@ViewChild('wrap', {static: true}) wrap: ElementRef;
@Input()
isHasRect = true;
@Input()
isHasPic = true;
@Input()
isHasText = true;
@Input()
hotZoneFontObj = {
size: 50,
name: 'BRLNSR_1',
color: '#8f3758'
}
@Input()
defaultItemType = 'text';
@Input() @Output()
hotZoneImgSize = 190; save = new EventEmitter();
saveDisabled = true; @ViewChild('canvas') canvas: ElementRef;
@ViewChild('wrap') wrap: ElementRef;
// @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;
constructor() {
}
_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();
} }
...@@ -127,22 +118,13 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { ...@@ -127,22 +118,13 @@ 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);
}
onItemAudioUploadSuccess(e, item) {
item.audio_url = e.url;
}
refreshBackground(callBack = null) { refreshBackground(callBack = null) {
if (!this.bg) { if (!this.bg) {
...@@ -180,25 +162,14 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { ...@@ -180,25 +162,14 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
const item = this.getHotZoneItem(); const item = this.getHotZoneItem();
this.hotZoneArr.push(item); this.hotZoneArr.push(item);
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);
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);
} }
refreshImage(img) { refreshImage(img) {
...@@ -217,7 +188,7 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { ...@@ -217,7 +188,7 @@ 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].title = 'item-' + (i + 1); this.hotZoneArr[i].text = 'item-' + (i + 1);
} }
} }
...@@ -235,7 +206,7 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { ...@@ -235,7 +206,7 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
} }
getHotZoneItem(saveData = null) { getHotZoneItem( saveData = null) {
const itemW = 200; const itemW = 200;
...@@ -248,46 +219,18 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { ...@@ -248,46 +219,18 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
item.x = this.canvasWidth / 2; item.x = this.canvasWidth / 2;
item.y = this.canvasHeight / 2; item.y = this.canvasHeight / 2;
item.itemType = this.defaultItemType;
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.showLineDash(); item.showLineDash();
const pic = new HotZoneImg(this.ctx);
pic.visible = false;
item['pic'] = pic;
if (saveData && saveData.pic_url) {
this.loadHotZonePic(pic, saveData.pic_url);
}
pic.x = item.x;
pic.y = item.y;
this.renderArr.push(pic);
const textLabel = new HotZoneLabel(this.ctx);
textLabel.fontSize = this.hotZoneFontObj.size;
textLabel.fontName = this.hotZoneFontObj.name;
textLabel.fontColor = this.hotZoneFontObj.color;
textLabel.textAlign = 'center';
// textLabel.setOutline();
// console.log('saveData:', saveData);
item['textLabel'] = textLabel;
textLabel.setScaleXY(this.mapScale);
if (saveData && saveData.text) {
textLabel.text = saveData.text;
textLabel.refreshSize();
}
textLabel.x = item.x;
textLabel.y = item.y;
this.renderArr.push(textLabel);
return item; return item;
} }
...@@ -297,7 +240,7 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { ...@@ -297,7 +240,7 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
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) {
...@@ -323,7 +266,7 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { ...@@ -323,7 +266,7 @@ 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 {
...@@ -348,29 +291,9 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { ...@@ -348,29 +291,9 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
} }
radioChange(e, item) {
item.itemType = e;
this.refreshItem(item);
// console.log(' in radioChange e: ', e);
}
refreshItem(item) {
switch (item.itemType) {
case 'rect':
this.setRectState(item);
break;
case 'pic':
this.setPicState(item);
break;
case 'text':
this.setTextState(item);
break;
default:
}
}
init() { init() {
...@@ -444,25 +367,20 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { ...@@ -444,25 +367,20 @@ 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);
item.audio_url = data.audio_url;
item.pic_url = data.pic_url;
item.text = data.text;
item.itemType = data.itemType;
this.refreshItem(item);
console.log('item: ', item); console.log('item: ', item);
this.hotZoneArr.push(item); this.hotZoneArr.push(item);
} }
this.refreshHotZoneId(); this.refreshHotZoneId();
// this.refreshImageId(); // this.refreshImageId();
} }
initImgArr() { initImgArr() {
console.log('this.imgItemArr: ', this.imgItemArr); console.log('this.imgItemArr: ', this.imgItemArr);
...@@ -528,40 +446,34 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { ...@@ -528,40 +446,34 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
this.oldPos = {x: this.mx, y: this.my}; this.oldPos = {x: this.mx, y: this.my};
for (let i = 0; i < this.hotZoneArr.length; i++) { const arr = this.hotZoneArr;
const item = this.hotZoneArr[i]; for (let i = arr.length - 1; i >= 0 ; i--) {
let callback; const item = arr[i];
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 (this.checkClickTarget(target)) { if (item) {
callback(target); if (this.checkClickTarget(item)) {
return;
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;
}
} }
} }
// this.hideAllLineDash();
} }
mapMove(event) { mapMove(event) {
if (!this.curItem) { if (!this.curItem) { return; }
return;
}
if (this.changeSizeFlag) { if (this.changeSizeFlag) {
this.changeSize(); this.changeSize();
...@@ -581,9 +493,6 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { ...@@ -581,9 +493,6 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
} }
this.oldPos = {x: this.mx, y: this.my}; this.oldPos = {x: this.mx, y: this.my};
this.saveDisabled = true;
} }
mapUp(event) { mapUp(event) {
...@@ -594,11 +503,13 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { ...@@ -594,11 +503,13 @@ 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;
...@@ -627,7 +538,7 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { ...@@ -627,7 +538,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;
...@@ -639,10 +550,10 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { ...@@ -639,10 +550,10 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
// s = lenW / this.curItem.width; // s = lenW / this.curItem.width;
// //
// } else { // } else {
if (lenH < minLen) { if (lenH < minLen) {
lenH = minLen; lenH = minLen;
} }
s = lenH / this.curItem.height; s = lenH / this.curItem.height;
// } // }
...@@ -654,7 +565,7 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { ...@@ -654,7 +565,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;
...@@ -702,9 +613,7 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { ...@@ -702,9 +613,7 @@ 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));
...@@ -723,7 +632,6 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { ...@@ -723,7 +632,6 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
// } // }
this.updateArr(this.hotZoneArr); this.updateArr(this.hotZoneArr);
this.updatePos()
TWEEN.update(); TWEEN.update();
...@@ -738,6 +646,7 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { ...@@ -738,6 +646,7 @@ 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;
...@@ -746,11 +655,11 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { ...@@ -746,11 +655,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()) {
...@@ -856,38 +765,41 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { ...@@ -856,38 +765,41 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
if (this.bg) { if (this.bg) {
bgItem['rect'] = this.bg.getBoundingBox(); bgItem['rect'] = this.bg.getBoundingBox();
} else { } else {
bgItem['rect'] = { bgItem['rect'] = {x: 0, y: 0, width: Math.round(this.canvasWidth * 100) / 100, height: Math.round(this.canvasHeight * 100) / 100};
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 = {
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,
fontSize: this.hotZoneFontObj.size,
fontName: this.hotZoneFontObj.name,
fontColor: this.hotZoneFontObj.color,
fontScale: hotZoneArr[i].textLabel ? hotZoneArr[i].textLabel.scaleX : 1,
imgScale: hotZoneArr[i].pic ? hotZoneArr[i].pic.scaleX : 1,
mapScale: this.mapScale
}; };
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'].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'].y = Math.round( (hotZoneItem['rect'].y - bgItem['rect'].y) * 100) / 100;
hotZoneItem['rect'].width = Math.round((hotZoneItem['rect'].width) * 100) / 100; hotZoneItem['rect'].width = Math.round( (hotZoneItem['rect'].width) * 100) / 100;
hotZoneItem['rect'].height = Math.round((hotZoneItem['rect'].height) * 100) / 100; hotZoneItem['rect'].height = Math.round( (hotZoneItem['rect'].height) * 100) / 100;
hotZoneItemArr.push(hotZoneItem); hotZoneItemArr.push(hotZoneItem);
} }
...@@ -896,91 +808,4 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { ...@@ -896,91 +808,4 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
this.save.emit({bgItem, hotZoneItemArr}); this.save.emit({bgItem, hotZoneItemArr});
} }
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;
}
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 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)) {
this.curItem = item;
}
}
private clickedHotZoneText(item: any) {
if (this.checkClickTarget(item)) {
this.curItem = item;
}
}
saveText(item) {
item.textLabel.text = item.text;
}
private loadHotZonePic(pic: HotZoneImg, url) {
const baseLen = this.hotZoneImgSize * this.mapScale;
pic.load(url).then(() => {
const s = getMinScale(pic, baseLen);
pic.setScaleXY(s);
});
}
} }
<div class="title-config"> <div class="title-config">
<div class="title-wrap"> <div class="title-wrap">
<div class="row" style="margin: 5px;"> <div class="row" style="margin: 5px;">
<div class="p-content" style="width:100%"> <div class="p-content" style="width:100%">
<div class="p-tool-box d-flex" style="background: #fff;"> <div class="p-tool-box d-flex" style="background: #fff;">
<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"> >
<span [ngStyle]="{'font-family': font}" >{{font}}</span> <nz-option [nzValue]="font" [nzLabel]="font" *ngFor="let font of fontFamilyList"></nz-option>
</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()"
nzPlaceHolder="Font Size"> nzPlaceHolder="Font Size">
<nz-option [nzValue]="i" [nzLabel]="'Size - ' + i" *ngFor="let i of fontSizeRange"></nz-option> <nz-option [nzValue]="i" [nzLabel]="'Size - ' + i" *ngFor="let i of fontSizeRange"></nz-option>
</nz-select> </nz-select>
<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"
nz-popover [(nzVisible)]="isShowFontColorPane" nzTrigger="click" nz-popover [(nzVisible)]="isShowFontColorPane" nzTrigger="click"
[nzContent]="colorPane"> [nzContent]="colorPane">
<i nz-icon type="down" theme="outline"></i> <i nz-icon type="down" theme="outline"></i>
</div> </div>
</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"> <div class="position-relative" (click)="onChangeStrikethrough()">
<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 id="titleContentEgret" frameborder="0" style="overflow: hidden;width: 100%; height:48px; margin: 0; padding: 0;"></iframe> <iframe #titleEl frameborder="0" style="overflow: hidden;width: 100%; height:48px; margin: 0; padding: 0;"></iframe>
</div> </div>
</div> </div>
...@@ -83,11 +76,37 @@ ...@@ -83,11 +76,37 @@
<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.css'; @import '../../style/common_mixin';
.title-config { .title-config {
.letter-wrap{ .letter-wrap{
...@@ -11,73 +11,39 @@ ...@@ -11,73 +11,39 @@
.type-row{ .type-row{
margin: 0;padding-top: 1rem; margin: 0;padding-top: 1rem;
} }
.icon-item{
margin-right: 16px;
float: left;
width: 45px;
height: 75px;
display: flex;
justify-content: center;
align-items: center;
position: relative;
.icon-badge{
position: absolute;
top: 0;
right: 0;
}
.img-box{
top: 0;
position: absolute;
width: 45px;
height: 50px;
display: flex;
justify-content: center;
align-items: center;
img{
max-width: 100%;
}
}
label{
position: absolute;
bottom: 0;
}
}
}
}
@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") ;
}
@mixin tool-btn { @mixin tool-btn {
border: 1px solid #ddd; border: 1px solid #ddd;
display: flex; display: flex;
...@@ -88,37 +54,16 @@ ...@@ -88,37 +54,16 @@
border-radius: 6px; border-radius: 6px;
color: #555; color: #555;
} }
.d-flex{
display: flex;
}
.position-relative {
position: relative;
}
.flex-fill {
-webkit-box-flex: 1;
flex: 1 1 auto;
justify-content: center;
display: flex;
}
.i-dropdown-menu{ .p-title-box {
width: 15px; .p-title {
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;
} }
.p-title-box input { input {
width: 300px; width: 300px;
margin-left: 10px; margin-left: 10px;
} }
}
.p-content { .p-content {
border: 1px solid #ddd; border: 1px solid #ddd;
...@@ -140,110 +85,115 @@ ...@@ -140,110 +85,115 @@
align-items: center; align-items: center;
border-bottom: 1px solid #ddd; border-bottom: 1px solid #ddd;
// save
.i-tool-save {
@include tool-btn();
color: white;
}
.i-tool-save:disabled {
color: #555;
}
// font-size
.i-tool-font-size {
@include tool-btn();
width: 37px;
} & > span {
// save
.i-tool-save {
//@include tool-btn();
color: white;
}
.i-tool-save:disabled {
color: #555;
}
// font-size
.i-tool-font-size {
//@include tool-btn();
width: 37px;
}
.i-tool-font-size:hover {
color: black;
border-color: #bbb;
}
// font-color
.i-tool-font-color, .i-tool-font-btn {
border: 1px solid #ddd;
//padding: 3px 7px;
border-radius: 6px;
width: 45px;
height: 31px;
background-color: white;
color: #555;
::ng-deep > span {
display: flex;
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
padding: 3px 7px;
}
.i-left {
.fa-font,.fa-bold,.fa-italic,.fa-strikethrough, .fa-underline {
font-size: 10px;
position: absolute; position: absolute;
color: #555; top: -5px;
left: 8px; right: 5px;
top: 7px;
} }
.i-color { }
width: 68%; .i-tool-font-size:hover {
height: 5px; color: black;
background-color: black; border-color: #bbb;
}
// font-color
.i-tool-font-color, .i-tool-font-btn {
border: 1px solid #ddd;
//padding: 3px 7px;
border-radius: 6px;
width: 45px;
height: 31px;
background-color: white;
color: #555;
::ng-deep > span {
display: flex;
position: absolute; position: absolute;
top: 21px; left: 0;
left: 5px; right: 0;
top: 0;
bottom: 0;
padding: 3px 7px;
} }
} .i-left {
.i-dropdown-menu { .fa-font,.fa-bold,.fa-italic,.fa-strikethrough, .fa-underline {
width: 15px; font-size: 10px;
font-size: 10px; position: absolute;
border-left: 1px solid #ddd; color: #555;
display: flex; left: 8px;
align-items: center; top: 7px;
.anticon-down { }
transform: scale(0.6); .i-color {
width: 68%;
height: 5px;
background-color: black;
position: absolute;
top: 21px;
left: 5px;
}
}
.i-dropdown-menu {
width: 15px;
font-size: 10px;
border-left: 1px solid #ddd;
display: flex;
align-items: center;
.anticon-down {
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;
justify-content: center;
align-items: center;
cursor: pointer;
}
// bg-color
.i-tool-bg-color {
@include tool-btn();
padding: 0 9px;
::ng-deep > span {
display: flex; display: flex;
justify-content: center;
align-items: center; align-items: center;
cursor: pointer;
} }
// bg-color
.i-tool-bg-color {
@include tool-btn();
padding: 0 9px;
::ng-deep > span {
display: flex;
align-items: center;
}
.i-color { .i-color {
display: block; display: block;
width: 16px; width: 16px;
height: 16px; height: 16px;
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;
...@@ -253,7 +203,9 @@ ...@@ -253,7 +203,9 @@
overflow: hidden; overflow: hidden;
} }
.p-sentence {
@include k-no-select();
}
.p-animation-index-box { .p-animation-index-box {
.i-animation-index { .i-animation-index {
...@@ -326,6 +278,7 @@ ...@@ -326,6 +278,7 @@
::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 {
...@@ -356,6 +309,7 @@ ...@@ -356,6 +309,7 @@
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,
...@@ -11,82 +10,6 @@ import { ...@@ -11,82 +10,6 @@ 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',
...@@ -96,45 +19,22 @@ export class LessonTitleConfigComponent implements OnInit, OnChanges, OnDestroy, ...@@ -96,45 +19,22 @@ export class LessonTitleConfigComponent implements OnInit, OnChanges, OnDestroy,
fontFamilyList = [ fontFamilyList = [
'Arial', 'Arial',
'BRLNSB', 'ARBLI'
'BRLNSDB',
'BRLNSR',
'GOTHIC',
'GOTHICB',
// "GOTHICBI",
// "GOTHICI",
'MMTextBook',
// "MMTextBook-Bold",
// "MMTextBook-Italic",
// "MMTextBook-BoldItalic",
]; ];
colorList = [ colorList = [
'#000000', '#111111',
'#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 = [ fontSizeRange: number[];
// {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 = '';
...@@ -145,17 +45,25 @@ export class LessonTitleConfigComponent implements OnInit, OnChanges, OnDestroy, ...@@ -145,17 +45,25 @@ export class LessonTitleConfigComponent implements OnInit, OnChanges, OnDestroy,
loopCnt = 0; loopCnt = 0;
maxLoops = 20; maxLoops = 20;
groupIconsCount = {
@ViewChild('titleEl', {static: true}) titleEl: ElementRef; a: Array.from(Array(11).keys()),
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();
...@@ -176,12 +84,16 @@ export class LessonTitleConfigComponent implements OnInit, OnChanges, OnDestroy, ...@@ -176,12 +84,16 @@ 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;
...@@ -190,23 +102,33 @@ export class LessonTitleConfigComponent implements OnInit, OnChanges, OnDestroy, ...@@ -190,23 +102,33 @@ 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 = editorTpl.replace('{{content}}', this.titleObj.content) ; this.editorContent = `<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"/>
</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;
} }
...@@ -237,7 +159,30 @@ export class LessonTitleConfigComponent implements OnInit, OnChanges, OnDestroy, ...@@ -237,7 +159,30 @@ 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 {
...@@ -250,9 +195,9 @@ export class LessonTitleConfigComponent implements OnInit, OnChanges, OnDestroy, ...@@ -250,9 +195,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;
} }
...@@ -269,13 +214,10 @@ export class LessonTitleConfigComponent implements OnInit, OnChanges, OnDestroy, ...@@ -269,13 +214,10 @@ 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();
const result = this.titleEW.document.execCommand(command, false, option); this.titleEW.document.execCommand(command, false, option);
console.log(result);
this.loopCnt = 0; this.loopCnt = 0;
return false; return false;
...@@ -287,7 +229,7 @@ export class LessonTitleConfigComponent implements OnInit, OnChanges, OnDestroy, ...@@ -287,7 +229,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.");
} }
} }
} }
...@@ -300,7 +242,7 @@ export class LessonTitleConfigComponent implements OnInit, OnChanges, OnDestroy, ...@@ -300,7 +242,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) {
...@@ -330,10 +272,9 @@ export class LessonTitleConfigComponent implements OnInit, OnChanges, OnDestroy, ...@@ -330,10 +272,9 @@ export class LessonTitleConfigComponent implements OnInit, OnChanges, OnDestroy,
this.titleUpdated.emit(this.titleObj); this.titleUpdated.emit(this.titleObj);
} }
shouldSave = () => { shouldSave = () => {
console.log('title shouldSave', this.titleObj); console.log('title shouldSave');
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.css'; @import '../../style/common_mixin';
.cmp-player-content-wrapper{ .cmp-player-content-wrapper{
max-height: 100%; max-height: 100%;
......
import { import {
AfterViewInit, AfterViewInit,
Component, Component,
ElementRef, ElementRef,
Input, Input,
OnChanges, OnChanges,
OnDestroy, OnDestroy,
OnInit, OnInit,
ViewChild ViewChild
} from '@angular/core'; } from '@angular/core';
@Component({ @Component({
...@@ -18,21 +18,21 @@ import { ...@@ -18,21 +18,21 @@ import {
export class PlayerContentWrapperComponent implements OnInit, OnChanges, OnDestroy, AfterViewInit { export class PlayerContentWrapperComponent implements OnInit, OnChanges, OnDestroy, AfterViewInit {
@ViewChild('wrapperEl', {static: true }) wrapperEl: ElementRef; @ViewChild('wrapperEl') wrapperEl: ElementRef;
// // aspect ratio? // // aspect ratio?
@Input() ratio; @Input() ratio;
_w: string; _w: string;
_h: string; _h: string;
constructor() { constructor() {
if (window.innerHeight < window.innerWidth) { if (window.innerHeight < window.innerWidth) {
this._h = '100%'; this._h = '100%';
this._w = 'auto'; this._w = 'auto';
} else { } else {
this._w = '100%'; this._w = '100%';
this._h = 'auto'; this._h = 'auto';
} }
} }
ngOnInit() { ngOnInit() {
if (!this.ratio) { if (!this.ratio) {
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
<!--[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 nzType="cloud-upload" nzTheme="outline" [style.font-size]="iconSize + 'em'"></i> <i nz-icon type="cloud-upload" theme="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 +19,7 @@ ...@@ -19,7 +19,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-icon icon="cloud-upload-alt"></fa-icon> <fa name="cloud-upload"></fa>
Uploading... Uploading...
</div> </div>
</div> </div>
...@@ -32,6 +32,6 @@ ...@@ -32,6 +32,6 @@
nz-popconfirm nzTitle="Are you sure ?" nz-popconfirm nzTitle="Are you sure ?"
(nzOnConfirm)="onDelete()" (nzOnConfirm)="onDelete()"
> >
<i nz-icon nzType="close" nzTheme="outline"></i> <i nz-icon type="close" theme="outline"></i>
</div> </div>
</div> </div>
@import '../../style/common_mixin.css'; @import '../../style/common_mixin';
.p-image-uploader { .p-image-uploader {
position: relative; position: relative;
...@@ -52,15 +52,10 @@ ...@@ -52,15 +52,10 @@
.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,19 +29,10 @@ export class UploadImageWithPreviewComponent implements OnDestroy, OnChanges { ...@@ -29,19 +29,10 @@ export class UploadImageWithPreviewComponent implements OnDestroy, OnChanges {
@Input() @Input()
disableUpload = false; disableUpload = false;
uploadUrl; uploadUrl = (<any> window).courseware.uploadUrl();
uploadData; uploadData = (<any> window).courseware.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) {
......
<div class="p-video-box">
<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"-->
...@@ -16,7 +16,8 @@ ...@@ -16,7 +16,8 @@
<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 nzType="plus" nzTheme="outline"></i> <i nz-icon type="plus" theme="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,9 +56,9 @@ ...@@ -55,9 +56,9 @@
</div> </div>
<div class="p-box d-flex align-items-center p-video-uploader"> <div class="p-box d-flex align-items-center p-video-uploader" style="top: 20px;">
<div class="p-upload-icon" *ngIf="!showUploadBtn && !videoUrl && !uploading"> <div class="p-upload-icon" *ngIf="!showUploadBtn && !videoUrl && !uploading">
<i nz-icon nzType="upload" nzTheme="outline"></i> <i nz-icon type="upload" theme="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">
...@@ -69,26 +70,26 @@ ...@@ -69,26 +70,26 @@
[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-icon icon="cloud-upload-alt"></fa-icon> <fa name="cloud-upload"></fa>
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-icon icon="cloud-upload-alt"></fa-icon> <fa name="cloud-upload"></fa>
<i nz-icon nzType="loading" nzTheme="outline"></i>Checking... <i nz-icon type="loading" theme="outline"></i>Checking...
</div> </div>
</div> </div>
<div class="p-preview" *ngIf="!uploading && videoUrl " > <div class="p-preview" *ngIf="!showUploadBtn && !uploading && videoUrl " >
<!--<video crossorigin="anonymous" [src]="videoUrl" controls #videoNode></video>--> <!--<video crossorigin="anonymous" [src]="videoUrl" controls #videoNode></video>-->
<video [src]="safeVideoUrl(videoUrl)" controls #videoNode></video> <video [src]="safeVideoUrl(videoUrl)" controls #videoNode (loadedmetadata)="videoLoadedMetaData()"></video>
</div> </div>
</div> </div>
<div [style.display]="!checkVideoExists?'none':''"> <div [style.display]="!checkVideoExists?'none':''">
<span><i nz-icon nzType="loading" nzTheme="outline"></i> checking file to upload</span> <span><i nz-icon type="loading" theme="outline"></i> checking file to upload</span>
</div>
</div> </div>
@import '../../style/common_mixin.css'; @import '../../style/common_mixin';
/*.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;
...@@ -33,56 +17,50 @@ ...@@ -33,56 +17,50 @@
background-color: #fafafa; background-color: #fafafa;
text-align: center; text-align: center;
color: #aaa; 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");
video{
max-height: 100%;
max-width: 100%;
}
}
} }
} }
.p-upload-icon {
text-align: center;
margin: auto;
}
.p-upload-icon .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-bar .p-progress-bg {
background-color: #1890ff;
border-radius: 1rem;
height: 100%;
}
.p-progress-bar .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");
}
.p-preview video{
max-height: 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, UploadChangeParam, UploadFile, UploadFileStatus} from 'ng-zorro-antd'; import {NzMessageService, UploadFile} 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', {static: true }) @ViewChild('videoNode')
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; uploadUrl = (<any> window).courseware.uploadUrl();
uploadData; uploadData = (<any> window).courseware.uploadData();
constructor(private nzMessageService: NzMessageService, constructor(private nzMessageService: NzMessageService,
private sanitization: DomSanitizer private sanitization: DomSanitizer
...@@ -58,16 +58,6 @@ export class UploadVideoComponent implements OnChanges, OnDestroy { ...@@ -58,16 +58,6 @@ 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) {
...@@ -81,7 +71,7 @@ export class UploadVideoComponent implements OnChanges, OnDestroy { ...@@ -81,7 +71,7 @@ export class UploadVideoComponent implements OnChanges, OnDestroy {
} }
safeVideoUrl(url) { safeVideoUrl(url) {
console.log(url); console.log(url)
return this.sanitization.bypassSecurityTrustResourceUrl(url); // `${url}`; return this.sanitization.bypassSecurityTrustResourceUrl(url); // `${url}`;
} }
videoLoadedMetaData() { videoLoadedMetaData() {
...@@ -89,7 +79,7 @@ export class UploadVideoComponent implements OnChanges, OnDestroy { ...@@ -89,7 +79,7 @@ export class UploadVideoComponent implements OnChanges, OnDestroy {
} }
handleChange(info: UploadChangeParam/* { type: string, file: UploadFile, event: any }*/): void { handleChange(info: { type: string, file: UploadFile, event: any }): void {
console.log('info:' , info); console.log('info:' , info);
...@@ -119,7 +109,7 @@ export class UploadVideoComponent implements OnChanges, OnDestroy { ...@@ -119,7 +109,7 @@ export class UploadVideoComponent implements OnChanges, OnDestroy {
break; break;
case 'progress': case 'progress':
this.progress = info.event.percent; this.progress = parseInt(info.event.percent, 10);
this.doProgress(this.progress); this.doProgress(this.progress);
break; break;
} }
...@@ -162,9 +152,9 @@ export class UploadVideoComponent implements OnChanges, OnDestroy { ...@@ -162,9 +152,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();
......
@import '../style/common_mixin.css';
.model-content {
width: 100%;
height: 100%;
}
<div class="model-content"> <div class="model-content">
<button style="margin: 4vw; display: flex; align-items: center" nz-button nzType="primary" nzGhost (click)="guideBtnClick(true)">
<i nz-icon type="play-circle"></i>
1分钟简易教程
</button>
<div style="position: absolute; left: 200px; top: 100px; width: 800px;"> <div nz-row >
<input type="text" nz-input [(ngModel)]="item.text" (blur)="save()">
<app-upload-image-with-preview </div>
[picUrl]="item.pic_url"
(imageUploaded)="onImageUploadSuccess($event, 'pic_url')" <div *ngFor="let it of picArr; let i = index" style="padding: 0.5vw; width: 50%;">
></app-upload-image-with-preview>
<div style="display: flex; align-items: center;">
<div style="width: 20%; padding-left: 20px">
<h5 style="padding-left: 5px; margin: auto"> 牛-{{i+1}}: </h5>
<div style="display: flex; justify-items: center; align-items: center; height: 40px;">
<!--<app-audio-recorder-->
<!--[audioUrl]="it.audio_url"-->
<!--(audioUploaded)="onAudioUploadSuccessByItem($event, it)">-->
<!--</app-audio-recorder>-->
<button style="margin-left: 10px;" nz-button nzType="danger" (click)="deleteItem(it)">
<span>删除</span>
</button>
</div>
</div>
<div class="item-box" style="width: 100%">
<div style="display: flex; align-items: center">
<span style="padding-right: 10px"> 类型:</span>
<nz-radio-group [(ngModel)]="it.optionType" (ngModelChange)="save()">
<label nz-radio nzValue="A">文本</label>
<label nz-radio nzValue="B">图片</label>
</nz-radio-group>
</div>
<div *ngIf="it.optionType == 'A'" style="width: 60%;">
<input style="width: 100%; margin-bottom: 0.5vw" type="text" nz-input placeholder="点击输入文本内容" [(ngModel)]="it.text" (blur)="saveItem()">
</div>
<div *ngIf="it.optionType == 'B'" style="width: 90%; margin: auto">
<app-upload-image-with-preview
[picUrl]="it['pic_url']"
(imageUploaded)="onImageUploadSuccessByItem($event, it)"
></app-upload-image-with-preview>
</div>
<app-audio-recorder
style="margin-top: 0.5vw"
[audioUrl]="it['audio_url']"
(audioUploaded)="onAudioUploadSuccessByItem($event, it)">
</app-audio-recorder>
</div>
</div>
</div>
<nz-divider></nz-divider>
<p>
</p>
<h3 style="padding-top: 30px;">
选项:
</h3>
<div nz-row nzType="flex" nzJustify="start" nzAlign="middle">
<div *ngFor="let it of optionArr; let i = index" style="padding: 0.5vw; padding-top: 2vw" nz-col nzSpan="6" class="item-box border">
<!--<nz-checkbox-group [(ngModel)]="it.picArr" (ngModelChange)="log(it.picArr)"></nz-checkbox-group>-->
<!--<div nz-col nzSpan="6" class="item-box" >-->
<!--<nz-checkbox-group [(ngModel)]="checkOptionsOne" (ngModelChange)="log(checkOptionsOne)"></nz-checkbox-group>-->
<h5> 草-{{i+1}}</h5>
<span style="width: 90%;"> 所属类别: </span>
<nz-radio-group style="width: 90%;" [(ngModel)]="it.type" (ngModelChange)="log(it.type)">
<!--<div nz-row nzType="flex" nzJustify="space-around" nzAlign="middle">-->
<div style="margin: auto" nz-row nzType="flex" nzJustify="start" nzAlign="middle">
<div *ngFor="let pic of it.picArr; let j = index" nz-col nzSpan="6">
<label style="" nz-radio nzValue={{j}}> 牛-{{j+1}} </label>
</div>
</div>
</nz-radio-group>
<span style="width: 90%; padding-top: 20px"> 选项类型: </span>
<div style="display: flex; align-items: center; width: 90%; padding-bottom: 10px">
<nz-radio-group [(ngModel)]="it.optionType" (ngModelChange)="save()">
<label nz-radio nzValue="A" style="width: 80px">文本</label>
<label nz-radio nzValue="B" style="width: 80px;">图片</label>
</nz-radio-group>
</div>
<div *ngIf="it.optionType == 'A'" style="width: 100%; height: 13vw;">
<input style="width: 80%; margin-left: 10%;" type="text" nz-input placeholder="" [(ngModel)]="it.text" (blur)="saveItem()">
</div>
<div *ngIf="it.optionType == 'B'" style="width: 90%; height: 13vw; margin: auto">
<app-upload-image-with-preview
style="width: 100%"
[picUrl]="it['pic_url']"
(imageUploaded)="onImageUploadSuccessByItem($event, it)"
></app-upload-image-with-preview>
</div>
<div style="display: flex; align-items: center; justify-items: center;">
<app-audio-recorder
[audioUrl]="it['audio_url']"
(audioUploaded)="onAudioUploadSuccessByItem($event, it)">
</app-audio-recorder>
<!--<div style="display: flex; align-items: center; justify-content: center; padding-bottom: 5px">-->
<button style="margin-left: 10px;" nz-button nzType="danger" (click)="deleteOption(it)">
<span>删除</span>
<!--<i nz-icon type="close"></i>-->
</button>
<!--</div>-->
</div>
<!--</div>-->
</div>
</div>
<nz-divider></nz-divider>
<div nz-row>
<div class="add-btn-box" nz-col nzSpan="8">
<!--<div style="width: 100%; height: 100%;">-->
<button style=" margin: auto; width: 60%; height: 60%;" nz-button nzType="dashed" class="add-btn"
(click)="addPic()">
<i nz-icon nzType="plus-circle" nzTheme="outline"></i>
类别(牛)
</button>
<!--</div>-->
</div>
<div class="add-btn-box" nz-col nzSpan="8">
<!--<div style="width: 100%; height: 100%;">-->
<button style=" margin: auto; width: 60%; height: 60%;" nz-button nzType="dashed" class="add-btn"
(click)="addOption()">
<i nz-icon nzType="plus-circle" nzTheme="outline"></i>
选项(草)
</button>
<!--</div>-->
</div>
</div>
<!--<div style="padding-bottom: 30px;">-->
<!--<h5> title-sound: </h5>-->
<!--<app-audio-recorder-->
<!--[audioUrl]="item.contentObj.title_audio_url"-->
<!--(audioUploaded)="onAudioUploadSuccessByItem($event, item.contentObj, 'title')">-->
<!--</app-audio-recorder>-->
<!--</div>-->
<!--<div style="padding-bottom: 30px;">-->
<!--<h5> bg-sound: </h5>-->
<!--<app-audio-recorder-->
<!--[audioUrl]="item.contentObj.bg_audio_url"-->
<!--(audioUploaded)="onAudioUploadSuccessByItem($event, item.contentObj, 'bg')">-->
<!--</app-audio-recorder>-->
<!--</div>-->
<!--<span style="margin-bottom: 20px"> 10 : 23 </span>-->
<!--<div *ngFor="let it of picArr; let i = index">-->
<!--<span> pic-{{i + 1}}: </span>-->
<!--<div style="display: flex; align-items: center; padding-bottom: 20px">-->
<!--<div style="width: 40%; padding-right: 20px">-->
<!--<app-upload-image-with-preview-->
<!--[picUrl]="it.pic_url"-->
<!--(imageUploaded)="onImageUploadSuccessByItem($event, it)"-->
<!--&gt;</app-upload-image-with-preview>-->
<!--</div>-->
<!--<div class="pic-sound-box">-->
<!--<div nz-row style="width: 50%; padding-bottom: 20px;">-->
<!--<div *ngFor="let it2 of it.soundArr; let i2 = index" nz-col nzSpan="8">-->
<!--<label nz-checkbox nzValue="{{'answer_' + (i2 + 1)}}" [(ngModel)]="it2.answer" (ngModelChange)="clickCheckBox()" >{{i2 + 1}}</label>-->
<!--</div>-->
<!--</div>-->
<!--<div *ngFor="let it2 of it.soundArr; let i2 = index" style="display: flex; align-items: center; padding-bottom: 5px">-->
<!--<span style="padding-right: 10px">sound-{{i2 + 1}}:</span>-->
<!--<app-audio-recorder-->
<!--[audioUrl]="it2.audio_url"-->
<!--(audioUploaded)="onAudioUploadSuccessByItem($event, it2)">-->
<!--</app-audio-recorder>-->
<!--</div>-->
<!--</div>-->
<!--</div>-->
<!--</div>-->
<!--<div style="margin: auto; width: 95%;" nz-row nzType="flex" nzJustify="start" nzAlign="middle">-->
<!--<div *ngFor="let it of picArr; let i = index"-->
<!--nz-col nzSpan="8" >-->
<!--<div class="item-box">-->
<!--<h5> id-{{i+1}} </h5>-->
<!--<div style="display: flex; align-items: center; justify-content: center; padding-bottom: 5px">-->
<!--<input type="text" nz-input placeholder="" [(ngModel)]="it.text" (blur)="saveItem()">-->
<!--<button style="margin-left: 10px;" nz-button nzType="danger" (click)="deleteItem(it)">-->
<!--<i nz-icon type="close"></i>-->
<!--</button>-->
<!--</div>-->
<!--<app-upload-image-with-preview-->
<!--style="width: 100%"-->
<!--[picUrl]="it.pic_url"-->
<!--(imageUploaded)="onImageUploadSuccessByItem($event, it)"-->
<!--&gt;</app-upload-image-with-preview>-->
<!--<div style="display: flex; align-items: center; justify-content: center">-->
<!--<span style="width: 80px;">-->
<!--question:-->
<!--</span>-->
<!--<app-audio-recorder-->
<!--[audioUrl]="it['q_audio_url']"-->
<!--(audioUploaded)="onAudioUploadSuccessByItem($event, it, 'q')">-->
<!--</app-audio-recorder>-->
<!--</div>-->
<!--<div style="display: flex; align-items: center; justify-content: center">-->
<!--<span style="width: 80px;">-->
<!--answer:-->
<!--</span>-->
<!--<app-audio-recorder-->
<!--[audioUrl]="it['a_audio_url']"-->
<!--(audioUploaded)="onAudioUploadSuccessByItem($event, it, 'a')">-->
<!--</app-audio-recorder>-->
<!--</div>-->
<!--<nz-radio-group [(ngModel)]="it.radioValue" >-->
<!--<label nz-radio nzValue="A" (click)="radioClick(it, 'A')"> <i nz-icon nzType="check" nzTheme="outline"></i> </label>-->
<!--<label nz-radio nzValue="B" (click)="radioClick(it, 'B')"> <i nz-icon nzType="close" nzTheme="outline"></i> </label>-->
<!--</nz-radio-group>-->
<!--</div>-->
<!--</div>-->
</div>
<div *ngIf="showGuideAudio" style="position: absolute; left: 0; top: 0; width: 100%; height: 100%; display: flex; align-items: center; justify-items: center; background: rgba(0,0,0,.7)" (click)="guideBtnClick(false)">
<app-audio-recorder <div style="margin: auto;">
[audioUrl]="item.audio_url" <video style="width: 60vw; height: auto" src="assets/guide/guide.mp4" controls="controls" type="video/mp4">
(audioUploaded)="onAudioUploadSuccess($event, 'audio_url')" 您的浏览器不支持 audio 标签。
></app-audio-recorder> </video>
<app-custom-hot-zone></app-custom-hot-zone>
<app-upload-video></app-upload-video>
<app-lesson-title-config></app-lesson-title-config>
</div> </div>
</div> </div>
\ No newline at end of file
@import '../style/common_mixin';
.model-content {
width: 100%;
height: 100%;
.item-box{
//margin: auto;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
padding: 10px;
padding-bottom: 2vw;
padding-top: 3vw;
}
.pic-sound-box {
width: 50%;
display: flex;
//align-items: center;
flex-direction: column
}
.add-btn-box {
display: flex;
align-items: center;
justify-content: center;
//width: 180px;
height: 15vw;
//background: #FFDC00;
padding: 10px;
padding-top: 1vw;
}
}
.border {
border-radius: 20px;
border-style: dashed;
}
import {Component, EventEmitter, Input, OnDestroy, OnChanges, OnInit, Output, ApplicationRef, ChangeDetectorRef} from '@angular/core'; import {
Component,
EventEmitter,
Input,
OnDestroy,
OnChanges,
OnInit,
Output,
ApplicationRef,
ChangeDetectorRef
} from '@angular/core';
@Component({ @Component({
selector: 'app-form', selector: 'app-form',
templateUrl: './form.component.html', templateUrl: './form.component.html',
styleUrls: ['./form.component.css'] styleUrls: ['./form.component.scss']
}) })
export class FormComponent implements OnInit, OnChanges, OnDestroy { export class FormComponent implements OnInit, OnChanges, OnDestroy {
// 储存数据用 picArr = [];
saveKey = "test_0011"; optionArr = [];
// 储存对象
item;
_item: any;
constructor(private appRef: ApplicationRef,private changeDetectorRef: ChangeDetectorRef) {
KEY = 'hw_005';
answerType = 'A';
showGuideAudio;
refreshTimeId;
refreshLabel = 0;
// @Input()
set item(item) {
this._item = item;
// this.init();
}
get item() {
return this._item;
}
@Output()
update = new EventEmitter();
constructor(private appRef: ApplicationRef,
public changeDetectorRef: ChangeDetectorRef) {
} }
...@@ -23,75 +60,307 @@ export class FormComponent implements OnInit, OnChanges, OnDestroy { ...@@ -23,75 +60,307 @@ export class FormComponent implements OnInit, OnChanges, OnDestroy {
ngOnInit() { ngOnInit() {
this.item = {}; this.item = {};
this.item.contentObj = {};
// 获取存储的数据 const getData = (<any> window).courseware.getData;
(<any> window).courseware.getData((data) => { getData((data) => {
if (data) { if (data) {
this.item = data; this.item = data;
} else {
this.item = {};
}
if ( !this.item.contentObj ) {
this.item.contentObj = {};
} }
console.log('~data:', data);
this.init(); this.init();
this.changeDetectorRef.markForCheck(); this.changeDetectorRef.markForCheck();
this.changeDetectorRef.detectChanges(); this.changeDetectorRef.detectChanges();
this.refresh(); this.refresh();
}, this.saveKey); }, this.KEY);
// this.initData();
} }
ngOnChanges() { ngOnChanges() {
} }
ngOnDestroy() { ngOnDestroy() {
}
clearTimeout( this.refreshTimeId);
}
init() { init() {
} if (this.item.contentObj.picArr) {
this.picArr = this.item.contentObj.picArr;
} else {
this.picArr = this.getDefaultPicArr();
this.item.contentObj.picArr = this.picArr;
}
if (!this.item.contentObj.optionArr) {
this.item.contentObj.optionArr = [];
}
/** this.optionArr = this.item.contentObj.optionArr;
* 储存图片数据
* @param e
*/
onImageUploadSuccess(e, key) { let tmpFlag = false;
for (let i = 0; i < this.picArr.length; i++) {
const data = this.picArr[i];
if (!data.optionType) {
tmpFlag = true;
}
if (!data.optionType) {
if (data.pic_url) {
data.optionType = 'B';
} else {
data.optionType = 'A';
}
}
this.item[key] = e.url; }
for (let i = 0; i < this.optionArr.length; i++) {
const data = this.optionArr[i];
if (!data.optionType) {
tmpFlag = true;
}
if (!data.optionType) {
if (data.pic_url) {
data.optionType = 'B';
} else {
data.optionType = 'A';
}
}
}
if (tmpFlag) {
this.save(); this.save();
}
console.log('item:' , this.item);
// this.startRefresh();
// this.picArr = this.getDefaultPicArr();
// this.item.contentObj.picArr = this.picArr;
// console.log('this.item:;', this.picArr);
}
startRefresh() {
this.refreshTimeId = setTimeout(() => {
this.refreshLabel ++;
this.startRefresh();
this.refresh();
}, 1000);
}
getDefaultPicArr() {
const arr = [];
// for (let i = 0; i < 4; i ++) {
// const data = {};
// data['pic_url'] = '';
//
// const soundArr = [];
// for (let i = 0; i < 3; i++) {
// const tmpData = {};
// tmpData['answer'] = false;
// tmpData['audio_url'] = '';
// soundArr.push(tmpData);
// }
// data['soundArr'] = soundArr;
//
// arr.push(data);
// }
return arr;
}
initData() {
}
deleteItem(data) {
const index = this.picArr.indexOf(data);
if (index !== -1) {
this.picArr.splice(index, 1);
}
// this.update.emit(this.item);
this.refreshOptionsPicArr();
this.save();
} }
/** deleteOption(data) {
* 储存音频数据 const index = this.optionArr.indexOf(data);
* @param e if (index !== -1) {
*/ this.optionArr.splice(index, 1);
onAudioUploadSuccess(e, key) { }
this.item[key] = e.url;
this.save(); this.save();
} }
refreshOptionsPicArr() {
for (let i = 0; i < this.optionArr.length; i++) {
const option = this.optionArr[i];
option.picArr = this.getOptionPicArr();
}
}
onImageUploadSuccessByItem(e, item, id = null) {
if (id != null) {
item[id + '_pic_url'] = e.url;
} else {
item.pic_url = e.url;
}
this.save();
// this.update.emit(this.item);
// console.log('this.item: ', this.item);
}
onAudioUploadSuccessByItem(e, item, id = null) {
if (id != null) {
item[id + '_audio_url'] = e.url;
} else {
item.audio_url = e.url;
}
// this.update.emit(this.item);
this.save();
}
addPic() {
const data = {
text: '',
pic_url: '',
audio_url: '',
optionType: 'A',
// text: '',
// radioValue: 'A'
};
this.picArr.push(data);
this.refreshOptionsPicArr();
this.saveItem();
}
addOption() {
const data = {
text: '',
pic_url: '',
audio_url: '',
type: '0',
optionType: 'A',
};
data['picArr'] = this.getOptionPicArr();
this.optionArr.push(data);
this.saveItem();
}
getOptionPicArr() {
const arr = [];
for (let i = 0; i < this.picArr.length; i++) {
const data = {};
data['label'] = '类别-' + (i + 1);
data['value'] = i;
arr.push(data);
}
return arr;
}
radioClick(it, radioValue) {
it.radioValue = radioValue;
this.saveItem();
}
clickCheckBox() {
console.log(' in clickCheckBox');
this.saveItem();
}
saveItem() {
console.log(' in saveItem');
// this.update.emit(this.item);
this.save();
}
log(a) {
console.log('a:', a);
this.save();
}
/**
* 储存数据
*/
save() { save() {
(<any> window).courseware.setData(this.item, null, this.saveKey); (<any> window).courseware.setData(this.item, null, this.KEY);
this.refresh(); this.refresh();
} }
/**
* 刷新 渲染页面
*/
refresh() { refresh() {
setTimeout(() => { setTimeout(() => {
this.appRef.tick(); this.appRef.tick();
}, 1); }, 1);
} }
guideBtnClick(value) {
this.showGuideAudio = value;
}
} }
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;
curImages: any;
}
declare let window: AirWindow;
class Sprite { class Sprite {
x = 0; x = 0;
...@@ -20,7 +16,7 @@ class Sprite { ...@@ -20,7 +16,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;
} }
...@@ -37,6 +33,7 @@ class Sprite { ...@@ -37,6 +33,7 @@ class Sprite {
export class MySprite extends Sprite { export class MySprite extends Sprite {
_width = 0; _width = 0;
...@@ -53,14 +50,6 @@ export class MySprite extends Sprite { ...@@ -53,14 +50,6 @@ export class MySprite extends Sprite {
skewX = 0; skewX = 0;
skewY = 0; skewY = 0;
_shadowFlag = false;
_shadowColor;
_shadowOffsetX = 0;
_shadowOffsetY = 0;
_shadowBlur = 5;
_radius = 0;
children = [this]; children = [this];
childDepandVisible = true; childDepandVisible = true;
...@@ -69,18 +58,8 @@ export class MySprite extends Sprite { ...@@ -69,18 +58,8 @@ export class MySprite extends Sprite {
img; img;
_z = 0; _z = 0;
_showRect;
init(imgObj = null, anchorX:number = 0.5, anchorY:number = 0.5) {
_bitmapFlag = false;
_offCanvas;
_offCtx;
isCircleStyle = false; // 切成圆形
parent;
_maskSpr;
init(imgObj = null, anchorX: number = 0.5, anchorY: number = 0.5) {
if (imgObj) { if (imgObj) {
...@@ -89,6 +68,7 @@ export class MySprite extends Sprite { ...@@ -89,6 +68,7 @@ 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;
...@@ -96,37 +76,6 @@ export class MySprite extends Sprite { ...@@ -96,37 +76,6 @@ 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;
}
setMaskSpr(spr) {
this._maskSpr = spr;
this._createOffCtx();
}
_createOffCtx() {
if (!this._offCtx) {
this._offCanvas = document.createElement('canvas'); // 创建一个新的canvas
this.width = this._offCanvas.width = this.width; // 创建一个正好包裹住一个粒子canvas
this.height = this._offCanvas.height = this.height;
this._offCtx = this._offCanvas.getContext('2d');
}
}
update($event = null) { update($event = null) {
if (!this.visible && this.childDepandVisible) { if (!this.visible && this.childDepandVisible) {
...@@ -145,8 +94,6 @@ export class MySprite extends Sprite { ...@@ -145,8 +94,6 @@ export class MySprite extends Sprite {
this.updateChildren(); this.updateChildren();
this.ctx.restore(); this.ctx.restore();
} }
drawInit() { drawInit() {
...@@ -165,99 +112,25 @@ export class MySprite extends Sprite { ...@@ -165,99 +112,25 @@ export class MySprite extends Sprite {
} }
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._radius) {
const r = this._radius;
const w = this.width;
const h = this.height;
this.ctx.beginPath()
this._roundRect(-w / 2, - h / 2, w, h, r * 1 || 0);
this.ctx.clip();
}
if (this.isCircleStyle) {
this.ctx.beginPath()
this.ctx.arc(0, 0, Math.max(this.width, this.height) / 2, 0, Math.PI * 2, false); // 圆形
this.ctx.clip();
}
if (this.img) { if (this.img) {
this.ctx.drawImage(this.img, this._offX, this._offY);
if (this._showRect) {
const rect = this._showRect;
this.ctx.drawImage(this.img, rect.x, rect.y, rect.width, rect.height, this._offX + rect.x, this._offY + rect.y, rect.width, rect.height);
} else {
if (this._offCtx) {
this._offScreenRender();
} else {
this.ctx.drawImage(this.img, this._offX, this._offY);
}
}
} }
} }
_offScreenRender() { updateChildren() {
this._offCtx.save();
this._offCtx.clearRect(0, 0, this.width, this.height);
this._offCtx.drawImage(this.img, 0, 0);
if (this._maskSpr) {
this._offCtx.globalCompositeOperation = 'destination-in';
this._offCtx.drawImage(this._maskSpr.img, this._maskSpr.x + this._maskSpr._offX - this._offX , this._maskSpr.y + this._maskSpr._offY - this._offY);
}
this.ctx.drawImage(this._offCanvas, this._offX, this._offY);
this._offCtx.restore();
}
_roundRect(x, y, w, h, r) {
const min_size = Math.min(w, h);
if (r > min_size / 2) r = min_size / 2;
// 开始绘制
const ctx = this.ctx;
ctx.beginPath();
ctx.moveTo(x + r, y);
ctx.arcTo(x + w, y, x + w, y + h, r);
ctx.arcTo(x + w, y + h, x, y + h, r);
ctx.arcTo(x, y + h, x, y, r);
ctx.arcTo(x, y, x + w, y, r);
ctx.closePath();
}
if (this.children.length <= 0) { return; }
updateChildren() { for (let i = 0; i < this.children.length; i++) {
if (this.children.length <= 0) { return; } if (this.children[i] === this) {
for (const child of this.children) {
if (child === this) {
if (this.visible) { if (this.visible) {
this.drawSelf(); this.drawSelf();
} }
} else { } else {
child.update();
this.children[i].update();
} }
} }
} }
...@@ -304,7 +177,7 @@ export class MySprite extends Sprite { ...@@ -304,7 +177,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 --;
} }
...@@ -313,20 +186,13 @@ export class MySprite extends Sprite { ...@@ -313,20 +186,13 @@ export class MySprite extends Sprite {
} }
_changeChildAlpha(alpha) { _changeChildAlpha(alpha) {
for (const child of this.children) { for (let i = 0; i < this.children.length; i++) {
if (child !== this) { if (this.children[i] != this) {
child.alpha = alpha; this.children[i].alpha = alpha;
} }
} }
} }
set bitmapFlag(v) {
this._bitmapFlag = v;
}
get bitmapFlag() {
return this._bitmapFlag;
}
set alpha(v) { set alpha(v) {
this._alpha = v; this._alpha = v;
if (this.childDepandAlpha) { if (this.childDepandAlpha) {
...@@ -375,6 +241,7 @@ export class MySprite extends Sprite { ...@@ -375,6 +241,7 @@ export class MySprite extends Sprite {
getBoundingBox() { getBoundingBox() {
const getParentData = (item) => { const getParentData = (item) => {
let px = item.x; let px = item.x;
...@@ -412,6 +279,11 @@ export class MySprite extends Sprite { ...@@ -412,6 +279,11 @@ export class MySprite extends Sprite {
const width = this.width * Math.abs(data.sx); const width = this.width * Math.abs(data.sx);
const height = this.height * Math.abs(data.sy); const height = this.height * Math.abs(data.sy);
// const x = this.x + this._offX * Math.abs(this.scaleX);
// const y = this.y + this._offY * Math.abs(this.scaleY);
// const width = this.width * Math.abs(this.scaleX);
// const height = this.height * Math.abs(this.scaleY);
return {x, y, width, height}; return {x, y, width, height};
} }
...@@ -427,7 +299,7 @@ export class ColorSpr extends MySprite { ...@@ -427,7 +299,7 @@ export class ColorSpr extends MySprite {
g = 0; g = 0;
b = 0; b = 0;
createGSCanvas() { createGSCanvas(){
if (!this.img) { if (!this.img) {
return; return;
...@@ -442,8 +314,8 @@ export class ColorSpr extends MySprite { ...@@ -442,8 +314,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];
...@@ -477,7 +349,7 @@ export class GrayscaleSpr extends MySprite { ...@@ -477,7 +349,7 @@ export class GrayscaleSpr extends MySprite {
grayScale = 120; grayScale = 120;
createGSCanvas() { createGSCanvas(){
if (!this.img) { if (!this.img) {
return; return;
...@@ -488,8 +360,8 @@ export class GrayscaleSpr extends MySprite { ...@@ -488,8 +360,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];
...@@ -532,10 +404,10 @@ export class BitMapLabel extends MySprite { ...@@ -532,10 +404,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 (const tmp of tmpArr) { for (let i = 0; i < tmpArr.length; i++) {
const label = new MySprite(this.ctx); const label = new MySprite(this.ctx);
label.init(data[tmp], 0); label.init(data[tmpArr[i]], 0);
this.addChild(label); this.addChild(label);
labelArr.push(label); labelArr.push(label);
...@@ -548,9 +420,9 @@ export class BitMapLabel extends MySprite { ...@@ -548,9 +420,9 @@ export class BitMapLabel extends MySprite {
this.height = h; this.height = h;
let offX = -totalW / 2; let offX = -totalW / 2;
for (const label of labelArr) { for (let i = 0; i < labelArr.length; i++) {
label.x = offX; labelArr[i].x = offX;
offX += label.width; offX += labelArr[i].width;
} }
this.labelArr = labelArr; this.labelArr = labelArr;
...@@ -563,22 +435,22 @@ export class BitMapLabel extends MySprite { ...@@ -563,22 +435,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 = 'Verdana'; fontName: String = 'Verdana';
textAlign = 'left'; textAlign: String = '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;
...@@ -609,7 +481,7 @@ export class Label extends MySprite { ...@@ -609,7 +481,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;
...@@ -628,7 +500,7 @@ export class Label extends MySprite { ...@@ -628,7 +500,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(() => { .onComplete(function() {
if (callBack) { if (callBack) {
callBack(); callBack();
} }
...@@ -636,16 +508,16 @@ export class Label extends MySprite { ...@@ -636,16 +508,16 @@ export class Label extends MySprite {
.start(); // Start the tween immediately. .start(); // Start the tween immediately.
} }
// setShadow(offX = 0, offY = 2, blur = 2, color = 'rgba(0, 0, 0, 0.2)') { setShadow(offX = 2, 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 = offX;
// this._shadowOffsetY = 5; this._shadowOffsetY = offY;
// // 轻微模糊阴影 // 轻微模糊阴影
// this._shadowBlur = 5; this._shadowBlur = blur;
// } }
setOutline(width = 5, color = '#ffffff') { setOutline(width = 5, color = '#ffffff') {
...@@ -662,15 +534,15 @@ export class Label extends MySprite { ...@@ -662,15 +534,15 @@ export class Label extends MySprite {
if (!this.text) { return; } if (!this.text) { return; }
// if (this._shadowFlag) { if (this._shadowFlag) {
//
// this.ctx.shadowColor = this._shadowColor; this.ctx.shadowColor = this._shadowColor;
// // 将阴影向右移动15px,向上移动10px // 将阴影向右移动15px,向上移动10px
// 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;
// } }
...@@ -714,10 +586,11 @@ export class RichTextOld extends Label { ...@@ -714,10 +586,11 @@ 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 (const word of words) { for (let i = 0; i < words.length; i++) {
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}#`);
...@@ -740,8 +613,8 @@ export class RichTextOld extends Label { ...@@ -740,8 +613,8 @@ export class RichTextOld extends Label {
this.ctx.fontWeight = this.fontWeight; this.ctx.fontWeight = this.fontWeight;
let curX = 0; let curX = 0;
for (const text of this.textArr) { for (let i = 0; i < this.textArr.length; i++) {
const w = this.ctx.measureText(text).width; const w = this.ctx.measureText(this.textArr[i]).width;
curX += w; curX += w;
} }
...@@ -763,7 +636,7 @@ export class RichTextOld extends Label { ...@@ -763,7 +636,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(() => { .onComplete(function() {
if (callBack) { if (callBack) {
callBack(); callBack();
} }
...@@ -799,7 +672,7 @@ export class RichTextOld extends Label { ...@@ -799,7 +672,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';
...@@ -822,10 +695,9 @@ export class RichTextOld extends Label { ...@@ -822,10 +695,9 @@ export class RichTextOld extends Label {
export class RichText extends Label { export class RichText extends Label {
disH = 30; disH = 30;
offW = 10;
constructor(ctx?: any) { constructor(ctx) {
super(ctx); super(ctx);
// this.dataArr = dataArr; // this.dataArr = dataArr;
...@@ -853,18 +725,18 @@ export class RichText extends Label { ...@@ -853,18 +725,18 @@ export class RichText extends Label {
const chr = this.text.split(' '); const chr = this.text.split(' ');
let temp = ''; let temp = '';
const row = []; const row = [];
const w = selfW - this.offW * 2; const w = selfW - 80;
const disH = (this.fontSize + this.disH) * this.scaleY; const disH = (this.fontSize + this.disH) * this.scaleY;
for (const c of chr) { for (let a = 0; a < chr.length; a++) {
if (this.ctx.measureText(temp).width < w && this.ctx.measureText(temp + (c)).width <= w) { if (this.ctx.measureText(temp).width < w && this.ctx.measureText(temp + (chr[a])).width <= w) {
temp += ' ' + c; temp += ' ' + chr[a];
} else { } else {
row.push(temp); row.push(temp);
temp = ' ' + c; temp = ' ' + chr[a];
} }
} }
row.push(temp); row.push(temp);
...@@ -904,40 +776,6 @@ export class RichText extends Label { ...@@ -904,40 +776,6 @@ export class RichText extends Label {
export class LineRect extends MySprite {
lineColor = '#ffffff';
lineWidth = 10;
setSize(w, h) {
this.width = w;
this.height = h;
}
drawLine() {
this.ctx.beginPath();
this.ctx.moveTo(this._offX, this._offY);
this.ctx.lineTo(this._offX + this.width, this._offY);
this.ctx.lineTo(this._offX + this.width, this._offY + this.height);
this.ctx.lineTo(this._offX, this._offY + this.height);
this.ctx.closePath();
this.ctx.lineWidth = this.lineWidth;
// this.ctx.fillStyle = "rgb(2,33,42)"; //指定填充颜色
// this.ctx.fill(); //对多边形进行填充
this.ctx.strokeStyle = this.lineColor; // "#ffffff";
this.ctx.stroke();
}
drawSelf() {
super.drawSelf();
this.drawLine();
}
}
export class ShapeRect extends MySprite { export class ShapeRect extends MySprite {
...@@ -996,83 +834,7 @@ export class ShapeCircle extends MySprite { ...@@ -996,83 +834,7 @@ 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 + this._offX, height - radius + this._offY, radius, 0, Math.PI / 2);
// 矩形下边线
ctx.lineTo(radius + this._offX, height + this._offY);
// 左下角圆弧,弧度从1/2PI到PI
ctx.arc(radius + this._offX, height - radius + this._offY, radius, Math.PI / 2, Math.PI);
// 矩形左边线
ctx.lineTo(0 + this._offX, radius + this._offY);
// 左上角圆弧,弧度从PI到3/2PI
ctx.arc(radius + this._offX, radius + this._offY, radius, Math.PI, Math.PI * 3 / 2);
// 上边线
ctx.lineTo(width - radius + this._offX, 0 + this._offY);
// 右上角圆弧
ctx.arc(width - radius + this._offX, radius + this._offY, radius, Math.PI * 3 / 2, Math.PI * 2);
// 右边线
ctx.lineTo(width + this._offX, height - radius + this._offY);
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 {
...@@ -1085,7 +847,7 @@ export class MyAnimation extends MySprite { ...@@ -1085,7 +847,7 @@ export class MyAnimation extends MySprite {
loop = false; loop = false;
playEndFunc; playEndFunc;
delayPerUnit = 0.07; delayPerUnit = 1;
restartFlag = false; restartFlag = false;
reverseFlag = false; reverseFlag = false;
...@@ -1119,13 +881,13 @@ export class MyAnimation extends MySprite { ...@@ -1119,13 +881,13 @@ export class MyAnimation extends MySprite {
this.frameArr[this.frameIndex].visible = true; this.frameArr[this.frameIndex].visible = true;
} }
_refreshSize(img: any) { _refreshSize(img) {
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'];
} }
} }
...@@ -1154,14 +916,14 @@ export class MyAnimation extends MySprite { ...@@ -1154,14 +916,14 @@ export class MyAnimation extends MySprite {
} }
showAllFrame() { showAllFrame() {
for (const frame of this.frameArr ) { for (let i = 0; i < this.frameArr.length; i++) {
frame.alpha = 1; this.frameArr[i].alpha = 1;
} }
} }
hideAllFrame() { hideAllFrame() {
for (const frame of this.frameArr) { for (let i = 0; i < this.frameArr.length; i++) {
frame.alpha = 0; this.frameArr[i].alpha = 0;
} }
} }
...@@ -1174,9 +936,8 @@ export class MyAnimation extends MySprite { ...@@ -1174,9 +936,8 @@ export class MyAnimation extends MySprite {
this.frameArr[this.frameIndex].visible = true; this.frameArr[this.frameIndex].visible = true;
if (this.playEndFunc) { if (this.playEndFunc) {
const func = this.playEndFunc; this.playEndFunc();
this.playEndFunc = null; this.playEndFunc = null;
func();
} }
} }
...@@ -1243,14 +1004,6 @@ export class MyAnimation extends MySprite { ...@@ -1243,14 +1004,6 @@ export class MyAnimation extends MySprite {
export function tweenChange(item, obj, time = 0.8, callBack = null, easing = null, update = null) { export function tweenChange(item, obj, time = 0.8, callBack = null, easing = null, update = null) {
const tween = createTween(item, obj, time, callBack, easing, update)
tween.start();
return tween;
}
export function createTween(item, obj, time = 0.8, callBack = null, easing = null, update = null) {
const tween = new TWEEN.Tween(item).to(obj, time * 1000); const tween = new TWEEN.Tween(item).to(obj, time * 1000);
if (callBack) { if (callBack) {
...@@ -1263,31 +1016,18 @@ export function createTween(item, obj, time = 0.8, callBack = null, easing = nul ...@@ -1263,31 +1016,18 @@ export function createTween(item, obj, time = 0.8, callBack = null, easing = nul
} }
if (update) { if (update) {
tween.onUpdate( (a, b) => { tween.onUpdate( (a, b) => {
update(a, b); update(a, b);
}); });
} }
return tween;
}
export function tweenQueue(arr) { tween.start();
return tween;
const showOneTween = () => {
const tween = arr.shift();
if (arr.length > 0) {
tween.onComplete( () => {
showOneTween();
});
}
tween.start();
};
showOneTween();
} }
export function rotateItem(item, rotation, time = 0.8, callBack = null, easing = null, loop = false) { export function rotateItem(item, rotation, time = 0.8, callBack = null, easing = null) {
const tween = new TWEEN.Tween(item).to({ rotation }, time * 1000); const tween = new TWEEN.Tween(item).to({ rotation }, time * 1000);
...@@ -1295,14 +1035,7 @@ export function rotateItem(item, rotation, time = 0.8, callBack = null, easing = ...@@ -1295,14 +1035,7 @@ export function rotateItem(item, rotation, time = 0.8, callBack = null, easing =
tween.onComplete(() => { tween.onComplete(() => {
callBack(); callBack();
}); });
} else if (loop) {
const speed = (rotation - item.rotation) / time;
tween.onComplete(() => {
item.rotation %= 360;
rotateItem(item, item.rotation + speed * time, time, null, easing, true);
});
} }
if (easing) { if (easing) {
tween.easing(easing); tween.easing(easing);
} }
...@@ -1336,7 +1069,7 @@ export function moveItem(item, x, y, time = 0.8, callBack = null, easing = null) ...@@ -1336,7 +1069,7 @@ export function moveItem(item, x, y, time = 0.8, callBack = null, easing = null)
if (callBack) { if (callBack) {
tween.onComplete(() => { tween.onComplete(() => {
callBack(); callBack();
}); });
} }
if (easing) { if (easing) {
...@@ -1362,7 +1095,7 @@ export function endShow(item, s = 1) { ...@@ -1362,7 +1095,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(() => { .onComplete(function() {
}) })
.start(); .start();
...@@ -1370,14 +1103,14 @@ export function endShow(item, s = 1) { ...@@ -1370,14 +1103,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(() => { .onComplete(function () {
if (callBack) { if (callBack) {
callBack(); callBack();
} }
...@@ -1393,7 +1126,7 @@ export function hideItem(item, time = 0.8, callBack = null, easing = null) { ...@@ -1393,7 +1126,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();
} }
...@@ -1404,7 +1137,7 @@ export function showItem(item, time = 0.8, callBack = null, easing = null) { ...@@ -1404,7 +1137,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(() => { .onComplete(function () {
if (callBack) { if (callBack) {
callBack(); callBack();
} }
...@@ -1422,9 +1155,9 @@ export function alphaItem(item, alpha, time = 0.8, callBack = null, easing = nul ...@@ -1422,9 +1155,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}, time * 1000) .to({alpha: 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(() => { .onComplete(function () {
if (callBack) { if (callBack) {
callBack(); callBack();
} }
...@@ -1444,7 +1177,7 @@ export function showStar(item, time = 0.8, callBack = null, easing = null) { ...@@ -1444,7 +1177,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(() => { .onComplete(function () {
if (callBack) { if (callBack) {
callBack(); callBack();
} }
...@@ -1500,22 +1233,22 @@ export function getAngleByPos(px, py, mx, my) { ...@@ -1500,22 +1233,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;
} }
...@@ -1527,7 +1260,7 @@ export function getAngleByPos(px, py, mx, my) { ...@@ -1527,7 +1260,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);
} }
} }
...@@ -1537,7 +1270,7 @@ export function removeItemFromArr(arr, item) { ...@@ -1537,7 +1270,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);
...@@ -1585,7 +1318,7 @@ export function getPosDistance(sx, sy, ex, ey) { ...@@ -1585,7 +1318,7 @@ export function getPosDistance(sx, sy, ex, ey) {
return len; return len;
} }
export function delayCall(second, callback) { export function delayCall(callback, second) {
const tween = new TWEEN.Tween(this) const tween = new TWEEN.Tween(this)
.delay(second * 1000) .delay(second * 1000)
.onComplete(() => { .onComplete(() => {
...@@ -1602,32 +1335,25 @@ export function formatTime(fmt, date) { ...@@ -1602,32 +1335,25 @@ 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 (const k in o) { for (var 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;
} }
export function getMinScale(item, maxW, maxH = null) { export function getMinScale(item, maxLen) {
if (!maxH) { const sx = maxLen / item.width;
maxH = maxW; const sy = maxLen / item.height;
}
const sx = maxW / item.width;
const sy = maxH / item.height;
const minS = Math.min(sx, sy); const minS = Math.min(sx, sy);
return minS; return minS;
} }
...@@ -1670,51 +1396,11 @@ export function jelly(item, time = 0.7) { ...@@ -1670,51 +1396,11 @@ export function jelly(item, time = 0.7) {
run(); run();
} }
export function jellyPop(item, time) {
if (item.jellyTween) {
TWEEN.remove(item.jellyTween);
}
const t = time / 6;
const baseSX = item.scaleX;
const baseSY = item.scaleY;
let index = 0;
const run = () => {
if (index >= arr.length) {
item.jellyTween = null;
return;
}
const data = arr[index];
const t = tweenChange(item, {scaleX: data[0], scaleY: data[1]}, data[2], () => {
index ++;
run();
}, TWEEN.Easing.Sinusoidal.InOut);
item.jellyTween = t;
};
const arr = [
[baseSX * 1.3, baseSY * 1.3, t],
[baseSX * 0.85, baseSY * 0.85, t * 1],
[baseSX * 1.1, baseSY * 1.1, t * 1],
[baseSX * 0.95, baseSY * 0.95, t * 1],
[baseSX * 1.02, baseSY * 1.02, t * 1],
[baseSX * 1, baseSY * 1, t * 1],
];
item.setScaleXY(0);
run();
}
export function showPopParticle(img, pos, parent, num = 20, minLen = 40, maxLen = 80, showTime = 0.4) { export function showPopParticle(img, pos, parent) {
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();
...@@ -1726,8 +1412,8 @@ export function showPopParticle(img, pos, parent, num = 20, minLen = 40, maxLen ...@@ -1726,8 +1412,8 @@ export function showPopParticle(img, pos, parent, num = 20, minLen = 40, maxLen
const randomR = 360 * Math.random(); const randomR = 360 * Math.random();
particle.rotation = randomR; particle.rotation = randomR;
const randomS = 0.3 + Math.random() * 0.7; const randomS = 0.5 + Math.random() * 0.5;
particle.setScaleXY(randomS * 0.3); particle.setScaleXY(randomS);
const randomX = Math.random() * 20 - 10; const randomX = Math.random() * 20 - 10;
particle.x += randomX; particle.x += randomX;
...@@ -1735,32 +1421,16 @@ export function showPopParticle(img, pos, parent, num = 20, minLen = 40, maxLen ...@@ -1735,32 +1421,16 @@ export function showPopParticle(img, pos, parent, num = 20, minLen = 40, maxLen
const randomY = Math.random() * 20 - 10; const randomY = Math.random() * 20 - 10;
particle.y += randomY; particle.y += randomY;
const randomL = minLen + Math.random() * (maxLen - minLen); const randomL = 40 + Math.random() * 40;
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, showTime, () => { moveItem(particle, particle.x + randomT.x, particle.y + randomT.y, 0.4, () => {
}, TWEEN.Easing.Exponential.Out);
// scaleItem(particle, 0, 0.6, () => {
//
// });
scaleItem(particle, randomS, 0.6, () => {
}, TWEEN.Easing.Exponential.Out); }, TWEEN.Easing.Exponential.Out);
setTimeout(() => { scaleItem(particle, 0, 0.6, () => {
hideItem(particle, 0.4, () => {
}, TWEEN.Easing.Cubic.In);
}, showTime * 0.5 * 1000);
});
} }
} }
...@@ -1802,7 +1472,7 @@ export function shake(item, time = 0.5, callback = null, rate = 1) { ...@@ -1802,7 +1472,7 @@ export function shake(item, time = 0.5, callback = null, rate = 1) {
}; };
const move1 = () => { const move1 = () => {
moveItem(item, baseX + offX, baseY + offY, time / 7.5, () => { moveItem(item, baseX + offX, baseY + offY, time / 8, () => {
move2(); move2();
}, easing); }, easing);
}; };
...@@ -1811,41 +1481,246 @@ export function shake(item, time = 0.5, callback = null, rate = 1) { ...@@ -1811,41 +1481,246 @@ export function shake(item, time = 0.5, callback = null, rate = 1) {
} }
export function getMaxScale(item, maxW, maxH) { // --------------- custom class --------------------
const sx = maxW / item.width;
const sy = maxH / item.height;
const maxS = Math.max(sx, sy);
return maxS;
}
export function createSprite(key) {
const image = window.curImages;
const spr = new MySprite();
spr.init(image.get(key));
return spr;
}
export class MyVideo extends MySprite { export class Cow extends MyAnimation {
element;
initVideoElement(videoElement) { idleFrameArr;
eatFrameArr;
likeFrameArr;
angryFrameArr;
happyFrameArr;
bubble1;
bubble2;
this.element = videoElement;
this.width = this.element.videoWidth;
this.height = this.element.videoHeight;
this.element.currentTime = 0.01; idle() {
this.setStyle('idle');
this.loop = true;
this.play();
this.showBubble();
} }
eat() {
drawSelf() { this.setStyle('eat');
super.drawSelf(); this.loop = false;
this.playEndFunc = () => {
this.idle();
};
this.ctx.drawImage(this.element, 0, 0, this.width, this.height); this.hideBubble();
} }
}
angry() {
// --------------- custom class -------------------- 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;
} }
...@@ -17,3 +19,11 @@ ...@@ -17,3 +19,11 @@
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,
MySprite, tweenChange, MyAnimation,
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";
...@@ -18,145 +41,2313 @@ import TWEEN from '@tweenjs/tween.js'; ...@@ -18,145 +41,2313 @@ import TWEEN from '@tweenjs/tween.js';
@Component({ @Component({
selector: 'app-play', selector: 'app-play',
templateUrl: './play.component.html', templateUrl: './play.component.html',
styleUrls: ['./play.component.css'] styleUrls: ['./play.component.scss']
}) })
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;
}
@ViewChild('canvas', {static: true }) canvas: ElementRef; @Input()
@ViewChild('wrap', {static: true }) wrap: ElementRef; sid;
// 数据 @ViewChild('canvas') canvas: ElementRef;
data; @ViewChild('wrap') wrap: ElementRef;
canvasWidth = 1280;
canvasHeight = 720;
canvasBaseW = 1280;
canvasBaseH = 720;
ctx; ctx;
fps = 0;
frametime = 0; // 上一帧动画的时间, 两帧时间差
canvasWidth = 1280; // canvas实际宽度
canvasHeight = 720; // canvas实际高度
canvasBaseW = 1280; // canvas 资源预设宽度 mx;
canvasBaseH = 720; // canvas 资源预设高度 my; // 点击坐标
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';
btnLeft;
btnRight;
pic1;
pic2;
canTouch = true; canTouch = true;
KEY = 'hw_005';
// -----
picArr;
itemArrA;
itemArrB;
curItem;
linkIdArr;
petalTime;
optionArr;
cowScale;
grassArr;
curGrass;
downFlag = true;
cowArr;
timeLabel;
clockUpdateFlag;
clock1Bg;
btnRestar;
restartBtn;
clock2Bg;
curCow;
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; curPic;
roleArr;
picIndex = 0;
curData;
bgTop;
topImg;
curWordArr;
wordMoveFlag;
maxScore;
bottomY;
leftScore;
rightScore;
leftScoreLabel;
rightScoreLabel;
addScoreNum = 20;
leftWin;
rightWin;
startPageArr = [];
bgArr;
rightArr;
title;
startBtn;
starArr;
wand;
light;
replayBtn;
endPageArr;
gameEndFlag;
showPetalFlag;
bg;
@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 {
// console.log('data:' , data); this.data = {};
}
console.log('data:' , data);
if (!this.data.contentObj) {
this.data.contentObj = {};
}
this.initDefaultData();
this.initAudio();
this.initImg();
this.initListener();
}, this.KEY);
//
// // this.initAudio();
// this.initImg();
// this.initListener();
}
initDefaultData() {
const picArr = this.data.contentObj.picArr;
// console.log('picArr: ', picArr);
if (!picArr || picArr.length == 0) {
const picArr = [
{text: 'ap'},
{text: 'am'}
];
// for (let i = 0; i < 2; i ++) {
//
// const data = {
// text: 'ap'
// };
//
// if (i == 0) {
// data.a_pic_url = 'assets/play/default/item.png';
// data.b_pic_url = 'assets/play/default/item.png';
// }
//
// picArr.push(data);
// }
this.data.contentObj.picArr = picArr;
const optionArr = [
{text: 'cap', type: '0'},
{text: 'map', type: '0'},
{text: 'clam', type: '1'}
];
this.data.contentObj.optionArr = optionArr;
}
}
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 = false;
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;
//
for (let i = 0; i < this.picArr.length; i++) {
const data = this.picArr[i];
if (!data.optionType) {
if (data.pic_url) {
data.optionType = 'B';
} else {
data.optionType = 'A';
}
}
}
for (let i = 0; i < this.optionArr.length; i++) {
const data = this.optionArr[i];
if (!data.optionType) {
if (data.pic_url) {
data.optionType = 'B';
} else {
data.optionType = 'A';
}
}
}
}
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);
}
}
arr = contentObj.optionArr;
if (arr) {
for (let i = 0; i < arr.length; i ++) {
addUrlToAudioObj(arr[i].audio_url);
}
}
const audioObj = this.audioObj;
const addOneAudio = (key, url, vlomue = 1, loop = false, callback = null) => {
const audio = new Audio();
audio.src = url;
audio.load();
audio.loop = loop;
audio.volume = vlomue;
audioObj[key] = audio;
if (callback) {
audio.onended = () => {
callback();
};
}
};
addOneAudio('click', this.rawAudios.get('click'), 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);
}
}
arr = this.data.contentObj.optionArr;
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.initClock();
// this.initCow();
// this.initItem();
// this.initGrass();
// this.showClock2();
}
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.optionType == 'B') {
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);
}
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.optionType == 'B') {
// 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.bgArr.push(bg);
}
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;
}
console.log(' in mapDown ');
this.downFlag = true;
this.curCow = null;
if ((!this.restartBtn || !this.restartBtn.visible) && this.curGrass) {
for (let i = 0; i < this.cowArr.length; i++) {
if (this.checkClickTarget(this.cowArr[i])) {
this.checkCowEatClick(this.cowArr[i]);
return;
}
}
}
if (this.curGrass) {
this.curGrass.light.visible = false;
this.curGrass = null;
}
if (this.restartBtn && this.restartBtn.visible) {
if (this.checkClickTarget(this.restartBtn)) {
this.clickRestart();
return;
}
} else {
const arr = this.grassArr;
for (let i = 0; i < arr.length; i++) {
if (this.checkClickTarget(arr[i])) {
this.clickGrass(arr[i]);
return;
}
}
}
for (let i = 0; i < this.cowArr.length; i++) {
if (this.checkClickTarget(this.cowArr[i].bubble2)) {
this.playAudio(this.cowArr[i].data.audio_url);
return;
}
}
}
mapMove(event) {
if (!this.curGrass) {
return;
}
if (!this.downFlag) {
return;
}
this.curGrass.x = this.mx;
this.curGrass.y = this.my;
}
mapUp(event) {
this.downFlag = false;
if (this.curGrass) {
if (!this.curCow) {
this.checkOnCow();
}
}
this.curCow = null;
}
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);
}
}
// 初始化 各事件监听
this.initListener();
// 若无数据 则为预览模式 需要填充一些默认数据用来显示
this.initDefaultData();
// 初始化 音频资源
this.initAudio();
// 初始化 图片资源
this.initImg();
// 开始预加载资源
this.load();
}, this.saveKey);
}
ngOnDestroy() {
window['curCtx'] = null;
window.cancelAnimationFrame(this.animationId);
this.cleanAudio();
}
updateClock() {
cleanAudio() { if (!this.clockUpdateFlag) {
if (this.audioObj) { return;
for (const key in this.audioObj) {
this.audioObj[key].pause();
}
} }
}
load() { const curDate = new Date();
const oldDate = this.timeLabel.date;
curDate.setTime(curDate.getTime() - oldDate.getTime());
// 预加载资源 const time = formatTime('mm:ss', curDate);
this.loadResources().then(() => { this.timeLabel.text = time;
window["air"].hideAirClassLoading(this.saveKey, this.data);
this.init();
this.update();
});
} }
init() { update() {
this.initCtx();
this.initData();
this.initView();
}
initCtx() { this.animationId = window.requestAnimationFrame(this.update.bind(this));
this.canvasWidth = this.wrap.nativeElement.clientWidth; // 清除画布内容
this.canvasHeight = this.wrap.nativeElement.clientHeight; this.ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight);
this.canvas.nativeElement.width = this.wrap.nativeElement.clientWidth;
this.canvas.nativeElement.height = this.wrap.nativeElement.clientHeight;
this.ctx = this.canvas.nativeElement.getContext('2d'); TWEEN.update();
this.canvas.nativeElement.width = this.canvasWidth;
this.canvas.nativeElement.height = this.canvasHeight;
window['curCtx'] = this.ctx;
window['curImages'] = this.images;
}
// this.updateWordArr();
this.updateArr(this.bgArr);
this.updateArr(this.renderArr);
this.updateArr(this.endPageArr);
this.updateClock();
}
updateItem(item) { updateItem(item) {
...@@ -178,8 +2369,6 @@ export class PlayComponent implements OnInit, OnDestroy { ...@@ -178,8 +2369,6 @@ export class PlayComponent implements OnInit, OnDestroy {
initListener() { initListener() {
this.winResizeEventStream this.winResizeEventStream
...@@ -213,6 +2402,7 @@ export class PlayComponent implements OnInit, OnDestroy { ...@@ -213,6 +2402,7 @@ export class PlayComponent implements OnInit, OnDestroy {
// --------------------------------------------- // ---------------------------------------------
let firstTouch = true; let firstTouch = true;
const touchDownFunc = (e) => { const touchDownFunc = (e) => {
...@@ -220,6 +2410,7 @@ export class PlayComponent implements OnInit, OnDestroy { ...@@ -220,6 +2410,7 @@ 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);
}; };
...@@ -237,6 +2428,7 @@ export class PlayComponent implements OnInit, OnDestroy { ...@@ -237,6 +2428,7 @@ 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);
}; };
...@@ -276,8 +2468,93 @@ export class PlayComponent implements OnInit, OnDestroy { ...@@ -276,8 +2468,93 @@ 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;
// };
// }
} }
...@@ -301,6 +2578,43 @@ export class PlayComponent implements OnInit, OnDestroy { ...@@ -301,6 +2578,43 @@ 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) => {// 预加载图片
...@@ -314,7 +2628,7 @@ export class PlayComponent implements OnInit, OnDestroy { ...@@ -314,7 +2628,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(() => {
...@@ -360,8 +2674,6 @@ export class PlayComponent implements OnInit, OnDestroy { ...@@ -360,8 +2674,6 @@ export class PlayComponent implements OnInit, OnDestroy {
checkClickTarget(target) { checkClickTarget(target) {
const rect = target.getBoundingBox(); const rect = target.getBoundingBox();
...@@ -394,297 +2706,22 @@ export class PlayComponent implements OnInit, OnDestroy { ...@@ -394,297 +2706,22 @@ 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;
update() { const _y = ey - sy;
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"], ['grass', "assets/play/grass.png"],
['btn_right', "assets/play/btn_right.png"], ['grass_light', "assets/play/grass_light.png"],
// ['text_bg', "assets/play/text_bg.png"], ['clock_1', "assets/play/clock_1.png"],
['clock_2', "assets/play/clock_2.png"],
['clock_1_bg', "assets/play/clock_1_bg.png"],
['clock_2_bg', "assets/play/clock_2_bg.png"],
['bubble_small', "assets/play/bubble_small.png"],
['bubble_big', "assets/play/bubble_big.png"],
['btn_restart', "assets/play/btn_restart.png"],
['idle_1', "assets/play/cow/idle/1.png"],
['idle_2', "assets/play/cow/idle/2.png"],
['idle_3', "assets/play/cow/idle/3.png"],
['idle_4', "assets/play/cow/idle/4.png"],
['idle_5', "assets/play/cow/idle/5.png"],
['idle_6', "assets/play/cow/idle/6.png"],
['idle_7', "assets/play/cow/idle/7.png"],
['idle_8', "assets/play/cow/idle/8.png"],
['idle_9', "assets/play/cow/idle/9.png"],
['idle_10', "assets/play/cow/idle/10.png"],
['idle_11', "assets/play/cow/idle/11.png"],
['idle_12', "assets/play/cow/idle/12.png"],
['eat_1', "assets/play/cow/eat/1.png"],
['eat_2', "assets/play/cow/eat/2.png"],
['eat_3', "assets/play/cow/eat/3.png"],
['eat_4', "assets/play/cow/eat/4.png"],
['eat_5', "assets/play/cow/eat/5.png"],
['eat_6', "assets/play/cow/eat/6.png"],
['eat_7', "assets/play/cow/eat/7.png"],
['eat_8', "assets/play/cow/eat/8.png"],
['eat_9', "assets/play/cow/eat/9.png"],
['eat_10', "assets/play/cow/eat/10.png"],
['eat_11', "assets/play/cow/eat/11.png"],
['eat_12', "assets/play/cow/eat/12.png"],
['angry_1', "assets/play/cow/angry/1.png"],
['angry_2', "assets/play/cow/angry/2.png"],
['angry_3', "assets/play/cow/angry/3.png"],
['angry_4', "assets/play/cow/angry/4.png"],
['angry_5', "assets/play/cow/angry/5.png"],
['angry_6', "assets/play/cow/angry/6.png"],
['like_1', "assets/play/cow/like/1.png"],
['like_2', "assets/play/cow/like/2.png"],
['like_3', "assets/play/cow/like/3.png"],
['like_4', "assets/play/cow/like/4.png"],
['like_5', "assets/play/cow/like/5.png"],
['like_6', "assets/play/cow/like/6.png"],
['happy_1', "assets/play/cow/happy/1.png"],
['happy_2', "assets/play/cow/happy/2.png"],
['happy_3', "assets/play/cow/happy/3.png"],
['happy_4', "assets/play/cow/happy/4.png"],
['petal_1', "assets/play/petal_1.png"],
['petal_2', "assets/play/petal_2.png"],
['petal_3', "assets/play/petal_3.png"],
]; ];
...@@ -11,7 +73,16 @@ const res = [ ...@@ -11,7 +73,16 @@ 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"],
]; ];
......
@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;
}
src/assets/play/bg.jpg

25.8 KB | W: | H:

src/assets/play/bg.jpg

155 KB | W: | H:

src/assets/play/bg.jpg
src/assets/play/bg.jpg
src/assets/play/bg.jpg
src/assets/play/bg.jpg
  • 2-up
  • Swipe
  • Onion skin
...@@ -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="http://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>
...@@ -2,9 +2,7 @@ ...@@ -2,9 +2,7 @@
"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",
......
...@@ -92,8 +92,7 @@ ...@@ -92,8 +92,7 @@
"variable-name": false, "variable-name": false,
"no-unused-expression": false, "no-unused-expression": false,
"align": false, "align": false
"no-string-literal": false
}, },
"rulesDirectory": [ "rulesDirectory": [
"codelyzer" "codelyzer"
......
This source diff could not be displayed because it is too large. You can view the blob instead.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment