Skip to content

Instantly share code, notes, and snippets.

@dtothefp
Created February 20, 2014 22:51
Show Gist options
  • Save dtothefp/9124970 to your computer and use it in GitHub Desktop.
Save dtothefp/9124970 to your computer and use it in GitHub Desktop.
Vanilla JS Draggable Directive
module = angular.module 'draggable', []
module.controller "dragDropCtrl", ($scope) ->
$scope.dropPosition = null
module.directive 'pixbiDraggable', ($timeout) ->
restrict: 'A'
controller: 'dragDropCtrl'
scope: {
dropPosition: "="
}
transclude: true
replace: true
# Did not make template because when replace is set to true Angular throws an error "must have exactly one root element"
template: '''
<div class="draggable" ng-transclude ng-mousedown="makeDraggable($event)" ng-mouseenter="makeCursor()" ng-mouseleave="removeCursor()" ng-mousemove="animateDrag($event)" ng-mouseup="stopDraggable($event)">
</div>
'''
link: ($scope, $element, $attributes) ->
draggable = false
elm = $element[0]
initialMousePosition = {}
offsetX = 0
offsetY = 0
totalX = 0
totalY = 0
lastX = 0
lastY = 0
elmAttrs = null
initialElmPos = {}
getElmAttr = ->
elmAttrs = {
top: elm.offsetTop
left: elm.offsetLeft
width: elm.offsetWidth
height: elm.offsetHeight
}
# TODO Element position/size is not correct upon initial execution of link function. Currently, using timeout to find attributes after link
$timeout( getElmAttr, 500)
$scope.makeDraggable = (e) ->
draggable = true
initialElmPos = {
top: elm.offsetTop
left: elm.offsetLeft
}
initialMousePosition =
x: e.pageX
y: e.pageY
$scope.animateDrag = (e) ->
e.preventDefault();
if draggable
elm.style.transform = elm.style.webkitTransform = "translate3d(#{totalX + (e.pageX - initialMousePosition.x)}px, #{totalY + (e.pageY - initialMousePosition.y)}px, 0)"
offsetX = e.pageX - initialMousePosition.x
offsetY = e.pageY - initialMousePosition.y
elmAttrs.top += offsetY - lastY
elmAttrs.left += offsetX - lastX
if checkDragPos elmAttrs, $scope.dropPosition
elm.style.transition = "all 1s ease"
# TODO Elements are stacking on top of one another, fix layout of where want elements to end up
elm.style.transform = elm.style.webkitTransform = "translate3d(" + ($scope.dropPosition.left + ( $scope.dropPosition.width / 2 ) - (elmAttrs.width / 3)) + "px, " + ($scope.dropPosition.top + ( $scope.dropPosition.height / 2 ) - (elmAttrs.height / 3)) + "px, 0)"
draggable = false
lastY = offsetY
lastX = offsetX
$scope.stopDraggable = (e) ->
if draggable
elm.style.transition = "all 1s ease"
elm.style.transform = elm.style.webkitTransform = "translate3d(#{initialElmPos.left}px, 0, 0)"
draggable = false
totalX += offsetX
totalY += offsetY
lastX = 0
lastY = 0
checkDragPos = (draggablePos, dropablePos ) ->
# TODO Currently only checking if element has entered bucked bounds from the left. Would want to check top, bottom, right depending upon layout
if draggablePos.left + draggablePos.width >= dropablePos["left"]
true
else if draggablePos.top <= (dropablePos.top + dropablePos.height) and draggablePos.left >= dropablePos.left
true
else
false
module.directive 'pixbiDropable', ($timeout) ->
restrict: "A"
controller: 'dragDropCtrl'
transclude: true
replace: true
template: '''
<div class="dropable"></div>
'''
scope:
dropPosition: "="
link: ($scope, $element, $attributes) ->
elm = $element[0]
$scope.dropPosition = null
checkPos = ->
$scope.dropPosition =
top: elm.offsetTop
left: elm.offsetLeft
width: elm.offsetWidth
height: elm.offsetHeight
# TODO Element position/size is not correct upon initial execution of link function. Currently, using timeout to find attributes after link
$timeout checkPos, 500
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment