Add hover handler. With this handler user-defined actions can be triggered as the mouse moves over the map and pauses. An example of use is send WMS/GetFeatureInfo requests. r=crschmidt,tschaub (closes #1255)

git-svn-id: http://svn.openlayers.org/trunk/openlayers@5746 dc9f47b5-9b13-0410-9fdd-eb0c1a62fdaf
This commit is contained in:
Éric Lemoine
2008-01-15 12:54:47 +00:00
parent c1185e8f8b
commit f053a4e0c8
5 changed files with 525 additions and 0 deletions

209
examples/hover-handler.html Normal file
View File

@@ -0,0 +1,209 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>OpenLayers Hover Handler Example</title>
<style type="text/css">
#map {
width: 340px;
height: 170px;
border: 1px solid gray;
}
#west {
width: 350px;
}
#east {
position: absolute;
left: 370px;
top: 3em;
}
table td {
text-align: center;
margin: 0;
border: 1px solid gray;
}
textarea.output {
text-align: left;
font-size: 0.9em;
width: 250px;
height: 65px;
overflow: auto;
}
</style>
<script src="../lib/Firebug/firebug.js"></script>
<script src="../lib/OpenLayers.js"></script>
<script type="text/javascript">
OpenLayers.Control.Hover = OpenLayers.Class(OpenLayers.Control, {
defaultHandlerOptions: {
'delay': 500,
'pixelTolerance': null,
'stopMove': false
},
initialize: function(options) {
this.handlerOptions = OpenLayers.Util.extend(
{}, this.defaultHandlerOptions
);
OpenLayers.Control.prototype.initialize.apply(
this, arguments
);
this.handler = new OpenLayers.Handler.Hover(
this,
{'pause': this.onPause, 'move': this.onMove},
this.handlerOptions
);
},
onPause: function(evt) {
var output = document.getElementById(this.key + 'Output');
var msg = 'pause ' + evt.xy;
output.value = output.value + msg + "\r\n";
},
onMove: function(evt) {
// if this control sent an Ajax request (e.g. GetFeatureInfo) when
// the mouse pauses the onMove callback could be used to abort that
// request.
}
});
var map, controls;
function init(){
map = new OpenLayers.Map('map');
var layer = new OpenLayers.Layer.WMS(
'OpenLayers WMS',
'http://labs.metacarta.com/wms/vmap0',
{layers: 'basic'}
);
map.addLayers([layer]);
controls = {
'long': new OpenLayers.Control.Hover({
handlerOptions: {
'delay': 2000
}
}),
'short': new OpenLayers.Control.Hover({
handlerOptions: {
'delay': 100
}
}),
'tolerant': new OpenLayers.Control.Hover({
handlerOptions: {
'delay': 1000,
'pixelTolerance': 6
}
}),
'untolerant': new OpenLayers.Control.Hover({
handlerOptions: {
'delay': 1000,
'pixelTolerance': 1
}
}),
'stoppropag': new OpenLayers.Control.Hover({
handlerOptions: {
'stopMove': true
}
})
};
var props = document.getElementById("props");
var control;
for(var key in controls) {
control = controls[key];
// only to route output here
control.key = key;
map.addControl(control);
}
map.zoomToMaxExtent();
}
function toggle(key) {
var control = controls[key];
if(control.active) {
control.deactivate();
} else {
control.activate();
}
var status = document.getElementById(key + "Status");
status.innerHTML = control.active ? "on" : "off";
var output = document.getElementById(key + "Output");
output.value = "";
}
</script>
</head>
<body onload="init()">
<h1 id="title">Hover Handler Example</h1>
<div id="west">
<div id="tags">
</div>
<p id="shortdesc">
This example shows the use of the hover handler.
</p>
<div id="map"></div>
<p>
The hover handler is to be used to emulate mouseovers on
objects on the map that aren't DOM elements. For example
one can use the hover hander to send WMS/GetFeatureInfo
requests as the user moves the mouse over the map.
</p>
<p>
The "delay" option specifies the number of milliseconds
before the event is considered a hover. Default is 500
milliseconds.
</p>
<p>
The "pixelTolerance" option specifies the maximum number
of pixels between mousemoves for an event to be
considered a hover. Default is null, which means no
pixel tolerance.
</p>
<p>
The "stopMove" option specifies whether other mousemove
listeners registered before the hover handler listener must
be notified on mousemoves or not. Default is false (meaning
that the other mousemove listeners will be notified on
mousemove).
</p>
</div>
<div id="east">
<table>
<caption>Controls with hover handlers (toggle on/off to clear output)</caption>
<tbody>
<tr>
<td>long delay (2 sec)</td>
<td><button id="longStatus" onclick="toggle('long')">off</button></td>
<td><textarea class="output" id="longOutput"></textarea></td>
</tr>
<tr>
<td>short delay (100 msec)</td>
<td><button id="shortStatus" onclick="toggle('short')">off</button></td>
<td><textarea class="output" id="shortOutput"></textarea></td>
</tr>
<tr>
<td>tolerant (6 pixels)</td>
<td><button id="tolerantStatus" onclick="toggle('tolerant')">off</button></td>
<td><textarea class="output" id="tolerantOutput"></textarea></td>
</tr>
<tr>
<td>untolerant (1 pixel)</td>
<td><button id="untolerantStatus" onclick="toggle('untolerant')">off</button></td>
<td><textarea class="output" id="untolerantOutput"></textarea></td>
</tr>
<tr>
<td>stop propagation</td>
<td><button id="stoppropagStatus" onclick="toggle('stoppropag')">off</button></td>
<td><textarea class="output" id="stoppropagOutput"></textarea></td>
</tr>
</tbody>
</table>
</div>
</body>
</html>

View File

@@ -117,6 +117,7 @@
"OpenLayers/Feature/WFS.js",
"OpenLayers/Handler.js",
"OpenLayers/Handler/Click.js",
"OpenLayers/Handler/Hover.js",
"OpenLayers/Handler/Point.js",
"OpenLayers/Handler/Path.js",
"OpenLayers/Handler/Polygon.js",

View File

@@ -0,0 +1,178 @@
/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the clear BSD license.
* See http://svn.openlayers.org/trunk/openlayers/license.txt
* for the full text of the license. */
/**
* @requires OpenLayers/Handler.js
*/
/**
* Class: OpenLayers.Handler.Hover
* The hover handler is to be used to emulate mouseovers on objects
* on the map that aren't DOM elements. For example one can use
* this handler to send WMS/GetFeatureInfo requests as the user
* moves the mouve over the map.
*
* Inherits from:
* - <OpenLayers.Handler>
*/
OpenLayers.Handler.Hover = OpenLayers.Class(OpenLayers.Handler, {
/**
* APIProperty: delay
* {Integer} - Number of milliseconds between mousemoves before
* the event is considered a hover. Default is 500.
*/
delay: 500,
/**
* APIProperty: pixelTolerance
* {Integer} - Maximum number of pixels between mousemoves for
* an event to be considered a hover. Default is null.
*/
pixelTolerance: null,
/**
* APIProperty: stopMove
* {Boolean} Stop other listeners from being notified on mousemoves.
* Default is false.
*/
stopMove: false,
/**
* Property: px
* {<OpenLayers.Pixel>} The location of the last mousemove, expressed
* in pixels.
*/
px: null,
/**
* Property: timerId
* {Number} The id of the timer.
*/
timerId: null,
/**
* Constructor: OpenLayers.Handler.Hover
* Construct a hover handler.
*
* Parameters:
* control - {<OpenLayers.Control>} The control that initialized this
* handler. The control is assumed to have a valid map property; that
* map is used in the handler's own setMap method.
* callbacks - {Object} An object whose properties correspond to abstracted
* events or sequences of browser events. The values for these
* properties are functions defined by the control that get called by
* the handler.
* options - {Object} An optional object whose properties will be set on
* the handler.
*/
initialize: function(control, callbacks, options) {
OpenLayers.Handler.prototype.initialize.apply(this, arguments);
},
/**
* Method: mousemove
* Called when the mouse moves on the map.
*
* Parameters:
* evt - {<OpenLayers.Event>}
*
* Returns:
* {Boolean} Continue propagating this event.
*/
mousemove: function(evt) {
if(this.passesTolerance(evt.xy)) {
this.clearTimer();
this.callback('move', [evt]);
this.px = evt.xy;
this.timerId = window.setTimeout(
OpenLayers.Function.bind(this.delayedCall, this, evt),
this.delay
);
}
return !this.stopMove;
},
/**
* Method: mouseout
* Called when the mouse goes out of the map.
*
* Parameters:
* evt - {<OpenLayers.Event>}
*
* Returns:
* {Boolean} Continue propagating this event.
*/
mouseout: function(evt) {
if (OpenLayers.Util.mouseLeft(evt, this.map.div)) {
this.clearTimer();
this.callback('move', [evt]);
}
return true;
},
/**
* Method: passesTolerance
* Determine whether the mouse move is within the optional pixel tolerance.
*
* Parameters:
* px - {<OpenLayers.Pixel>}
*
* Returns:
* {Boolean} The mouse move is within the pixel tolerance.
*/
passesTolerance: function(px) {
var passes = true;
if(this.pixelTolerance && this.px) {
var dpx = Math.sqrt(
Math.pow(this.px.x - px.x, 2) +
Math.pow(this.px.y - px.y, 2)
);
if(dpx < this.pixelTolerance) {
passes = false;
}
}
return passes;
},
/**
* Method: clearTimer
* Clear the timer and set <timerId> to null.
*/
clearTimer: function() {
if(this.timerId != null) {
window.clearTimeout(this.timerId);
this.timerId = null;
}
},
/**
* Method: delayedCall
* Triggers pause callback.
*
* Parameters:
* evt - {<OpenLayers.Event>}
*/
delayedCall: function(evt) {
this.callback('pause', [evt]);
},
/**
* APIMethod: deactivate
* Deactivate the handler.
*
* Returns:
* {Boolean} The handler was successfully deactivated.
*/
deactivate: function() {
var deactivated = false;
if(OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) {
this.clearTimer();
deactivated = true;
}
return deactivated;
},
CLASS_NAME: "OpenLayers.Handler.Hover"
});

View File

@@ -0,0 +1,136 @@
<html>
<head>
<script src="../../lib/OpenLayers.js"></script>
<script type="text/javascript">
function test_Handler_Hover_events(t) {
t.plan(10);
var map = new OpenLayers.Map('map');
var control = {
map: map
};
map.events.registerPriority = function(type, obj, func) {
var r = func();
if(typeof r == "string") {
// this is one of the mock handler methods
t.eq(OpenLayers.Util.indexOf(nonevents, type), -1,
"registered method is not one of the events " +
"that should not be handled");
t.ok(OpenLayers.Util.indexOf(events, type) > -1,
"activate calls registerPriority with browser event: " + type);
t.eq(typeof func, "function",
"activate calls registerPriority with a function");
t.eq(func(), type,
"activate calls registerPriority with the correct method");
t.eq(obj["CLASS_NAME"], "OpenLayers.Handler.Hover",
"activate calls registerPriority with the handler");
}
}
function setMethod(key) {
handler[key] = function() {return key};
}
// list below events that should be handled (events) and those
// that should not be handled (nonevents) by the handler
var events = ["mousemove", "mouseout"];
var nonevents = ["mousedown", "mouseup", "click", "dblclick", "resize", "focus", "blur"];
var handler = new OpenLayers.Handler.Hover(control);
// set browser event like properties on the handler
for(var i=0; i<events.length; ++i) {
setMethod(events[i]);
}
handler.activate();
}
function test_Handler_Hover_callbacks(t) {
t.plan(8);
var map = new OpenLayers.Map('map', {controls: []});
var control = {
map: map
};
var timers = {};
var sto = window.setTimeout;
window.setTimeout = function(func, delay) {
var key = Math.random();
timers[key] = true;
t.ok(typeof func == "function",
"setTimeout called with a function");
t.eq(delay, handler.delay,
"setTimeout called with proper delay");
// execute function that is supposed to be delayed
func();
return key;
}
var cto = window.clearTimeout;
window.clearTimeout = function(key) {
if(timers[key] === true) {
delete timers[key];
} else {
t.fail("clearTimeout called with non-existent timerId");
}
}
var handler = new OpenLayers.Handler.Hover(control, {});
handler.activate();
var testEvt;
// test pause and move callbacks - four tests here (2 from setTimeout above)
testEvt = Math.random();
handler.callbacks = {
"pause": function(evt) {
t.eq(evt, testEvt,
"pause callback called with correct evt");
},
"move": function(evt) {
t.eq(evt, testEvt,
"move callback called with correct evt");
}
};
map.events.triggerEvent("mousemove", testEvt);
handler.clearTimer();
// test pixelTolerance - four tests here (2 from setTimeout above)
handler.pixelTolerance = 2;
handler.px = new OpenLayers.Pixel(0, 0);
testEvt = {
xy: new OpenLayers.Pixel(0, 1)
};
// mouse moves one pixel, callbacks shouldn't be called
handler.callbacks = {
"pause": function(evt) {
t.fail("(pixelTolerance met) pause callback shouldn't be called");
},
"move": function(evt) {
t.fail("(pixelTolerance met) move callback shoudln't be called");
}
};
map.events.triggerEvent("mousemove", testEvt);
handler.clearTimer();
handler.px = new OpenLayers.Pixel(0, 0);
testEvt = {
xy: new OpenLayers.Pixel(3, 3)
};
// mouse moves 3x3 pixels, callbacks should be called
handler.callbacks = {
"pause": function(evt) {
t.ok(evt == testEvt, "(pixelTolerance unmet) pause callback called");
},
"move": function(evt) {
t.ok(evt == testEvt, "(pixelTolerance unmet) move callback called");
}
};
map.events.triggerEvent("mousemove", testEvt);
handler.clearTimer();
window.setTimeout = sto;
window.clearTimeout = cto;
}
</script>
</head>
<body>
<div id="map" style="width: 300px; height: 150px;"/>
</body>
</html>

View File

@@ -88,6 +88,7 @@
<li>Control/test_SelectFeature.html</li>
<li>test_Handler.html</li>
<li>Handler/test_Click.html</li>
<li>Handler/test_Hover.html</li>
<li>Handler/test_Drag.html</li>
<li>Handler/test_Feature.html</li>
<li>Handler/test_Keyboard.html</li>