import { Component, EventEmitter, Input, OnDestroy, OnChanges, OnInit, Output, ApplicationRef, ChangeDetectorRef, ViewChild, ViewChildren } from '@angular/core'; import * as _ from 'lodash'; import { NzMessageService } from 'ng-zorro-antd'; import {HttpClient} from '@angular/common/http'; import html2canvas from 'html2canvas'; const AnimationType = [ { name: 'Slide', value: 'animated fadeInRight' }, { name: 'Fade', value: 'animated fadeInDown' }, { name: 'Zoom', value: 'animated zoomInUp' }, { name: 'Jack', value: 'animated rotateIn' // jackInTheBox }, { name: 'Roll', value: 'animated rollIn' } ]; @Component({ selector: 'app-form', templateUrl: './form.component.html', styleUrls: ['./form.component.scss'] }) export class FormComponent implements OnInit, OnChanges, OnDestroy { // 储存数据用 saveKey = 'ww_text'; // 储存对象 item; @ViewChild('box', {static: true}) box; @ViewChildren('list') list; curDom; itemBackup: any; isMovingItem = false; ratio: number; moveOffset: any; fontFamilyList: string[]; fontSizeRange: number[]; colorList: string[]; MIN_FONT_SIZE = 1; MAX_FONT_SIZE = 12; isShowFontColorPane = false; isShowBGColorPane = false; isShowAnimationPane = false; isShowAnimationOrder = true; fontFamily: string; bgColor: string; fontSize: number; fontColor = 'black'; position: any; curAnimationName: string; animations: any[]; _selectedAnimation: any; extraData = { changeDirtyCount: 0 }; _curItem; set curItem(value) { let changed = false; if (_.get(value, 'id') !== _.get(this._curItem, 'id')) { changed = true; } this._curItem = value; if (changed) { this.onCurItemChanged(); } } get curItem() { return this._curItem; } set selectedAnimation(value) { let changed = false; if (_.get(value, 'id') !== _.get(this._selectedAnimation, 'id')) { changed = true; } this._selectedAnimation = value; if (changed) { this.onSelectedAnimationChanged(); } } get selectedAnimation() { return this._selectedAnimation; } AnimationType = AnimationType; uploadUrl; uploadData; constructor(private appRef: ApplicationRef, private http: HttpClient, private nzMessageService: NzMessageService, private changeDetectorRef: ChangeDetectorRef) { this.uploadUrl = (<any> window).courseware.uploadUrl(); this.fontSizeRange = []; for (let i = this.MIN_FONT_SIZE; i <= this.MAX_FONT_SIZE; ++i) { this.fontSizeRange.push(i); } const color_black = '#111111'; const color_gray = '#aaaaaa'; const color_silver = '#dddddd'; const color_navy = '#001f3f'; const color_blue = '#0074d9'; const color_aqua = '#7fdbff'; const color_teal = '#39cccc'; const color_olive = '#3d9970'; const color_green = '#2ecc40'; const color_lime = '#01ff70'; const color_yellow = '#ffdc00'; const color_orange = '#ff851b'; const color_red = '#ff4136'; const color_maroon = '#85144b'; const color_fuchsia = '#f012be'; const color_purple = '#b10dc9'; // Ken 2018-10-30 14:37 宁波那边要加5个颜色 this.colorList = [ color_black, 'white', '#595959', color_gray, color_silver, color_navy, color_blue, 'blue', color_aqua, color_teal, '#64c0bd', color_olive, '#72ac4d', color_green, color_lime, 'yellow', color_yellow, color_orange, '#f45970', color_red, '#be0712', color_maroon, color_fuchsia, color_purple ]; this.fontFamilyList = [ 'Arial', 'monospace', 'ChalkboardSE-Regular' ]; } init() { this.curItem = null; this.extraData.changeDirtyCount = 0; this.isMovingItem = false; this.item.contentObj.items = this.item.contentObj.items || []; // ver 区分数据 this.item.contentObj.ver = this.item.contentObj.ver || 1; this.animations = this.item.contentObj.animations = this.item.contentObj.animations || []; // Ken 2018-09-14 09:33 为item添加id属性, 对于旧数据, 要自动添加此属性 if (!_.get(this.item.contentObj.items, '[0].id')) { this.item.contentObj.items.forEach((item, index) => { item.id = index + 1; }); } this.itemBackup = _.cloneDeep(this.item); } ngOnInit() { this.item = { contentObj: {} }; this.init(); // 获取存储的数据 ( window as any).courseware.getData((data) => { if (data) { this.item = data; } this.init(); this.changeDetectorRef.markForCheck(); this.changeDetectorRef.detectChanges(); this.refresh(); }, this.saveKey); } ngOnChanges() { } ngOnDestroy() { } /** * 储存数据 */ save() { (window as any).courseware.setData(this.item, null, this.saveKey); this.refresh(); } /** * 刷新 渲染页面 */ refresh() { setTimeout(() => { this.appRef.tick(); }, 1); } resize(rect) { if (!this.box) { return; } this.ratio = rect.clientWidth / this.box.nativeElement.clientWidth; this.box.nativeElement.style.transform = `scale(${this.ratio})`; } onEdit(item, event) { item._inEdit = true; const dom = event.target; dom.setAttribute('contenteditable', ''); dom.classList.add('p-edit'); dom.focus(); event.stopPropagation(); event.preventDefault(); } onBlur(item, dom) { if (dom.innerText) { if (item.text !== dom.innerText.trim()) { item.text = dom.innerText.trim(); this.extraData.changeDirtyCount++; } item._inEdit = false; dom.removeAttribute('contenteditable'); dom.classList.remove('p-edit'); } else { this.onBtnDelete(); } } onTitleChange() { this.extraData.changeDirtyCount = this.extraData.changeDirtyCount+1; this.createCover(); } createCover() { html2canvas(document.getElementById("canvas")).then((canvas) => { // document.body.appendChild(canvas); const video_preview_thumb = canvas.toDataURL(); const img = this.convertImageToBlob(video_preview_thumb); const formData = new FormData(); const ext = img.type.replace('image/', ''); formData.append('file', img, `cover.${ext}`); this.http.post(this.uploadUrl, formData).subscribe( (res: any) => { (window as any).courseware.sendEvent("screenshot", {"url": res.url}, this.saveKey); }, (err) => { console.log(err); this.nzMessageService.error('封面截取失败'); } ); }); } convertImageToBlob(data) { const imgType = data.substring(data.indexOf(':') + 1, data.indexOf(';')); const binary = atob(data.split(',')[1]); const array = []; let i = 0; while (i < binary.length) { array.push (binary.charCodeAt(i)); i++; } return new Blob([ new Uint8Array(array) ], {type: imgType}); } onSelect(item, event) { this.curItem = item; this.curDom = event.target; this.fontSize = this.curItem.fontSize; this.fontFamily = this.curItem.fontFamily; event.stopPropagation(); } onClickBox() { this.curItem = null; } onChangeFontFamily() { this.curItem.fontFamily = this.fontFamily; this.extraData.changeDirtyCount++; } onChangeFontSize(delta = 0) { if (!this.curItem) { return; } this.fontSize = this.fontSize + delta; this.fontSize = Math.max(this.MIN_FONT_SIZE, this.fontSize); this.fontSize = Math.min(this.MAX_FONT_SIZE, this.fontSize); this.curItem.fontSize = this.fontSize; this.extraData.changeDirtyCount++; } onChangeFontColor() { if (!this.curItem) { return; } this.curItem.color = this.fontColor; this.extraData.changeDirtyCount++; } onChangeColor(color) { if (this.isShowBGColorPane) { this.item.contentObj.bgColor = color; this.extraData.changeDirtyCount++; } else if (this.isShowFontColorPane) { this.fontColor = this.curItem.color = color; this.extraData.changeDirtyCount++; } } absolute2Relative(value) { return value * this.ratio; } relative2Absolute(value) { return value / this.ratio; } onMouseDown(item, event) { if (item !== this.curItem) { return; } if (this.curItem && !this.curItem._inEdit) { this.isMovingItem = true; this.moveOffset = {x: event.x, y: event.y}; } } onMouseMove(event) { if (this.isMovingItem) { if (this.curItem) { this.curItem.position.left += this.relative2Absolute(event.x - this.moveOffset.x); this.curItem.position.top += this.relative2Absolute(event.y - this.moveOffset.y); this.moveOffset = {x: event.x, y: event.y}; this.extraData.changeDirtyCount++; } } } onMouseUp(event) { this.isMovingItem = false; } onBtnSave() { this.createCover(); this.save(); this.extraData.changeDirtyCount = 0; } onMoveSentence(x, y, event) { if (this.curItem && !this.curItem._inEdit) { this.curItem.position.left += x; this.curItem.position.top += y; this.extraData.changeDirtyCount++; event.stopPropagation(); event.preventDefault(); } } onBtnMoveToCenter(isHorizontal, isVertical) { if (!this.curItem) { return; } const {clientWidth, clientHeight} = this.curDom; const {clientWidth: boxClientWidth, clientHeight: boxClientHeight} = this.box.nativeElement; if (isHorizontal) { this.curItem.position.left = (boxClientWidth - clientWidth) / 2; } if (isVertical) { this.curItem.position.top = (boxClientHeight - clientHeight) / 2; } this.extraData.changeDirtyCount++; } onNewSentence(event) { const left = this.relative2Absolute(event.layerX); const top = this.relative2Absolute(event.layerY); const id = _.get(_.last(this.item.contentObj.items), 'id') || 0; const item = { id: id + 1, color: this.fontColor, text: 'text', fontFamily: this.fontFamily || 'Arial', fontSize: this.fontSize || 6, _inEdit: false, position: {left, top} }; this.item.contentObj.items.push(item); setTimeout(() => { item._inEdit = true; const dom = _.get(this.box.nativeElement.getElementsByClassName('p-selected'), '[0]'); if (dom) { dom.setAttribute('contenteditable', ''); dom.classList.add('p-edit'); dom.focus(); item.position.top -= (dom.clientHeight / 2); this.extraData.changeDirtyCount++; document.execCommand('selectAll', false, null); } }, 1); this.curItem = item; this.extraData.changeDirtyCount++; } onBtnDelete() { const removedItem = _.remove(this.item.contentObj.items, (i) => { return i === this.curItem; }); if (removedItem) { this.extraData.changeDirtyCount++; _.remove(this.animations, {id: this.curItem.id}); this.curItem = null; } } onBtnRestore() { this.extraData.changeDirtyCount = 0; this.curItem = null; this.item = _.cloneDeep(this.itemBackup); this.animations = this.item.contentObj.animations; } onBtnShowAnimationPane() { this.isShowAnimationPane = !this.isShowAnimationPane; } onBtnToggleDisplayAnimationOrder() { this.isShowAnimationOrder = !this.isShowAnimationOrder; } onBtnMoveAnimation(value) { // [value] -1: MoveUp, 1: MoveDown if (!this.selectedAnimation) { this.nzMessageService.error(`Please select an animation first`); return; } const index = _.findIndex(this.animations, this.selectedAnimation); const tmp = this.animations[index + value]; if (tmp) { this.animations[index + value] = this.animations[index]; this.animations[index] = tmp; this.extraData.changeDirtyCount++; } else { // this.nzMessageService.error(`MoveAnimation Error, index = ${index}, length = ${this.animations.length}`); } } onBtnRemoveAnimation() { const removed = _.remove(this.animations, {id: this.selectedAnimation.id}); if (removed) { this.extraData.changeDirtyCount++; } } onClickAnimation(item) { this.selectedAnimation = item; this.curAnimationName = item.value; } onSetAnimation(item) { if (!this.curItem) { this.nzMessageService.warning('Please select a text which you want to set animation'); return; } const animation = _.find(this.animations, {id: this.curItem.id}); if (!animation) { this.animations.push({ id: this.curItem.id, name: item.name, value: item.value, initStyle: {opacity: 0}, beforeAnimation: {opacity: 1}, }); this.extraData.changeDirtyCount++; } else if (animation.name !== item.name) { animation.name = item.name; animation.value = item.value; this.extraData.changeDirtyCount++; } } // curItem changed onCurItemChanged() { if (!this.curItem) { this.selectedAnimation = null; this.curAnimationName = null; return; } this.selectedAnimation = _.find(this.animations, {id: this.curItem.id}); if (this.selectedAnimation) { this.curAnimationName = this.selectedAnimation.value; } } // selectedAnimation changed onSelectedAnimationChanged() { if (!this.selectedAnimation) { return; } this.curItem = _.find(this.item.contentObj.items, {id: this.selectedAnimation.id}); } getIndexOfAnimationByItem(item) { return _.findIndex(this.animations, {id: item.id}); } }