Zac Fukuda
061

Make HTML Element Draggable within Browser Window

This is an extended version of previous example Make Html Element Draggable with Bar, to confine a draggable html element in the visible area of window.

Codebase

index.html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Draggable</title>
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <div class="draggable-object">
    <div class="draggable-subject">Draggable</div>
  </div>
  <script src="app.js"></script>
</body>
</html>

index.html is no different from the previous example.

style.css
@charset "utf-8";

.draggable-object {
  position: absolute;
}

.draggable-subject {
  cursor: grab;
}
.draggable-subject:active {
  cursor: grabbing;
}

/* Only for demo */
html, body {
  width: 100%;
  height: 100%;
}

body {
  margin: 0;
  font-family: sans-serif;
}

.draggable-object {
  width: 160px;
  height: 160px;
  border: 1px solid #ddd;
  border-radius: 2px;
  display: inline-block;
}

.draggable-subject {
  background: #f0f0f0;
  padding: 4px 8px;
}

style.css is also no different from the previous example.

app.js
const draggableObject = document.querySelector('.draggable-object')
const draggableSubject = document.querySelector('.draggable-subject')
const unit = 'px'
let positionLeft = 0, positionTop = 0
let positionLeftMax = 9999, positionTopMax = 9999

function setMaxPositions() {
  positionLeftMax = innerWidth - draggableObject.offsetWidth
  positionTopMax = innerHeight - draggableObject.offsetHeight
}

function clamp(value, min, max) {
  return Math.min(max, Math.max(min, value))
}

function startDrag(e) {
  e.preventDefault()
  document.onmousemove = drag
}

function drag(e) {
  positionLeft += e.movementX
  positionTop += e.movementY

  draggableObject.style.left = clamp(positionLeft, 0, positionLeftMax) + unit
  draggableObject.style.top = clamp(positionTop, 0, positionTopMax) + unit
}

function endDrag() {
  document.onmousemove = null
}

setMaxPositions()
draggableSubject.onmousedown = startDrag
draggableSubject.onmouseup = endDrag

Note

The JavaScript code above has one issue.

When you release a mouse while your pointer is outside browser window, mouseup event will not be triggered. This causes the browser behavior that even when your pointer goes back inside browser—with mouse releasing—the mousemove event is still in effect. The draggable element keeps tracing your pointer. In order to cancel the mousemove event, you have to once again mousedown the bar, then fire mouseup.