1

I am adding a resize functionality following a codepen example mentioned in the comments using MARGIN=4 (here I was not able to add the codepen link) The codepen was the best working example which I could find.

Have added 4 elements on all the 4 edges of the box.

I Have added hostlisteners to pointerdown , pointermove and pointerup but I am stuck with executing the animate() function present in Resizable directive.

In the directive the code has mainly 3 functions doing all the calculations onDown() , calc(e), animate()

import { Directive,
         ElementRef,
         HostListener } from '@angular/core';
import { DraggableDirective } from './draggable.directive';

@Directive({
 selector: '[appResizable]' // Attribute selector
})

export class ResizableDirective extends DraggableDirective{

constructor(public element:ElementRef){
super(element);
}

minWidth = 60;
minHeight = 40;
// Thresholds
MARGINS = 4;

//End Of whats configurable
clicked = null;
public onRightEdge; onBottomEdge; onLeftEdge; onTopEdge;
public b; x; y;

redraw = false;
e;
clickedDragging = false;

ngOnInit(){
 this.animate() 
}

@HostListener('dragStart', ['$event'])
 onDragStart(e:PointerEvent): void{
 this.clickedDragging = true;
 this.onDown(e);
 e.preventDefault();
 }

@HostListener('dragMove', ['$event'])
  onDragMove(ee): void{
   if (!this.dragging || ee.pointerId !== this.pointerId) {
    return;
   }
   if((<HTMLElement>event.srcElement).id === ('side-top')){
   this.onMove(ee);
   ee.preventDefault();
   }
 }

 @HostListener('dragEnd', ['$event'])
     ondragend(ev): void{
     this.onUp(ev);
  }

onMove(ee){
    if (!this.dragging || ee.pointerId !== this.pointerId) {
     return;
   }
   if(this.clickedDragging){
     this.calc(ee);
     this.e = ee;
     this.redraw = true;
    }
   }

onDown(e){
    this.calc(e);

    let isResizing = this.onRightEdge || this.onBottomEdge || 
                     this.onLeftEdge || this.onTopEdge;

    this.clicked = {
      x: this.x,
      y: this.y,
      cx: e.clientX,
      cy: e.clientY,
      w: this.b.width,
      h: this.b.height,
      isResizing: isResizing,
      onRightEdge: this.onRightEdge,
      onBottomEdge: this.onBottomEdge,
      onLeftEdge: this.onLeftEdge,
      onTopEdge: this.onTopEdge,
   }

 }

calc(e){
   this.b = this.element.nativeElement.getBoundingClientRect();
   this.x = e.clientX - this.b.left;
   this.y = e.clientY - this.b.top;

   this.onRightEdge = this.x >= this.b.width - this.MARGINS;
   this.onBottomEdge = this.y >= this.b.height - this.MARGINS;
   this.onLeftEdge = this.x < this.MARGINS;
   this.onTopEdge = this.y < this.MARGINS;
  }

animate(){
  requestAnimationFrame(this.animate);
  if(!this.redraw)return;
  this.redraw = false;

  if(this.clicked && this.clicked.isResizing){

    if(this.clicked.onRightEdge){ 
      this.element.nativeElement.style.width = Math.max(this.x, 
      this.minWidth) + 'px';
    }

   if(this.clicked.onBottomEdge){
       this.element.nativeElement.style.height = Math.max(this.y, 
       this.minHeight) + 'px';
    }

   if(this.clicked.onLeftEdge){
     let currentWidth = Math.max(this.clicked.cx - 
         this.e.clientX + this.clicked.w, this.minWidth);

     if(currentWidth > this.minWidth){
      this.element.nativeElement.style.width = currentWidth + 'px';
      this.element.nativeElement.style.left = this.e.clientX + 'px';
     }
    }

    if (this.clicked.onTopEdge) {
     var currentHeight = Math.max(this.clicked.cy - 
                                  this.e.clientY  +
                                   this.clicked.h, this.minHeight);
     if (currentHeight > this.minHeight) {
      this.element.nativeElement.style.height = currentHeight + 'px';
      this.element.nativeElement.style.top = this.e.clientY + 'px'; 
     }
    }

  return;
 }
}

onUp(ev) {
   this.calc(ev);
   this.clicked = null;
   }  
}

HTML snippet on which directive has been applied

<div class="box" *ngFor="let box of dropzone1" appDroppable (dragStart)="currentBox = box" appMovable>
    {{ box.dis }}

    <div class="side side-h" id="side-top" (dragStart)=(e) (dragMove)=(e) (dragEnd)=(e) appResizable></div>
    <div class="side side-v" id="side-right" (click)="clcikme(e)" ></div>
    <div class="side side-h" id="side-bottom" (click)="clcikme(e)"></div>
    <div class="side side-v" id="side-left" (click)="clcikme(e)"></div>
</div>

In the codepen example for b

this.b = this.element.nativeElement.getBoundingClientRect();

the whole element has been taken which I'll also have to do, in my case I have the border on which the directive is there

I am attaching a working stackblitz the resizable directive is present in draggable folder and used in hello component In the stackblitz console logging of pointerdown, pointermove can also be seen.

https://stackblitz.com/edit/angular-pcpev1?file=src/app/hello.component.html

Error in console animate of undefined

Please refer to the codepen example from the comments.

Update

https://stackblitz.com/edit/angular-pcpev1?file=src%2Fapp%2Fhello.component.html

2
  • codepen link codepen.io/zz85/pen/gbOoVP Commented Aug 26, 2019 at 13:05
  • Have you tried using the angular animations api ? Commented Aug 26, 2019 at 14:21

1 Answer 1

3

Sorry I can't fix your code because it's a mess, you just do this completely wrong, you just did two approaches I suggest in one code. Also you're leaking resize internals outside of directive, the divs need to be hidden, outside you only should use resize attribute and everything should be created inside directive.

Here, this is started for one top side:

@Directive({
    selector: '[resize]'
})
class Resizable implements OnInit, OnDestroy {
    private nodes: HtmlElement[] = [];
    private data: {x: number, y: number, rect: ClientRect, direction: string};
    constructor(@Inject(ElementRef) private element: ElementRef) {
        this.mousemove = this.mousemove.bind(this);
        this.mouseup = this.mouseup.bind(this);
    }
    mousemove(e) {
        if (this.data) {
            switch(this.data.direction) {
                case 'top':
                    var offset = this.data.y - e.clientY;
                    var height = this.data.rect.height;
                    var top = this.data.rect.top;
                    var style = this.element.nativeElement.style;
                    style.height = height + offset + 'px';
                    style.top = top - offset + 'px';
                    break;
            }
        }
    }
    ngOnInit() {
        var node = document.createElement('div');
        node.classList.add('border-top', 'border');
        this.element.nativeElement.appendChild(node);
        this.nodes.push(node);
        window.addEventListener('mousemove', this.mousemove);
        window.addEventListener('mouseup', this.mouseup);
    }
    @HostListener('mousedown', ['$event'])
    mousedown(e) {
        if (e.target.classList.contains('border')) {
            var rect = this.element.nativeElement.getBoundingClientRect();
            this.data = {
                x: e.clientX,
                y: e.clientY,
                rect,
                direction: e.target.className.match(/border-([^ ]+)/)[1]
            };
            e.preventDefault();
        } else {
            delete this.data;
        }
    }
    mouseup(e) {
         delete this.data;
    }
    ngOnDestroy() {
        this.nodes.forEach(n => n.remove());
        window.removeEventListener('mousemove', this.mousemove);
        window.removeEventListener('mouseup', this.mouseup);
    }
}

here is CodePen demo

Sign up to request clarification or add additional context in comments.

12 Comments

Thanks alot , how can I apply this to rest of the 3 sides
@Enthu You need to create divs for each side (with class border-xxx) create CSS that will move element to the side and do similar calculation inside switch(this.data.direction) {, with bottom, right, and left
Thanksyou very much , I'll implement and in case any issues I'll ask, thanks alot
@Enthu it have to be dragged if you want to change only one side. the left and top need to be changed when you resize by dragging top and left side.
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.