I want to be able to click on a canvas, move it to the map, drop it on the map. After dropping it on the map, they can select the canvas on the map and move it again. The process is repeated. I have trouble with the ignoreMouseMove variable, it does not reset to false and is always true.
Here is link to the demo: https://pokemon-map-electro2k.c9users.io/index.html
var moveCanvas = function ($canvas, e) {
$(".map ul li." + $canvas).offset({
left: e.pageX - 30,
top: e.pageY - 30
});
};
// When user first click on canvas
var onmousemove = function ($canvas) {
var ignoreMouseMove = false;
// Make canvas follow cursor in the map area
$(".map").mousemove(function (e) {
if (ignoreMouseMove) return; // event handling mousemove is "disabled"
moveCanvas($canvas, e);
}).click(function () {
// "re-enable" mousemove
ignoreMouseMove = true;
// When canvas is click on again within the map area, make canvas follow cursor
$(".map ul li").click(function () {
$(".map").mousemove(function (e) {
if (!ignoreMouseMove) return;
moveCanvas($canvas, e);
}).click(function () {
// Click function does not work anymore. ignoreMouseMove can't be reset. It is always true
ignoreMouseMove = false;
})
});
});
};
You may need to change the below line
// "re-enable" mousemove
ignoreMouseMove = true;
in to
// "re-enable" mousemove
ignoreMouseMove = !ignoreMouseMove;
Related
I have a slider made on the basis of scroll. The slider was made specifically for the adaptive. But from dekstop I had a problem. When I start to swipe scroll I have links clicked automatically. How can I prevent it?
$('.js_slider-item').on('dragstart', function() {
return false;
});
// slider
$('.js_slider-viewport').each(function() {
var slider = $(this),
sliderClosest = $(this).closest('.js_slider'),
sliderMouse = false,
sliderPos,
sliderX,
scroll,
movePos,
moveX,
moveWalk;
// mousedown
slider.on('mousedown', function(e) {
sliderMouse = true;
sliderPos = slider.offset();
sliderX = e.pageX - sliderPos.left;
scroll = slider.scrollLeft();
});
// mouseleave
slider.on('mouseleave', function(e) {
sliderMouse = false;
});
// mouseup
slider.on('mouseup', function(e) {
sliderMouse = false;
});
// mousemove
slider.on('mousemove', function(e) {
if (!sliderMouse) return;
e.preventDefault();
movePos = slider.offset(),
moveX = e.pageX - sliderPos.left,
moveWalk = (moveX - sliderX) * 2;
slider.scrollLeft(scroll - moveWalk);
});
});
https://jsfiddle.net/xLwDgZODc/52dwu7v9/17/
You can add an event listener to divert all the click event over document or window so that it will not do default behavior on click anywhere in the page (document/window)
code might look like (sample code -sudo code)
// override the click all over the window
$(document).on('click' function () {
// console.log(' click is not allowed while scrolling');
alert('clicked blocked ');
})//
Then once user stopped scrolling, you can remove the click listener
// remove event listener from document
$(document).removeEventListener("click", function () {
// console.log(' click is not allowed while scrolling');
alert('clicked blocked ');
});
I am trying to catch when user press left button on mouse while hovering over cells in a html table using vanilla javascript. The purpose is to paint a cell in black when user is clicking with mouse while dragging (drawing like in MsPaint, when you draw a line for example)
I added an "over" event listener on each td of my table and used buttons property to check if left button is pressed or not:
celle = document.getElementsByTagName("td");
for (i=0;i<celle.length;i++)
celle[i].addEventListener("mouseover", function(e){
if(e.buttons == 1 ){
e.target.style.backgroundColor="black";
}
})
This code works but not always and not perfectly. First it starts setting the background color of the next element, not the one on which I pressed the mouse. Moreover, sometimes it doesn't set any color at all (there is a small icon like "accessed denied" in Chrome's window). It appears to work quite randomly and unpredicatably.
I tried also with jQuery, but I found similar problems. Anyone can help me?
Thanks a lot
Split the problem into several parts. I would add a mousedown and mouseup eventlistener to the whole window and set a global state if you're currently drawing:
var drawState=false
window.addEventListener("mousedown",function(e){
if(e.button===1){
drawState = true;
}});
window.addEventListener("mouseup",function(e){
if(e.button===1){
drawState = false;
}});
You can improve the window listeners with some checks, if the mouse is over a cell.
After this you can add a mouseenter listener to all your cells. Mouseenter is only fired once you enter a cell and not on every move inside the element:
celle[i].addEventListener("mouseenter", function(e){
if(drawState){
e.target.style.backgroundColor="black";
}
})
Instead of tracking mouseover, track three events:
mousemove - to constantly get the mouse position
mousedown - to set the mouse state as currently clicked down
mouseup - to set the mouse state as currently released
It works this way:
handleMousemove constantly updates the mouse position and check mouse state
When the mouse is clicked down, handleMousedown is fired
handleMousedown set the state as 'down'
When handleMousemove sees that mouse state is 'down', it fires click event at the current mouse position
When the mouse is released, handleMouseup is fired
handleMouseup set the state as 'released' and everything returns to normal
Repeat
var mouseIsDown = false;
var mousePosition = { x:-1, y:-1 };
let handleMousemove = (event) => {
// get the mouse position
mousePosition.x = event.x;
mousePosition.y = event.y;
if(mouseIsDown) // if mouse state is currently down, fire click at mouse position
{
let elem = document.elementFromPoint(mousePosition.x, mousePosition.y);
// you can add some conditions before clicking
if(something)
{
elem.click();
}
}
};
let handleMousedown = (event) => {
mouseIsDown = true;
// set the mouse state as 'down'
};
let handleMouseup = (event) => {
mouseIsDown = false;
// set the mouse state as 'release'
};
document.addEventListener('mousemove', handleMousemove);
document.addEventListener('mousedown', handleMousedown);
document.addEventListener('mouseup', handleMouseup);
Working fiddle: https://jsfiddle.net/Black3800/9wvh8bzg/5/
Thanks to everybody for your kind answers. Proposed codes work almost ok. The only problem is that sometimes browser shows the NO SYMBOL cursor. Unfortunately I can't post an image but you can find it here:
NO Symbol
and the only way to keep on drawing is clicking outside the table and then clicking again inside.
This is my code:
var mouseIsDown = false;
var mousePosition = { x:-1, y:-1 };
let handleMousemove = (event) => {
// get the mouse position
mousePosition.x = event.x;
mousePosition.y = event.y;
if(mouseIsDown) // if mouse state is currently down, fire click at mouse position
{
let elem = document.elementFromPoint(mousePosition.x, mousePosition.y);
// you can add some conditions before clicking
if (event.buttons==1)
{
elem.click();
}
}
};
let handleMousedown = (event) => {
mouseIsDown = true;
// set the mouse state as 'down'
};
let handleMouseup = (event) => {
mouseIsDown = false;
// set the mouse state as 'release'
};
document.addEventListener('mousemove', handleMousemove);
document.addEventListener('mousedown', handleMousedown);
document.addEventListener('mouseup', handleMouseup);
celle = document.getElementsByTagName("td");
for (i=0;i<celle.length;i++)
celle[i].addEventListener("click", function(e){
e.target.style.backgroundColor="black";
}
)
Isn't it easier to just add a listener for "click" ? If the element is clicked it also over the cell.
celle[i].addEventListener("click", function(e){
e.target.style.backgroundColor="black";
}
All,
I try to build a resizer UI like this:
My code is like:
<span class="grabber" draggable="false" #mousedown="grab"></span>
grab: function(e) {
var initX = e.screenX;
var mousemove = function(e) {
var offset = e.screenX - initX
initX = e.screenX;
}
var cancel = function(e) {
$(document).off("mousemove")
$(document).off("mouseup")
}
$(document).on("mousemove", mousemove)
$(document).on("mouseup", cancel)
mousemove = null;
cancel = null;
}
Basic idea is: I attach that grab event handler to mousedown, inside which I listen to mousemove until mouseup, then I remove those two event handlers from document.
I am pretty new to Chrome Performance tool, so I just simply record some drag of that resizer, then mouseup and drag again.
The result is confused, especially the number of listener goes up like crazy(but there seems no memory leak). I wonder where did I do wrong?
So what is happening here:
<span class="grabber" draggable="false" #mousedown="grab"></span>
every time mousedown happens vue runs grab
The safer thing to do in this case is attach the events directly to e.target also setting your handler function to null in the cancel function.
grab: function(e) {
var initX = e.screenX;
var target = e.target;
var mousemove = function(e) {
var offset = e.screenX - initX
initX = e.screenX;
}
var cancel = function(e) {
$(target).off("mousemove")
$(target).off("mouseup")
mousemove = null;
cancel = null;
}
$(target).on("mousemove", mousemove)
$(target).on("mouseup", cancel)
}
Use a flag variable instead of adding and removing the handler.
var mouseIsDown = false;
$(document).on("mousedown", function() {
mouseIsDown = true;
});
$(document).on("mouseup", function() {
mouseIsDown = false;
})
$(document).on("mousemove", function() {
if (mouseIsDown) {
// do what you want
}
});
The mousedown handler could be attached to specific elements that you can grab, rather than document.
Is there a way to receive right click mouse events on a Fabric.js canvas?
The following code works only with left click:
canvas.observe('mouse:down', function(){console.log('mouse down'));
NOTE: Most answers above are outdated; this answer applies to the latest Fabric version 2.7.0
Simply enable firing right/middle click events for your Fabric canvas
The config for firing right click and middle click events in the canvas can be found here for fireRightClick and here for fireMiddleClick and are set to false by default. This means right and middle click events are by default disabled.
The parameter stopContextMenu for stopping context menu to show up on the canvas when right clicking can be found here
You can enable these simply by setting the values when creating your canvas:
var canvas = new fabric.Canvas('canvas', {
height: height,
width: width,
fireRightClick: true, // <-- enable firing of right click events
fireMiddleClick: true, // <-- enable firing of middle click events
stopContextMenu: true, // <-- prevent context menu from showing
});
Now your mousedown event will fire for all clicks and you can distinguish them by using the button identifier on the event:
For canvas:
canvas.on('mouse:down', (event) => {
if(event.button === 1) {
console.log("left click");
}
if(event.button === 2) {
console.log("middle click");
}
if(event.button === 3) {
console.log("right click");
}
}
For objects:
object.on('mousedown', (event) => {
if(event.button === 1) {
console.log("left click");
}
if(event.button === 2) {
console.log("middle click");
}
if(event.button === 3) {
console.log("right click");
}
}
When clicking on objects you can reach the "real" mouse dom event through event.e:
if(event.button === 3){
console.log(event.e);
}
I've implemented right click by extending the fabric.Canvas class. Take a look here the _onMouseDown method.
Basically the right mouse down event for an object was disabled in fabricjs by default.
If you want to handle right clicks (on canvas or its objects), then set context menu listener on upper-canvas element. Using canvas method findTarget you can check if any target was clicked and if so, you can check type of the target.
let scope = this;
jQuery(".upper-canvas").on('contextmenu', function (options: any) {
let target: any = scope.canvas.findTarget(options, false);
if (target) {
let type: string = target.type;
if (type === "group") {
console.log('right click on group');
} else {
scope.canvas.setActiveObject(target);
console.log('right click on target, type: ' + type);
}
} else {
scope.canvas.discardActiveObject();
scope.canvas.discardActiveGroup();
scope.canvas.renderAll();
console.log('right click on canvas');
}
options.preventDefault();
});
The way I did this was to listen for a right click event across the entire canvas and match up the x,y coordinates of the click event to the object which is currently sitting at the given location. This solution feels a little like a hack but hey, it works!
$('#my_canvas').bind('contextmenu', function (env) {
var x = env.offsetX;
var y = env.offsetY;
$.each (canvas._objects, function(i, e) {
// e.left and e.top are the middle of the object use some "math" to find the outer edges
var d = e.width / 2;
var h = e.height / 2;
if (x >= (e.left - d) && x <= (e.left+d)) {
if(y >= (e.top - h) && y <= (e.top+h)) {
console.log("clicked canvas obj #"+i);
//TODO show custom menu at x, y
return false; //in case the icons are stacked only take action on one.
}
}
});
return false; //stops the event propigation
});
Here's what I did, which makes use of some built-in fabric object detection code:
$('.upper-canvas').bind('contextmenu', function (e) {
var objectFound = false;
var clickPoint = new fabric.Point(e.offsetX, e.offsetY);
e.preventDefault();
canvas.forEachObject(function (obj) {
if (!objectFound && obj.containsPoint(clickPoint)) {
objectFound = true;
//TODO: whatever you want with the object
}
});
});
I need to do the following. As soon as the user clicks on a div, i want to save the mouse coordinations while the user is moving the cursor over the div and is holding the left mouse button. When the user leaves the div or releases the left button, i want to stop recording the coordinates. I've got the following code:
$(document).ready(function() {
var coordhdl = new coordinateHandler();
$("#test").mousedown(function(e) {
$("#test").mousemove(function(ee) {
$("#test").mouseup(function(e) {
stopIt = true;
});
if(stopIt == false)
{
coordhdl.addCords(ee.pageX - this.offsetLeft, ee.pageY - this.offsetTop);
}
});
});
});
The problems with this code are:
It records coordinate even when the user only clicked the div without pressing the left button.
It doesn't stop recording the coordinates once it has been clicked.
I am new to Javascript/jQuery, so I don't know very much about it.
Something like this should work. It sets a flag to true/false when the mouse is pressed/released respectively. When the mouse moves, if the flag is set, the coordinates are added:
$(document).ready(function() {
var isDown = false,
coordhdl = new coordinateHandler();
$("#test").mousedown(function() {
isDown = true;
}).mouseup(function() {
isDown = false;
}).mousemove(function(e) {
if(isDown) {
coordhdl.addCords(ee.pageX - this.offsetLeft, ee.pageY - this.offsetTop);
}
});
});
Here's a demo of something similar in action (it simply writes the coordinates to a p element instead of using your coordinateHandler object).
Don't attach the event handlers inside the event handlers. On every mouse move you attach a new mouseup event handler. They don't get overridden, they get appended.
Use a "global" flag instead:
$(document).ready(function() {
var coordhdl = new coordinateHandler(),
recording = false;
$("#test").mousedown(function(e) {
recording = true;
}).mousemove(function(e) {
if(recording) {
coordhdl.addCords(e.pageX - this.offsetLeft, e.pageY - this.offsetTop);
}
}).mouseup(function(e) {
recording = false;
});
});
Every time there is a mousedown event, you add a mousemove handler, and every time the mouse moves, you add another mouseup handler. I can't see where the stopIt variable is declared so the scope of this variable may also be an issue. You don't need to nest the handlers, so try it this way.
$(document).ready(function() {
var coordhdl = new coordinateHandler();
var isRecording = false;
$("#test").mousedown(function(e) { isRecording = true })
.mouseup(function(e) { isRecording = false })
.mousemove(function(ee) {
if(isRecording)
{
coordhdl.addCords(ee.pageX - this.offsetLeft, ee.pageY - this.offsetTop);
}
});
});