UNPKG

mutable-div

Version:

Directives to enable moving or resizing a div element.

369 lines (361 loc) 20.6 kB
import * as i0 from '@angular/core'; import { EventEmitter, Directive, Input, Output, HostListener, Component, ViewChildren, NgModule } from '@angular/core'; import * as i1 from '@angular/common'; import { CommonModule } from '@angular/common'; class DraggableElementDirective { constructor(el) { this.el = el; this.pointerDown = false; this.rotate = 0; this.coordinates = new EventEmitter(); this.stopped = new EventEmitter(); el.nativeElement.style.position = 'absolute'; } onPointerDown(event) { event.preventDefault(); this.pointerDown = true; this.setOriginalPosition(event); } onPointerUp() { this.stopped.emit(); } onPointerMove(event) { if (this.pointerDown) { const element = this.el.nativeElement; const newPosition = this.setNewPosition(event); this.setOriginalPosition(event); element.style.left = (element.offsetLeft + newPosition.x) + 'px'; element.style.top = (element.offsetTop + newPosition.y) + 'px'; this.coordinates.emit({ x: newPosition.x, y: newPosition.y }); } } onWindowPointerUp() { this.pointerDown = false; } onPanStart(event) { this.onPointerDown(event.srcEvent); } onPanEnd() { this.onPointerUp(); } onPanMove(event) { this.onPointerMove(event.srcEvent); } onWindowPanEnd() { this.onWindowPointerUp(); } setOriginalPosition(event) { switch (this.rotate) { case 90: this.originalPosition = { x: event.clientY, y: screen.width - event.clientX }; break; case 180: this.originalPosition = { x: screen.width - event.clientX, y: screen.height - event.clientY }; break; case 270: this.originalPosition = { x: screen.height - event.clientY, y: event.clientX }; break; default: this.originalPosition = { x: event.clientX, y: event.clientY }; } } setNewPosition(event) { let newPosition = { x: 0, y: 0 }; switch (this.rotate) { case 90: newPosition = { x: event.clientY - this.originalPosition.x, y: (screen.width - event.clientX) - this.originalPosition.y }; break; case 180: newPosition = { x: (screen.width - event.clientX) - this.originalPosition.x, y: (screen.height - event.clientY) - this.originalPosition.y }; break; case 270: newPosition = { x: (screen.height - event.clientY) - this.originalPosition.x, y: event.clientX - this.originalPosition.y }; break; default: newPosition = { x: event.clientX - this.originalPosition.x, y: event.clientY - this.originalPosition.y }; } return newPosition; } /** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DraggableElementDirective, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Directive }); } /** @nocollapse */ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: DraggableElementDirective, selector: "[draggable]", inputs: { rotate: "rotate" }, outputs: { coordinates: "coordinates", stopped: "stopped" }, host: { listeners: { "pointerdown": "onPointerDown($event)", "pointerup": "onPointerUp()", "window:pointermove": "onPointerMove($event)", "window:pointerup": "onWindowPointerUp()", "panstart": "onPanStart($event)", "panend": "onPanEnd()", "window:panmove": "onPanMove($event)", "window:panend": "onWindowPanEnd()" } }, ngImport: i0 }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DraggableElementDirective, decorators: [{ type: Directive, args: [{ selector: '[draggable]' }] }], ctorParameters: function () { return [{ type: i0.ElementRef }]; }, propDecorators: { rotate: [{ type: Input }], coordinates: [{ type: Output }], stopped: [{ type: Output }], onPointerDown: [{ type: HostListener, args: ['pointerdown', ['$event']] }], onPointerUp: [{ type: HostListener, args: ['pointerup'] }], onPointerMove: [{ type: HostListener, args: ['window:pointermove', ['$event']] }], onWindowPointerUp: [{ type: HostListener, args: ['window:pointerup'] }], onPanStart: [{ type: HostListener, args: ['panstart', ['$event']] }], onPanEnd: [{ type: HostListener, args: ['panend'] }], onPanMove: [{ type: HostListener, args: ['window:panmove', ['$event']] }], onWindowPanEnd: [{ type: HostListener, args: ['window:panend'] }] } }); class ResizeHandlersComponent { constructor() { this.selected = false; this.minimumSize = 20; } ngAfterViewInit() { this.setHandlePositions(); } ngOnChanges() { if (this.selected) { this.setHandlePositions(); } } setHandlePositions() { this.handles.forEach((element, index) => { switch (index) { case 0: this.setHandleStyles(element, { left: '-7px', right: '', top: '-7px', bottom: '' }); break; case 1: this.setHandleStyles(element, { left: '', right: '-7px', top: '-7px', bottom: '' }); break; case 2: this.setHandleStyles(element, { left: '-7px', right: '', top: '', bottom: '-7px' }); break; default: this.setHandleStyles(element, { left: '', right: '-7px', top: '', bottom: '-7px' }); } }); } setHandleStyles(element, styles) { element.nativeElement.style.left = styles.left; element.nativeElement.style.right = styles.right; element.nativeElement.style.top = styles.top; element.nativeElement.style.bottom = styles.bottom; } onPointerDown(event) { event.stopPropagation(); } resize(className, coordinates) { const parentElement = this.parentElement.nativeElement; const size = this.calculatingPosition(parentElement, className, coordinates); if (size.width > this.minimumSize && size.height > this.minimumSize) { if (className.includes('TOP-LEFT')) { parentElement.style.left = size.position.x + 'px'; parentElement.style.width = size.width + 'px'; parentElement.style.top = size.position.y + 'px'; parentElement.style.height = size.height + 'px'; } else if (className.includes('TOP-RIGHT')) { parentElement.style.width = size.width + 'px'; parentElement.style.top = size.position.y + 'px'; parentElement.style.height = size.height + 'px'; } else if (className.includes('BOTTOM-LEFT')) { parentElement.style.left = size.position.x + 'px'; parentElement.style.width = size.width + 'px'; parentElement.style.height = size.height + 'px'; } else { parentElement.style.width = size.width + 'px'; parentElement.style.height = size.height + 'px'; } } this.setHandlePositions(); } calculatingPosition(parentElement, className, coordinates) { switch (this.rotate) { case 90: return { width: className.includes('LEFT') ? parentElement.offsetWidth - coordinates.y : parentElement.offsetWidth + coordinates.y, height: className.includes('TOP') ? parentElement.offsetHeight + coordinates.x : parentElement.offsetHeight - coordinates.x, position: { x: parentElement.offsetLeft + coordinates.y, y: parentElement.offsetTop - coordinates.x } }; break; case 180: return { width: className.includes('LEFT') ? parentElement.offsetWidth + coordinates.x : parentElement.offsetWidth - coordinates.x, height: className.includes('TOP') ? parentElement.offsetHeight + coordinates.y : parentElement.offsetHeight - coordinates.y, position: { x: parentElement.offsetLeft - coordinates.x, y: parentElement.offsetTop - coordinates.y } }; break; case 270: return { width: className.includes('LEFT') ? parentElement.offsetWidth + coordinates.y : parentElement.offsetWidth - coordinates.y, height: className.includes('TOP') ? parentElement.offsetHeight - coordinates.x : parentElement.offsetHeight + coordinates.x, position: { x: parentElement.offsetLeft - coordinates.y, y: parentElement.offsetTop + coordinates.x } }; break; default: return { width: className.includes('LEFT') ? parentElement.offsetWidth - coordinates.x : parentElement.offsetWidth + coordinates.x, height: className.includes('TOP') ? parentElement.offsetHeight - coordinates.y : parentElement.offsetHeight + coordinates.y, position: { x: parentElement.offsetLeft + coordinates.x, y: parentElement.offsetTop + coordinates.y } }; } } /** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ResizeHandlersComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); } /** @nocollapse */ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: ResizeHandlersComponent, selector: "lib-resize-handlers", inputs: { parentElement: "parentElement", rotate: "rotate", selected: "selected" }, viewQueries: [{ propertyName: "handles", predicate: ["handle"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div *ngIf=\"selected\" class=\"resize-handlers\">\n <div #handle #topLeft\n class=\"TOP-LEFT handle\"\n draggable\n (pointerdown)=\"onPointerDown($event)\"\n (coordinates)=\"resize(topLeft.className, $event)\"></div>\n <div #handle #topRight\n class=\"TOP-RIGHT handle\"\n draggable\n (pointerdown)=\"onPointerDown($event)\"\n (coordinates)=\"resize(topRight.className, $event)\"></div>\n <div #handle #bottomLeft\n class=\"BOTTOM-LEFT handle\"\n draggable\n (pointerdown)=\"onPointerDown($event)\"\n (coordinates)=\"resize(bottomLeft.className, $event)\"></div>\n <div #handle #bottomRight\n class=\"BOTTOM-RIGHT handle\"\n draggable\n (pointerdown)=\"onPointerDown($event)\"\n (coordinates)=\"resize(bottomRight.className, $event)\"></div>\n</div>\n", styles: [".resize-handlers{width:100%;height:100%;position:absolute;top:0;left:0;border:2px solid #424242;box-sizing:border-box}.handle{position:absolute;width:20px;height:20px;background:#fff;opacity:50%}.TOP-LEFT{left:-7px;top:-7px;border-top:3px solid #424242;border-left:3px solid #424242}.TOP-LEFT:hover,.TOP-LEFT:active{border-radius:unset;background:transparent;border-bottom:black;border-right:black}.TOP-RIGHT{right:-7px;top:-7px;border-top:3px solid #424242;border-right:3px solid #424242}.TOP-RIGHT:hover,.TOP-RIGHT:active{border-radius:unset;background:transparent;border-bottom:black;border-left:black}.BOTTOM-LEFT{left:-7px;bottom:-7px;border-bottom:3px solid #424242;border-left:3px solid #424242}.BOTTOM-LEFT:hover,.BOTTOM-LEFT:active{border-radius:unset;background:transparent;border-top:black;border-right:black}.BOTTOM-RIGHT{right:-7px;bottom:-7px;border-bottom:3px solid #424242;border-right:3px solid #424242}.BOTTOM-RIGHT:hover,.BOTTOM-RIGHT:active{border-radius:unset;background:transparent;border-top:black;border-left:black}\n"], dependencies: [{ kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: DraggableElementDirective, selector: "[draggable]", inputs: ["rotate"], outputs: ["coordinates", "stopped"] }] }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ResizeHandlersComponent, decorators: [{ type: Component, args: [{ selector: 'lib-resize-handlers', template: "<div *ngIf=\"selected\" class=\"resize-handlers\">\n <div #handle #topLeft\n class=\"TOP-LEFT handle\"\n draggable\n (pointerdown)=\"onPointerDown($event)\"\n (coordinates)=\"resize(topLeft.className, $event)\"></div>\n <div #handle #topRight\n class=\"TOP-RIGHT handle\"\n draggable\n (pointerdown)=\"onPointerDown($event)\"\n (coordinates)=\"resize(topRight.className, $event)\"></div>\n <div #handle #bottomLeft\n class=\"BOTTOM-LEFT handle\"\n draggable\n (pointerdown)=\"onPointerDown($event)\"\n (coordinates)=\"resize(bottomLeft.className, $event)\"></div>\n <div #handle #bottomRight\n class=\"BOTTOM-RIGHT handle\"\n draggable\n (pointerdown)=\"onPointerDown($event)\"\n (coordinates)=\"resize(bottomRight.className, $event)\"></div>\n</div>\n", styles: [".resize-handlers{width:100%;height:100%;position:absolute;top:0;left:0;border:2px solid #424242;box-sizing:border-box}.handle{position:absolute;width:20px;height:20px;background:#fff;opacity:50%}.TOP-LEFT{left:-7px;top:-7px;border-top:3px solid #424242;border-left:3px solid #424242}.TOP-LEFT:hover,.TOP-LEFT:active{border-radius:unset;background:transparent;border-bottom:black;border-right:black}.TOP-RIGHT{right:-7px;top:-7px;border-top:3px solid #424242;border-right:3px solid #424242}.TOP-RIGHT:hover,.TOP-RIGHT:active{border-radius:unset;background:transparent;border-bottom:black;border-left:black}.BOTTOM-LEFT{left:-7px;bottom:-7px;border-bottom:3px solid #424242;border-left:3px solid #424242}.BOTTOM-LEFT:hover,.BOTTOM-LEFT:active{border-radius:unset;background:transparent;border-top:black;border-right:black}.BOTTOM-RIGHT{right:-7px;bottom:-7px;border-bottom:3px solid #424242;border-right:3px solid #424242}.BOTTOM-RIGHT:hover,.BOTTOM-RIGHT:active{border-radius:unset;background:transparent;border-top:black;border-left:black}\n"] }] }], ctorParameters: function () { return []; }, propDecorators: { parentElement: [{ type: Input }], rotate: [{ type: Input }], selected: [{ type: Input }], handles: [{ type: ViewChildren, args: ['handle'] }] } }); class ResizableElementDirective { constructor(el, container) { this.el = el; this.container = container; this.rotate = 0; this.selected = false; this.stopped = new EventEmitter(); } ngOnInit() { this.addHandlersToElement(); } ngOnChanges() { if (this.resizeHandlersComponent) { this.resizeHandlersComponent.instance.selected = this.selected; this.resizeHandlersComponent.instance.rotate = this.rotate; } } addHandlersToElement() { this.resizeHandlersComponent = this.container.createComponent(ResizeHandlersComponent); this.resizeHandlersComponent.instance.parentElement = this.el; this.resizeHandlersComponent.instance.rotate = this.rotate; this.resizeHandlersComponent.instance.selected = this.selected; this.el.nativeElement.appendChild(this.resizeHandlersComponent.location.nativeElement); } onPointerDown() { this.resizeHandlersComponent.instance.selected = true; } onPointerUp() { this.stopped.emit(); } onWindowPointerUp(targetEvent) { if (!this.el.nativeElement.contains(targetEvent)) { this.resizeHandlersComponent.instance.selected = false; } } /** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ResizableElementDirective, deps: [{ token: i0.ElementRef }, { token: i0.ViewContainerRef }], target: i0.ɵɵFactoryTarget.Directive }); } /** @nocollapse */ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: ResizableElementDirective, selector: "[resizable]", inputs: { rotate: "rotate", selected: "selected" }, outputs: { stopped: "stopped" }, host: { listeners: { "pointerdown": "onPointerDown()", "pointerup": "onPointerUp()", "window:pointerup": "onWindowPointerUp($event.target)" } }, usesOnChanges: true, ngImport: i0 }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ResizableElementDirective, decorators: [{ type: Directive, args: [{ selector: '[resizable]' }] }], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: i0.ViewContainerRef }]; }, propDecorators: { rotate: [{ type: Input }], selected: [{ type: Input }], stopped: [{ type: Output }], onPointerDown: [{ type: HostListener, args: ['pointerdown'] }], onPointerUp: [{ type: HostListener, args: ['pointerup'] }], onWindowPointerUp: [{ type: HostListener, args: ['window:pointerup', ['$event.target']] }] } }); class MutableDivModule { /** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: MutableDivModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); } /** @nocollapse */ static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "16.2.12", ngImport: i0, type: MutableDivModule, declarations: [DraggableElementDirective, ResizableElementDirective, ResizeHandlersComponent], imports: [CommonModule], exports: [DraggableElementDirective, ResizableElementDirective] }); } /** @nocollapse */ static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: MutableDivModule, imports: [CommonModule] }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: MutableDivModule, decorators: [{ type: NgModule, args: [{ declarations: [ DraggableElementDirective, ResizableElementDirective, ResizeHandlersComponent ], imports: [ CommonModule ], exports: [ DraggableElementDirective, ResizableElementDirective, ] }] }] }); /* * Public API Surface of mutable-div */ /** * Generated bundle index. Do not edit. */ export { DraggableElementDirective, MutableDivModule, ResizableElementDirective }; //# sourceMappingURL=mutable-div.mjs.map