Files
openlayers/lib/OpenLayers/Control/PanZoomBar.js
ahocevar e7107b96cb Fixing PanZoomBar and Panel issues after #164.
For PanZoomBar, this fixes the slider behavior. Now the buttonclick listener argument also includes a buttonXY property, and PanZoomPanel does not need an Events instance for the zoombarDiv any more.
For Panel, this fixes events for panels outside the map. Just setting the element on the Events instance was no longer enough after e70569b2bb. Events::attachToElement is now used, and it needed to be modified to also work if the Events instance had no element previously.
Finally, I renamed the button property of the buttonclick listener argument to buttonElement, to not confuse it with the browser event button property, and added some more tests and documentation.
2012-01-22 21:30:40 +01:00

396 lines
12 KiB
JavaScript

/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for
* full list of contributors). Published under the Clear BSD license.
* See http://svn.openlayers.org/trunk/openlayers/license.txt for the
* full text of the license. */
/**
* @requires OpenLayers/Control/PanZoom.js
*/
/**
* Class: OpenLayers.Control.PanZoomBar
* The PanZoomBar is a visible control composed of a
* <OpenLayers.Control.PanPanel> and a <OpenLayers.Control.ZoomBar>.
* By default it is displayed in the upper left corner of the map as 4
* directional arrows above a vertical slider.
*
* Inherits from:
* - <OpenLayers.Control.PanZoom>
*/
OpenLayers.Control.PanZoomBar = OpenLayers.Class(OpenLayers.Control.PanZoom, {
/**
* APIProperty: zoomStopWidth
*/
zoomStopWidth: 18,
/**
* APIProperty: zoomStopHeight
*/
zoomStopHeight: 11,
/**
* Property: slider
*/
slider: null,
/**
* Property: sliderEvents
* {<OpenLayers.Events>}
*/
sliderEvents: null,
/**
* Property: zoombarDiv
* {DOMElement}
*/
zoombarDiv: null,
/**
* Property: divEvents
* {<OpenLayers.Events>}
*/
divEvents: null,
/**
* APIProperty: zoomWorldIcon
* {Boolean}
*/
zoomWorldIcon: false,
/**
* APIProperty: panIcons
* {Boolean} Set this property to false not to display the pan icons. If
* false the zoom world icon is placed under the zoom bar. Defaults to
* true.
*/
panIcons: true,
/**
* APIProperty: forceFixedZoomLevel
* {Boolean} Force a fixed zoom level even though the map has
* fractionalZoom
*/
forceFixedZoomLevel: false,
/**
* Property: mouseDragStart
* {<OpenLayers.Pixel>}
*/
mouseDragStart: null,
/**
* Property: deltaY
* {Number} The cumulative vertical pixel offset during a zoom bar drag.
*/
deltaY: null,
/**
* Property: zoomStart
* {<OpenLayers.Pixel>}
*/
zoomStart: null,
/**
* Constructor: OpenLayers.Control.PanZoomBar
*/
/**
* APIMethod: destroy
*/
destroy: function() {
this._removeZoomBar();
this.map.events.un({
"changebaselayer": this.redraw,
scope: this
});
OpenLayers.Control.PanZoom.prototype.destroy.apply(this, arguments);
delete this.mouseDragStart;
delete this.zoomStart;
},
/**
* Method: setMap
*
* Parameters:
* map - {<OpenLayers.Map>}
*/
setMap: function(map) {
OpenLayers.Control.PanZoom.prototype.setMap.apply(this, arguments);
this.map.events.register("changebaselayer", this, this.redraw);
},
/**
* Method: redraw
* clear the div and start over.
*/
redraw: function() {
if (this.div != null) {
this.removeButtons();
this._removeZoomBar();
}
this.draw();
},
/**
* Method: draw
*
* Parameters:
* px - {<OpenLayers.Pixel>}
*/
draw: function(px) {
// initialize our internal div
OpenLayers.Control.prototype.draw.apply(this, arguments);
px = this.position.clone();
// place the controls
this.buttons = [];
var sz = {w: 18, h: 18};
if (this.panIcons) {
var centered = new OpenLayers.Pixel(px.x+sz.w/2, px.y);
var wposition = sz.w;
if (this.zoomWorldIcon) {
centered = new OpenLayers.Pixel(px.x+sz.w, px.y);
}
this._addButton("panup", "north-mini.png", centered, sz);
px.y = centered.y+sz.h;
this._addButton("panleft", "west-mini.png", px, sz);
if (this.zoomWorldIcon) {
this._addButton("zoomworld", "zoom-world-mini.png", px.add(sz.w, 0), sz);
wposition *= 2;
}
this._addButton("panright", "east-mini.png", px.add(wposition, 0), sz);
this._addButton("pandown", "south-mini.png", centered.add(0, sz.h*2), sz);
this._addButton("zoomin", "zoom-plus-mini.png", centered.add(0, sz.h*3+5), sz);
centered = this._addZoomBar(centered.add(0, sz.h*4 + 5));
this._addButton("zoomout", "zoom-minus-mini.png", centered, sz);
}
else {
this._addButton("zoomin", "zoom-plus-mini.png", px, sz);
centered = this._addZoomBar(px.add(0, sz.h));
this._addButton("zoomout", "zoom-minus-mini.png", centered, sz);
if (this.zoomWorldIcon) {
centered = centered.add(0, sz.h+3);
this._addButton("zoomworld", "zoom-world-mini.png", centered, sz);
}
}
return this.div;
},
/**
* Method: _addZoomBar
*
* Parameters:
* centered - {<OpenLayers.Pixel>} where zoombar drawing is to start.
*/
_addZoomBar:function(centered) {
var imgLocation = OpenLayers.Util.getImageLocation("slider.png");
var id = this.id + "_" + this.map.id;
var zoomsToEnd = this.map.getNumZoomLevels() - 1 - this.map.getZoom();
var slider = OpenLayers.Util.createAlphaImageDiv(id,
centered.add(-1, zoomsToEnd * this.zoomStopHeight),
{w: 20, h: 9},
imgLocation,
"absolute");
slider.style.cursor = "move";
this.slider = slider;
this.sliderEvents = new OpenLayers.Events(this, slider, null, true,
{includeXY: true});
this.sliderEvents.on({
"touchstart": this.zoomBarDown,
"touchmove": this.zoomBarDrag,
"touchend": this.zoomBarUp,
"mousedown": this.zoomBarDown,
"mousemove": this.zoomBarDrag,
"mouseup": this.zoomBarUp,
"dblclick": this.doubleClick,
"click": this.doubleClick
});
var sz = {
w: this.zoomStopWidth,
h: this.zoomStopHeight * this.map.getNumZoomLevels()
};
var imgLocation = OpenLayers.Util.getImageLocation("zoombar.png");
var div = null;
if (OpenLayers.Util.alphaHack()) {
var id = this.id + "_" + this.map.id;
div = OpenLayers.Util.createAlphaImageDiv(id, centered,
{w: sz.w, h: this.zoomStopHeight},
imgLocation,
"absolute", null, "crop");
div.style.height = sz.h + "px";
} else {
div = OpenLayers.Util.createDiv(
'OpenLayers_Control_PanZoomBar_Zoombar' + this.map.id,
centered,
sz,
imgLocation);
}
div.style.cursor = "pointer";
div.className = "olButton";
this.zoombarDiv = div;
this.div.appendChild(div);
this.startTop = parseInt(div.style.top);
this.div.appendChild(slider);
this.map.events.register("zoomend", this, this.moveZoomBar);
centered = centered.add(0,
this.zoomStopHeight * this.map.getNumZoomLevels());
return centered;
},
/**
* Method: _removeZoomBar
*/
_removeZoomBar: function() {
this.sliderEvents.un({
"touchmove": this.zoomBarDrag,
"mousedown": this.zoomBarDown,
"mousemove": this.zoomBarDrag,
"mouseup": this.zoomBarUp,
"dblclick": this.doubleClick,
"click": this.doubleClick
});
this.sliderEvents.destroy();
this.div.removeChild(this.zoombarDiv);
this.zoombarDiv = null;
this.div.removeChild(this.slider);
this.slider = null;
this.map.events.unregister("zoomend", this, this.moveZoomBar);
},
/**
* Method: onButtonClick
*/
onButtonClick: function(evt) {
OpenLayers.Control.PanZoom.prototype.onButtonClick.apply(this, arguments);
if (evt.buttonElement === this.zoombarDiv) {
var levels = evt.buttonXY.y / this.zoomStopHeight;
if(this.forceFixedZoomLevel || !this.map.fractionalZoom) {
levels = Math.floor(levels);
}
var zoom = (this.map.getNumZoomLevels() - 1) - levels;
zoom = Math.min(Math.max(zoom, 0), this.map.getNumZoomLevels() - 1);
this.map.zoomTo(zoom);
}
},
/*
* Method: zoomBarDown
* event listener for clicks on the slider
*
* Parameters:
* evt - {<OpenLayers.Event>}
*/
zoomBarDown:function(evt) {
if (!OpenLayers.Event.isLeftClick(evt) && !OpenLayers.Event.isSingleTouch(evt)) {
return;
}
this.map.events.on({
"touchmove": this.passEventToSlider,
"mousemove": this.passEventToSlider,
"mouseup": this.passEventToSlider,
scope: this
});
this.mouseDragStart = evt.xy.clone();
this.zoomStart = evt.xy.clone();
this.div.style.cursor = "move";
// reset the div offsets just in case the div moved
this.zoombarDiv.offsets = null;
OpenLayers.Event.stop(evt);
},
/*
* Method: zoomBarDrag
* This is what happens when a click has occurred, and the client is
* dragging. Here we must ensure that the slider doesn't go beyond the
* bottom/top of the zoombar div, as well as moving the slider to its new
* visual location
*
* Parameters:
* evt - {<OpenLayers.Event>}
*/
zoomBarDrag:function(evt) {
if (this.mouseDragStart != null) {
var deltaY = this.mouseDragStart.y - evt.xy.y;
var offsets = OpenLayers.Util.pagePosition(this.zoombarDiv);
if ((evt.clientY - offsets[1]) > 0 &&
(evt.clientY - offsets[1]) < parseInt(this.zoombarDiv.style.height) - 2) {
var newTop = parseInt(this.slider.style.top) - deltaY;
this.slider.style.top = newTop+"px";
this.mouseDragStart = evt.xy.clone();
}
// set cumulative displacement
this.deltaY = this.zoomStart.y - evt.xy.y;
OpenLayers.Event.stop(evt);
}
},
/*
* Method: zoomBarUp
* Perform cleanup when a mouseup event is received -- discover new zoom
* level and switch to it.
*
* Parameters:
* evt - {<OpenLayers.Event>}
*/
zoomBarUp:function(evt) {
if (!OpenLayers.Event.isLeftClick(evt) && evt.type !== "touchend") {
return;
}
if (this.mouseDragStart) {
this.div.style.cursor="";
this.map.events.un({
"touchmove": this.passEventToSlider,
"mouseup": this.passEventToSlider,
"mousemove": this.passEventToSlider,
scope: this
});
var zoomLevel = this.map.zoom;
if (!this.forceFixedZoomLevel && this.map.fractionalZoom) {
zoomLevel += this.deltaY/this.zoomStopHeight;
zoomLevel = Math.min(Math.max(zoomLevel, 0),
this.map.getNumZoomLevels() - 1);
} else {
zoomLevel += this.deltaY/this.zoomStopHeight;
zoomLevel = Math.max(Math.round(zoomLevel), 0);
}
this.map.zoomTo(zoomLevel);
this.mouseDragStart = null;
this.zoomStart = null;
this.deltaY = 0;
OpenLayers.Event.stop(evt);
}
},
/*
* Method: moveZoomBar
* Change the location of the slider to match the current zoom level.
*/
moveZoomBar:function() {
var newTop =
((this.map.getNumZoomLevels()-1) - this.map.getZoom()) *
this.zoomStopHeight + this.startTop + 1;
this.slider.style.top = newTop + "px";
},
CLASS_NAME: "OpenLayers.Control.PanZoomBar"
});