UNPKG

@ngfx/ui

Version:

Angular UI library for gaming and creative applications

260 lines (259 loc) 11.4 kB
import { Directive, ElementRef, Input, HostListener } from '@angular/core'; import { NgFxController } from './../../services/controller/controller.service'; export class NgFxDraggableDirective { constructor(_el, _controller) { this._el = _el; this._controller = _controller; this._elem = _el.nativeElement; } ngOnInit() { const nodeList = (((this._elem.getElementsByClassName('ngfx__handle')))); this._touchItem = null; this._handle = nodeList[0]; this.control.height = this._elem.clientHeight; this.control.width = this._elem.clientWidth; if (this.control.orient === 'is--hor') { this.control.currentValue = 0; this.control.position = 'translate(' + 0 + 'px' + ',' + 0 + 'px' + ')'; } else if (this.control.orient === 'is--vert') { this.control.currentValue = 0; this.control.position = 'translate(' + 0 + 'px' + ',' + 0 + 'px' + ')'; } else if (this.control.orient === 'is--joystick') { this.control.currentValue = [0, 0]; this.control.x = this.control.y = 76; this.control.position = 'translate(' + 76 + 'px' + ',' + 76 + 'px' + ')'; } this._lastPos = { transform: this.control.position }; this.setActualPosition(this.control.position); } onMouseLeave(e) { } onMouseEnter(e) { if (this.control.isActive) { this.control.hasUserInput = true; } } onTouchStart(e) { this.control.hasUserInput = true; this.onTouchDown(e); } onTouchDown(e) { e.preventDefault(); this.control.isActive = true; this.control.hasUserInput = true; this._rect = this._elem.getBoundingClientRect(); this.control.height = this._elem.clientHeight; this.control.width = this._elem.clientWidth; this._elem.addEventListener('touchmove', this.onTouchMove.bind(this)); this._elem.addEventListener('touchend', this.onMouseUp.bind(this)); if (this._touchItem === null) { this._touchItem = e.touches.length - 1; } this.control.x = e.touches[this._touchItem].pageX - this._rect.left - this._handle.clientWidth / 2; this.control.y = e.touches[this._touchItem].pageY - this._rect.top - this._handle.clientWidth / 2; this.setPosition(this.control.x, this.control.y); } onMouseDown(e) { e.preventDefault(); this.control.isActive = true; this.control.hasUserInput = true; this._rect = this._elem.getBoundingClientRect(); this.control.height = this._elem.clientHeight; this.control.width = this._elem.clientWidth; this.control.x = e.offsetX; this.control.y = e.offsetY; this._elem.addEventListener('mousemove', this.onMouseMove.bind(this)); this._elem.addEventListener('mouseup', this.onMouseUp.bind(this)); window.addEventListener('mousemove', this.onMouseMove.bind(this)); window.addEventListener('mouseup', this.onMouseUp.bind(this)); this.setPosition(this.control.x, this.control.y); } onTouchMove(e) { e.preventDefault(); this._handle.style.opacity = '0.8'; if (this._touchItem === null) { this._touchItem = e.touches.length - 1; } this.control.x = e.touches[this._touchItem].pageX - this._rect.left - 22; this.control.y = e.touches[this._touchItem].pageY - this._rect.top - 66; this.setPosition(this.control.x, this.control.y); if (this.control.orient === 'is--hor') { this.control.currentValue = this.scale(this.control.x, 0, this.control.width - 44, (this.control.min), (this.control.max)); } else if (this.control.orient === 'is--vert') { this.control.currentValue = this.scale(this.control.y, 0, this.control.height - 44, (this.control.min), (this.control.max)); } else if (this.control.orient === 'is--joystick') { this.control.currentValue = [ this.scale(this.control.x, 0, this.control.width - 44, this.control.min[0], this.control.max[0]), this.scale(this.control.y, 0, this.control.height - 44, this.control.min[1], this.control.max[1]) ]; } this.control.timeStamp = e.timeStamp; this.onEvent(); } onMouseMove(e) { const parent = (((e.target)).parentNode); if (!this.control.isActive) { return; } if (this.control.isActive && parent === this._elem) { this._handle.style.opacity = '0.8'; this.control.x = e.offsetX; this.control.y = e.offsetY; } else { this._handle.style.opacity = '0.8'; this.control.x = (this._elem.getBoundingClientRect().left - e.offsetX) * -1; this.control.y = (this._elem.getBoundingClientRect().top - e.offsetY) * -1; } if (this.control.hasUserInput && this.control.isActive) { this.setPosition(this.control.x, this.control.y); if (this.control.orient === 'is--hor') { this.control.currentValue = this.scale(this.control.x, 0, this.control.width - 44, (this.control.min), (this.control.max)); } if (this.control.orient === 'is--vert') { this.control.currentValue = this.scale(this.control.y, 0, this.control.height - 44, (this.control.min), (this.control.max)); } if (this.control.orient === 'is--joystick') { this.control.currentValue = [ this.scale(this.control.x, 0, this.control.width - 44, this.control.min[0], this.control.max[0]), this.scale(this.control.y, 0, this.control.height - 44, this.control.min[1], this.control.max[1]) ]; } this.control.timeStamp = e.timeStamp; this.onEvent(); } } onMouseUp(e) { this.control.isActive = false; this.control.hasUserInput = false; this._handle.style.opacity = '0.3'; if ('ontouchstart' in document.documentElement) { this._touchItem = null; } else { this._elem.removeEventListener('mousemove', this.onMouseMove.bind(this)); this._elem.removeEventListener('mouseup', this.onMouseUp.bind(this)); } if (this.control.orient === 'is--joystick' && this.control.snapToCenter === true) { const center = this.getCenter([0, this.control.width - this._handle.offsetWidth], [0, this.control.height - this._handle.offsetHeight]); this.control.x = center[0]; this.control.y = center[1]; this.setPosition(center[0], center[1]); } } onTouchEnd(e) { this.onMouseUp(e); } onEvent() { if (this.control.isActive) { this._controller.onEvent.emit({ type: 'change', endFrame: true, control: this.control }); } } getCenter(xRange, yRange) { const cX = xRange[1] - (xRange[1] - xRange[0]) / 2; const cY = yRange[1] - (yRange[1] - yRange[0]) / 2; return [cX, cY]; } distance(dot1, dot2) { const x1 = dot1[0]; const y1 = dot1[1]; const x2 = dot2[0]; const y2 = dot2[1]; return Math.sqrt(Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2)); } scale(v, min, max, gmin, gmax) { return ((v - min) / (max - min)) * (gmax - gmin) + gmin; } circularBounds(x, y, xRange, yRange) { const center = this.getCenter(xRange, yRange); const dist = this.distance([x, y], center); const radius = xRange[1] - center[0]; if (dist <= radius) { return [x, y]; } else { x = x - center[0]; y = y - center[1]; const radians = Math.atan2(y, x); return [Math.cos(radians) * radius + center[0], Math.sin(radians) * radius + center[1]]; } } clamp(value, range) { return Math.max(Math.min(value, range[1]), range[0]); } setActualPosition(pos) { const transformRegex = new RegExp(/(\d+(\.\d+)?)/g); const positions = pos.match(transformRegex); this._handle.style.transform = 'matrix3d(1,0,0.00,0,0.00,1,0.00,0,0,0,1,0,' + positions[0] + ',' + positions[1] + ',0,1)'; } setPosition(x, y) { if (this.control.orient === 'is--joystick') { this._joystickPos = this.circularBounds(this.control.x, this.control.y, [0, this.control.width - this._handle.offsetWidth], [0, this.control.height - this._handle.offsetHeight]); this.control.x = this.clamp(this._joystickPos[0], [0, this.control.width - this._handle.offsetWidth]); this.control.y = this.clamp(this._joystickPos[1], [0, this.control.height - this._handle.offsetHeight]); this.control.position = 'translate(' + this.control.x + 'px' + ',' + this.control.y + 'px' + ')'; this.setActualPosition(this.control.position); } else { if (x <= 0) { this.control.x = 0; } else if (x > this._elem.clientWidth - this._handle.offsetWidth) { this.control.x = this._elem.clientWidth - this._handle.offsetWidth; } else { this.control.x = x; } if (y <= 0) { this.control.y = 0; } else if (y > this._elem.clientHeight - this._handle.offsetHeight) { this.control.y = this._elem.clientHeight - this._handle.offsetHeight; } else { this.control.y = y; } this.control.position = 'translate(' + this.control.x + 'px' + ',' + this.control.y + 'px' + ')'; this.setActualPosition(this.control.position); } } } NgFxDraggableDirective.decorators = [ { type: Directive, args: [{ selector: '[ngfxDraggable]' },] }, ]; NgFxDraggableDirective.ctorParameters = () => [ { type: ElementRef }, { type: NgFxController } ]; NgFxDraggableDirective.propDecorators = { control: [{ type: Input, args: ['control',] }], onMouseLeave: [{ type: HostListener, args: ['mouseleave', ['$event'],] }], onMouseEnter: [{ type: HostListener, args: ['mouseenter', ['$event'],] }], onTouchStart: [{ type: HostListener, args: ['touchstart', ['$event'],] }], onMouseDown: [{ type: HostListener, args: ['mousedown', ['$event'],] }], onMouseUp: [{ type: HostListener, args: ['mouseup', ['$event'],] }], onTouchEnd: [{ type: HostListener, args: ['touchend', ['$event'],] }] }; if (false) { NgFxDraggableDirective.prototype._rect; NgFxDraggableDirective.prototype._joystickPos; NgFxDraggableDirective.prototype._touchItem; NgFxDraggableDirective.prototype._elem; NgFxDraggableDirective.prototype._handle; NgFxDraggableDirective.prototype._timeout; NgFxDraggableDirective.prototype._animation; NgFxDraggableDirective.prototype._lastPos; NgFxDraggableDirective.prototype.control; NgFxDraggableDirective.prototype._el; NgFxDraggableDirective.prototype._controller; }