greensock draggable / triggering click and drag - javascript

I have an issue which is related to greensock animation but also may be a more general js issue in that I need to transfer a mousedown event to a second draggable instance after killing the first draggable instance.
the codepen hopefully will illustrate what i am trying to do.. code is underneath.
Codepen URL: http://codepen.io/anon/pen/ypdGn
var detachdraggable;
var rotatedraggable;
function makeRotateDraggable() {
// create rotate draggable for the cards..
rotatedraggable = Draggable.create(".dragclone", {
type:"rotation",
throwProps:true,
dragResistance : 0,
edgeResistance : 1,
bounds:{minRotation:-60, maxRotation:60},
onDragStart : function() {
var $el = $(this.target);
var cardStartAngle = $el.data('startangle');
},
onDrag: function() {
currentCardAngle = this.rotation;
var $el = $(this.target);
var cardStartAngle = $el.data('startangle');
cardDirection = ( currentCardAngle > cardStartAngle ) ? "up":"down";
cardTravelDegrees = Math.abs(currentCardAngle - cardStartAngle);
this.vars.type = "x";
},
onDragEnd: function() {
},
onClick: function() {
return false;
}
});
$('.dragclone').mousedown(function() {
$('.dragclone').css('z-index','10');
rotatedraggable[0].enable();
});
$('.dragclone').mouseout(function() {
detachdraggable[0].disable();
$('.dragclone').trigger('mousedown');
});
$('.dragclone').trigger('mouseout');
}
// first setup the x,y draggable..
detachdraggable = Draggable.create('.dragclone', {
type: "x,y",
edgeResistance:1,
throwProps:true,
onPress:function() {
startX = this.x;
startY = this.y;
},
onDrag:function() {
var xChange = this.x - startX,
yChange = this.y - startY,
ratio = Math.abs(xChange / yChange),
direction = [];
// NB:: you can adjust these ratio thresholds to make things
// more or less sensitive to diagonal movement.
if (ratio > 0.25) {
direction.push((xChange < 0) ? "left" : "right");
}
if (ratio < 4) {
direction.push((yChange < 0) ? "up" : "down");
}
if(direction[0] == "left") {
// TweenMax.to( $('.cloned'), .0001, {right:-xChange + 135});
}
// moving up so lets switch cards !!
if(direction[0] == "up") {
if(Math.abs(yChange) > 20) {
makeRotateDraggable();
}
}
},
onDragEnd:function() {
// driftDragCardBack();
// if(!cardPopping) { driftClonedCardBack(); }
},
onThrowComplete: function() {
}
});
I am battling to switch between 2 draggables setup on same element, am wondering if this is possible at all. basically the codepen has an example of what I want to do, but it isnt seamless. draggable is setup for element of type x,y, what i want to do is when the drag direction is up kill the type x,y draggable and switch to a type: rotation draggable so that the card moves around on an axis. you can see mine does that, but only if you release and then click again - is there any way to make this seamless, so it just switches mid-drag ?
thanks,
Justin

See http://codepen.io/anon/pen/klanu
I've never used greensock but just had a look at their document:
https://greensock.com/docs/#/HTML5/Drag/Draggable/startDrag/
First of all you had a couple of issues within your code. You don't need to create rotatedraggable inside a function, just create it, it's not enabled anyways. I also moved
$('.dragclone').mousedown(function() {
$('.dragclone').css('z-index','10');
detachdraggable[0].enable();
});
outside the function.
In your 2nd draggable, you were calling createRotation to create the rotation but like I said you can create it at the start. When the div is moved to the top, I just disabled the current drag and enabled the 1st one and called dragStart on it. e is what's passed to drag of the 2nd.
if(Math.abs(yChange) > 20) {
detachdraggable[0].disable();
rotatedraggable[0].enable();
rotatedraggable[0].startDrag(e);
}

Related

Custom drag drop implementation

I am rolling out a custom drag drop implementation which is a simplified version of the Dragula library. Here are my fiddles:
With Dragula: http://jsfiddle.net/8m4jrfwn/
With my custom drag drop implementation: http://jsfiddle.net/7wLtojs4/1/
The issue I am seeing is that my custom drag and drop implementation is a bit to free-form. I would like for the user to only be able to drop on the top or bottom of another div with the class box. How can I make this possible? Code here:
function handleMouseDown(e) {
window.dragging = {};
dragging.pageX = e.pageX;
dragging.pageY = e.pageY;
dragging.elem = this;
dragging.offset = $(this).offset();
$('body')
.on('mouseup', handleMouseUp)
.on('mousemove', handleDragging);
}
function handleDragging(e) {
let left = dragging.offset.left + (e.pageX - dragging.pageX);
let top = dragging.offset.top + (e.pageY - dragging.pageY);
$(dragging.elem)
.offset({top: top, left: left});
}
function handleMouseUp() {
$('body')
.off('mousemove', handleDragging)
.off('mouseup', handleMouseUp);
}
let boxElement = '.item';
$(boxElement).mousedown(handleMouseDown);
I does not see any logic here about what will happen on mouseup event. Seems you need detect on mouseup new order of elements and then exchange their positions.
For this you should know positions of all of them. On mouseup you can reorder them based on new positions.
In my realization(https://jsfiddle.net/jaromudr/c99oueg5/) I used next logic:
onMove(draggable) {
const sortedDraggables = this.getSortedDraggables()
const pinnedPositions = sortedDraggables.map((draggable) => draggable.pinnedPosition)
const currentIndex = sortedDraggables.indexOf(draggable)
const targetIndex = indexOfNearestPoint(pinnedPositions, draggable.position, this.options.radius, getYDifference)
if (targetIndex !== -1 && currentIndex !== targetIndex) {
arrayMove(sortedDraggables, currentIndex, targetIndex)
this.bubling(sortedDraggables, draggable)
}
}
bubling(sortedDraggables, currentDraggable) {
const currentPosition = this.startPosition.clone()
sortedDraggables.forEach((draggable) => {
if (!draggable.pinnedPosition.compare(currentPosition)) {
if (draggable === currentDraggable && !currentDraggable.nativeDragAndDrop) {
draggable.pinnedPosition = currentPosition.clone()
} else {
draggable.pinPosition(currentPosition, (draggable === currentDraggable) ? 0 : this.options.timeExcange)
}
}
currentPosition.y = currentPosition.y + draggable.getSize().y + this.verticalGap
})
}
where on move we detect if position in list was changed and move other draggables to their new positions.
On drag end we just move currentDraggable to pinnedPosition

Executing a line in a conditional AND by default on start

I have this fiddle: http://jsfiddle.net/zhaem/Lyzrtefo/7/
var orangeMode = true
var isTracking = true
getMouseXY = function(e) {
if (isTracking) {
var tempX = e.pageX
var tempY = e.pageY
if (tempX < 0){tempX = 0}
if (tempY < 0){tempY = 0}
document.getElementById("circle1").style.top = (tempY - 25) + "px";
document.getElementById("circle1").style.left = (tempX - 25) + "px";
}
return true
}
document.onmousemove = getMouseXY;
var toggleTrackCircle = function() {
isTracking = !isTracking;
console.log(isTracking);
}
document.getElementById("circle1").addEventListener("click", toggleTrackCircle);
flip = function() {
orangeMode = !orangeMode;
if (orangeMode) {
document.getElementById("circle1").style.backgroundColor = "orange";
document.getElementById("circle1").addEventListener('mouseover', function() {isTracking = true;})
// When the above line is executed the circle will stick to your cursor on HOVER after clicking and setting it down.
} else {
document.getElementById("circle1").style.backgroundColor = "blue";
}
}
document.getElementById("box3").addEventListener("click", flip);
There is this one line, that when present will change the behavior of the interaction. (You can always click to stop the cursor from tracking you, but when this line is there, the circle will re-stick to it on hover, and when it's not, it will only restick on hover + click.
document.getElementById("circle1").addEventListener('mouseover', function() {isTracking = true;})
I'm trying to wrap it in some conditional logic in the flip function (which you can control by tapping the red box in the corner) so that orangeMode == it sticks on hover and not orangeMode it only re-sticks on click.
The flip function works fine for changing the color, but this event listener isn't performing like I'd want. (once you cycle through it does work but for either state and it's not running orangeMode unload.
Any help would be much appreciated.
You need to put 'isTracking=true;' inside a named function, so you can use "removeEventListener" to take the function off. That means you add this function:
var trackCircle = function() {
isTracking = true;
}
Then you reference that on click instead of the anonymous function:
circle.addEventListener('mouseover', trackCircle)
Then you simply remove that event in your else:
circle.removeEventListener('mouseover', trackCircle)
Oh, and I'd add this at the top so you don't need to keep repeating the getElementById phrase:
circle = document.getElementById("circle1");
Hope that helps. Oh, and here's the edit to your fiddle:
http://jsfiddle.net/Lyzrtefo/9/

Scrolling in a single direction: horizontal OR vertical

I am looking for a way to only scroll horizontal OR vertical inside a html table view while maintaining a header and row that is always visible. Preferably I would like something similar to this but in pure Javascript without ember or coffeescript. I prefer not to use the ember-table because the rest of my project is not based on ember and I am unfamiliar with it.
So I started out with something similar here. It has the benefit of having the header row and column but it scrolls in both the horizontal direction as well as the vertical direction. The difference between this example and the first one is that the addepar table only scrolls in one direction. Which is a more calm user experience.
I have been looking into possible ways to get to where I want. The first part seems to be to check in which direction the user is scrolling. Such a thing can be done with jQuery;
var previousScrollvertical = 0,
previousScrollHorizontal = 0;
$(window).scroll(function(){
var currentVerticalScroll = $(this).scrollTop(),
currentHorizontalScroll = $(this).scrollLeft();
if(currentVerticalScroll==previousScrollvertical) {
if (currentHorizontalScroll > previousScrollHorizontal){
console.log('Right');
} else {
console.log('left');
}
} else if(currentHorizontalScroll==previousScrollHorizontal) {
if (currentVerticalScroll > previousScrollvertical){
console.log('down');
} else {
console.log('up');
}
}
previousScrollHorizontal = currentHorizontalScroll;
previousScrollvertical =currentVerticalScroll;
});
This snippet of code works on any website that has jQuery loaded. You can try it out from the console.
But from here I seem to be stuck. Is it possible to block a scroll direction with jQuery? Is there an easier way to achieve this? Should I be considering a completely different route?
The short answer is to use jQuery's scrollTop or scrollLeft to set the scroll of the direction you want to block back to what it was before.
I've created a quick example that shows how one might do that in practice:
Live Demo
var $container = $('.table-container');
var $table = $container.find('table');
var previousScroll = [0, 0];
var correction = false;
// Adjust the threshold to a larger number if you'd like it
// to take longer to switch between horizontal and vertical
// scrolling
var threshold = 10;
var direction;
var directionTimeout;
$container.on('scroll', function (event) {
if (!correction) {
var element = event.currentTarget,
$element = $(event.currentTarget),
x = element.scrollLeft,
y = element.scrollTop;
var diff = [
Math.abs(x - previousScroll[0]),
Math.abs(y - previousScroll[1])
];
correction = true;
if (!direction) {
if (diff[0] > diff[1]) {
direction = 'horizontal';
} else if (diff[0] < diff[1]) {
direction = 'vertical';
} else {
direction = 'vertical';
}
}
if (direction === 'horizontal') {
$element.scrollTop(previousScroll[1]);
previousScroll = [x, previousScroll[1]];
} else {
$element.scrollLeft(previousScroll[0]);
previousScroll = [previousScroll[0], y];
}
clearTimeout(directionTimeout);
directionTimeout = setTimeout(function () {
direction = null;
}, threshold);
} else {
correction = false;
}
});

Dragging a window by its components using Javascript

I have developed a Windows application using TideSDK with HTML , CSS and Javascript.To give it a widget look I disappered its title bar.So I can't drag it.The TideSDK documentation says "after disappearing title bars, you can drag window using its contents with javascript".
How can I drag the window with javascript selecting its components(tiles in my case)?Any tutorial or code as I found nothing on google with my search.
My App looks like below:
I've written the following generic function for dragging using JS:
function setDragOfElementOnAnother ($draggableElement, $draggedElememnt, allowDragPredicate) {
var stopDragFunction = function() {
$draggedElememnt.data("drag", false);
$draggedElememnt.removeData("startPoint");
$("html, body").unbind("mouseup.drag");
$("html, body").unbind("mousemove.drag");
};
var dragFunction = function(e) {
if (!parseBoolean($draggedElememnt.data("drag")))
return;
var begin = $draggedElememnt.data("startPoint");
$draggedElememnt.css({ left: e.clientX - begin.x, top: e.clientY - begin.y });
};
$draggableElement.mousedown(function(e) {
if ((e.clientX - $(this).offset().left < 0 || $(this).offset().left + $(this).width() < e.clientX) ||
e.clientY - $(this).offset().top < 0)
return;
if (allowDragPredicate && !allowDragPredicate(e))
return;
$draggedElememnt.data("drag", true);
$draggedElememnt.data("startPoint", Point(e.clientX - $(this).offset().left, e.clientY - $(this).offset().top));
$("html, body").bind("mouseup.drag", stopDragFunction);
$("html, body").bind("mousemove.drag", dragFunction);
});
$draggableElement.mouseup(stopDragFunction);
$draggableElement.mousemove(dragFunction);
}
This function is used to declare dragging of one element using another.
Prerequisites:
(1) The dragged element's position has to be either fixed or absolute (relative should also work). (2) jQuery.
By specifying both dragged and draggable elements as the same one, pressing on the element and moving the mouse will cause the element to drag.
The 'allowDragPredicate' variable is optional, and is useful to create boundaries.
EDIT: Forgot. Also add the code:
function Point(xVal, yVal) {
if (xVal === undefined) {
xVal = 0;
}
if (yVal === undefined) {
yVal = 0;
}
return {
x: xVal,
y: yVal
};
}
EDIT 2: And:
function parseBoolean(str) {
if (str === true)
return true;
if (str)
return /^true$/i.test(str);
return false;
}
EDIT 3: And, added a simple jsFiddle example.

html5 animate canvas with elements already drawn

Can I get some help with animating elements on a canvas? I would like to get the elements already drawn on the canvas and "move" them off the canvas and display the new elements. My functions are in javascript and work nicely. I would just like to add animation. TIA.
just have an event handler control the left of the style for that canvas's id and then specify a loop to have it change or move to the left/right based on time.
(function() {
var speed = 10,
movePic = function(moveBy) {
var el = document.getElementById("animationStyle"),
left = el.offsetLeft
if ((moveBy > 0 && left > 399) || (moveBy < 0 && left < 51)) {
clearTimeout(timer);
timer = setInterval(function () {
movePic(moveBy * -1);
}, speed);
}
el.style.left = left + moveBy + "px";
};
var timer = setInterval(function () {
movePic(3)
}, speed);
}());
This would move it back and forth, this is an example that should help you get started.

Categories