class DraggableView extends View { static get MIN_DRAG_DISTANCE() { return 15; } constructor(element) { super(element); this.element.addEventListener("mousedown", this.onMouseDown.bind(this)); document.body.addEventListener("mousemove", this.onMouseMove.bind(this)); document.body.addEventListener("mouseup", this.onMouseUp.bind(this)); //The touch events this.element.addEventListener("touchstart", this.onMouseDown.bind(this)); document.body.addEventListener("touchmove", this.onMouseMove.bind(this)); document.body.addEventListener("touchend", this.onMouseUp.bind(this)); } /** * Is called on every attempt to drag the element. * Implement this and return true or false, indicating whether the view may be dragged depending on it's current properties. */ mayBeDragged() { return true; } /** * Implement this and return some data if you want anything to be dragged at all. */ getDraggedData() { return null; } /** * Return a string identifier of the data this view holds that may be dragged. */ getDraggedDataType() { return "generic"; } /** * You must implement this and return the DragTargetView holding this DraggableView. */ getDragSourceView() { console.error("You didn't implement getDragSourceView() in your draggable view. You must return the DragTargetView holding the DraggableView."); return null; } /** * Called when the element was just briefly clicked. */ onClicked() { } onDragStart() { } onDragEnd() { } onMouseDown(event) { if (!this.dragging && !this.disabled && this.mayBeDragged()) { var cursorX = event.clientX; var cursorY = event.clientY; if (event.touches && event.touches.length > 0) { var touch = event.touches[0]; cursorX = touch.clientX; cursorY = touch.clientY; } this.dragStartPosition = { x: cursorX, y: cursorY }; this.element.style.width = this.element.clientWidth + "px"; this.element.style.height = this.element.clientHeight + "px"; this.dragging = true; this.dragStartTime = new Date().getTime(); } } onMouseMove(event) { var cursorX = event.clientX; var cursorY = event.clientY; if (event.touches && event.touches.length > 0) { var touch = event.touches[0]; cursorX = touch.clientX; cursorY = touch.clientY; } if (this.dragging) { var distanceX = cursorX - this.dragStartPosition.x; var distanceY = cursorY - this.dragStartPosition.y; var draggedDistance = Math.sqrt(distanceX * distanceX + distanceY * distanceY); if (draggedDistance >= DraggableView.MIN_DRAG_DISTANCE) { if (!this.dragStarted) { this.onDragStart(); this.dragStarted = true; } var width = this.element.clientWidth; var height = this.element.clientHeight; this.element.style.position = "fixed"; this.element.style.zIndex = "1000"; this.element.style.left = (cursorX - (width / 2)) + "px"; this.element.style.top = (cursorY - (height / 2)) + "px"; DragTargetView.dragObject(this.getDraggedData(), this.getDraggedDataType(), this.getDragSourceView(), cursorX, cursorY); } } } onMouseUp(event) { var cursorX = event.clientX; var cursorY = event.clientY; if (event.touches && event.touches.length > 0) { var touch = event.touches[0]; cursorX = touch.clientX; cursorY = touch.clientY; } var wasDragging = this.dragging; var droppedSomewhere = (wasDragging && DragTargetView.dropObject(this.getDraggedData(), cursorX, cursorY)); if (this.dragging) { this.dragging = false; this.dragStarted = false; this.onDragEnd(droppedSomewhere); } this.element.style.left = ""; this.element.style.top = ""; this.element.style.position = ""; this.element.style.zIndex = ""; this.element.style.width = ""; this.element.style.height = ""; var isShort = (new Date().getTime() - this.dragStartTime < 150); //Check if it was actually just a click if it was not dropped on anything. if (isShort) { if (!droppedSomewhere) { this.onClicked(); } return; } //When arriving here, it must be a legitimate drop. } }