Skip to content

Instantly share code, notes, and snippets.

@DavidSouther
Last active September 3, 2015 17:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save DavidSouther/20e89d7fdc9af99fcf58 to your computer and use it in GitHub Desktop.
Save DavidSouther/20e89d7fdc9af99fcf58 to your computer and use it in GitHub Desktop.
An Angular 1.x dragging directive. The drag directive has several callback attributes available, the main being drag itself. For every drag event, the component has an opportunity to update itself.
var log = debug('draggable');
function Draggable(element, scope){
var apply;
if(scope.$apply){
apply = function(fn){
return function(){
var context = this;
var args = arguments;
scope.$apply(function(){
switch(args.length){
case 0: fn.call(context); break;
case 1: fn.call(context, args[0]); break;
case 2: fn.call(context, args[0], args[1]); break;
default: fn.apply(context, args);
}
});
};
};
} else {
apply = function(fn){
return fn;
};
}
scope.startDrag = scope.startDrag || angular.noop;
scope.stopDrag = scope.stopDrag || angular.noop;
scope.drag = scope.drag || angular.noop;
element.addEventListener('mousedown', this.down = apply(function(evt){
stopEvent(evt);
log('Down');
scope.dragging = true;
scope.dragStart({'$event': evt});
document.addEventListener('mouseup', this.up = apply(function(evt){
// stopEvent(evt);
if(!scope.dragging){ return; }
log('Up');
scope.dragStop({'$event': evt});
scope.dragging = false;
this.remove();
}.bind(this)), false);
document.addEventListener('mouseout', this.out = apply(function(evt){
// stopEvent(evt);
if(evt.toElement !== document.children[0]){ return ; }// Exiting the document
if(!scope.dragging){ return; }
log('Out');
scope.dragStop({'$event': evt});
scope.dragging = false;
this.remove();
}.bind(this)), false);
document.addEventListener('mousemove', this.move = apply(function(evt){
stopEvent(evt);
log('Moving');
if(!scope.dragging){ return; }
log('Dragging');
scope.drag({'$event': evt});
}.bind(this)), false);
}.bind(this)), false);
if(scope.$on){
scope.$on('$destroy', function(){
this.destroy();
}.bind(this));
}
}
Draggable.prototype.destroy = function(){
if(!this.element){
// The element is already destroyed?
return;
}
this.element.removeEventListener('mousedown', this.down);
this.remove();
};
Draggable.prototype.remove = function(){
document.removeEventListener('mouseup', this.up);
document.removeEventListener('mouseout', this.out);
document.removeEventListener('mousemove', this.move);
};
function Drag(){
this.restrict = 'A';
this.scope = {
dragStart: '&',
dragStop: '&',
drag: '&'
};
}
Drag.prototype.link = function(scope, elem){
new Draggable(elem[0], scope);
};
Drag.factory = function(){
return new Drag();
};
angular.module('ttop.util.drag', [
])
.value('Draggable', Draggable)
.directive('drag', Drag.factory)
;
function stopEvent(evt){
if(evt.stopPropagation){evt.stopPropagation();}
if(evt.preventDefault){evt.preventDefault();}
evt.returnValue = false;
}
function Token(){
this.templateUrl = 'map/token';
this.controller = TokenController;
this.scope = {
x: '=',
y: '=',
name: '=',
color: '='
};
this.link = function(scope, iElement, iAttrs, controller){
controller.element = iElement[0];
};
}
TokenController.$inject = ['$timeout'];
function TokenController($timeout){
this.isDetailsVisible = false;
}
TokenController.prototype = Object.create({
moveToken: function($event){
var zoom = this.figureZoom();
this.x += $event.movementX / 48 / zoom.scaleX;
this.y += $event.movementY / 48 / zoom.scaleY;
},
figureZoom: function(){
var e = this.element;
while(e.parentElement.nodeName !== "MAP"){ e = e.parentElement; };
var transform = window.getComputedStyle(e).transform;
var matrix = transform.match(/matrix\((.*)\)/)[1].split(',');
// Should expand to useing a full decomposition, but no rotations
return {
scaleX: matrix[0],
scaleY: matrix[3]
}
}
});
angular.module('ttop.map.token', [
'ttop.util.drag',
'map.token.template'
])
.component('token', Token)
.filter('shortName', function(){
return function(name){
return name.charAt(0);
};
})
;
md-card(
drag="state.moveToken($event);"
style="\
position: absolute;\
top: {{ state.y * 48 }};\
left: {{ state.x * 48 }};\
width: 48;\
height: 48;\
background: {{state.color}};\
border: 2px solid black;\
border-radius: {{ state.scale / 4}};\
display: table;\
"
)
div(
style="display: table-cell; vertical-align: middle; text-align: center;"
)
div
| {{ state.name | shortName }}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment