Here is a fiddle showing an example of what I'm trying to do. (I know it doesn't look right but it just needs some changes and that isn't the problem I'm facing :p ).
Im creating a pie chart using Raphael SVG, and the tooltip is also an svg element.
draw_tooltip(SVGpaper, this, 0);
is used to clear the tooltip.
The problem is I don't understand how to properly handle the mouseover event. On each event the tooltip needs to popup after clearing the previous tooltip, which I've tried to manage using the counter. But as is apparent from the fiddle, the mouseover event isn't smooth. Also, it stays even while shifting to other arcs and when it moves out of the pie.
Pleae suggest some solution!
I suspect the problem you are having, is that the new path/element that is being displayed for the tooltip, is then interfering with the mouse events, stopping the event from working. So Raphael can be a bit fiddly for mouse events, if dragging/moving. There's probably a couple of different ways around it. One may be handling events more globally and deciding what to do with them, or if you don't mind it, move the tooltip a bit further from the cursor location.
arc.mouseover(function (e) {
x = e.pageX + 50;
y = e.pageY;
draw_tooltip(this, 1, display_text, x, y);
});
arc.mouseout( function(e) {
popup.remove();
popup_txt.remove();
transparent_txt.remove();
});
arc.mousemove( function(e) {
popup.attr({ x: e.pageX - 70, y: e.pageY - 70 });
popup_txt.attr({ x: e.pageX - 25, y: e.pageY - 45});
transparent_txt.attr({ x: e.pageX - 120, y: e.pageY - 120 });
});
}
I've also changed the path for a rect and a couple of bits, but the main thing is keeping the tooltip away from the event location. Otherwise I wonder if you may need to handle it from jquery or possibly to a handler thats attached to other elements than the arc, which will depend on the complexity of the page maybe. See if this solution will do.
Fiddle here http://jsfiddle.net/74YNb/13/ (text alignment may need tweaking for all browsers)
Related
I'm writing tests and trying to simulate a "mousemove" event. The method I am using which works in Chrome, Firefox, Safari, and IE 10 & 11 is:
var e = new MouseEvent('mousemove',{
"clientX": 250,
"clientY": 100,
});
myElem.dispatchEvent(e);
But it does not work in Edge. The "mousemove" event fires and is caught by my listener, but the position is incorrect. Instead of using the provided coordinates, it appears to use the window origin, 0,0.
My actual code does runs correctly in Edge, so it appears to solely be an issue with simulating the event. But the added complication is this is for a d3 chart and the mouse position is being read with d3.mouse, so I cannot rule out that there is something different in Edge in the interaction between d3.mouse and a mouse event.
Other approaches I have tried include using a CustomEvent and using a PointerEvent, but both seemed to trigger the eventListener, but not even be readable by d3.mouse.
UPDATE
Originally I thought that the specified coordinates were completely ignored; this is not the case. The reality is even more bizarre. If I use absurdly high numbers, then I can get it to register over my element. But real numbers are considered waaay off screen.
For example, if my element getBoundingClientRect gives me:
left: 100,
top: 10,
width: 500,
height: 300
and I use coordinates such as:
var e = new MouseEvent('mousemove',{
"clientX": 350,
"clientY": 150,
});
which should place my cursor over the element, Edge seems to think my cursor it is way off screen. If instead I put in numbers such as:
var e = new MouseEvent('mousemove',{
"clientX": 100000,
"clientY": 50000,
});
Edge will then consider this to be over my element.
The d3.mouse method returns the x,y coordinates of the mouse event relative to the graph container. The clientX and clientY values you are using to simulate the mouse event provide the x,y coordinates of the mouse event relative to the current window. So, the coordinate sets are not the same. You can manually calculate the same coordinate values as the d3.mouse method via:
d3MouseX = clientX - rect.left
d3MouseY = clientY - rect.top
where rect.left and rect.top are the coordinates of the bounding rectangle for the graph object. You can get these coordinates with the e.target.getBoundingClientRect() method.
I am trying to create a canvas that allows me to draw on it rectangles using mouse events. Very similar to the way selection works in windows, I want to be able to click down anywhere on my page, drag left/right/up/down, then once I release, a rectangle is drawn with the starting coordinates (x1 and y1) on mousedown and the ending coordinates (x2, y2) on mouseup.
I've been trying to create eventListeners bound to my canvas that return the starting and ending coordinates on mousedown and mouseup respectively, but my variables stay undefined.
My canvas spans the entire length of my window so no need to take into account relative positioning. Also the solution has to be implemented using purely Javascript, no JQuery allowed.
Thank you for your help!
UPDATE
Ignore most of what is underneath, re-reading your question, it seems like you have the theory nailed. Your problem is most likely the mousedown and mouseup function parameters are missing. Try the following;
document.getElementsByTagName('canvas')[0].addEventListener('mousedown', function(e){
// I THINK IT'S THE e ON THE LINE ABOVE THIS THAT YOU'RE MISSING.
// YOU CAN THEN ACCESS THE POSITION OF THE MOUSE USING;
mouse.x = e.pageX;
mouse.Y = e.pageY;
})
I won't write the code for you, but I can give you theory.
Store your mouse x & y variables in an object such as mouse = {}.
Add an event listener to the canvas for mouse down (click) and store the e.pageX and e.pageY in mouse.firstX and mouse.firstY. Use something like:
document.getElementsByTagName('canvas')[0].addEventListener('mousedown', function(e){
mouse.firstX = e.pageX;
mouse.firstY = e.pageY;
})
Create a second event listener for the canvas for mouseup and store this set of e.pageX and e.pageY in mouse.secondX and mouse.secondY.
Calculate the difference between firstX and secondX, firstY and secondY to work out big your rectangle sound be.
var width = mouse.firstX + mouse.secondX // rect width
var height = mouse.firstY + mouse.secondY // rect height
Then, using these calculations, draw a rectangle on your canvas using firstX and firstY as the position parameters.
I hope this is relatively clear and helpful for you. If not, this might help;
http://simonsarris.com/blog/140-canvas-moving-selectable-shapes
I'm trying to make a stage that can be zoomed by mousewheel. I'm using the stage.scale and jquery event. But I have not been able to make the zoom done with the mouse pointer as center. So when my mouse is on a point, I want to zoom in it centrically.
I've make this example, that doesen't work for now :
http://fiddle.jshell.net/rr7pLapz/1/
Here is my zoom function :
$("#cont").bind('mousewheel', function(e) {
var x = e.offsetX;
var y = e.offsetY;
if (e.originalEvent.wheelDelta > 0) {
STAGE.scale({
x:STAGE.scale().x+1,
y:STAGE.scale().y+1
});
STAGE.x(-x + 500/(STAGE.scale().x));
STAGE.y(-y + 350/(STAGE.scale().y));
STAGE.batchDraw();
}
else {
if (STAGE.scale().x > 1) {
STAGE.x(-x + 500/(STAGE.scale().x));
STAGE.y(-y + 350/(STAGE.scale().y));
STAGE.scale({
x:STAGE.scale().x-1,
y:STAGE.scale().y-1
});
STAGE.batchDraw();
}
}
});
Can you help ? Many thanks.
Here is a manual way to do it:
First, store the mouse position in stage coordinates. Then apply the scale, and get the new mouse position in stage coordinates. Then offset the stage by oldPosition - newPosition. This effectively puts the same point in the stage back under the mouse.
Or as Mark said, you can do it via layer offsets. Though that might not be the most convenient way to do it, depending how your project is setup to use kinetic's features. See these links:
Scaling to a fixed point in KineticJS
KineticJS Canvas - Scale group from center point
Also some side notes:
You have some duplication in that code. Why not only have one line under each wheelDelta condition, to determine the newScale, then use that variable in the following lines.
I've found that it makes a smooth zoom to do scale *= 1.2 and scale /= 1.2 rather than the straight adding you're doing there. Just a suggestion.
Using canvas and mousemove I create a masking effect.
Example: FIDDLE
The masking effect works but on fast scrolling performance isn't ideal.
How can I improve the framerate?
I fixed it simply by using the window mouse coordinates, instead of the listener on the canvas (assuming you want the picture to just be black).
http://jsfiddle.net/gfZ5C/166/
I also changed to requestAnimationFrame, you'll notice a complete FPS difference in the movement of the circle, instead of it moving according to the listener.
window.onmousemove = function (e) {
circle.posX = e.pageX-can.offsetLeft;
circle.posY = e.pageY-can.offsetTop;
circle.hide = (circle.posX >= 550 || circle.posY >= 550) ? true : false;
}
if (!circle.hide) ctx.arc(circle.posX, circle.posY, 70, 0, Math.PI * 2, true);
I left it at 550, so that you could see it actually disappear, you can change it to a big number if you want the circle to just drag right off the canvas.
Also there is no lag on the circle following the mouse now.
Update:
Fixed the fiddle so that the circle adjusts for window offset too.
The offset is relevant to its parent element, so depending on how far deep your canvas is, you will have to subtract each elements offset that it is inside.
Update:
Switched to handle 'onmouse' events, this will work much better on a real site, because mousing over the iFrame doesn't work well, but it still works. Will work 100% as intended on a real site.
I'm just learning Kinetic.js, and I really enjoy how easy it's making using the HTML5 <canvas> element.
I have a large layer that's bigger than the "stage" (to use Kinetic parlance) but is draggable. The drag functionality seems to interfere with the click handler in two different ways: Some single clicks do not register; and and of those that do, the location is only accurate if the layer is in its original position.
Here's a fiddle displaying the issue I'm having. In my actual code, the bottom layer is actually an image.
http://jsfiddle.net/EKaAv/1/
layer.on ('click', function(e) {
console.log(e);
var mousePos = stage.getMousePosition(); // mouse position relative to stage
var xclick = mousePos.x;
var yclick = mousePos.y;
var circle = new Kinetic.Circle({
x: xclick - layer.getX(), // since position is relative to stage, adjust by layer X
y: yclick - layer.getY(), // same as above
radius: 25,
fill: 'red',
opacity: 0.5
});
layer.add(circle);
stage.draw(); // redraw the stage immediately
});
Any clicks that seem to not be registered are due to the draggable event firing which overrides the click event.