I'm pretty new at Raphael JS, and SVG in general. Currently I'm using SVG and Raphael on a map-functionality.
I'm having an issue with a hover effect which offsets the given element you hover with 10px. However, if you move your mouse slowly into the element the hoverIn and hoverOut will happen a bunch of times resulting in flickering.
I think I could resolve this by cloning the countries and leave it hidden and stationary, when hovering. I could do this I say, because the map contains hundreds of shapes...
What is the approach? What should I do?
If I understand correctly the element moves when you hover over it, which cause the hoverOut event. What do you want to happen with slow mouse movements? It moves once, stays moved until the mouse gets inside?
You need to set a variable on the element to show when it's been shifted 10px. Then you can do something like (pseudocode)
hoverIn() {
if (isShifted) {
inWhenShifted = true
} else {
// offset element
isShifted = true
}
hoverOut() {
if (isShifted) {
if (inWhenShifted) {
// put element back
isShifted = false
inWhenShifted = false
} else {
// do nothing?, this is the case where the hoverOut fired
// because we moved the element
}
} else {
// do nothing?, this is the case where we hoverOut again after shifting
// the element back
}
}
Related
I have a website for CVOID-19 that displays cases on a MapBox map. One of the buttons on the website hides the case info so you get the the full map. The width transition of the case info box works nicely, but it leaves the map un-resized. Thankfully there is a method conveniently named map.resize() that resizes the map into it's appropriate size after the width of the case info box goes down to zero using a transitionend event. However the resizing isn't transitioned at all and it ends up looking incredibly janky with the sudden resizing of the map out of no where.
This is the solution I came up with, on the start of the transition you call the map.resize() function every 10 ms, and then you stop the interval once the transition has ended, it ends up looking quite a bit smoother.
let mapResizer;
countryPanel.addEventListener("transitionstart", (e) => {
if (e.target == countryPanel) {
mapResizer = setInterval(map.resize, 10);
}
})
countryPanel.addEventListener("transitionend", (e) => {
if (e.target == countryPanel) {
if (e.target.classList.contains("hide")) {
showBtn.hidden = false;
}
clearInterval(mapResizer);
}
})
Here is the website displaying the effect when you click the hide UI button (the little arrow pointing to the left): https://people.rit.edu/ajr6974/330/Project%203/
I'd like to get the current value of my transform: rotate, just before the mouse leaves. In the current state, the event seems to be caught when the mouse has already left my button and returns 0deg which is true at this moment.
My point is to play the same animation in reverse mode. For that, I need to get the current value of the rotation and make a transition from Xdeg to 0deg. I firstly tried to accomplish it in full CSS but the animation is suddenly broken when mouse leaves. I also tried to play another animation when the mouse is not on the button but the result is not as clean as I expected since it begins from a predefined value and not the current rotate value.
You can find my fiddle here : https://jsfiddle.net/yn460w6j/
Thanks to #lakenen for the degree function, btw !
I little play with that, use only js to solve this. I'm adding class to spinner when mouseover on button. Next, when mouseleave I am setting listener on stop animation iteration. When it complete I just remove animation class from spinner.
var $spinner = $("#random_glyph");
var $button = $("#random_button");
$button.on("mouseover", function() {
$spinner.addClass('animation');
});
$button.on("mouseleave", function() {
$button.bind("webkitAnimationIteration, mozAnimationIteration, animationiteration", function(e){
$spinner.removeClass('animation');
$(this).unbind(e);
});
});
https://jsfiddle.net/9jLstovx/
This is pretty much what I'm working on: https://jsfiddle.net/atg5m6ym/2625/
I'm animating a div with jQuery to move left, then logging to the console when I hover over the div and when I move my mouse away from it:
$("div").animate({left: '250px'}, 6000);
$('div').hover(function() {
console.log("Mouse hovered on div!");
}).mouseleave(function() {
console.log("Mouse left div!");
})
Naturally, the program will run console.log("Mouse hovered on div!"); once I put my mouse on the element.
However, if I leave my mouse idle and the animated element moves onto it, nothing in $('div').hover(function(){}) will run. I have to move my mouse onto the element for the code to run, not let the element come to the mouse.
The same thing also happens if I hover onto the element, and then leave my mouse idle. Nothing in $('div').mouseleave(function(){}) will run after the element leaves, until I move my mouse from its position.
Is there any way to work around this? I am working with animated divs and I need code to run even if the mouse is idle and the divs pass through it.
Manually take the mouse's last known position and compare it to the position of the circle. This is kind of extensive but it should get you the right results.
Here is a JSFiddle:
https://jsfiddle.net/3vpaoj59/
$("div").animate({left: '250px'}, 6000);
$(document).ready(function() {
// record down the position of the cursor
var cursorX;
var cursorY;
document.onmousemove = function(e){
cursorX = e.pageX;
cursorY = e.pageY;
}
// boolean to know if hovered or not, and to know whether to report in console.log
var hover = false;
// function to call by setinterval to check if mouse is within radius
function checkMouse(){
// find the centerpoint of the circle by taking its position then adding half its width/height to each coordinate
var left = $("#foo").offset().left+$("#foo").width()/2;
var top = $("#foo").offset().top+$("#foo").height()/2;
// use pythagorean theorem to find distance between two points
var xdist = Math.pow(Math.abs(cursorX - left),2);
var ydist = Math.pow(Math.abs(cursorY - top),2);
var hypotenuse = Math.round(Math.sqrt(xdist+ydist));
// check if the distance is less than radius
if(hypotenuse <= $("#foo").width()/2 && !hover){
// if true and not already reported true, report then fix
console.log("mouse hovered on div!");
hover = true;
} else if (hypotenuse > $("#foo").width()/2 && hover){
// if false and not already reported false, report then fix
console.log("mouse left div!");
hover = false;
}
}
// repeatedly call this
setInterval(checkMouse, 100);
});
I changed the div's ID to "foo" for convenience. Make sure to do this as well so that the code works for your project, or modify the JS to not use "foo".
Explanation:
The reason why your problem was occurring was because your mouse's coords are only updated every time you move your cursor, and that's when hover states are checked by .hover. As such, we need to emulate the event that determines hover and call it repeatedly even when the cursor hasn't moved to make sure the hover state is updated.
I am currently switching the menu of my site from pure JavaScript to jQuery. My menu has a rollout / rollin effect.
The menu has an outer wrapper which has an onmouseout event set. If this fires, the relatedTarget is checked whether it's a child of the outer wrapper. If not, the rollin shall happen.
What happens right now is, that if the mouse is moved from the menu's inner wrapper (this is to center the actual menu) to the menu's outer wrapper, the onmouseout fires. There seems to be a tiny part which doesn't belong to the menuOuterWrapper.
The site isn't online right now, so I've prepared a Fiddle here. You will see the problem if you move your mouse from the gray area above the handle to the left or right dark area. The menu will roll in and then immediately out again. The rollin shall only occur when the mouse is moved out of the outer wrapper, i.e. under the dark gray area (or the light gray handle area). To see the dark gray areas, you might have to increase the width of the result block. [EDIT: I reduced the width of inner to 600px, so the dark side areas should be visible by default now.]
SO tells me that I shall include code when linking to JSFiddle. I don't want to break the rules but I'll be honest: I'm clueless where the problem comes from. My best idea is that I made a mistake in my isChildOf implementation, so I'll give you this:
jQuery.fn.isChildOf = function (parentId) {
if ($(this).parents("#" + parentId).length > 0) {
return true;
} else {
return false;
}
};
$('#outer').on('mouseout', function(event) {
if (!$(event.relatedTarget).isChildOf("outer")) {
mouseIsOverMenu = false;
menu_rollin();
}
});
Although this is a minimal example, I did nearly the same with pure JS, where it worked fine. So I guess it's something in the jQuery part. Since these are my first steps with jQuery, it is even more likely.
Every help you can provide is highly appreciated :)
[UPDATE]
I got it working now. The problem was that I didn't check for the relatedTarget to be "outer" itself. So when the mouse leaves the content div and enters the outer div, mouseout fires and of course, outer is no child of itself. So I amended it to
$('#outer').on('mouseout', function(event) {
if (!(event.relatedTarget.id == "outer") &&
!$(event.relatedTarget).isChildOf("outer")) {
mouseIsOverMenu = false;
menu_rollin();
}
});
and that fixed the problem.
if i understood your question right.
This might help
$('#inner').on('mouseover', function() {
mouseIsOverMenu = true;
setTimeout(menu_rollout, 500);
});
$('#inner').on('mouseout', function(event) {
if (!$(event.relatedTarget).isChildOf("outer")) {
mouseIsOverMenu = false;
menu_rollin();
}
});
What i did is i have changed the id of #outer to #inner.
This is a dirty hack, but your problem seems to be with the mouseout function applying too frequently, and what functionality you really want is capturing the mouse leaving the bottom of the menu/content.
Here's some code that will do just that.
$('#outer').on('mouseout', function(event) {
if(event.clientY >= document.getElementById('outer').offsetHeight){
mouseIsOverMenu = false;
menu_rollin();
}
});
here's the associated jsFiddle
I'm using the following code to allow users to resize a DIV element vertically, but when the click and drag the handle, text and other elements on the page get selected as if the user was just clicking and highlighting everything on the page. Is there a way to prevent this from happening as this looks very bad? This is being used with Prototype.js.
function DragCorner(container, handle) {
var container = $(container);
var handle = $(handle);
// Add property to container to store position variables
container.moveposition = {y:0};
function moveListener(event) {
// Calculate how far the mouse moved
var moved = { y:(container.moveposition.y - event.pointerY()) };
// Reset container's x/y utility property
container.moveposition = {y:event.pointerY()};
// Update container's size
var size = container.getDimensions();
container.setStyle({height: size.height + moved.y + 'px'});
}
// Listen for 'mouse down' on handle to start the move listener
handle.observe('mousedown', function(event) {
// Set starting x/y
container.moveposition = {y:event.pointerY()};
// Start listening for mouse move on body
Event.observe(document.body,'mousemove',moveListener);
});
// Listen for 'mouse up' to cancel 'move' listener
Event.observe(document.body,'mouseup', function(event) {
Event.stopObserving(document.body,'mousemove',moveListener);
console.log('stop listening');
});
}
Following up your earlier question and answer, add a small handle element and make it as the only element that can be selected and draggable. Also I guess you made that div's position as relative and handle position as absolute. Right??
Adding the following to the DIV fixed this:
onselectstart="return false;"