/* Copyright (c) 2006-2010 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.js
*/
/**
* Class: OpenLayers.Control.ScaleLine
* The ScaleLine displays a small line indicator representing the current
* map scale on the map. By default it is drawn in the lower left corner of
* the map.
*
* Inherits from:
* - <OpenLayers.Control>
*
* Is a very close copy of:
* - <OpenLayers.Control.Scale>
*/
OpenLayers.Control.ScaleLine = OpenLayers.Class(OpenLayers.Control, {
/**
* Property: maxWidth
* {Integer} Maximum width of the scale line in pixels. Default is 100.
*/
maxWidth: 100,
/**
* Property: topOutUnits
* {String} Units for zoomed out on top bar. Default is km.
*/
topOutUnits: "km",
/**
* Property: topInUnits
* {String} Units for zoomed in on top bar. Default is m.
*/
topInUnits: "m",
/**
* Property: bottomOutUnits
* {String} Units for zoomed out on bottom bar. Default is mi.
*/
bottomOutUnits: "mi",
/**
* Property: bottomInUnits
* {String} Units for zoomed in on bottom bar. Default is ft.
*/
bottomInUnits: "ft",
/**
* Property: eTop
* {DOMElement}
*/
eTop: null,
/**
* Property: eBottom
* {DOMElement}
*/
eBottom:null,
/**
* APIProperty: geodesic
* {Boolean} Use geodesic measurement. Default is false. The recommended
* setting for maps in EPSG:4326 is false, and true EPSG:900913. If set to
* true, the scale will be calculated based on the horizontal size of the
* pixel in the center of the map viewport.
*/
geodesic: false,
/**
* Constructor: OpenLayers.Control.ScaleLine
* Create a new scale line control.
*
* Parameters:
* options - {Object} An optional object whose properties will be used
* to extend the control.
*/
initialize: function(options) {
OpenLayers.Control.prototype.initialize.apply(this, [options]);
},
/**
* Method: draw
*
* Returns:
* {DOMElement}
*/
draw: function() {
OpenLayers.Control.prototype.draw.apply(this, arguments);
if (!this.eTop) {
// stick in the top bar
this.eTop = document.createElement("div");
this.eTop.className = this.displayClass + "Top";
var theLen = this.topInUnits.length;
this.div.appendChild(this.eTop);
if((this.topOutUnits == "") || (this.topInUnits == "")) {
this.eTop.style.visibility = "hidden";
} else {
this.eTop.style.visibility = "visible";
}
// and the bottom bar
this.eBottom = document.createElement("div");
this.eBottom.className = this.displayClass + "Bottom";
this.div.appendChild(this.eBottom);
if((this.bottomOutUnits == "") || (this.bottomInUnits == "")) {
this.eBottom.style.visibility = "hidden";
} else {
this.eBottom.style.visibility = "visible";
}
}
this.map.events.register('moveend', this, this.update);
this.update();
return this.div;
},
/**
* Method: getBarLen
* Given a number, round it down to the nearest 1,2,5 times a power of 10.
* That seems a fairly useful set of number groups to use.
*
* Parameters:
* maxLen - {float} the number we're rounding down from
*
* Returns:
* {Float} the rounded number (less than or equal to maxLen)
*/
getBarLen: function(maxLen) {
// nearest power of 10 lower than maxLen
var digits = parseInt(Math.log(maxLen) / Math.log(10));
var pow10 = Math.pow(10, digits);
// ok, find first character
var firstChar = parseInt(maxLen / pow10);
// right, put it into the correct bracket
var barLen;
if(firstChar > 5) {
barLen = 5;
} else if(firstChar > 2) {
barLen = 2;
} else {
barLen = 1;
}
// scale it up the correct power of 10
return barLen * pow10;
},
/**
* Method: update
* Update the size of the bars, and the labels they contain.
*/
update: function() {
var res = this.map.getResolution();
if (!res) {
return;
}
var curMapUnits = this.map.getUnits();
var inches = OpenLayers.INCHES_PER_UNIT;
// convert maxWidth to map units
var maxSizeData = this.maxWidth * res * inches[curMapUnits];
var geodesicRatio = 1;
if(this.geodesic === true) {
var maxSizeGeodesic = (this.map.getGeodesicPixelSize().w ||
0.000001) * this.maxWidth;
var maxSizeKilometers = maxSizeData / inches["km"];
geodesicRatio = maxSizeGeodesic / maxSizeKilometers;
maxSizeData *= geodesicRatio;
}
// decide whether to use large or small scale units
var topUnits;
var bottomUnits;
if(maxSizeData > 100000) {
topUnits = this.topOutUnits;
bottomUnits = this.bottomOutUnits;
} else {
topUnits = this.topInUnits;
bottomUnits = this.bottomInUnits;
}
// and to map units units
var topMax = maxSizeData / inches[topUnits];
var bottomMax = maxSizeData / inches[bottomUnits];
// now trim this down to useful block length
var topRounded = this.getBarLen(topMax);
var bottomRounded = this.getBarLen(bottomMax);
// and back to display units
topMax = topRounded / inches[curMapUnits] * inches[topUnits];
bottomMax = bottomRounded / inches[curMapUnits] * inches[bottomUnits];
// and to pixel units
var topPx = topMax / res / geodesicRatio;
var bottomPx = bottomMax / res / geodesicRatio;
// now set the pixel widths
// and the values inside them
if (this.eBottom.style.visibility == "visible"){
this.eBottom.style.width = Math.round(bottomPx) + "px";
this.eBottom.innerHTML = bottomRounded + " " + bottomUnits ;
}
if (this.eTop.style.visibility == "visible"){
this.eTop.style.width = Math.round(topPx) + "px";
this.eTop.innerHTML = topRounded + " " + topUnits;
}
},
CLASS_NAME: "OpenLayers.Control.ScaleLine"
});