A draggable and resizable div using Angular (Part 2: Resizing)

Chris Engelsma
4 min readApr 12, 2021

Note: This tutorial builds off of previous code that can be found here.

The repository for this project can be found on Github.

Now that we have a div that can be dragged around, let’s build in the elements to resize it. We want the div to be resizable on all sides, as well as each corner. To do that, we introduce 8 new elements (one for each side, and one for each corner).

frame.component.html

...<div class="resizers"
[style.width.px]="size.x"
[style.height.px]="size.y">
<div class="resizer right"></div>
<div class="resizer left"></div>
<div class="resizer bottom"></div>
<div class="resizer top"></div>
<div class="resizer top-right"></div>
<div class="resizer top-left"></div>
<div class="resizer bottom-left"></div>
<div #resizeCorner class="resizer bottom-right"></div>
</div>
</div>
...

frame.component.scss

.resizers {
box-sizing: border-box;

.resizer {
opacity: 1;
width: 6px;
height: 6px;
border-radius: 1px;
background: white;
border: 1px solid #d50000;
position: absolute;
}

.right {
top: 0;
right: -3px;
height: 100%;
cursor: ew-resize;
}

.bottom {
bottom: -3px;
left: 0;
width: 100%;
cursor: ns-resize;
}

.top {
top: -3px;
left: 0;
width: 100%;
cursor: ns-resize;
}

.left {
top: 0;
left: -3px;
height: 100%;
cursor: ew-resize;
}

.bottom-right {
right: -3px;
bottom: -3px;
cursor: nwse-resize;
}

.top-right {
right: -3px;
top: -3px;
cursor: nesw-resize;
}

.top-left {
left: -3px;
top: -3px;
cursor: nwse-resize;
}

.bottom-left {
left: -3px;
bottom: -3px;
cursor: nesw-resize;
}
}
}

In order to see what we’re building, we give our resizers a background color and outline. When we’re finished, we could choose to hide this by setting the opacity to zero.

We specify each anchor position and cursor display individually. By setting the cursor display, the user can intuitively know what to do when they hover over each resizer.

We add a reference #resizeCorner to the final resizer as we’ll be using the position of this corner to help compute the resizing.

Our div should now look like this:

Note the box around the div showing each individual resizer

Now that we’ve placed our resizers where we want them to go, we now need to assign functionality to them. Let’s create a function to handle similar to the function startDrag from the previous tutorial, only we’ll be calling it (drum roll) startResize .

Our startResize will need to know the resizing anchor and direction in order to properly compute the resize. We’ll define two simple types to handle those:

export type ResizeAnchorType =
| 'top'
| 'left'
| 'bottom'
| 'right'

export type ResizeDirectionType =
| 'x'
| 'y'
| 'xy';

The ResizeAnchorType defines the anchor location of the resizer, and the ResizeDirectionType defines the resize axis.

We can now define our startResize function:

startResize($event, anchors: ResizeAnchorType[], direction: ResizeDirectionType): void {  $event.preventDefault();  const mouseX = $event.clientX;
const mouseY = $event.clientY;
const lastX = this.position.x;
const lastY = this.position.y;
const dimensionWidth = this.resizeCornerRef.nativeElement.parentNode.offsetWidth;
const dimensionHeight = this.resizeCornerRef.nativeElement.parentNode.offsetHeight;

const duringResize = (e) => {
let dw = dimensionWidth;
let dh = dimensionHeight;
if (direction === 'x' || direction === 'xy') {
if (anchors.includes('left')) {
dw += ( mouseX - e.clientX );
} else if (anchors.includes('right')) {
dw -= ( mouseX - e.clientX );
}
}
if (direction === 'y' || direction === 'xy') {
if (anchors.includes('top')) {
dh += ( mouseY - e.clientY );
} else if (anchors.includes('bottom')) {
dh -= ( mouseY - e.clientY );
}
}

if (anchors.includes('left')) {
this.position.x = lastX + e.clientX - mouseX;
this.size.w = Math.max(dw, this.minSize.w);
}

if (anchors.includes('top')) {
this.position.y = lastY + e.clientY - mouseY;
this.size.h = Math.max(dh, this.minSize.h);
}

if (anchors.includes('bottom') || anchors.includes('right')) {
this.size.w = Math.max(dw, this.minSize.w);
this.size.h = Math.max(dh, this.minSize.h);
}

this.lastSize = { ...this.size };
};

const finishResize = (e) => {
this._document.removeEventListener('mousemove', duringResize);
this._document.removeEventListener('mouseup', finishResize);
};

this._document.addEventListener('mousemove', duringResize);
this._document.addEventListener('mouseup', finishResize);
}

Let’s break this down:

  • Upon starting to resize, we must capture the div’s resting position and size, as well as the mouse’s beginning position.
  • In the same way we duringDrag and finishDrag in the previous tutorial, we similarly define duringResize and finishResize functions.
  • Within the duringResize function, we provide all the logic to adjust the size and position of the FrameComponent . This requires handling each size based on which anchor is being activated, as well as which direction we are resizing. This involves using some simple equations. I won’t go into each one in this tutorial, although I’m more than happy to follow up with more explanation if need be.
  • We then make sure to remove the event listeners when the user releases the mouse button.

Finally, we bind to this function for each resizer in the template:

frame.component.html

...<div class="resizers"
[style.width.px]="size.w"
[style.height.px]="size.h">
<div (mousedown)="startResize($event, ['right'], 'x')" class="resizer right"></div>
<div (mousedown)="startResize($event, ['left'], 'x')" class="resizer left"></div>
<div (mousedown)="startResize($event, ['bottom'],'y')" class="resizer bottom"></div>
<div (mousedown)="startResize($event, ['top'], 'y')" class="resizer top"></div>
<div (mousedown)="startResize($event, ['top','right'], 'xy')" class="resizer top-right"></div>
<div (mousedown)="startResize($event, ['top','left'], 'xy')" class="resizer top-left"></div>
<div (mousedown)="startResize($event, ['bottom','left'], 'xy')" class="resizer bottom-left"></div>
<div #resizeCorner (mousedown)="startResize($event, ['bottom','right'], 'xy')" class="resizer bottom-right"></div>

</div>
...

Running this application we can now find that our div is fully resizable and draggable!

A resizable and draggable div

Happy Coding!

--

--

Chris Engelsma

Geophysicist, software engineer, and web developer. Hopefully if I throw enough spaghetti at the wall something sticks.