import { Component, OnInit, Input, HostBinding, Renderer2, AfterViewInit, ElementRef, HostListener, Output, EventEmitter, OnDestroy } from '@angular/core'; import { fromEvent, Subscription, BehaviorSubject } from 'rxjs'; import { IPosition, Position } from './helper/position'; import { HelperBlock } from './helper/helper-block'; @Component({ selector: 'farris-splitter-bar', template: ` ss `, host: { 'ngDraggable': 'true' }, styles: [` :host{ width: 8px; background: #ebebeb; cursor: move; } ` ] }) export class SplitterBarComponent implements OnInit, AfterViewInit, OnDestroy { // 这个组件没有被使用过,目前实现拖拽都是用ngResizable @HostBinding('class.f-component-splitter-bar') klass = true; // @HostBinding('attr.ngDraggable') draggable = true; @Input() zIndexMoving: any; @Input() position: IPosition = { x: 0, y: 0 }; @Input() trackPosition = true; @Input() gridSize = 1; @Input() lockAxis: string = null; @Input() scale = 1; @Output() started = new EventEmitter(); @Output() stopped = new EventEmitter(); @Output() edge = new EventEmitter(); @Output() endOffset = new EventEmitter(); @Output() movingOffset = new EventEmitter(); set order(value: number) { this._order = value; this.orderState.next(value); } _order: number; orderState = new BehaviorSubject({}); el: HTMLElement allowDrag: boolean = true; preventDefaultEvent: boolean = true; oldZIndex: any; rightMovedMax: any; leftMovedMax: any; // 鼠标初始位置 private orignal: Position = null; private draggingSub: Subscription = null; private moving = false; private _zIndex: any; private _helperBlock: HelperBlock = null; private needTransform = false; private oldTrans = new Position(0, 0); private tempTrans = new Position(0, 0); private currTrans = new Position(0, 0); private movedTrans: Position = new Position(0, 0); constructor( private elementRef: ElementRef, private renderer: Renderer2 ) { this._helperBlock = new HelperBlock(elementRef.nativeElement, renderer); } ngOnInit() { this.el = this.elementRef.nativeElement; } ngAfterViewInit() { this.orderState.subscribe(data => { if (data !== undefined && this.renderer) { this.renderer.setStyle(this.el, 'order', data); } }) // console.log("bar" + this.el.getBoundingClientRect().left, this.el.getBoundingClientRect().top) } ngOnDestroy() { this.orignal = null; this.oldTrans = null; this.tempTrans = null; this.currTrans = null; this.movedTrans = null; this._helperBlock.dispose(); this._helperBlock = null; if (this.draggingSub) { this.draggingSub.unsubscribe(); } } private moveTo(p: Position) { if (this.orignal) { p.subtract(this.orignal); this.tempTrans.set(p); this.tempTrans.divide(this.scale); this.transform(); this.movingOffset.emit(this.currTrans.value); } } private transform() { let translateX = this.tempTrans.x + this.oldTrans.x; let translateY = this.tempTrans.y + this.oldTrans.y; if (this.lockAxis === 'x') { translateX = this.oldTrans.x; this.tempTrans.x = 0; } else if (this.lockAxis === 'y') { translateY = this.oldTrans.y; this.tempTrans.y = 0; console.log(this.movedTrans.x + this.tempTrans.x, this.movedTrans.x, this.tempTrans.x, this.rightMovedMax, this.leftMovedMax); if (this.movedTrans.x + this.tempTrans.x > this.rightMovedMax && this.movedTrans.x + this.tempTrans.x > 0) { return; } if (this.movedTrans.x + this.tempTrans.x <= 0 && Math.abs(this.movedTrans.x + this.tempTrans.x) > this.leftMovedMax) { return; } } // Snap to grid: by grid size if (this.gridSize > 1) { translateX = Math.round(translateX / this.gridSize) * this.gridSize; translateY = Math.round(translateY / this.gridSize) * this.gridSize; } let value = `translate(${Math.round(translateX)}px, ${Math.round(translateY)}px)`; this.renderer.setStyle(this.el, 'transform', value); this.renderer.setStyle(this.el, '-webkit-transform', value); this.renderer.setStyle(this.el, '-ms-transform', value); this.renderer.setStyle(this.el, '-moz-transform', value); this.renderer.setStyle(this.el, '-o-transform', value); // save current position this.currTrans.x = translateX; this.currTrans.y = translateY; } private putBack() { if (this._zIndex) { this.renderer.setStyle(this.el, 'z-index', this._zIndex); } else if (this.zIndexMoving) { if (this.oldZIndex) { this.renderer.setStyle(this.el, 'z-index', this.oldZIndex); } else { this.el.style.removeProperty('z-index'); } } if (this.moving) { this.stopped.emit(this.el); // Remove the helper div: this._helperBlock.remove(); if (this.needTransform) { if (Position.isIPosition(this.position)) { this.oldTrans.set(this.position); } else { this.oldTrans.reset(); } this.transform(); this.needTransform = false; } this.moving = false; this.endOffset.emit(this.currTrans.value); this.renderer.removeStyle(this.el, 'transform'); if (this.trackPosition) { this.oldTrans.add(this.tempTrans); this.movedTrans.add(this.tempTrans); } this.tempTrans.reset(); if (!this.trackPosition) { this.transform(); } if (this.movedTrans.x + this.tempTrans.x >= this.rightMovedMax && this.movedTrans.x + this.tempTrans.x >= 0) { this.movedTrans.x = this.rightMovedMax; } if (this.movedTrans.x + this.tempTrans.x <= 0 && Math.abs(this.movedTrans.x + this.tempTrans.x) >= this.leftMovedMax) { this.movedTrans.x = -this.leftMovedMax; } const element = this.el; this.renderer.removeClass(element, 'ng-dragging'); /** * Fix performance issue: * https://github.com/xieziyu/angular2-draggable/issues/112 */ this.unsubscribeEvents(); } } private pickUp() { // get old z-index: this.oldZIndex = this.el.style.zIndex ? this.el.style.zIndex : ''; if (window) { this.oldZIndex = window.getComputedStyle(this.el, null).getPropertyValue('z-index'); } if (this.zIndexMoving) { this.renderer.setStyle(this.el, 'z-index', this.zIndexMoving); } if (!this.moving) { this.started.emit(this.el); this.moving = true; const element = this.el; this.renderer.addClass(element, 'ng-dragging'); /** * Fix performance issue: * https://github.com/xieziyu/angular2-draggable/issues/112 */ this.subscribeEvents(); } } private subscribeEvents() { this.draggingSub = fromEvent(document, 'mousemove', { passive: false }).subscribe(event => this.onMouseMove(event as MouseEvent)); this.draggingSub.add(fromEvent(document, 'touchmove', { passive: false }).subscribe(event => this.onMouseMove(event as TouchEvent))); this.draggingSub.add(fromEvent(document, 'mouseup', { passive: false }).subscribe(() => this.putBack())); // checking if browser is IE or Edge - https://github.com/xieziyu/angular2-draggable/issues/153 let isIEOrEdge = /msie\s|trident\//i.test(window.navigator.userAgent); if (!isIEOrEdge) { this.draggingSub.add(fromEvent(document, 'mouseleave', { passive: false }).subscribe(() => this.putBack())); } this.draggingSub.add(fromEvent(document, 'touchend', { passive: false }).subscribe(() => this.putBack())); this.draggingSub.add(fromEvent(document, 'touchcancel', { passive: false }).subscribe(() => this.putBack())); } private unsubscribeEvents() { this.draggingSub.unsubscribe(); this.draggingSub = null; } @HostListener('mousedown', ['$event']) @HostListener('touchstart', ['$event']) onMouseDown(event: MouseEvent | TouchEvent) { // 1. skip right click; if (event instanceof MouseEvent && event.button === 2) { return; } // 2. if handle is set, the element can only be moved by handle let target = event.target || event.srcElement; // 3. if allow drag is set to false, ignore the mousedown if (this.allowDrag === false) { return; } if (this.preventDefaultEvent) { event.stopPropagation(); event.preventDefault(); } this.orignal = Position.fromEvent(event, this.el); this.currTrans.reset(); this.oldTrans.reset(); this.pickUp(); } onMouseMove(event: MouseEvent | TouchEvent) { if (this.moving && this.allowDrag) { if (this.preventDefaultEvent) { event.stopPropagation(); event.preventDefault(); } // Add a transparent helper div: this._helperBlock.add(); this.moveTo(Position.fromEvent(event, this.el)); } } }