In this example : Undo/Redo
Drop the start node on to the canvas.
Mousedown on the port and drag it.
Now while dragging press RIGHT CLICK.
Now the issue is that the port become detach from the start node. It should not be happen.
Please look in to the image below for better understanding.
Please help me to overcome this issue.
Thanks in advance.
I have closely analyse the issue and come to the conclusion as :
Problem is on Mouse Down and Mouse Up.
As I have seen when I have mouse down and drag the port and then press right mouse down.
then what happen is mouse down called in the canvas.js.
Then when right mouse up then mouse up of canvas.js called and make mouseDown = false.
this.html.bind("mouseup touchend", $.proxy(function(event)
{
if (this.mouseDown === false)
return;
event = this._getEvent(event);
this.mouseDown = false;// it makes mouseDown false
this.onMouseUp();
}, this));
So for know quick fix I have ckecked if right mouse up and right mouse down then return as:
In Mouse Down :
this.html.bind("mousedown touchstart", $.proxy(function(event)
{
event.preventDefault();
if(event.which == 3)//added this in the mouse down
return;
event = this._getEvent(event);
this.mouseDownX = event.clientX;
this.mouseDownY = event.clientY;
var pos = this.fromDocumentToCanvasCoordinate(event.clientX, event.clientY);
this.mouseDown = true;
this.onMouseDown(pos.x, pos.y);
}, this));
In Mouse Up :
this.html.bind("mouseup touchend", $.proxy(function(event)
{
//added extra condition for right click
if (this.mouseDown === false || event.which == 3)
return;
event = this._getEvent(event);
this.mouseDown = false;// it makes mouseDown false
this.onMouseUp();
}, this));
After above modification the problem is resolved, I might be wrong. Please correct me, as i have not tested it deeply but ya its working. I need your guidance on that. Sorry for altering the code.
THANKS YOU SO MUCH:)
This is a bug and will be fixed in one of the next releases.
Related
I noticed that these function doesn't work good in Firefox, but does in Chrome.
I use these function in a game in Js to shoot bullet (left mouse click) and to create a fireball all around the player with the right click that burns everyone in a small radius.
document.onclick = function(event) {
if(!player){ //to avoid onclick to be used before calling Player();
return;
}
if(player.canAttack && player.distance >= 80) { //not for sword attack
performAttack(player);
player.canAttack = false;
}
if(player.distance < 80)
performAttack(player);
//event.preventDefault();
}
document.oncontextmenu = function(event) {
//hide default behaviour of right click -> no context menu popup
event.preventDefault();
if(player.obtainedGadjet > 0) {
player.pressingMouseRight = true;
performSpecialAttack(player);
}
}
In the performAttack function I set player.isStopped = true, so my updatePlayer() doesn't change player.x and player.y while he's attacking. The same for the fireball attack. I want my player stays there.
It works in chrome, my player stops, attacks,and then can moves again, but in Firefox if I right click it somethimes acts instead as I have left clicked, so shoot the magic ball, and maybe then the fireball too. Furthermore, my player ignore isStopped = true, it seems like in Firefox oncontextmenu has "lower priority" than other events.
Any idea?
Thanks
Please note that a click event contains information about which button was pressed. You can try yourself with something like:
document.addEventListener('click', function(ev){
console.log(ev.button);
});
And, yes, click events are fired when you right-click, even if you're doing something on related contextmenu events.
So your code should look a bit more like
document.addEventListener('click', function(ev){
if (ev.button === 0) {
// Perform primary action
} else if (ev.button === 2) {
// Perform secondary action
}
});
document.addEventListener('contextmenu', function(ev){
ev.preventDefault();
});
Using the same click event is advisable as said by Ivan. You may also want to read this other discussion here on SO about best practices and why it's not always good to disable default right click behaviour (i.e.: it's not always guaranteed to work).
Go to kitchensink, using middle button of mouse, try to click and hold the mouse on empty area of canvas and move the mouse.
The selection rectangle is displayed. How to disable this? I ask because, I have middle mouse button click and drag bound to canvas pan in previous version of fabric. Upgrading to new version, the canvas is behaving in unexpected manner.
I've tried to disable selection on the canvas on mouse down if the event.button == 1 by doing canvas.selectable = false; in mousedown and set it to true back in mouseup event handler.
That didn't work.
Any ideas how to disable the selection using middle mouse button click and drag?
The problem is that fabric recently enabled click for other button rather than left.
The point is that left is handled, right is handled, middle is not...
I guess the middle button follow the flow of the left button just because it is not the right one.
here a snippet from the mousedown handler function of fabric as at version 1.7.3 ( current as feb 2017 ).
__onMouseDown: function (e) {
var target = this.findTarget(e);
// if right click just fire events
var isRightClick = 'which' in e ? e.which === 3 : e.button === 2;
if (isRightClick) {
if (this.fireRightClick) {
this._handleEvent(e, 'down', target ? target : null);
}
return;
}
... continue normal flow ...
so this require a proper fix.
Posting a custom event as suggested is a patch, but normally this should not happen at all.
(since i m a mantainer for the project i m going to fix this)
Prasanth, your problem is simple. You have typo. Try to use like this:
canvas.selection = false;
Here is a code which you can try:
canvas.on('mouse:down',function(e){
canvas.selection = true;
});
canvas.on('mouse:down',function(e){
if( e.e.button == 1 ) {
canvas.selection = false;
};
});
I am developing an HTML5 Canvas project and while adding multitouch support for mobile devices, I seem to have run into an issue on Mobile Safari in iOS 7.1.
The main way that users interact with my app is by clicking and dragging. On the desktop, I add the appropriate mouse event listeners to my canvas...
c.addEventListener('mousedown', mouseDown, false);
c.addEventListener('mousemove', mouseMoved, false);
c.addEventListener('mouseup', mouseUp, false);
... have these event handlers calculate mouse position and call out to a more generic function that just accepts the X and Y position of the event...
function mouseDown(evt)
{
var pos = getMousePos(evt);
inputDown(pos);
}
function mouseUp(evt)
{
var pos = getMousePos(evt);
inputUp(pos);
}
function mouseMoved(evt)
{
var pos = getMousePos(evt);
inputMoved(pos);
}
function getMousePos(evt)
{
var rect = c.getBoundingClientRect();
return { 'x': evt.clientX - rect.left, 'y': evt.clientY - rect.top }
}
... and everything works great. I designed this level of abstraction to allow for easy expansion to other input methods. So now I attempt to use the Touch API to expand this. First I add my handlers to the canvas right next to the mouse handlers...
c.addEventListener("touchstart", touchDown, false);
c.addEventListener("touchmove", touchMoved, false);
c.addEventListener("touchend", touchUp, false);
c.addEventListener("touchcancel", touchUp, false);
... then add my thin event handlers to abstract away the touch events ...
function touchDown(evt)
{
evt.preventDefault();
// Ignore touches after the first.
if (activeTouch != null)
return;
if (evt.changedTouches.length > 0)
{
activeTouch = evt.changedTouches[0].identifier;
var pos = getTouchPos(evt);
inputDown(pos);
}
}
function touchUp(evt)
{
var pos = getTouchPos(evt);
activeTouch = null;
inputUp(pos);
}
function touchMoved(evt)
{
var pos = getTouchPos(evt);
inputMoved(pos);
}
function getTouchPos(evt)
{
var canX = 0;
var canY = 0;
for( var i = 0; i < evt.touches.length; i++ )
{
if (evt.touches[i].identifier == activeTouch)
{
canX = evt.touches[i].pageX - c.offsetLeft;
canY = evt.touches[i].pageY - c.offsetTop;
break;
}
}
return { 'x': canX, 'y': canY }
}
... and this is where I run into trouble! You can see things get a little hairy but inefficiencies aside, I think I am using everything correctly. The problem is that getTouchPos(evt) seems unable to get the correct X, Y position of a touch on touchstart. On my first touch, I get a position of 0,0. If I drag my finger, the touchmove fires multiple times and the X,Y coordinates reported seem fine. If I lift my finger, touchend fires and I also get a correct location. However, if I touch again, touchstart fires and rather than where I am touching, I get the X,Y coordinates of where my last touch ended!
I've gone in with a debugger and sure enough, the stale/uninitialized values are right there in the Touch objects I get in the event data. Am I doing anything obviously wrong? I don't understand why I seem to be getting bad coordinates from touchstart events. What can I do to work around this issue? Is there another source I can use to get the correct position? A subtle tweak to event order?
Here's a link to an online demo of the full code if you'd like to run some in-browser debug.
And thanks in advance for any help.
I'm not sure if it's obvious, but it was a fun issue to debug. So basically, the confusion comes down to this guy:
function mouseMoved(evt) {
var pos = getMousePos(evt);
inputMoved(pos);
}
For your mouse events, everything works great, because you're bound to mousemove.
c.addEventListener('mousemove', mouseMoved, false);
Which calls
function mouseMoved(evt) {
var pos = getMousePos(evt);
inputMoved(pos);
}
So, as you move your mouse around, your posX/posY values are updated continuously. (Hopefully you see the issue now :)
For TouchEvents, when a user touches (but does not move), you only trigger touchstart and touchend. It isn't until a user drags, that touchmove gets called, which in turn calls the function touchMoved (that calls inputMoved - which updates your posX/posY values).
The easiest way to address this issue on your page is just to call inputMoved in both touchstart and touchmove so your MassHaver instance has the latest state.
I want to cancel an HTML5 drag operation based on some condition. I have tried to search this but found nothing useful. It seems that there is no way to cancel an HTML5 drag and drop using JavaScript. returning false in the dragstart doesn't seem to do anything. Any ideas?
You can cancel it by calling event.preventDefault() in the event handler.
For example this should work:
<p id="p1" draggable="true" ondragstart="dragstart_handler(event);">This element is draggable.</p>
<script>
var enableDragDrop = true;
function dragstart_handler(ev) {
if (!enableDragDrop) {
ev.preventDefault();
}
console.log("dragStart");
}
</script>
I think you need to do something tricky to make it work, for I do not know how to stop a drag from js, but you can fake a drag with mousedown,mousedown,mouseup and a isDragging flag
some code look like:
var isDragging = false
var fakeDraggingElement
var currentDragging
$('#item').mousedown(function(e){
e.preventDefault()
isDragging = true
currentDragging = this
//change your cursor and make it loos like dragging
$('#parent').css({cursor: 'move'})
//fake dragging element
fakeDraggingElement = $(this).clone().css({
opacity:0.5,
position:'absolute',
top:e.pageY+offsetY, //parent offset
left:e.pageX+offsetX,//parent offset
}).appendTo(parent)
}).mousemove(function(e){
if(!isDragging){
return
}
fakeDraggingElement.css({
top:e.pageY+offsetY, //parent offset
left:e.pageX+offsetX,//parent offset
})
}).mousedown(function(e){
if(!isDragging){
return
}
cancleDrag()
//your old drop
ondrop(currentDragging,e.target)
})
function cancleDrag(){
isDragging = false
$(currentDragging).remove()
currentDragging = undefined
}
EDIT:
got it. Its a bit roundabout, but works. Take advantage of the fact that the drag event is a cancellable mouse event, and cancelling it stops all further drag actions. Create a drag event on your condition and call preventDefault(). The following cancels it after 3 seconds:
setTimeout(function(){document.getElementById("drag").ondrag = function(e){
e.preventDefault();
this.ondrag = null;
return false;
};},3000);
Note first that I clear all ondrag events after it is cancelled, which you may need to adjust if you need other ondrag events, and second that this truly cancels all parts of the drag, so you don't get an ondragend event after, as shown in this jsfiddle:
http://jsfiddle.net/MaxPRafferty/aCkbR/
Source: HTML5 Spec: http://www.w3.org/html/wg/drafts/html/master/editing.html#dndevents
Anyone have any idea how to detect a mouseup event on a scrollbar? It works in FF, but not in Chrome or IE9.
I set up a quick demo: http://jsfiddle.net/2EE3P/
The overall idea is that I want to detect a scrollEnd event. There is obviously no such thing so I was going with a combination of mouseUp and timers, but mouseUp isn't firing in most browsers! The div contains a grid of items so when the user stops scrolling I want to adjust the scroll position to the nearest point that makes sense, e.g. the edge of the nearest cell. I don't, however, want to automatically adjust the position if they're in the middle of scrolling.
I'll also happily accept any answer that gives me the equivalent of scrollEnd
found a solution that works without timers but only if you are scrolling the complete window.
switch(event.type){
case 'mousedown':
_btnDown = true;
//THIS IS ONLY CAUSE MOUSEUP ON SCROLLBAR IS BUGGY
$(document).bind('mousemove',function(event){
if(event.pageX < ($(window).width() - 30)){
//mouse is off scrollbar
$(this).unbind(event);
$(this).trigger('mouseup');
}
});
break:
case 'mouseup':
//do whatever
_btnDown = false;
break;
}
pretty dirty .. but works.
Using jquery there is a .scroll event you can use. Maybe use a global variable to keep track of when .scrollTop() (it returns the number of pixels there are above the screen) has stopped changing? Still creates a race condition, but it should work.
Answering my own question so I can close it -- there is no good solution to this, so timers it is...
I was handling the same problem. For me IE9 don't emit mouseup event for scrollbars. So, I checked and on IE9 when you "mouseup" it emits a mousemove event. So what I did was monitor scrolling, and monitor mousemove. When user is scrolling, and a mousemove event happens, then I understand it as a mouseup event. Only do this check for IE9, cheching the proto property availability. The code will also run for Opera, but Opera has the mouseup and then no problem for me when both events happens. Here is the code, I write AngularJS + ZEPTO code, so get the idea and write your own code, don't expect to copy&paste this code directly:
// Global for scrolling timeout
var q;
// Action to do when stop scrolling
var updatePosition = function() {
// Put the code for stop scrolling action here
}
$(document).on('mousemove', function(e) {
console.log('MOUSE MOVE ' + e.pageX + ',' + e.pageY);
if(!('__proto__' in {})) {
// for IE only, because it dont have mouseup
if($scope.scrolling && $scope.mouse_down) {
console.log('FAKE MOUSE UP FOR IE');
// Only simulate the mouseup if mouse is down and scrolling
$scope.scrolling = false;
$scope.mouse_down = false;
// Update Position is the action i do when mouseup, stop scrolling
updatePostition();
}
}
});
$(window).on('scroll', function(){
console.log('SCROLLING');
// Set the scrolling flag to true
if(!$scope.scrolling) {
$scope.scrolling = true;
}
// Stop if for some reason you disabled the scrolling monitor
if(!$scope.monitor_scrolling) return;
// Monitor scroll with a timeout
// Update Position is the action i do when stop scrolling
var speed = 200;
$timeout.cancel(q);
q = $timeout(updatePostition, speed);
});
$(window).on('mousedown', function() {
console.log('MOUSE DOWN');
// Stop monitor scrolling
$scope.monitor_scroll = false;
// Set that user is mouse down
$scope.mouse_down = true;
});
$(window).on('mouseup', function() {
console.log('MOUSE UP');
// Enable scrolling monitor
$scope.monitor_scroll = true;
// Change mouse state
$scope.mouse_down = false;
// Action when stop scrolling
updatePostition();
});
Was fighting with this problem. My system also runs for mobile and I have a large horizontal scrolling, that always when user stop scrolling, it need to find the actual item the used is viewing and centralize this item on screen (updatePosition). Hope this can help you. This is to support IE9+, FF, Chorme and Opera, I'm not worrying with old browsers.
Best Regards
Is very late but.... there are solution with any scroll in any part of your page.... I do it with the next code...
onScroll = function(){
$(window).unbind("mouseup").one('mouseup',function(e) {
alert("scroll up")
});
};
$(window).bind("scroll", onScroll);
body{
height:5000px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>