I have a feature where box can be dragged and dropped into the grey area(Please refer to the stackblitz link) Once the box is dragged and dropped , the box can only be moved within the grey area by clicking on the pink color of the box.
Resizing functionality has also been added, so the box can be resized.
Before resize directive was added the box can only be moved within grey area but after adding adding the resize directive when we resize, the box starts moving out of the grey area , the issue is the box should not move out of the grey area when resizing is done
Stackblitz link
https://stackblitz.com/edit/angular-rgeq2p?file=src/app/hello.component.html
hello.component.html [ has the box and directives applied on the box ]
<div appMovableArea appDropzone (drop)="move(currentBox, dropzone1)">
<div *ngFor="let box of dropzone1"
appDroppable
(dragStart)="currentBox = box"
appMovable
resize>
{{ box.dis }}
</div>
</div>
where the box has (dragStart) output event emitter which is bound to draggable directive([appDroppable + draggable] and for the move functionality appMovable, appMovableArea directives are there) .And the events are shared among directives using Droppable.service.ts
The (drop) is an output event emitter applied on grey area using dropzone[appDropzone] directive
import { Directive, ElementRef, EventEmitter, HostBinding, HostListener,
OnInit, Output, SkipSelf } from '@angular/core';
import { DroppableService } from './droppable.service';
@Directive({
selector: '[appDropzone]',
providers: [DroppableService]
})
export class DropzoneDirective implements OnInit {
@Output() drop = new EventEmitter<PointerEvent>();
@Output() remove = new EventEmitter<PointerEvent>();
private clientRect: ClientRect;
constructor(@SkipSelf() private allDroppableService: DroppableService,
private innerDroppableService: DroppableService,
private element: ElementRef) { }
ngOnInit(): void {
this.allDroppableService.dragStart$.subscribe(() =>
this.onDragStart());
this.allDroppableService.dragEnd$.subscribe(event =>
this.onDragEnd(event));
this.allDroppableService.dragMove$.subscribe(event => {
if (this.isEventInside(event)) {
this.onPointerEnter();
} else {
this.onPointerLeave();
}
});
this.innerDroppableService.dragStart$.subscribe(() =>
this.onInnerDragStart());
this.innerDroppableService.dragEnd$.subscribe(event =>
this.onInnerDragEnd(event));
}
private onPointerEnter(): void {
if (!this.activated) {
return;
}
this.entered = true;
}
private onPointerLeave(): void {
if (!this.activated) {
return;
}
this.entered = false;
}
private onDragStart(): void {
this.clientRect = this.element.nativeElement.getBoundingClientRect();
this.activated = true;
}
private onDragEnd(event: PointerEvent): void {
if (!this.activated) {
return;
}
if (this.entered) {
this.drop.emit(event);
}
}
private onInnerDragStart() {
this.activated = true;
this.entered = true;
}
private onInnerDragEnd(event: PointerEvent) {
if (!this.entered) {
this.remove.emit(event);
}
}
private isEventInside(event: PointerEvent) {
return event.clientX >= this.clientRect.left &&
event.clientX <= this.clientRect.right &&
event.clientY >= this.clientRect.top &&
event.clientY <= this.clientRect.bottom;
}
}
Then on the box (dragStart) output event emitter which is present indraggable directive[appDraggable] which listens for pointerdown events
import { Directive, EventEmitter, HostBinding, HostListener, Output,
ElementRef } from '@angular/core';
@Directive({
selector: '[appDraggable],[appDroppable]'
})
export class DraggableDirective {
@Output() dragStart = new EventEmitter<PointerEvent>();
@Output() dragMove = new EventEmitter<PointerEvent>();
@Output() dragEnd = new EventEmitter<PointerEvent>();
constructor(public element: ElementRef) {}
@HostListener('pointerdown', ['$event'])
onPointerDown(event: PointerEvent): void {
if (event.button !== 0) {
return;
}
this.pointerId = event.pointerId;
this.dragging = true;
this.dragStart.emit(event);
}
@HostListener('document:pointermove', ['$event'])
onPointerMove(event: PointerEvent): void {
if (!this.dragging || event.pointerId !== this.pointerId) {
return;
}
this.dragMove.emit(event);
}
@HostListener('document:pointercancel', ['$event'])
@HostListener('document:pointerup', ['$event'])
onPointerUp(event: PointerEvent): void {
if (!this.dragging || event.pointerId !== this.pointerId) {
return;
}
this.dragging = false;
this.dragEnd.emit(event);
}
}
Movable directive for maintaining move inside the grey area which in turn uses calculation based from movable-area directive
import { Directive, ElementRef, HostBinding, HostListener, Input } from
'@angular/core';
import { DraggableDirective } from './draggable.directive';
import { DomSanitizer, SafeStyle } from '@angular/platform-browser';
interface Position {
x: number;
y: number;
}
@Directive({
selector: '[appMovable]'
})
export class MovableDirective extends DraggableDirective {
@HostBinding('style.transform') get transform(): SafeStyle {
return this.sanitizer.bypassSecurityTrustStyle(
`translateX(${this.position.x}px) translateY(${this.position.y}px)`
);
}
@HostBinding('class.movable') movable = true;
position: Position = {x: 0, y: 0};
private startPosition: Position;
@Input('appMovableReset') reset = false;
constructor(private sanitizer: DomSanitizer, public element: ElementRef) {
super(element);
}
@HostListener('dragStart', ['$event'])
onDragStart(event: PointerEvent) {
this.startPosition = {
x: event.clientX - this.position.x,
y: event.clientY - this.position.y
}
}
@HostListener('dragMove', ['$event'])
onDragMove(event: PointerEvent) {
this.position.x = event.clientX - this.startPosition.x;
this.position.y = event.clientY - this.startPosition.y;
}
@HostListener('dragEnd', ['$event'])
onDragEnd(event: PointerEvent) {
if (this.reset) {
this.position = {x: 0, y: 0};
}
}
}
The resize directive is also present in the stackblitz link. And styles for resize directive are present in styles.css
One small hack you can do is add
'resizing'
class to the element in resize directive and check whether that class is present in draggable directive if present do not make it draggable. I can't get your code because it's so difficult. I don't know why you made this so complex.Here is implementation of Drag&Drop directive, sorry can't fix your code because it's a mess same as resize:
Directive
CSS
Template:
Demo: https://codepen.io/jcubic/pen/wvwJNqQ?editors=0110