Skip to content

Instantly share code, notes, and snippets.

@DavidSouther
Created September 3, 2015 17:04
Show Gist options
  • Save DavidSouther/b625771fd2ab968e776e to your computer and use it in GitHub Desktop.
Save DavidSouther/b625771fd2ab968e776e to your computer and use it in GitHub Desktop.
A hastily sanitized demo of a Draggable directive.
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||angular.noop)({'$event': evt});
document.addEventListener('mouseup', this.up = apply(function(evt){
// stopEvent(evt);
if(!scope.dragging){ return; }
log('Up');
(scope.dragStop||angular.noop)({'$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||angular.noop)({'$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||angular.noop)({'$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(
ng-mouseover="state.show($event)"
ng-mouseout="state.hide($event)"
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