Commit af06ba7b authored by starry_sky's avatar starry_sky

master

parent 3695f7ce
...@@ -4,21 +4,10 @@ angularjs技术框架下的H5互动模板框架脚手架,基于NG-ZORRO实现 ...@@ -4,21 +4,10 @@ angularjs技术框架下的H5互动模板框架脚手架,基于NG-ZORRO实现
# 使用简介 # 使用简介
## 前期准备
* git下载 https://git-scm.com/downloads
* nodejs下载 https://nodejs.org/zh-cn/download/
* 谷歌浏览器下载 https://www.google.cn/chrome/
都下载最新版就行,然后默认安装就可以
## 生成项目 ## 生成项目
* 登录绘玩云课件开发平台:http://staging-teach.ireadabc.com/ * 登录绘玩云课件开发平台:http://staging-teach.ireadabc.com/
* 点击“登录账号,查看我的课件” * 点击“模板管理” 菜单,然后点击“新建模板”, 填写必要的信息,在“技术选型”一项上选择“Angular”
* 输入测试的用户名/密码:developers/12345678
* 在右上角“个人中心”的下拉菜单里,点击“我的模板” 菜单,然后点击“新建模板”, 填写必要的信息,在“技术选型”一项上选择“Angular”
* 点击“确定”后,列表页就会出现一个新生成的模板项目 * 点击“确定”后,列表页就会出现一个新生成的模板项目
* 在项目的卡片下找到“开发”按钮,则会弹出相对应的git地址 * 在项目的卡片下找到“开发”按钮,则会弹出相对应的git地址
...@@ -28,8 +17,7 @@ angularjs技术框架下的H5互动模板框架脚手架,基于NG-ZORRO实现 ...@@ -28,8 +17,7 @@ angularjs技术框架下的H5互动模板框架脚手架,基于NG-ZORRO实现
// xxx 是上面项目对应的Git地址 // xxx 是上面项目对应的Git地址
git clone xxx git clone xxx
cd 项目名称/ cd 项目名称/
npm install -g yarn npm install
yarn install
npm start npm start
//启动成功后打开浏览器,输入:http://localhost:4200 则可以看到这个项目的初始化效果了 //启动成功后打开浏览器,输入:http://localhost:4200 则可以看到这个项目的初始化效果了
...@@ -164,152 +152,6 @@ npm start ...@@ -164,152 +152,6 @@ npm start
}); });
``` ```
### 互动课件
通过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、测试自己的交互事件,看看老师端和学生端是否是自己想要的展示效果
### 补充方法 ### 补充方法
......
...@@ -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){
...@@ -80,20 +80,21 @@ const runSpawn = async function (){ ...@@ -80,20 +80,21 @@ const runSpawn = async function (){
console.log(err); console.log(err);
reject(); reject();
} }
console.log(files);
for(let i=0;i<files.length;i++){ for(let i=0;i<files.length;i++){
tarStream.addEntry(zippath+"/"+files[i]); tarStream.addEntry(zippath+"/"+files[i]);
} }
let writeStream = fs.createWriteStream(zipdir); let writeStream = fs.createWriteStream(zipdir);
tarStream.pipe(writeStream); tarStream.pipe(writeStream);
writeStream.on('close', () => { writeStream.on('close', () => {
console.log(`模板 ${pkg.name} 打包已完成!`); console.log(`模板 ${pkg.name} 打包已完成!`);
resolve(); resolve();
}) })
}); });
}); });
}); });
} }
// let projects = ""; // let projects = "";
...@@ -101,7 +102,7 @@ const runSpawn = async function (){ ...@@ -101,7 +102,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 +111,6 @@ let exec = async function(){ ...@@ -110,5 +111,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.
...@@ -4,54 +4,73 @@ ...@@ -4,54 +4,73 @@
"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",
"node-sass": "^4.14.1",
"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"
}, },
"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" "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;
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
<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>
...@@ -76,7 +76,7 @@ ...@@ -76,7 +76,7 @@
<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>
......
...@@ -42,8 +42,8 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { ...@@ -42,8 +42,8 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
@Output() @Output()
save = new EventEmitter(); save = new EventEmitter();
@ViewChild('canvas', {static: true }) canvas: ElementRef; @ViewChild('canvas') canvas: ElementRef;
@ViewChild('wrap', {static: true }) wrap: ElementRef; @ViewChild('wrap') wrap: ElementRef;
// @HostListener('window:resize', ['$event']) // @HostListener('window:resize', ['$event'])
canvasWidth = 1280; canvasWidth = 1280;
...@@ -613,9 +613,7 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { ...@@ -613,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));
......
<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="body">
<div ng-app class="model-content">
<div class="title">
<h2>
标题
</h2>
<p style="margin: 5px 0;">标题:</p>
<input class="input_button" type="text" [(ngModel)]="item.contentObj.title.text" (ngModelChange)="save()">
<p style="margin: 5px 0;">题号:</p>
<input style="width: 100px;" type="text" [(ngModel)]="item.contentObj.title.number" (ngModelChange)="save()">
<p style="margin: 5px 0;">标题-音频:</p>
<app-audio-recorder class="audio_load"
[audioUrl]="item.contentObj.title.audio_url"
(audioUploaded)="onAudioUploadSuccessByItem($event, item.contentObj.title)">
</app-audio-recorder>
<p style="margin: 5px 0;">背景音乐-音频</p>
<app-audio-recorder class="audio_load"
[audioUrl]="item.contentObj.audio_url"
(audioUploaded)="onAudioUploadSuccessByItem($event, item.contentObj)">
</app-audio-recorder>
<button *ngIf="item.contentObj.values.length != 4" class="button_add" (click)="addValue()">
添加一句内容
</button>
</div>
<div class="upload_items">
<div class="load_values_item" *ngFor="let value of values; let i = index" style="display: block;">
<h3>第{{i + 1}}句</h3>
<nz-radio-group [(ngModel)]="value.number" (ngModelChange)="save()" class="gruop_load">
显示序号:
<label nz-radio nzValue="true"></label>
<label nz-radio nzValue="false"></label>
</nz-radio-group>
<p style="margin: 5px 0;">句子文本</p>
<input class="input_button" type="text" [(ngModel)]="value.text" (ngModelChange)="sentence_handle(i)">
<p style="margin: 5px 0;">答案</p>
<nz-select nzMode="multiple" nzShowSearch nzAllowClear nzPlaceHolder="输入可快速查询" [(ngModel)]="value.answer" (ngModelChange)= "sentence_handle(i)">
<div *ngFor="let text of value.word;let j = index">
<nz-option [nzValue]="j" [nzLabel]= "j+1+ '-' + value.word[j]"></nz-option>
</div>
</nz-select>
<p style="margin: 5px 0;">答案颜色</p>
<nz-select [(ngModel)]="value.answer_color" (ngModelChange)="save()">
<nz-option nzValue="C6161E" nzLabel="红色"></nz-option>
<nz-option nzValue="BACF41" nzLabel="绿色"></nz-option>
<nz-option nzValue="6D3E21" nzLabel="巧克力色"></nz-option>
<nz-option nzValue="000000" nzLabel="黑色"></nz-option>
</nz-select>
<div class="colorview"></div>
<p style="margin: 5px 0;">点击音效</p>
<app-audio-recorder
[audioUrl]="value.audio_url"
(audioUploaded)="onAudioUploadSuccessByItem($event, value)"
>
</app-audio-recorder>
<h5 style="margin-top: 10px;margin-bottom: 10px;">图片</h5>
<app-upload-image-with-preview class="img_load"
[picUrl]="value.img_url"
(imageUploaded)="onImageUploadSuccessByItem($event, value)"
></app-upload-image-with-preview>
<div class="model-content"> <button style="margin-left: 10px;" class="button_remove" nz-button nzType="danger" (click)="deleteValue(value)">
删除
</button>
<div style="position: absolute; left: 200px; top: 100px; width: 800px;">
<input type="text" nz-input [(ngModel)]="item.text" (blur)="save()">
<app-upload-image-with-preview
[picUrl]="item.pic_url"
(imageUploaded)="onImageUploadSuccess($event, 'pic_url')"
></app-upload-image-with-preview>
<app-audio-recorder
[audioUrl]="item.audio_url"
(audioUploaded)="onAudioUploadSuccess($event, 'audio_url')"
></app-audio-recorder>
<app-custom-hot-zone></app-custom-hot-zone>
<app-upload-video></app-upload-video>
<app-lesson-title-config></app-lesson-title-config>
</div> </div>
</div>
\ No newline at end of file
</div>
\ No newline at end of file
@import '../style/common_mixin';
p{
margin: 0;
padding: 0;
color: #707F88;
}
nz-select{
width: 100%;
height: 50px;
// border:1px solid #dbdbdb;
// background-color: #ffffff;
border: 0px;
// outline: 1px solid rgb(204,204,204);
}
.body{
background-color: #C2D9FF;
height: 1200px;
}
input{
width:100%;
height:50px;
border:1px solid #dbdbdb;
outline:none;
font-size:20px;
text-indent:10px;
}
.model-content{
width: 80%;
margin: 0 auto;
min-width: 1200px;
padding-top: 20px;
.gruop_load{
display: block;
}
.title{
width: 800px;
background-color: #ffffff;
padding: 30px;
border-radius: 10px;
margin: 0 auto;
box-shadow: 5px 5px 10px #9DC3F1;
position: relative;
}
.button_add{
border: 2px solid #ddd;
margin: 20px;
width: 200px;
height: 100px;
border-radius: 5px;
background-color: #fafafa;
outline: none;
position: absolute;
right :50px;
top: 150px;
}
}
.upload_items{
display: flex;
flex-wrap: wrap;
margin-top: 20px;
.load_values_item{
border-radius: 10px;
width: 24%;
padding: 30px;
margin: 0 0.5%;
box-sizing: border-box;
position: relative;
box-shadow: 5px 5px 20px #9DC3F1;
background-color: #ffffff;
}
.button_remove{
position: absolute;
top: 20px;
right: 25px;
}
}
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 {
// 储存数据用 KEY = 'hw-24';
saveKey = "test_0011";
// 储存对象
item;
values = [];
constructor(private appRef: ApplicationRef,private changeDetectorRef: ChangeDetectorRef) { _item: any;
set item(item) {
this._item = item;
// this.init();
}
get item() {
return this._item;
} }
@Output()
update = new EventEmitter();
ngOnInit() { constructor(private appRef: ApplicationRef,
public changeDetectorRef: ChangeDetectorRef){
}
this.item = {}; init(){
if ( !this.item.contentObj ) {
this.item.contentObj = {};
}
if (this.item.contentObj.values) {
this.values = this.item.contentObj.values;
} else {
const arr = [];
this.values = arr;
this.item.contentObj.values = this.values;
}
if(!this.item.contentObj.title){
this.item.contentObj.title = {
text:"",
audio_url:"",
number: ""
};
}
if(!this.item.audio_url){
this.item.audio_url = "";
}
}
// 获取存储的数据 onImageUploadSuccessByItem(e, item, id = null) {
(<any> window).courseware.getData((data) => {
if (data) { if (id != null) {
this.item = data; item[id + '_img_url'] = e.url;
} } else {
item.img_url = e.url;
}
this.init(); this.save();
this.changeDetectorRef.markForCheck(); }
this.changeDetectorRef.detectChanges();
this.refresh(); onAudioUploadSuccessByItem(e, item, id = null) {
}, this.saveKey); if (id != null) {
item[id + '_audio_url'] = e.url;
} else {
item.audio_url = e.url;
}
this.save();
} }
addValue() {
this.values.push({
number : "false",
text: "",
answer: [],
audio_url: "",
img_url: "",
answer_color:"000000",
word : []
});
console.log('values', this.values);
ngOnChanges() { this.save();
} }
ngOnDestroy() { deleteValue(data) {
console.log("删除");
const index = this.values.indexOf(data);
if (index !== -1) {
this.values.splice(index, 1);
}
this.save();
} }
ngOnInit() {
this.item = {};
this.item.contentObj = {};
this.item.contentObj.audio_url= "";
this.item.contentObj.title = {
text:"",
audio_url:"",
number:"",
};
init() {
} if(!this.item.contentObj.values){
const arr = [];
this.values = arr;
this.item.contentObj.values = this.values;
}
/**
* 储存图片数据
* @param e
*/
onImageUploadSuccess(e, key) {
this.item[key] = e.url; const getData = (<any> window).courseware.getData;
this.save(); getData((data) => {
}
if (data) {
this.item = data;
} else {
this.item = {};
}
if ( !this.item.contentObj ) {
this.item.contentObj = {};
}
this.refresh();
this.init();
/** this.changeDetectorRef.markForCheck();
* 储存音频数据 this.changeDetectorRef.detectChanges();
* @param e
*/
onAudioUploadSuccess(e, key) { }, this.KEY);
}
this.item[key] = e.url; saveItem() {
console.log(' in saveItem');
this.save(); this.save();
} }
sentence_handle(i){
let Arr = this.item.contentObj.values[i].text;
if(Arr == ""){
this.item.contentObj.values[i].word = [];
this.item.contentObj.values[i].answer = [];
}
else{
let value = Arr.split(/\s+/);
this.item.contentObj.values[i].word = value;
}
if(this.item.contentObj.values[i].word[this.item.contentObj.values[i].word.length - 1] == "")
this.item.contentObj.values[i].word.splice(this.item.contentObj.values[i].word.length - 1,1);
for(let j = 0;j < this.item.contentObj.values[i].answer.length;j++){
if(this.item.contentObj.values[i].answer[j] + 1 > this.item.contentObj.values[i].word.length){
this.item.contentObj.values[i].answer[j] = "";
}
}
if(this.item.contentObj.values[i].answer == [])
this.item.contentObj.values[i].answer = [];
this.item.contentObj.values[i].answer.sort(function(a, b){return a - b});
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);
} }
ngOnDestroy(): void {
throw new Error("Method not implemented.");
}
ngOnChanges(changes: import("@angular/core").SimpleChanges): void {
throw new Error("Method not implemented.");
}
} }
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;
...@@ -19,7 +15,7 @@ class Sprite { ...@@ -19,7 +15,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;
} }
...@@ -70,7 +66,7 @@ export class MySprite extends Sprite { ...@@ -70,7 +66,7 @@ export class MySprite extends Sprite {
_z = 0; _z = 0;
init(imgObj = null, anchorX: number = 0.5, anchorY: number = 0.5) { init(imgObj = null, anchorX:number = 0.5, anchorY:number = 0.5) {
if (imgObj) { if (imgObj) {
...@@ -162,7 +158,6 @@ export class MySprite extends Sprite { ...@@ -162,7 +158,6 @@ export class MySprite extends Sprite {
if (this._shadowFlag) { if (this._shadowFlag) {
this.ctx.shadowOffsetX = this._shadowOffsetX; this.ctx.shadowOffsetX = this._shadowOffsetX;
this.ctx.shadowOffsetY = this._shadowOffsetY; this.ctx.shadowOffsetY = this._shadowOffsetY;
this.ctx.shadowBlur = this._shadowBlur; this.ctx.shadowBlur = this._shadowBlur;
...@@ -180,21 +175,22 @@ export class MySprite extends Sprite { ...@@ -180,21 +175,22 @@ export class MySprite extends Sprite {
} }
} }
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.children[i] === this) {
if (this.visible) { if (this.visible) {
this.drawSelf(); this.drawSelf();
} }
} else { } else {
child.update();
this.children[i].update();
} }
} }
} }
...@@ -241,7 +237,7 @@ export class MySprite extends Sprite { ...@@ -241,7 +237,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 --;
} }
...@@ -250,9 +246,9 @@ export class MySprite extends Sprite { ...@@ -250,9 +246,9 @@ 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;
} }
} }
} }
...@@ -363,7 +359,7 @@ export class ColorSpr extends MySprite { ...@@ -363,7 +359,7 @@ export class ColorSpr extends MySprite {
g = 0; g = 0;
b = 0; b = 0;
createGSCanvas() { createGSCanvas(){
if (!this.img) { if (!this.img) {
return; return;
...@@ -378,8 +374,8 @@ export class ColorSpr extends MySprite { ...@@ -378,8 +374,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];
...@@ -413,7 +409,7 @@ export class GrayscaleSpr extends MySprite { ...@@ -413,7 +409,7 @@ export class GrayscaleSpr extends MySprite {
grayScale = 120; grayScale = 120;
createGSCanvas() { createGSCanvas(){
if (!this.img) { if (!this.img) {
return; return;
...@@ -424,8 +420,8 @@ export class GrayscaleSpr extends MySprite { ...@@ -424,8 +420,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];
...@@ -468,10 +464,10 @@ export class BitMapLabel extends MySprite { ...@@ -468,10 +464,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);
...@@ -484,9 +480,9 @@ export class BitMapLabel extends MySprite { ...@@ -484,9 +480,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;
...@@ -499,22 +495,22 @@ export class BitMapLabel extends MySprite { ...@@ -499,22 +495,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;
...@@ -545,7 +541,7 @@ export class Label extends MySprite { ...@@ -545,7 +541,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;
...@@ -564,7 +560,7 @@ export class Label extends MySprite { ...@@ -564,7 +560,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();
} }
...@@ -572,16 +568,16 @@ export class Label extends MySprite { ...@@ -572,16 +568,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 = 5;
// this._shadowOffsetY = 5; this._shadowOffsetY = 5;
// // 轻微模糊阴影 // 轻微模糊阴影
// this._shadowBlur = 5; this._shadowBlur = 5;
// } }
setOutline(width = 5, color = '#ffffff') { setOutline(width = 5, color = '#ffffff') {
...@@ -650,10 +646,11 @@ export class RichTextOld extends Label { ...@@ -650,10 +646,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}#`);
...@@ -676,8 +673,8 @@ export class RichTextOld extends Label { ...@@ -676,8 +673,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;
} }
...@@ -699,7 +696,7 @@ export class RichTextOld extends Label { ...@@ -699,7 +696,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();
} }
...@@ -735,7 +732,7 @@ export class RichTextOld extends Label { ...@@ -735,7 +732,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';
...@@ -760,7 +757,7 @@ export class RichText extends Label { ...@@ -760,7 +757,7 @@ export class RichText extends Label {
disH = 30; disH = 30;
constructor(ctx?: any) { constructor(ctx) {
super(ctx); super(ctx);
// this.dataArr = dataArr; // this.dataArr = dataArr;
...@@ -794,12 +791,12 @@ export class RichText extends Label { ...@@ -794,12 +791,12 @@ export class RichText extends Label {
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);
...@@ -839,40 +836,6 @@ export class RichText extends Label { ...@@ -839,40 +836,6 @@ export class RichText extends Label {
export class LineRect extends MySprite {
lineColor = '#ffffff';
lineWidth = 10;
setSize(w, h) {
this.width = w;
this.height = h;
}
drawLine() {
this.ctx.beginPath();
this.ctx.moveTo(this._offX, this._offY);
this.ctx.lineTo(this._offX + this.width, this._offY);
this.ctx.lineTo(this._offX + this.width, this._offY + this.height);
this.ctx.lineTo(this._offX, this._offY + this.height);
this.ctx.closePath();
this.ctx.lineWidth = this.lineWidth;
// this.ctx.fillStyle = "rgb(2,33,42)"; //指定填充颜色
// this.ctx.fill(); //对多边形进行填充
this.ctx.strokeStyle = this.lineColor; // "#ffffff";
this.ctx.stroke();
}
drawSelf() {
super.drawSelf();
this.drawLine();
}
}
export class ShapeRect extends MySprite { export class ShapeRect extends MySprite {
...@@ -931,83 +894,7 @@ export class ShapeCircle extends MySprite { ...@@ -931,83 +894,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, height - radius, radius, 0, Math.PI / 2);
// 矩形下边线
ctx.lineTo(radius, height);
// 左下角圆弧,弧度从1/2PI到PI
ctx.arc(radius, height - radius, radius, Math.PI / 2, Math.PI);
// 矩形左边线
ctx.lineTo(0, radius);
// 左上角圆弧,弧度从PI到3/2PI
ctx.arc(radius, radius, radius, Math.PI, Math.PI * 3 / 2);
// 上边线
ctx.lineTo(width - radius, 0);
// 右上角圆弧
ctx.arc(width - radius, radius, radius, Math.PI * 3 / 2, Math.PI * 2);
// 右边线
ctx.lineTo(width, height - radius);
ctx.closePath();
if (this.fill) {
ctx.fillStyle = this.fillColor;
ctx.fill();
}
if (this.stroke) {
ctx.lineWidth = this.lineWidth;
ctx.strokeStyle = this.strokeColor;
ctx.stroke();
}
ctx.restore();
}
drawSelf() {
super.drawSelf();
this.drawShape();
}
}
export class MyAnimation extends MySprite { export class MyAnimation extends MySprite {
...@@ -1054,13 +941,13 @@ export class MyAnimation extends MySprite { ...@@ -1054,13 +941,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'];
} }
} }
...@@ -1089,14 +976,14 @@ export class MyAnimation extends MySprite { ...@@ -1089,14 +976,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;
} }
} }
...@@ -1189,7 +1076,7 @@ export function tweenChange(item, obj, time = 0.8, callBack = null, easing = nul ...@@ -1189,7 +1076,7 @@ export function tweenChange(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);
}); });
} }
...@@ -1242,7 +1129,7 @@ export function moveItem(item, x, y, time = 0.8, callBack = null, easing = null) ...@@ -1242,7 +1129,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) {
...@@ -1268,7 +1155,7 @@ export function endShow(item, s = 1) { ...@@ -1268,7 +1155,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();
...@@ -1276,14 +1163,14 @@ export function endShow(item, s = 1) { ...@@ -1276,14 +1163,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();
} }
...@@ -1299,7 +1186,7 @@ export function hideItem(item, time = 0.8, callBack = null, easing = null) { ...@@ -1299,7 +1186,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();
} }
...@@ -1310,7 +1197,7 @@ export function showItem(item, time = 0.8, callBack = null, easing = null) { ...@@ -1310,7 +1197,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();
} }
...@@ -1328,9 +1215,9 @@ export function alphaItem(item, alpha, time = 0.8, callBack = null, easing = nul ...@@ -1328,9 +1215,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();
} }
...@@ -1350,7 +1237,7 @@ export function showStar(item, time = 0.8, callBack = null, easing = null) { ...@@ -1350,7 +1237,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();
} }
...@@ -1406,22 +1293,22 @@ export function getAngleByPos(px, py, mx, my) { ...@@ -1406,22 +1293,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;
} }
...@@ -1433,7 +1320,7 @@ export function getAngleByPos(px, py, mx, my) { ...@@ -1433,7 +1320,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);
} }
} }
...@@ -1443,7 +1330,7 @@ export function removeItemFromArr(arr, item) { ...@@ -1443,7 +1330,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);
...@@ -1508,20 +1395,18 @@ export function formatTime(fmt, date) { ...@@ -1508,20 +1395,18 @@ 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;
} }
...@@ -1573,9 +1458,9 @@ export function jelly(item, time = 0.7) { ...@@ -1573,9 +1458,9 @@ export function jelly(item, time = 0.7) {
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();
...@@ -1587,8 +1472,8 @@ export function showPopParticle(img, pos, parent, num = 20, minLen = 40, maxLen ...@@ -1587,8 +1472,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;
...@@ -1596,32 +1481,16 @@ export function showPopParticle(img, pos, parent, num = 20, minLen = 40, maxLen ...@@ -1596,32 +1481,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);
});
} }
} }
...@@ -1663,7 +1532,7 @@ export function shake(item, time = 0.5, callback = null, rate = 1) { ...@@ -1663,7 +1532,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);
}; };
......
...@@ -2,7 +2,9 @@ ...@@ -2,7 +2,9 @@
width: 100%; width: 100%;
height: 100%; height: 100%;
background: #ffffff; background: #ffffff;
background-repeat: no-repeat;
background-size: cover; background-size: cover;
overflow: hidden;
} }
#canvas { #canvas {
......
import {Component, ElementRef, ViewChild, OnInit, Input, OnDestroy, HostListener} from '@angular/core'; import {Component, ElementRef, ViewChild, OnInit, Input, OnDestroy, HostListener} from '@angular/core';
import { import {
MySprite,
Label, Label,
MySprite, tweenChange, moveItem,
rotateItem,
removeItemFromArr,
ShapeRect,
RichText,
} from './Unit'; } from './Unit';
import {res, resAudio} from './resources'; import {res, resAudio} from './resources';
...@@ -10,165 +15,89 @@ import {res, resAudio} from './resources'; ...@@ -10,165 +15,89 @@ 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 { THIS_EXPR } from '@angular/compiler/src/output/output_ast';
@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 {
@ViewChild('canvas', {static: true }) canvas: ElementRef;
@ViewChild('wrap', {static: true }) wrap: ElementRef;
// 数据 // 数据
data; _data;
audioObj = {};
ctx;
canvasWidth = 1280; // canvas实际宽度
canvasHeight = 720; // canvas实际高度
canvasBaseW = 1280; // canvas 资源预设宽度
canvasBaseH = 720; // canvas 资源预设高度
mx; // 点击x坐标
my; // 点击y坐标
// 资源
rawImages = new Map(res);
rawAudios = new Map(resAudio);
images = new Map(); images = new Map();
animationId: any; animationId: any;
winResizeEventStream = new Subject();
renderArr;
audioObj = {}; number_id = 1;
renderArr; index_item = 0;
mapScale = 1;
canvasLeft; canvasLeft;
canvasTop; canvasTop;
saveKey = 'test_0011'; optionRect;
btnLeft;
btnRight;
pic1;
pic2;
canTouch = true;
curPic;
@HostListener('window:resize', ['$event'])
onResize(event) {
this.winResizeEventStream.next();
}
ngOnInit() {
this.data = {};
// 获取数据
const getData = (<any> window).courseware.getData;
getData((data) => {
if (data && typeof data == 'object') {
this.data = data;
}
// console.log('data:' , data);
// 初始化 各事件监听
this.initListener();
// 若无数据 则为预览模式 需要填充一些默认数据用来显示
this.initDefaultData();
// 初始化 音频资源
this.initAudio();
// 初始化 图片资源
this.initImg();
// 开始预加载资源
this.load();
}, this.saveKey);
}
ngOnDestroy() { mx;
window['curCtx'] = null; my;
window.cancelAnimationFrame(this.animationId);
}
values_bool = [0,0,0,0];
load() { //按钮
img_button = [];
label_title;
items_Text = [[],[],[],[]];
item = [];
answer = [[],[],[],[]];
play_button;
label_title_top_bg;
// 预加载资源 @ViewChild('canvas') canvas: ElementRef;
this.loadResources().then(() => { @ViewChild('wrap') wrap: ElementRef;
window["air"].hideAirClassLoading(this.saveKey, this.data); canvasWidth = 1280;
this.init(); canvasHeight = 720;
this.update();
});
}
canvasBaseW = 1280;
canvasBaseH = 720;
init() { bgWidth = 1280;
bgHeight = 720;
this.initCtx(); ctx;
this.initData();
this.initView();
}
initCtx() { play_button_bool = false;
this.canvasWidth = this.wrap.nativeElement.clientWidth; currentTime = 0;
this.canvasHeight = this.wrap.nativeElement.clientHeight;
this.canvas.nativeElement.width = this.wrap.nativeElement.clientWidth; KEY = 'hw-24';
this.canvas.nativeElement.height = this.wrap.nativeElement.clientHeight;
//资源
rawImages = new Map(res);
rawAudios = new Map(resAudio);
this.ctx = this.canvas.nativeElement.getContext('2d'); winResizeEventStream = new Subject();
this.canvas.nativeElement.width = this.canvasWidth;
this.canvas.nativeElement.height = this.canvasHeight;
window['curCtx'] = this.ctx; @Input()
set data(data) {
this._data = data;
} }
get data() {
return this._data;
updateItem(item) {
if (item) {
item.update();
}
} }
updateArr(arr) { @HostListener('window:resize', ['$event'])
if (!arr) { onResize(event) {
return; this.winResizeEventStream.next();
}
for (let i = 0; i < arr.length; i++) {
arr[i].update(this);
}
} }
initListener() { initListener() {
this.winResizeEventStream this.winResizeEventStream
...@@ -209,6 +138,7 @@ export class PlayComponent implements OnInit, OnDestroy { ...@@ -209,6 +138,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);
}; };
...@@ -226,6 +156,7 @@ export class PlayComponent implements OnInit, OnDestroy { ...@@ -226,6 +156,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);
}; };
...@@ -269,26 +200,140 @@ export class PlayComponent implements OnInit, OnDestroy { ...@@ -269,26 +200,140 @@ export class PlayComponent implements OnInit, OnDestroy {
addTouchListener(); addTouchListener();
} }
checkClickTarget(target) {
playAudio(key, now = false, callback = null) { const rect = target.getBoundingBox();
const audio = this.audioObj[key]; if (this.checkPointInRect(this.mx, this.my, rect)) {
if (audio) { return true;
if (now) { }
audio.pause(); return false;
audio.currentTime = 0; }
}
if (callback) { initDefaultData() {
audio.onended = () => { console.log(this.data);
callback();
}; if ( !this.data.contentObj ) {
this.data.contentObj = {};
}
if(!this.data.contentObj.audio_url){
this.data.contentObj.audio_url= "";
}
if(!this.data.contentObj.title){
this.data.contentObj.title = {
text:"",
audio_url:"",
number: "",
};
}
if(!this.data.contentObj.values){
this.data.contentObj.values = [];
}
if(this.data.contentObj.values.length == 0 && this.data.contentObj.title.text == "" && this.data.contentObj.title.audio_url == "" && this.data.contentObj.audio_url == "" && this.data.contentObj.title.number == ""){
const value_Arr = [];
const text_1 = "I think the";
const text_2 = "could chew the"
for(let i = 0;i < 4;i++){
if(i % 2 == 0){
value_Arr.push({
text : text_1,
number : "true",
img_url : "assets/play/default/1.png",
audio_url : "assets/play/default/item1.mp3",
answer : "3",
answer_color: "B8C955",
word : ["I","think","the","chimp"]
})
}
else{
value_Arr.push({
text : text_2,
number : "false",
img_url : "assets/play/default/2.png",
audio_url : "assets/play/default/item2.mp3",
answer : "3",
answer_color: "613821",
word : ["could","chew","the","chick"]
})
}
} }
audio.play();
this.data.contentObj.title.text = 'Listen,trace and write.Then chant.';
this.data.contentObj.title.audio_url = 'assets/play/default/audio.mp3';
this.data.contentObj.audio_url = 'assets/play/music/demo.mp3';
this.data.contentObj.title.number = "c";
this.data.contentObj.values = value_Arr;
}
// if (!this.data.contentObj.title && !this.data.contentObj.audio_url) {
// this.data.contentObj.title.text = 'Listen,trace and write.Then chant.';
// this.data.contentObj.title.audio_url = 'assets/play/default/audio.mp3';
// this.data.contentObj.audio_url = 'assets/play/music/demo.mp3';
// console.log(123123);
// }
// if(this.data.contentObj.title.text == "" && this.data.contentObj.values.length == 0){
// this.data.contentObj.title.text = 'Listen,trace and write.Then chant.';
// console.log(123);
// }
}
//更新数据
updateArr(arr) {
if (!arr) {
return;
}
for (let i = 0; i < arr.length; i++) {
arr[i].update(this);
} }
} }
update() {
this.animationId = window.requestAnimationFrame(this.update.bind(this));
// 清除画布内容
this.ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight);
// 更新动画
TWEEN.update();
this.updateArr(this.renderArr);
}
//加载数据
load_date(){
const contentObj = this.data.contentObj;
if (contentObj) {
const addPicUrl = (url) => {
if (url) {
this.rawImages.set(url, url);
}
};
for(let i = 0; i < contentObj.values.length;i++){
addPicUrl(contentObj.values[i].img_url);
}
}
this.loadResources().then(() => {
// this.setfontData();
window['air'].hideAirClassLoading(this.KEY, this.data);
this.init();
this.update();
});
}
loadResources() { loadResources() {
const pr = []; const pr = [];
...@@ -303,7 +348,7 @@ export class PlayComponent implements OnInit, OnDestroy { ...@@ -303,7 +348,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(() => {
...@@ -315,17 +360,16 @@ export class PlayComponent implements OnInit, OnDestroy { ...@@ -315,17 +360,16 @@ export class PlayComponent implements OnInit, OnDestroy {
}); });
return Promise.all(pr); return Promise.all(pr);
} }
//加载图片
preload(url) { preload(url) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const img = new Image(); const img = new Image();
// img.crossOrigin = "anonymous";
img.onload = () => resolve(img); img.onload = () => resolve(img);
img.onerror = reject; img.onerror = reject;
img.src = url; img.src = url;
}); });
} }
//加载声音
preloadAudio(url) { preloadAudio(url) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const audio = new Audio(); const audio = new Audio();
...@@ -340,7 +384,6 @@ export class PlayComponent implements OnInit, OnDestroy { ...@@ -340,7 +384,6 @@ export class PlayComponent implements OnInit, OnDestroy {
}); });
} }
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;
...@@ -348,332 +391,437 @@ export class PlayComponent implements OnInit, OnDestroy { ...@@ -348,332 +391,437 @@ export class PlayComponent implements OnInit, OnDestroy {
} }
ngOnInit() {
const getData = (<any> window).courseware.getData;
getData((data) => {
if (data && typeof data == 'object') {
this.data = data;
} else {
this.data = {msg: "xxxx"};
}
checkClickTarget(target) { this.initDefaultData();
const rect = target.getBoundingBox(); this.load_date();
this.initAudio();
this.initListener();
}, this.KEY);
}
if (this.checkPointInRect(this.mx, this.my, rect)) { initData(){
return true; this.renderArr = [];
}
return false;
} }
getWorlRect(target) { initAudio() {
let rect = target.getBoundingBox(); const contentObj = this.data.contentObj;
if (!contentObj) { return; }
if (target.parent) { const addUrlToAudioObj = (audioUrl) => {
const pRect = this.getWorlRect(target.parent); if (audioUrl) {
rect.x += pRect.x;
rect.y += pRect.y;
}
return rect;
}
checkPointInRect(x, y, rect) { const audio = new Audio();
if (x >= rect.x && x <= rect.x + rect.width) { audio.src = audioUrl;
if (y >= rect.y && y <= rect.y + rect.height) { audio.load();
return true; this.audioObj[audioUrl] = audio;
} }
} };
return false;
}
let arr = contentObj.values;
if (arr) {
for (let i = 0; i < arr.length; i++) {
addUrlToAudioObj(arr[i].audio_url);
}
}
addUrlToAudioObj(this.data.contentObj.audio_url);
addUrlToAudioObj(this.data.contentObj.title.audio_url);
addUrlToAudioObj("assets/play/music/click.mp3");
addUrlToAudioObj(key, url = null, vlomue = 1, loop = false, callback = null) {
const audioObj = this.audioObj; const audioObj = this.audioObj;
const addOneAudio = (key, url, vlomue = 1, loop = false, callback = null) => {
if (url == null) { const audio = new Audio();
url = key; audio.src = url;
} audio.load();
audio.loop = loop;
this.rawAudios.set(key, url); audio.volume = vlomue;
const audio = new Audio(); audioObj[key] = audio;
audio.src = url;
audio.load();
audio.loop = loop;
audio.volume = vlomue;
audioObj[key] = audio; if (callback) {
audio.onended = () => {
callback();
};
}
};
if (callback) {
audio.onended = () => {
callback();
};
}
} }
addUrlToImages(url) { ngOnDestroy() {
this.rawImages.set(url, url);
} }
playAudio(key, now = false, callback = null) {
const audio = this.audioObj[key];
if (audio) {
if (now) {
audio.pause();
audio.currentTime = 0;
}
if (callback) {
audio.onended = () => {
callback();
// ======================================================编写区域========================================================================== };
}
audio.play();
/**
* 添加默认数据 便于无数据时的展示
*/
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';
} }
console.log(this.audioObj);
} }
playAudio_ps(bool,key){
/** const audio = this.audioObj[key];
* 添加预加载图片 if(!bool){
*/ audio.currentTime = this.currentTime;
initImg() { this.play_button.init(this.images.get('stop'));
audio.play();
this.addUrlToImages(this.data.pic_url); this.play_button_bool = !bool;
this.addUrlToImages(this.data.pic_url_2); }
else{
} audio.pause();
this.play_button.init(this.images.get('play'));
/** this.currentTime = audio.currentTime;
* 添加预加载音频 this.play_button_bool = !bool;
*/ }
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; init() {
this.canvasWidth = this.wrap.nativeElement.clientWidth;
const pic1 = new MySprite(); this.canvasHeight = this.wrap.nativeElement.clientHeight;
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; this.canvas.nativeElement.width = this.wrap.nativeElement.clientWidth;
} this.canvas.nativeElement.height = this.wrap.nativeElement.clientHeight;
this.initData();
this.initCtx();
this.initView();
btnLeftClicked() { window["air"].hideAirClassLoading("hw_006",this.data);
}
this.lastPage(); initCtx() {
}
btnRightClicked() { this.ctx = this.canvas.nativeElement.getContext('2d');
this.canvas.nativeElement.width = this.canvasWidth;
this.canvas.nativeElement.height = this.canvasHeight;
this.nextPage(); window['curCtx'] = this.ctx;
this.ctx.font="64px MMTextBook-Bold";
} }
lastPage() { addBlanks(item,text_value,as_v){
const Blanks = new Label();
if (this.curPic == this.pic1) { Blanks.text = "";
return; for(let x = 0; x < text_value.length;x++)
{
Blanks.text += "_";
} }
Blanks.fontSize = item.fontSize;
this.canTouch = false; Blanks.width = this.ctx.measureText(Blanks.text).width;
Blanks.height = 60;
const moveLen = this.canvasWidth; Blanks.textAlign = 'center';
tweenChange(this.pic1, {x: this.pic1.x + moveLen}, 1); Blanks.fontColor = "#000000";
tweenChange(this.pic2, {x: this.pic2.x + moveLen}, 1, () => { Blanks.fontSize = 64;
this.canTouch = true;
this.curPic = this.pic1; Blanks.x = this.ctx.measureText(item.text).width;
}); Blanks.y = item.y + 5;
} this.items_Text[this.index_item][as_v] = Blanks;
nextPage() { item.addChild(Blanks);
}
if (this.curPic == this.pic2) {
return; addAnswer(item,as,index,bool){
const Answer = new Label();
if(bool[index]){
Answer.text = this.data.contentObj.values[index].word[this.data.contentObj.values[index].answer[as]];
}
else
Answer.text = "";
Answer.fontColor = "#" + this.data.contentObj.values[index].answer_color;
Answer.textAlign = 'center';
Answer.fontSize = item.fontSize;
Answer.width = this.ctx.measureText(Answer.text).width;
Answer.x = this.ctx.measureText(item.text).width;
this.answer[index][as] = Answer;
item.addChild(Answer);
}
//Answer.text = this.data.contentObj.values[index].answer;
addNumber(item,Arr,nu){
const Number = new Label();
Number.fontName = "MMTextBook-Bold";
console.log(item);
if(Arr[nu].number == "true"){
Number.text = this.number_id + ". ";
Number.fontSize = item.fontSize;
Number.color = "#000000";
this.number_id+=1;
}
else{
Number.text = " ";
Number.fontSize = item.fontSize;
Number.color = "#000000";
}
Number.x = -70;
// Number.y = 5;
item.addChild(Number);
}
initView(){
let Bgx = document.body.clientWidth /this.bgWidth;
let Bgy = document.body.clientHeight /this.bgHeight;
// let Bgy = document.body.clientWidth /this.bgHeight;
const bg_img = new MySprite();
bg_img.init(this.images.get('bg'));
bg_img.width = 0;
bg_img.height = 200;
bg_img.setScaleXY(1);
const play_button = new MySprite();
play_button.init(this.images.get('play'));
play_button.setScaleXY(Math.max(Math.min(Bgx ,Bgy) * 0.8,0.2));
play_button.x = document.body.clientWidth - (50 * document.body.clientWidth / 1600);
this.play_button = play_button;
play_button.y = document.body.clientHeight - (40 * document.body.clientHeight / 805);
if(this.play_button_bool,this.data.contentObj.audio_url)
bg_img.addChild(play_button);
this.renderArr.push(bg_img);
const label_title_top_bg = new MySprite();
label_title_top_bg.init(this.images.get('title_bg'));
label_title_top_bg.setScaleXY(Bgx * 0.4);
const sx = this.canvasWidth / this.canvasBaseW;
label_title_top_bg.x = 65 * sx + 105 * (document.body.clientWidth / 1600);
label_title_top_bg.y = Bgx * 26;
const label_title_top = new Label();
label_title_top.text = this.data.contentObj.title.number.toUpperCase();
label_title_top.setScaleXY(1);
label_title_top.fontSize = 110;
label_title_top.y = 0;
label_title_top.fontColor = '#FFDB84';
label_title_top.textAlign = 'center';
label_title_top.fontName = 'BRLNSDB';
label_title_top_bg.addChild(label_title_top);
const label_title = new Label();
label_title.text = this.data.contentObj.title.text;
label_title.fontName = 'BRLNSDB';
label_title.setMaxSize(1000);
label_title.fontSize = Math.min(Bgx * 50,55);
// label_title.x = label_title_top_bg.x - 800 + label_title_top_bg.width / 2 * Bgx + this.ctx.measureText(label_title.text).width * Bgx;
label_title.x = label_title_top_bg.x + label_title_top_bg.width / 2 * Bgx + this.ctx.measureText(label_title.text).width * label_title.fontSize / 64 / 2;
label_title.y = label_title_top_bg.y;
label_title.fontColor = '#000';
label_title.textAlign = 'center';
bg_img.addChild(label_title_top_bg);
this.label_title = label_title;
bg_img.addChild(label_title);
const optionRect = new ShapeRect();
optionRect.init();
optionRect.fillColor = '#ffffff';
optionRect.x = this.wrap.nativeElement.clientWidth / 2;
optionRect.y = this.wrap.nativeElement.clientHeight * 0.5;
optionRect.width = this.wrap.nativeElement.clientWidth;
optionRect.height = this.wrap.nativeElement.clientHeight * 0.75;
optionRect.setShadow(0, 4, 10);
this.renderArr.push(optionRect);
this.optionRect = optionRect;
let Arr = this.data.contentObj.values;
this.number_id = 1;
this.index_item = 0;
let c = true;
for(let i = 0; i < Arr.length;i++){
let as_v = 0;
const items = new Label();
items.fontName = 'MMTextBook-Bold';
items.fontSize = 64;
items.text = "";
c = true;
for(let j = 0; j < Arr[i].word.length; j++){
if(j != Arr[i].answer[as_v])
items.text += Arr[i].word[j] + " ";
else{
for(let x = 0; x < Arr[i].word[j].length;x++)
{
if(x == Math.floor(Arr[i].word[j].length / 2 ))
{
items.text += " ";
this.addBlanks(items,Arr[i].word[Arr[i].answer[as_v]],as_v);
this.addAnswer(items,as_v,i,this.values_bool);
as_v++;
}
items.text += " ";
}
items.text += " ";
}
}
items.text += ".";
items.y = Bgy * 100 * i - Bgy * 160;
items.x = -Bgx * 450;
items.width = items.text.length * 30;
items.setScaleXY(Math.min(Bgx,Bgy));
if(this.values_bool[i])
items.fontColor = "#000000";
else
items.fontColor = "#DEE0DF";
this.item[i] = items;
this.addNumber(items,Arr,i);
const img = new MySprite();
img.init(this.images.get(Arr[i].img_url));
console.log(img.height);
img.setScaleXY(Math.min(300 / img.width,140 / img.height) * Math.min(Math.max(Bgx,Bgy) * 0.6,0.7));
img.x = this.ctx.measureText(items.text).width + 100;
this.img_button[i] = img;
items.addChild(img);
optionRect.addChild(items);
this.index_item++;
} }
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() { onclick_img(index){
this.playAudio(this.data.audio_url_2); this.playAudio(this.data.contentObj.values[index].audio_url, true);
return;
} }
onclick_items_text(item,index){
item.fontColor = "#000000";
for(let i = 0; i < this.items_Text[index].length;i++){
this.answer[index][i].text = this.data.contentObj.values[index].word[this.data.contentObj.values[index].answer[i]];
}
}
mapDown(event) { mapDown(event) {
if (!this.canTouch) { if(this.checkClickTarget(this.label_title)){
this.playAudio(this.data.contentObj.title.audio_url, true);
return; return;
} }
if ( this.checkClickTarget(this.btnLeft) ) { if(this.checkClickTarget(this.play_button)){
this.btnLeftClicked(); this.playAudio_ps(this.play_button_bool,this.data.contentObj.audio_url);
return;
}
if ( this.checkClickTarget(this.btnRight) ) {
this.btnRightClicked();
return;
} }
if ( this.checkClickTarget(this.pic1) ) { for(let i = 0; i < this.data.contentObj.values.length; i++){
this.pic1Clicked(); if(this.checkClickTarget(this.img_button[i])){
return;
this.onclick_img(i);
return;
}
} }
if ( this.checkClickTarget(this.pic2) ) {
this.pic2Clicked(); for(let i = 0; i < this.data.contentObj.values.length; i++){
return; for(let j = 0;j < this.items_Text[i].length;j++){
if(this.checkClickTarget(this.items_Text[i][j])){
this.onclick_items_text(this.item[i],i);
this.values_bool[i] = 1;
console.log(this.values_bool);
if(this.data.contentObj.values[i].audio_url)
this.playAudio(this.data.contentObj.values[i].audio_url, true);
else
this.playAudio('assets/play/default/click.mp3',true);
// this.onclick_items_text(this.items_Text);
return;
}
}
} }
} }
mapMove(event) { mapMove(event){
} }
mapUp(event){
mapUp(event) {
} }
checkPointInRect(x, y, rect) {
if (x >= rect.x && x <= rect.x + rect.width) {
if (y >= rect.y && y <= rect.y + rect.height) {
return true;
}
}
return false;
}
getPosByAngle(angle, len) {
update() { const radian = angle * Math.PI / 180;
const x = Math.sin(radian) * len;
// ---------------------------------------------------------- const y = Math.cos(radian) * 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);
return {x, y};
} }
getPosDistance(sx, sy, ex, ey) {
const _x = ex - sx;
const _y = ey - sy;
const len = Math.sqrt( Math.pow(_x, 2) + Math.pow(_y, 2) );
return len;
}
} }
const res = [ const res = [
// ['bg', "assets/play/bg.jpg"], ['bg', "assets/play/bg.png"],
['btn_left', "assets/play/btn_left.png"], ['btn_left', "assets/play/btn_left.png"],
['btn_right', "assets/play/btn_right.png"], ['btn_right', "assets/play/btn_right.png"],
// ['text_bg', "assets/play/text_bg.png"], ['text_bg', "assets/play/text_bg.png"],
['play',"assets/play/play.png"],
['stop',"assets/play/stop.png"],
['title_bg',"assets/play/bg_top.png"]
]; ];
...@@ -11,7 +15,10 @@ const res = [ ...@@ -11,7 +15,10 @@ const res = [
const resAudio = [ const resAudio = [
['click', "assets/play/music/click.mp3"],
// ['click', "assets/play/music/click.mp3"],
]; ];
......
import { TestBed } from '@angular/core/testing';
import { ConfigService } from './config.service';
describe('ConfigService', () => {
beforeEach(() => TestBed.configureTestingModule({}));
it('should be created', () => {
const service: ConfigService = TestBed.get(ConfigService);
expect(service).toBeTruthy();
});
});
import { Injectable } from '@angular/core';
import {HttpClient} from "@angular/common/http";
import {Observable} from "rxjs";
@Injectable({
providedIn: 'root'
})
export class ConfigService {
configUrl = 'proxy.conf.json';
constructor( private http: HttpClient ) { }
getConfig() {
return this.http.get(this.configUrl)
.pipe(
);
}
showConfig() {
this.getConfig()
.subscribe((data) => {
console.log('data:', data);
});
}
test(data) {
// return new Promise<any> {
// return new Promise((resolve, reject) => {
// this.http.get(url).subscribe((res) => {
// resolve(res);
// }, reject);
// });
//
return this.get('/api/login');
// return this.http.post('/login', data);
}
get(url: string): Promise<any> {
return new Promise((resolve, reject) => {
this.http.get(url).subscribe((res) => {
resolve(res);
}, reject);
});
}
// login(user): Observable<any> {
//
//
// return this.http.post('/login', user).pipe(
// tap((data => {
// console.log('login', data)
// localStorage.setItem('token', _.get(data, 'token'));
// delete data['token'];
// localStorage.setItem('info', JSON.stringify(data));
// this.getInfoPromise = this.load('/user/getInfo');
// }))
// );
// }
}
@mixin hide-overflow-text {
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
@mixin k-no-select {
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
@mixin k-img-bg {
background-repeat: no-repeat;
background-position: center;
background-size: contain;
}
.anticon{
vertical-align: .1em!important;
}
File mode changed from 100755 to 100644
File mode changed from 100644 to 100755
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
...@@ -4,11 +4,12 @@ ...@@ -4,11 +4,12 @@
<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>
......
<!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>
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