OpenLayers SelectFeature control with hover delay? - javascript

Using OpenLayers, I have a OpenLayers.Control.SelectFeature installed on a layer, with the hover option set to true. When creating the layer I call
<layer>.events.register("featureselected",...)
and
<layer>.events.register("featureunselected",...)
to register functions that create and destroy a popup. This all works fine. Now I want to add a small delay before the popup is created in order to avoid the popup flickering that currently occurs when moving the mouse across multiple features. However, I can't seem to figure out how to do this. I did find the OpenLayers.Handler.Hover handler, which has a delay option, but I don't know how to combine that with the SelectFeature control (if I even can).

I think this post has some valuable info, which I'm about to verify. Some answers down, someone talks about the flickering.
edit: In case you are making your own labels, I noticed the effect is less when you raise the labelOutlineWidth . It seems that only the letters of the label count as 'hover' and not the whole PointRadius radius. When you make the label outline too big, the label looks like a fly that hit a windscreen though (not a square but it follows the label contours, the letters more specifically).
update: apparently this is why when you hover a text label , check this out: pointer events properties. set this attribute (pointerEvents: ) in your OpenLayers.Style and try value 'all' and the others. It sure makes a difference for me.

I bind my feature selections a little different, here's a quick (untested) example that should get you what you need.
var timer,
delay = 500, //delay in ms
hover = new OpenLayers.Control.SelectFeature( <layer> , {
hover: true,
onSelect: function (feature) {
// setup a timer to run select function
timer = window.setTimeout(function () {
// your select code
}, delay);
},
onUnselect: function () {
// first cancel the pending timer (no side effects)
window.clearTimeout(timer);
// your unselect code
}
});
<map>.addControl(hover);
hover.activate();

Related

How to make the cursor change in d3.js when I want?

This is a question related to Basic Javascript loading message while js processing completes
My main problem is that cursor not is changed before my two functions drawlegend() and display() are called, but changes after everthing has finnished.
With the code as below where the restore of the cursor temporary commented out, I get the hourglass, but after everything has finnished.
How to get my cursor to change to an hourglass before my slow functions are called?
examplefunc()
{
mini.append("text")
.text(series[i].name)
.attr("x",30)
.attr("y",(15+(15*i)))
.attr("stroke",(d3.rgb(192,192,192)))
.attr("fill",(d3.rgb(192,192,192)))
.attr("stroke-width",0)
.style("font-size","12px")
.attr("text-anchor","start")
.attr("id","legend")
.on('mouseup', legendclick);
}
//===== legend clicked
function legendclick()
{
//--- get mouse pos
var origin = d3.mouse(this);
//--- get channel
var ch=Math.floor((origin[1]-4)/15);
//--- toggle active state
if (series[ch].active==true)
series[ch].active=false;
else
series[ch].active=true;
setTimeout(setcursor("wait"),5);
drawlegend();
display();
//setTimeout(setcursor("default"),5); // temp removed to see any result at all
}
//===== set cursor
function setcursor(cursor)
{
d3.select("body").style("cursor", cursor);
}
It is known that executing things in javascript, hangs your application. This means that only the eventual output is displayed on your screen. Thus, when you change the cursor to "wait" and after execution to "cursor", the javascript hasn't changed it, because the ui thread was busy calculating the things in the functions "drawlegend" and "display". However, I think when you execute the "drawlegend" and "display" asynchronous like
setTimeout(function () {
drawLegend();
display();
setcursor("default");
}, 0);
then things should go like you want to.
Let me know if this works for you.
Extra info: on this slideshare (especially slide 5) is explained what your problem is.

Trigger event on animation complete (no control over animation)

I've a scenario that requires me to detect animation stop of a periodically animated element and trigger a function. I've no control over the element's animation. The animation can be dynamic so I can't use clever setTimeout.
Long Story
The simplified form of the problem is that I'm using a third party jQuery sliding banners plugin that uses some obfuscated JavaScript to slide banners in and out. I'm in need of figuring out a hook on slideComplete sort of event, but all I have is an element id. Take this jsfiddle as an example and imagine that the javascript has been obfuscated. I need to trigger a function when the red box reaches the extremes and stops.
I'm aware of the :animated pseudo selector but I think it will need me to constantly poll the required element. I've gone through this, this, and this, but no avail. I've checked jquery promise but I couldn't figure out to use that in this scenario. This SO question is closest to my requirements but it has no answers.
P.S. Some more information that might be helpful:
The element isn't created by JavaScript, it is present on page load.
I've control over when to apply the plugin (that makes it periodically sliding banner) on the element
Most of the slideshow plugins I have used use changing classes at the end of the animation... You could extend the "addClass" method of jQuery to allow you to capture the class change as long as the plugin you use is using that method like it should:
(function($){
$.each(["addClass","removeClass"],function(i,methodname){
var oldmethod = $.fn[methodname];
$.fn[methodname] = function(){
oldmethod.apply( this, arguments );
this.trigger(methodname+"change");
return this;
}
});
})(jQuery);
I threw together a fiddle here
Even with obfuscated code you should be able to use this method to check how they are sending in the arguments to animate (I use the "options" object when I send arguments to animate usually) and wrap their callback function in an anonymous function that triggers an event...
like this fiddle
Here is the relevant block of script:
(function($){
$.each(["animate"],function(i,methodname){
var oldmethod = $.fn[methodname];
$.fn[methodname] = function(){
var args=arguments;
that=this;
var oldcall=args[2];
args[2]=function(){
oldcall();
console.log("slideFinish");
}
oldmethod.apply( this, args );
return this;
}
});
})(jQuery);
Well since you didn't give any indication as to what kind of animation is being done, I'm going to assume that its a horizontal/vertical translation, although I think this could be applied to other effects as well. Because I don't know how the animation is being accomplished, a setInterval evaluation would be the only way I can guess at how to do this.
var prevPos = 0;
var isAnimating = setInterval(function(){
if($(YOUROBJECT).css('top') == prevPos){
//logic here
}
else{
prevPos = $(YOUROBJECT).css('top');
}
},500);
That will evaluate the vertical position of the object every .5 seconds, and if the current vertical position is equal to the one taken .5 seconds ago, it will assume that animation has stopped and you can execute some code.
edit --
just noticed your jsfiddle had a horizontal translation, so the code for your jsfiddle is here http://jsfiddle.net/wZbNA/3/

Image map with overlay not working in IE

I am trying to create an interactive map with an overlay using html image maps.
To see it, please visit: http://www.surge.ca/testing/WFA2100/index.html
The explanation:
When you hover over an <area> of the map, it bring up an overlay with links.
To prevent the overlay from closing when you move to it, as you are no longer hovering over the area, I am using a setTimeout before it closes the overlay.
The problem:
It works like I want in every browser but IE.
In IE 7 and 8, when you hover over an overlay that is above another <area>, it immediately switches to the overlay of that <area>.
At first, I thought it was a z-index issue where the <area>'s z-index was above the overlay, but I think my z-index is set up correctly. I am also thinking that it could just be how IE handles image maps?
The code:
Here is the code that sets up the events.
jQuery(function($){
// binds mouseenter and mouseleave to <area>
$('area').bind('mouseenter',function(){
sectionNum = this.hash;
sectionNum = sectionNum.replace(/#/,'');
showOverlay(sectionNum);
clearTimeout(timer);
}).bind('mouseleave', function(){
timerClose();
});
$('.map_info').bind('mouseenter', function(){
clearTimeout(timer);
}).bind('mouseleave', function(){
timerClose();
});
});
// sets timer before closing to allow cancel
var timer;
function timerClose(){
timer = setTimeout(function(){hideOverlay();},500);
}
The problem is that IE clear the setTimeout when hover ends. I didn't ran your code but I had same problem and cpuld fix it by passing the setTimeout function as an string.
For example setTimeout(alert('hi'), 1000) wasn't working on a function that was running in a hover state but setTimeout("alert('hi')", 1000) was working.
In your code maybe replacing
timer = setTimeout(function(){hideOverlay();},500);
with
timer = setTimeout("function(){hideOverlay();}",500);
solve the problem.
It seems IE run code that passed in string in global scope.
Also I can see you have jQuery in your page. There is a jQuery plug-in called hoverIntent that do hover delay very nice. Maybe plug-in writer wrote more cross-browser code.
Let me know if it works. :)

How can I reveal content and maintain its visibility when mousing to a child element?

I'm asking a question very similar to this one—dare I say identical?
An example is currently in the bottom navigation on this page.
I'm looking to display the name and link of the next and previous page when a user hovers over their respective icons. I'm pretty sure my solution will entail binding or timers, neither of which I'm seeming to understand very well at the moment.
Currently, I have:
$(document).ready(function() {
var dropdown = $('span.hide_me');
var navigator = $('a.paginate_link');
dropdown.hide();
$(navigator).hover(function(){
$(this).siblings(dropdown).fadeIn();
}, function(){
setTimeout(function(){
dropdown.fadeOut();
}, 3000);
});
});
with its respective HTML (some ExpressionEngine code included—apologies):
<p class="older_entry">Older<span class="hide_me">Older entry:
<br />
{title}</span></p>
{/exp:weblog:next_entry}
<p class="blog_home">Blog Main<span class="hide_me">Back to the blog</span></p>
{exp:weblog:prev_entry weblog="blog"}
<p class="newer_entry">Newer<span class="hide_me">Newer entry:
<br />
{title}</span></p>
This is behaving pretty strangely at the moment. Sometimes it waits three seconds, sometimes it waits one second, sometimes it doesn't fade out altogether.
Essentially, I'm looking to fade in 'span.hide_me' on hover of the icons ('a.paginate_link'), and I'd like it to remain visible when users mouse over the span.
Think anyone could help walk me through this process and understand exactly how the timers and clearing of the timers is working?
Thanks so much, Stack Overflow. You guys have been incredible as I walk down this road of learning to make the internet.
If you just want to get it working, you can try to use a tooltip plugin like this one.
If you want to understand how this should be done: first, get rid of the timeout, and make it work without it. The difference (from the user's point of view) is very small, and it simplifies stuff (developing and debugging). After you get it working like you want, put the timeout back in.
Now, the problem is you don't really want to hide the shown element on the navigator mouse-out event. You want to hide it in its own mouse out event. So I think you can just pass the first argument to the navigator hover function, and add another hover to dropdowns, that will have an empty function as a first argument, and the hiding code in its second argument.
EDIT (according to your response to stefpet's answer)
I understand that you DO want the dropdown to disappear if the mouse moves out of the navigator, UNLESS its moved to the dropdown itself. This complicates a little, but here is how it can be done: on both types of items mouse-out event, you set a timer that calls a function that hides the dropdown. lets say the timer is 1 second. on both kind of item mouse-in even, you clear this timer (see the w3school page on timing for syntax, etc). plus, in the navigator's mouse-in you have to show the dropdown.
Another issue with the timer in your code is that it will always execute when mouse-out. Due to the 3 seconds delay you might very well trigger it again when mouse-over but since the timer still exist it will fade out despite you actually have the mouse over the element.
Moving the mouse back and forth quickly will trigger multiple timers.
Try to get it to work without the timer first, then (if really needed) add the additional complexity with the delay (which you must keep track of and remove/reset depending on state).
Here was the final working code, for anyone who comes across this again. Feel free to let me know if I could have improved it in any ways:
$(document).ready(function() {
var dropdown = $('span.hide_me');
var navigator = $('a.paginate_link');
dropdown.hide();
$(navigator).hover(function(){
clearTimeout(emptyTimer);
$(this).siblings(dropdown).fadeIn();
}, function(){
emptyTimer = setTimeout(function(){
dropdown.fadeOut();
}, 500);
});
$(dropdown).hover(function(){
clearTimeout(emptyTimer);
}, function(){
emptyTimer = setTimeout(function(){
dropdown.fadeOut();
}, 500);
});
});

Mootools Slider plugin functions

I am using mootools to create a CSS skin for the Youtube chromeless player using the javascript API to control playback. I cannot post the code unfortunately. The question I have is a more general one. When using the slider plugin a call to mySlider.set(step) moves the knob to the correct step on the slider but it triggers all of the plugins event functions (onChange, onTick, onComplete). The problem with this is, how do you know if the sliders knob position was changed by a user or a call to the set() function? I would have thought there would be a function reserved for when the knob was released by a mouse only and not be called if the position was simply set in code. I have code that updates the knobs position based on where the videos playback duration is currently at. I need to be able to move the knob to the current position in code without it thinking a user let go of the knob.
To simplify the question, is there a way to set the knobs position on a slider in code without triggering the functions used when a user interacts?
You can find the Slider plugin reference here http://mootools.net/docs/more/Drag/Slider
Thanks
I got this problem and ended up doing this
var slider = new Slider(track,knob, {
onChange: function(){
console.log("doesn't fire after autosize()");
}
});
// fake .set();
slider.step = 50; // new value
slider.autosize(); // redraw the knob
Make a variable that indicates that you're setting it programatically, then skip your event handlers if the variable is true.
Then, each time you set the slider in code, set the variable to true first, then back to false afterwords in a finally block.

Categories