merge with trunk

This commit is contained in:
Bart van den Eijnden
2012-02-28 13:31:14 +01:00
119 changed files with 2543 additions and 855 deletions

View File

@@ -15,6 +15,16 @@
*/
OpenLayers.Animation = (function(window) {
/**
* Property: isNative
* {Boolean} true if a native requestAnimationFrame function is available
*/
var isNative = !!(window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame);
/**
* Function: requestFrame
* Schedule a function to be called at the next available animation frame.
@@ -89,6 +99,7 @@ OpenLayers.Animation = (function(window) {
}
return {
isNative: isNative,
requestFrame: requestFrame,
start: start,
stop: stop

View File

@@ -60,28 +60,6 @@ OpenLayers.String = {
return str.replace(/^\s\s*/, '').replace(/\s\s*$/, '');
},
/**
* APIFunction: camelize
* Camel-case a hyphenated string.
* Ex. "chicken-head" becomes "chickenHead", and
* "-chicken-head" becomes "ChickenHead".
*
* Parameters:
* str - {String} The string to be camelized. The original is not modified.
*
* Returns:
* {String} The string, camelized
*/
camelize: function(str) {
var oStringList = str.split('-');
var camelizedString = oStringList[0];
for (var i=1, len=oStringList.length; i<len; i++) {
var s = oStringList[i];
camelizedString += s.charAt(0).toUpperCase() + s.substring(1);
}
return camelizedString;
},
/**
* APIFunction: format
* Given a string with tokens in the form ${token}, return a string

View File

@@ -716,7 +716,8 @@ OpenLayers.Bounds.fromArray = function(bbox, reverseAxisOrder) {
* from a size
*
* Parameters:
* size - {<OpenLayers.Size>}
* size - {<OpenLayers.Size>|Object} OpenLayers.Size or an object with
* a 'w' and 'h' properties.
*
* Returns:
* {<OpenLayers.Bounds>} New bounds object built from the passed-in size.

View File

@@ -163,7 +163,7 @@ OpenLayers.Element = {
var value = null;
if (element && element.style) {
value = element.style[OpenLayers.String.camelize(style)];
value = element.style[style];
if (!value) {
if (document.defaultView &&
document.defaultView.getComputedStyle) {
@@ -171,7 +171,7 @@ OpenLayers.Element = {
var css = document.defaultView.getComputedStyle(element, null);
value = css ? css.getPropertyValue(style) : null;
} else if (element.currentStyle) {
value = element.currentStyle[OpenLayers.String.camelize(style)];
value = element.currentStyle[style];
}
}

View File

@@ -139,10 +139,7 @@ OpenLayers.Control = OpenLayers.Class({
* APIProperty: events
* {<OpenLayers.Events>} Events instance for listeners and triggering
* control specific events.
*/
events: null,
/**
*
* Register a listener for a particular event with the following syntax:
* (code)
* control.events.register(type, obj, listener);
@@ -161,6 +158,7 @@ OpenLayers.Control = OpenLayers.Class({
* activate - Triggered when activated.
* deactivate - Triggered when deactivated.
*/
events: null,
/**
* Constructor: OpenLayers.Control

View File

@@ -24,6 +24,14 @@ OpenLayers.Control.Attribution =
*/
separator: ", ",
/**
* APIProperty: template
* {String} Template for the attribution. This has to include the substring
* "${layers}", which will be replaced by the layer specific
* attributions, separated by <separator>. The default is "${layers}".
*/
template: "${layers}",
/**
* Constructor: OpenLayers.Control.Attribution
*
@@ -86,7 +94,9 @@ OpenLayers.Control.Attribution =
}
}
}
this.div.innerHTML = attributions.join(this.separator);
this.div.innerHTML = OpenLayers.String.format(this.template, {
layers: attributions.join(this.separator)
});
}
},

View File

@@ -31,8 +31,17 @@ OpenLayers.Control.DrawFeature = OpenLayers.Class(OpenLayers.Control, {
*/
callbacks: null,
/**
* Supported event types:
/**
* APIProperty: events
* {<OpenLayers.Events>} Events instance for listeners and triggering
* control specific events.
*
* Register a listener for a particular event with the following syntax:
* (code)
* control.events.register(type, obj, listener);
* (end)
*
* Supported event types (in addition to those from <OpenLayers.Control.events>):
* featureadded - Triggered when a feature is added
*/

View File

@@ -22,15 +22,24 @@
*/
OpenLayers.Control.Geolocate = OpenLayers.Class(OpenLayers.Control, {
/**
* Supported event types:
* - *locationupdated* Triggered when browser return a new position. Listeners will
* receive an object with a 'position' property which is the browser.geolocation.position
* native object, as well as a 'point' property which is the location transformed in the
* current map projection.
* - *locationfailed* Triggered when geolocation has failed
* - *locationuncapable* Triggered when control is activated on a browser
* which doesn't support geolocation
/**
* APIProperty: events
* {<OpenLayers.Events>} Events instance for listeners and triggering
* control specific events.
*
* Register a listener for a particular event with the following syntax:
* (code)
* control.events.register(type, obj, listener);
* (end)
*
* Supported event types (in addition to those from <OpenLayers.Control.events>):
* locationupdated - Triggered when browser return a new position. Listeners will
* receive an object with a 'position' property which is the browser.geolocation.position
* native object, as well as a 'point' property which is the location transformed in the
* current map projection.
* locationfailed - Triggered when geolocation has failed
* locationuncapable - Triggered when control is activated on a browser
* which doesn't support geolocation
*/
/**

View File

@@ -169,8 +169,17 @@ OpenLayers.Control.GetFeature = OpenLayers.Class(OpenLayers.Control, {
*/
filterType: OpenLayers.Filter.Spatial.BBOX,
/**
* Supported event types:
/**
* APIProperty: events
* {<OpenLayers.Events>} Events instance for listeners and triggering
* control specific events.
*
* Register a listener for a particular event with the following syntax:
* (code)
* control.events.register(type, obj, listener);
* (end)
*
* Supported event types (in addition to those from <OpenLayers.Control.events>):
* beforefeatureselected - Triggered when <click> is true before a
* feature is selected. The event object has a feature property with
* the feature about to select

View File

@@ -34,6 +34,15 @@ OpenLayers.Control.KeyboardDefaults = OpenLayers.Class(OpenLayers.Control, {
*/
slideFactor: 75,
/**
* APIProperty: observeElement
* {DOMelement|String} The DOM element to handle keys for. You
* can use the map div here, to have the navigation keys
* work when the map div has the focus. If undefined the
* document is used.
*/
observeElement: null,
/**
* Constructor: OpenLayers.Control.KeyboardDefaults
*/
@@ -43,8 +52,11 @@ OpenLayers.Control.KeyboardDefaults = OpenLayers.Class(OpenLayers.Control, {
* Create handler.
*/
draw: function() {
this.handler = new OpenLayers.Handler.Keyboard( this, {
"keydown": this.defaultKeyPress });
var observeElement = this.observeElement || document;
this.handler = new OpenLayers.Handler.Keyboard( this,
{"keydown": this.defaultKeyPress},
{observeElement: observeElement}
);
},
/**
@@ -62,7 +74,7 @@ OpenLayers.Control.KeyboardDefaults = OpenLayers.Class(OpenLayers.Control, {
* evt - {Event}
*/
defaultKeyPress: function (evt) {
var size;
var size, handled = true;
switch(evt.keyCode) {
case OpenLayers.Event.KEY_LEFT:
this.map.pan(-this.slideFactor, 0);
@@ -106,7 +118,14 @@ OpenLayers.Control.KeyboardDefaults = OpenLayers.Class(OpenLayers.Control, {
case 95: // -/_ (some ASCII)
this.map.zoomOut();
break;
}
default:
handled = false;
}
if (handled) {
// prevent browser default not to move the page
// when moving the page with the keyboard
OpenLayers.Event.stop(evt);
}
},
CLASS_NAME: "OpenLayers.Control.KeyboardDefaults"

View File

@@ -197,11 +197,25 @@ OpenLayers.Control.LayerSwitcher =
* evt - {Event}
*/
onButtonClick: function(evt) {
if (evt.buttonElement === this.minimizeDiv) {
var button = evt.buttonElement;
if (button === this.minimizeDiv) {
this.minimizeControl();
} else if (evt.buttonElement === this.maximizeDiv) {
} else if (button === this.maximizeDiv) {
this.maximizeControl();
};
} else if (button._layerSwitcher === this.id) {
if (button["for"]) {
button = document.getElementById(button["for"]);
}
if (!button.disabled) {
if (button.type == "radio") {
button.checked = true;
this.map.setBaseLayer(this.map.getLayer(button._layer));
} else {
button.checked = !button.checked;
this.updateMap();
}
}
}
},
/**
@@ -213,14 +227,6 @@ OpenLayers.Control.LayerSwitcher =
* layersType - {String}
*/
clearLayersArray: function(layersType) {
var layers = this[layersType + "Layers"];
if (layers) {
for(var i=0, len=layers.length; i<len ; i++) {
var layer = layers[i];
OpenLayers.Event.stopObservingElement(layer.inputElem);
OpenLayers.Event.stopObservingElement(layer.labelSpan);
}
}
this[layersType + "LayersDiv"].innerHTML = "";
this[layersType + "Layers"] = [];
},
@@ -320,32 +326,26 @@ OpenLayers.Control.LayerSwitcher =
inputElem.value = layer.name;
inputElem.checked = checked;
inputElem.defaultChecked = checked;
inputElem.className = "olButton";
inputElem._layer = layer.id;
inputElem._layerSwitcher = this.id;
if (!baseLayer && !layer.inRange) {
inputElem.disabled = true;
}
var context = {
'inputElem': inputElem,
'layer': layer,
'layerSwitcher': this
};
var onInputClick = OpenLayers.Function.bindAsEventListener(
this.onInputClick, context
);
OpenLayers.Event.observe(inputElem, "mousedown", onInputClick);
OpenLayers.Event.observe(inputElem, "touchstart", onInputClick);
// create span
var labelSpan = document.createElement("span");
OpenLayers.Element.addClass(labelSpan, "labelSpan");
var labelSpan = document.createElement("label");
labelSpan["for"] = inputElem.id;
OpenLayers.Element.addClass(labelSpan, "labelSpan olButton");
labelSpan._layer = layer.id;
labelSpan._layerSwitcher = this.id;
if (!baseLayer && !layer.inRange) {
labelSpan.style.color = "gray";
}
labelSpan.innerHTML = layer.name;
labelSpan.style.verticalAlign = (baseLayer) ? "bottom"
: "baseline";
OpenLayers.Event.observe(labelSpan, "click", onInputClick);
OpenLayers.Event.observe(labelSpan, "touchstart", onInputClick);
// create line break
var br = document.createElement("br");
@@ -376,49 +376,6 @@ OpenLayers.Control.LayerSwitcher =
return this.div;
},
/**
* Method:
* A label has been clicked, check or uncheck its corresponding input
*
* Parameters:
* e - {Event}
*
* Context:
* - {Object}
*
* Object structure:
* inputElem - {DOMElement}
* layerSwitcher - {<OpenLayers.Control.LayerSwitcher>}
* layer - {<OpenLayers.Layer>}
*/
onInputClick: function(e) {
if (!this.inputElem.disabled) {
if (this.inputElem.type == "radio") {
this.inputElem.checked = true;
this.layer.map.setBaseLayer(this.layer);
} else {
this.inputElem.checked = !this.inputElem.checked;
this.layerSwitcher.updateMap();
}
}
OpenLayers.Event.stop(e);
},
/**
* Method: onLayerClick
* Need to update the map accordingly whenever user clicks in either of
* the layers.
*
* Parameters:
* e - {Event}
*/
onLayerClick: function(e) {
this.updateMap();
},
/**
* Method: updateMap
* Cycles through the loaded data and base layer input arrays and makes

View File

@@ -17,16 +17,17 @@
*/
OpenLayers.Control.Measure = OpenLayers.Class(OpenLayers.Control, {
/**
/**
* APIProperty: events
* {<OpenLayers.Events>} Events instance for listeners and triggering
* control specific events.
*
* Register a listener for a particular event with the following syntax:
* (code)
* control.events.register(type, obj, listener);
* (end)
*
* Listeners will be called with a reference to an event object. The
* properties of this event depends on exactly what happened.
*
* Supported control event types (in addition to those from <OpenLayers.Control>):
* Supported event types (in addition to those from <OpenLayers.Control.events>):
* measure - Triggered when a measurement sketch is complete. Listeners
* will receive an event with measure, units, order, and geometry
* properties.

View File

@@ -137,6 +137,13 @@ OpenLayers.Control.ModifyFeature = OpenLayers.Class(OpenLayers.Control, {
*/
mode: null,
/**
* APIProperty: createVertices
* {Boolean} Create new vertices by dragging the virtual vertices
* in the middle of each edge. Default is true.
*/
createVertices: true,
/**
* Property: modified
* {Boolean} The currently selected feature has been modified.
@@ -677,7 +684,7 @@ OpenLayers.Control.ModifyFeature = OpenLayers.Class(OpenLayers.Control, {
}
// add virtual vertices in the middle of each edge
if(geometry.CLASS_NAME != "OpenLayers.Geometry.MultiPoint") {
if (control.createVertices && geometry.CLASS_NAME != "OpenLayers.Geometry.MultiPoint") {
for(i=0, len=geometry.components.length; i<len-1; ++i) {
var prevVertex = geometry.components[i];
var nextVertex = geometry.components[i + 1];

View File

@@ -493,14 +493,14 @@ OpenLayers.Control.OverviewMap = OpenLayers.Class(OpenLayers.Control, {
this.ovmap.zoomToMaxExtent();
// check extent rectangle border width
this.wComp = parseInt(OpenLayers.Element.getStyle(this.extentRectangle,
'border-left-width')) +
'borderLeftWidth')) +
parseInt(OpenLayers.Element.getStyle(this.extentRectangle,
'border-right-width'));
'borderRightWidth'));
this.wComp = (this.wComp) ? this.wComp : 2;
this.hComp = parseInt(OpenLayers.Element.getStyle(this.extentRectangle,
'border-top-width')) +
parseInt(OpenLayers.Element.getStyle(this.extentRectangle,
'border-bottom-width'));
'borderBottomWidth'));
this.hComp = (this.hComp) ? this.hComp : 2;
this.handlers.drag = new OpenLayers.Handler.Drag(

View File

@@ -23,17 +23,17 @@
*/
OpenLayers.Control.SLDSelect = OpenLayers.Class(OpenLayers.Control, {
/**
/**
* APIProperty: events
* {<OpenLayers.Events>} Events instance for listeners and triggering
* control specific events.
*
* Register a listener for a particular event with the following syntax:
* (code)
* control.events.register(type, obj, listener);
* (end)
*
* Listeners will be called with a reference to an event object. The
* properties of this event depends on exactly what happened.
*
* Supported control event types (in addition to those from
* <OpenLayers.Control>):
* Supported event types (in addition to those from <OpenLayers.Control.events>):
* selected - Triggered when a selection occurs. Listeners receive an
* event with *filters* and *layer* properties. Filters will be an
* array of OpenLayers.Filter objects created in order to perform

View File

@@ -21,13 +21,22 @@
*/
OpenLayers.Control.SelectFeature = OpenLayers.Class(OpenLayers.Control, {
/**
* Supported event types:
* - *beforefeaturehighlighted* Triggered before a feature is highlighted
* - *featurehighlighted* Triggered when a feature is highlighted
* - *featureunhighlighted* Triggered when a feature is unhighlighted
* - *boxselectionstart* Triggered before box selection starts
* - *boxselectionend* Triggered after box selection ends
/**
* APIProperty: events
* {<OpenLayers.Events>} Events instance for listeners and triggering
* control specific events.
*
* Register a listener for a particular event with the following syntax:
* (code)
* control.events.register(type, obj, listener);
* (end)
*
* Supported event types (in addition to those from <OpenLayers.Control.events>):
* beforefeaturehighlighted - Triggered before a feature is highlighted
* featurehighlighted - Triggered when a feature is highlighted
* featureunhighlighted - Triggered when a feature is unhighlighted
* boxselectionstart - Triggered before box selection starts
* boxselectionend - Triggered after box selection ends
*/
/**

View File

@@ -17,16 +17,17 @@
*/
OpenLayers.Control.Snapping = OpenLayers.Class(OpenLayers.Control, {
/**
/**
* APIProperty: events
* {<OpenLayers.Events>} Events instance for listeners and triggering
* control specific events.
*
* Register a listener for a particular event with the following syntax:
* (code)
* control.events.register(type, obj, listener);
* (end)
*
* Listeners will be called with a reference to an event object. The
* properties of this event depends on exactly what happened.
*
* Supported control event types (in addition to those from <OpenLayers.Control>):
* Supported event types (in addition to those from <OpenLayers.Control.events>):
* beforesnap - Triggered before a snap occurs. Listeners receive an
* event object with *point*, *x*, *y*, *distance*, *layer*, and
* *snapType* properties. The point property will be original point

View File

@@ -18,16 +18,17 @@
*/
OpenLayers.Control.Split = OpenLayers.Class(OpenLayers.Control, {
/**
/**
* APIProperty: events
* {<OpenLayers.Events>} Events instance for listeners and triggering
* control specific events.
*
* Register a listener for a particular event with the following syntax:
* (code)
* control.events.register(type, obj, listener);
* (end)
*
* Listeners will be called with a reference to an event object. The
* properties of this event depends on exactly what happened.
*
* Supported control event types (in addition to those from <OpenLayers.Control>):
* Supported event types (in addition to those from <OpenLayers.Control.events>):
* beforesplit - Triggered before a split occurs. Listeners receive an
* event object with *source* and *target* properties.
* split - Triggered when a split occurs. Listeners receive an event with

View File

@@ -21,33 +21,42 @@
*/
OpenLayers.Control.TransformFeature = OpenLayers.Class(OpenLayers.Control, {
/**
* Supported event types:
* - *beforesetfeature* Triggered before a feature is set for
* tranformation. The feature will not be set if a listener returns
* false. Listeners receive a *feature* property, with the feature
* that will be set for transformation. Listeners are allowed to
* set the control's *scale*, *ratio* and *rotation* properties,
* which will set the initial scale, ratio and rotation of the
* feature, like the <setFeature> method's initialParams argument.
* - *setfeature* Triggered when a feature is set for tranformation.
* Listeners receive a *feature* property, with the feature that
* is now set for transformation.
* - *beforetransform* Triggered while dragging, before a feature is
* transformed. The feature will not be transformed if a listener
* returns false (but the box still will). Listeners receive one or
* more of *center*, *scale*, *ratio* and *rotation*. The *center*
* property is an <OpenLayers.Geometry.Point> object with the new
* center of the transformed feature, the others are Floats with the
* scale, ratio or rotation change since the last transformation.
* - *transform* Triggered while dragging, when a feature is transformed.
* Listeners receive an event object with one or more of *center*,
* *scale*, *ratio* and *rotation*. The *center* property is an
* <OpenLayers.Geometry.Point> object with the new center of the
* transformed feature, the others are Floats with the scale, ratio
* or rotation change of the feature since the last transformation.
* - *transformcomplete* Triggered after dragging. Listeners receive
* an event object with the transformed *feature*.
/**
* APIProperty: events
* {<OpenLayers.Events>} Events instance for listeners and triggering
* control specific events.
*
* Register a listener for a particular event with the following syntax:
* (code)
* control.events.register(type, obj, listener);
* (end)
*
* Supported event types (in addition to those from <OpenLayers.Control.events>):
* beforesetfeature - Triggered before a feature is set for
* tranformation. The feature will not be set if a listener returns
* false. Listeners receive a *feature* property, with the feature
* that will be set for transformation. Listeners are allowed to
* set the control's *scale*, *ratio* and *rotation* properties,
* which will set the initial scale, ratio and rotation of the
* feature, like the <setFeature> method's initialParams argument.
* setfeature - Triggered when a feature is set for tranformation.
* Listeners receive a *feature* property, with the feature that
* is now set for transformation.
* beforetransform - Triggered while dragging, before a feature is
* transformed. The feature will not be transformed if a listener
* returns false (but the box still will). Listeners receive one or
* more of *center*, *scale*, *ratio* and *rotation*. The *center*
* property is an <OpenLayers.Geometry.Point> object with the new
* center of the transformed feature, the others are Floats with the
* scale, ratio or rotation change since the last transformation.
* transform - Triggered while dragging, when a feature is transformed.
* Listeners receive an event object with one or more of *center*,
* scale*, *ratio* and *rotation*. The *center* property is an
* <OpenLayers.Geometry.Point> object with the new center of the
* transformed feature, the others are Floats with the scale, ratio
* or rotation change of the feature since the last transformation.
* transformcomplete - Triggered after dragging. Listeners receive
* an event object with the transformed *feature*.
*/
/**

View File

@@ -154,8 +154,17 @@ OpenLayers.Control.WMSGetFeatureInfo = OpenLayers.Class(OpenLayers.Control, {
*/
hoverRequest: null,
/**
* Supported event types (in addition to those from <OpenLayers.Control>):
/**
* APIProperty: events
* {<OpenLayers.Events>} Events instance for listeners and triggering
* control specific events.
*
* Register a listener for a particular event with the following syntax:
* (code)
* control.events.register(type, obj, listener);
* (end)
*
* Supported event types (in addition to those from <OpenLayers.Control.events>):
* beforegetfeatureinfo - Triggered before the request is sent.
* The event object has an *xy* property with the position of the
* mouse click or hover event that triggers the request.

View File

@@ -135,8 +135,17 @@ OpenLayers.Control.WMTSGetFeatureInfo = OpenLayers.Class(OpenLayers.Control, {
*/
hoverRequest: null,
/**
* Supported event types (in addition to those from <OpenLayers.Control>):
/**
* APIProperty: events
* {<OpenLayers.Events>} Events instance for listeners and triggering
* control specific events.
*
* Register a listener for a particular event with the following syntax:
* (code)
* control.events.register(type, obj, listener);
* (end)
*
* Supported event types (in addition to those from <OpenLayers.Control.events>):
* beforegetfeatureinfo - Triggered before each request is sent.
* The event object has an *xy* property with the position of the
* mouse click or hover event that triggers the request and a *layer*

View File

@@ -108,7 +108,7 @@ OpenLayers.Events.buttonclick = OpenLayers.Class({
var propagate = true,
element = OpenLayers.Event.element(evt);
if (element && (OpenLayers.Event.isLeftClick(evt) || !~evt.type.indexOf("mouse"))) {
if (OpenLayers.Element.hasClass(element, "olAlphaImg")) {
if (element.nodeType === 3 || OpenLayers.Element.hasClass(element, "olAlphaImg")) {
element = element.parentNode;
}
if (OpenLayers.Element.hasClass(element, "olButton")) {

View File

@@ -71,6 +71,13 @@ OpenLayers.Format.GPX = OpenLayers.Class(OpenLayers.Format.XML, {
* "http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd"
*/
schemaLocation: "http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd",
/**
* APIProperty: creator
* {String} The creator attribute to be added to the written GPX files.
* Defaults to "OpenLayers"
*/
creator: "OpenLayers",
/**
* Constructor: OpenLayers.Format.GPX
@@ -190,7 +197,7 @@ OpenLayers.Format.GPX = OpenLayers.Class(OpenLayers.Format.XML, {
var attributes = {};
var attrNode = node.firstChild, value, name;
while(attrNode) {
if(attrNode.nodeType == 1) {
if(attrNode.nodeType == 1 && attrNode.firstChild) {
value = attrNode.firstChild;
if(value.nodeType == 3 || value.nodeType == 4) {
name = (attrNode.prefix) ?
@@ -218,8 +225,9 @@ OpenLayers.Format.GPX = OpenLayers.Class(OpenLayers.Format.XML, {
write: function(features, metadata) {
features = OpenLayers.Util.isArray(features) ?
features : [features];
var gpx = this.createElementNSPlus("gpx:gpx");
var gpx = this.createElementNS(this.namespaces.gpx, "gpx");
gpx.setAttribute("version", "1.1");
gpx.setAttribute("creator", this.creator);
this.setAttributes(gpx, {
"xsi:schemaLocation": this.schemaLocation
});

View File

@@ -23,6 +23,15 @@
*/
OpenLayers.Format.SLD = OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC, {
/**
* APIProperty: profile
* {String} If provided, use a custom profile.
*
* Currently supported profiles:
* - GeoServer - parses GeoServer vendor specific capabilities for SLD.
*/
profile: null,
/**
* APIProperty: defaultVersion
* {String} Version number to assume if none found. Default is "1.0.0".

View File

@@ -220,6 +220,78 @@ OpenLayers.Format.SLD.v1 = OpenLayers.Class(OpenLayers.Format.Filter.v1_0_0, {
);
}
},
"LabelPlacement": function(node, symbolizer) {
this.readChildNodes(node, symbolizer);
},
"PointPlacement": function(node, symbolizer) {
var config = {};
this.readChildNodes(node, config);
config.labelRotation = config.rotation;
delete config.rotation;
var labelAlign,
x = symbolizer.labelAnchorPointX,
y = symbolizer.labelAnchorPointY;
if (x <= 1/3) {
labelAlign = 'l';
} else if (x > 1/3 && x < 2/3) {
labelAlign = 'c';
} else if (x >= 2/3) {
labelAlign = 'r';
}
if (y <= 1/3) {
labelAlign += 'b';
} else if (y > 1/3 && y < 2/3) {
labelAlign += 'm';
} else if (y >= 2/3) {
labelAlign += 't';
}
config.labelAlign = labelAlign;
OpenLayers.Util.applyDefaults(symbolizer, config);
},
"AnchorPoint": function(node, symbolizer) {
this.readChildNodes(node, symbolizer);
},
"AnchorPointX": function(node, symbolizer) {
var labelAnchorPointX = this.readers.ogc._expression.call(this, node);
// always string, could be empty string
if(labelAnchorPointX) {
symbolizer.labelAnchorPointX = labelAnchorPointX;
}
},
"AnchorPointY": function(node, symbolizer) {
var labelAnchorPointY = this.readers.ogc._expression.call(this, node);
// always string, could be empty string
if(labelAnchorPointY) {
symbolizer.labelAnchorPointY = labelAnchorPointY;
}
},
"Displacement": function(node, symbolizer) {
this.readChildNodes(node, symbolizer);
},
"DisplacementX": function(node, symbolizer) {
var labelXOffset = this.readers.ogc._expression.call(this, node);
// always string, could be empty string
if(labelXOffset) {
symbolizer.labelXOffset = labelXOffset;
}
},
"DisplacementY": function(node, symbolizer) {
var labelYOffset = this.readers.ogc._expression.call(this, node);
// always string, could be empty string
if(labelYOffset) {
symbolizer.labelYOffset = labelYOffset;
}
},
"LinePlacement": function(node, symbolizer) {
this.readChildNodes(node, symbolizer);
},
"PerpendicularOffset": function(node, symbolizer) {
var labelPerpendicularOffset = this.readers.ogc._expression.call(this, node);
// always string, could be empty string
if(labelPerpendicularOffset) {
symbolizer.labelPerpendicularOffset = labelPerpendicularOffset;
}
},
"Label": function(node, symbolizer) {
var value = this.readers.ogc._expression.call(this, node);
if (value) {
@@ -338,6 +410,15 @@ OpenLayers.Format.SLD.v1 = OpenLayers.Class(OpenLayers.Format.Filter.v1_0_0, {
"CssParameter": function(node, symbolizer) {
var cssProperty = node.getAttribute("name");
var symProperty = this.cssMap[cssProperty];
// for labels, fill should map to fontColor and fill-opacity
// to fontOpacity
if (symbolizer.label) {
if (cssProperty === 'fill') {
symProperty = "fontColor";
} else if (cssProperty === 'fill-opacity') {
symProperty = "fontOpacity";
}
}
if(symProperty) {
// Limited support for parsing of OGC expressions
var value = this.readers.ogc._expression.call(this, node);
@@ -876,24 +957,140 @@ OpenLayers.Format.SLD.v1 = OpenLayers.Class(OpenLayers.Format.Filter.v1_0_0, {
}
// add in optional Font
if(symbolizer.fontFamily != null ||
symbolizer.fontSize != null ||
symbolizer.fontWeight != null ||
symbolizer.fontStyle != null) {
this.writeNode("Font", symbolizer, node);
symbolizer.fontSize != null ||
symbolizer.fontWeight != null ||
symbolizer.fontStyle != null) {
this.writeNode("Font", symbolizer, node);
}
// add in optional LabelPlacement
if (symbolizer.labelAnchorPointX != null ||
symbolizer.labelAnchorPointY != null ||
symbolizer.labelAlign != null ||
symbolizer.labelXOffset != null ||
symbolizer.labelYOffset != null ||
symbolizer.labelRotation != null ||
symbolizer.labelPerpendicularOffset != null) {
this.writeNode("LabelPlacement", symbolizer, node);
}
// add in optional Halo
if(symbolizer.haloRadius != null ||
symbolizer.haloColor != null ||
symbolizer.haloOpacity != null) {
this.writeNode("Halo", symbolizer, node);
symbolizer.haloColor != null ||
symbolizer.haloOpacity != null) {
this.writeNode("Halo", symbolizer, node);
}
// add in optional Fill
if(symbolizer.fillColor != null ||
symbolizer.fillOpacity != null) {
this.writeNode("Fill", symbolizer, node);
if(symbolizer.fontColor != null ||
symbolizer.fontOpacity != null) {
this.writeNode("Fill", {
fillColor: symbolizer.fontColor,
fillOpacity: symbolizer.fontOpacity
}, node);
}
return node;
},
"LabelPlacement": function(symbolizer) {
var node = this.createElementNSPlus("sld:LabelPlacement");
if (symbolizer.labelAnchorPointX != null ||
symbolizer.labelAnchorPointY != null ||
symbolizer.labelAlign != null ||
symbolizer.labelXOffset != null ||
symbolizer.labelYOffset != null ||
symbolizer.labelRotation != null) {
this.writeNode("PointPlacement", symbolizer, node);
}
if (symbolizer.labelPerpendicularOffset != null) {
this.writeNode("LinePlacement", symbolizer, node);
}
return node;
},
"LinePlacement": function(symbolizer) {
var node = this.createElementNSPlus("sld:LinePlacement");
this.writeNode("PerpendicularOffset", symbolizer.labelPerpendicularOffset, node);
return node;
},
"PerpendicularOffset": function(value) {
return this.createElementNSPlus("sld:PerpendicularOffset", {
value: value
});
},
"PointPlacement": function(symbolizer) {
var node = this.createElementNSPlus("sld:PointPlacement");
if (symbolizer.labelAnchorPointX != null ||
symbolizer.labelAnchorPointY != null ||
symbolizer.labelAlign != null) {
this.writeNode("AnchorPoint", symbolizer, node);
}
if (symbolizer.labelXOffset != null ||
symbolizer.labelYOffset != null) {
this.writeNode("Displacement", symbolizer, node);
}
if (symbolizer.labelRotation != null) {
this.writeNode("Rotation", symbolizer.labelRotation, node);
}
return node;
},
"AnchorPoint": function(symbolizer) {
var node = this.createElementNSPlus("sld:AnchorPoint");
var x = symbolizer.labelAnchorPointX,
y = symbolizer.labelAnchorPointY;
if (x != null) {
this.writeNode("AnchorPointX", x, node);
}
if (y != null) {
this.writeNode("AnchorPointY", y, node);
}
if (x == null && y == null) {
var xAlign = symbolizer.labelAlign.substr(0, 1),
yAlign = symbolizer.labelAlign.substr(1, 1);
if (xAlign === "l") {
x = 0;
} else if (xAlign === "c") {
x = 0.5;
} else if (xAlign === "r") {
x = 1;
}
if (yAlign === "b") {
y = 0;
} else if (yAlign === "m") {
y = 0.5;
} else if (yAlign === "t") {
y = 1;
}
this.writeNode("AnchorPointX", x, node);
this.writeNode("AnchorPointY", y, node);
}
return node;
},
"AnchorPointX": function(value) {
return this.createElementNSPlus("sld:AnchorPointX", {
value: value
});
},
"AnchorPointY": function(value) {
return this.createElementNSPlus("sld:AnchorPointY", {
value: value
});
},
"Displacement": function(symbolizer) {
var node = this.createElementNSPlus("sld:Displacement");
if (symbolizer.labelXOffset != null) {
this.writeNode("DisplacementX", symbolizer.labelXOffset, node);
}
if (symbolizer.labelYOffset != null) {
this.writeNode("DisplacementY", symbolizer.labelYOffset, node);
}
return node;
},
"DisplacementX": function(value) {
return this.createElementNSPlus("sld:DisplacementX", {
value: value
});
},
"DisplacementY": function(value) {
return this.createElementNSPlus("sld:DisplacementY", {
value: value
});
},
"Font": function(symbolizer) {
var node = this.createElementNSPlus("sld:Font");
// add in CssParameters

View File

@@ -0,0 +1,142 @@
/* 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/Format/SLD/v1_0_0.js
*/
/**
* Class: OpenLayers.Format.SLD/v1_0_0_GeoServer
* Read and write SLD version 1.0.0 with GeoServer-specific enhanced options.
* See http://svn.osgeo.org/geotools/trunk/modules/extension/xsd/xsd-sld/src/main/resources/org/geotools/sld/bindings/StyledLayerDescriptor.xsd
* for more information.
*
* Inherits from:
* - <OpenLayers.Format.SLD.v1_0_0>
*/
OpenLayers.Format.SLD.v1_0_0_GeoServer = OpenLayers.Class(
OpenLayers.Format.SLD.v1_0_0, {
/**
* Property: version
* {String} The specific parser version.
*/
version: "1.0.0",
/**
* Property: profile
* {String} The specific profile
*/
profile: "GeoServer",
/**
* Constructor: OpenLayers.Format.SLD.v1_0_0_GeoServer
* Create a new parser for GeoServer-enhanced SLD version 1.0.0.
*
* Parameters:
* options - {Object} An optional object whose properties will be set on
* this instance.
*/
/**
* Property: readers
* Contains public functions, grouped by namespace prefix, that will
* be applied when a namespaced node is found matching the function
* name. The function will be applied in the scope of this parser
* with two arguments: the node being read and a context object passed
* from the parent.
*/
readers: OpenLayers.Util.applyDefaults({
"sld": OpenLayers.Util.applyDefaults({
"Priority": function(node, obj) {
var value = this.readers.ogc._expression.call(this, node);
if (value) {
obj.priority = value;
}
},
"VendorOption": function(node, obj) {
if (!obj.vendorOptions) {
obj.vendorOptions = [];
}
obj.vendorOptions.push({
name: node.getAttribute("name"),
value: this.getChildValue(node)
});
}
}, OpenLayers.Format.SLD.v1_0_0.prototype.readers["sld"])
}, OpenLayers.Format.SLD.v1_0_0.prototype.readers),
/**
* Property: writers
* As a compliment to the readers property, this structure contains public
* writing functions grouped by namespace alias and named like the
* node names they produce.
*/
writers: OpenLayers.Util.applyDefaults({
"sld": OpenLayers.Util.applyDefaults({
"Priority": function(priority) {
return this.writers.sld._OGCExpression.call(
this, "sld:Priority", priority
);
},
"VendorOption": function(option) {
return this.createElementNSPlus("sld:VendorOption", {
attributes: {name: option.name},
value: option.value
});
},
"TextSymbolizer": function(symbolizer) {
var writers = OpenLayers.Format.SLD.v1_0_0.prototype.writers;
var node = writers["sld"]["TextSymbolizer"].apply(this, arguments);
if (symbolizer.externalGraphic || symbolizer.graphicName) {
this.writeNode("Graphic", symbolizer, node);
}
if ("priority" in symbolizer) {
this.writeNode("Priority", symbolizer.priority, node);
}
return this.addVendorOptions(node, symbolizer);
},
"PointSymbolizer": function(symbolizer) {
var writers = OpenLayers.Format.SLD.v1_0_0.prototype.writers;
var node = writers["sld"]["PointSymbolizer"].apply(this, arguments);
return this.addVendorOptions(node, symbolizer);
},
"LineSymbolizer": function(symbolizer) {
var writers = OpenLayers.Format.SLD.v1_0_0.prototype.writers;
var node = writers["sld"]["LineSymbolizer"].apply(this, arguments);
return this.addVendorOptions(node, symbolizer);
},
"PolygonSymbolizer": function(symbolizer) {
var writers = OpenLayers.Format.SLD.v1_0_0.prototype.writers;
var node = writers["sld"]["PolygonSymbolizer"].apply(this, arguments);
return this.addVendorOptions(node, symbolizer);
}
}, OpenLayers.Format.SLD.v1_0_0.prototype.writers["sld"])
}, OpenLayers.Format.SLD.v1_0_0.prototype.writers),
/**
* Method: addVendorOptions
* Add in the VendorOption tags and return the node again.
*
* Parameters:
* node - {DOMElement} A DOM node.
* symbolizer - {Object}
*
* Returns:
* {DOMElement} A DOM node.
*/
addVendorOptions: function(node, symbolizer) {
var options = symbolizer.vendorOptions;
if (options) {
for (var i=0, ii=options.length; i<ii; ++i) {
this.writeNode("VendorOption", options[i], node);
}
}
return node;
},
CLASS_NAME: "OpenLayers.Format.SLD.v1_0_0_GeoServer"
});

View File

@@ -221,13 +221,13 @@ OpenLayers.Handler.Box = OpenLayers.Class(OpenLayers.Handler, {
document.body.removeChild(testDiv);
var left = parseInt(OpenLayers.Element.getStyle(this.zoomBox,
"border-left-width"));
"borderLeftWidth"));
var right = parseInt(OpenLayers.Element.getStyle(
this.zoomBox, "border-right-width"));
this.zoomBox, "borderRightWidth"));
var top = parseInt(OpenLayers.Element.getStyle(this.zoomBox,
"border-top-width"));
"borderTopWidth"));
var bottom = parseInt(OpenLayers.Element.getStyle(
this.zoomBox, "border-bottom-width"));
this.zoomBox, "borderBottomWidth"));
this.boxOffsets = {
left: left,
right: right,

View File

@@ -33,6 +33,13 @@ OpenLayers.Handler.Keyboard = OpenLayers.Class(OpenLayers.Handler, {
*/
eventListener: null,
/**
* Property: observeElement
* {DOMElement|String} The DOM element on which we listen for
* key events. Default to the document.
*/
observeElement: null,
/**
* Constructor: OpenLayers.Handler.Keyboard
* Returns a new keyboard handler.
@@ -71,9 +78,10 @@ OpenLayers.Handler.Keyboard = OpenLayers.Class(OpenLayers.Handler, {
*/
activate: function() {
if (OpenLayers.Handler.prototype.activate.apply(this, arguments)) {
this.observeElement = this.observeElement || document;
for (var i=0, len=this.KEY_EVENTS.length; i<len; i++) {
OpenLayers.Event.observe(
document, this.KEY_EVENTS[i], this.eventListener);
this.observeElement, this.KEY_EVENTS[i], this.eventListener);
}
return true;
} else {
@@ -89,7 +97,7 @@ OpenLayers.Handler.Keyboard = OpenLayers.Class(OpenLayers.Handler, {
if (OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) {
for (var i=0, len=this.KEY_EVENTS.length; i<len; i++) {
OpenLayers.Event.stopObserving(
document, this.KEY_EVENTS[i], this.eventListener);
this.observeElement, this.KEY_EVENTS[i], this.eventListener);
}
deactivated = true;
}

View File

@@ -1,8 +1,9 @@
/* 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.
*
* full text of the license. */
/**
* @requires OpenLayers/BaseTypes/Class.js
* @requires OpenLayers/Animation.js
*/

View File

@@ -58,6 +58,21 @@ OpenLayers.Layer = OpenLayers.Class({
alwaysInRange: null,
/**
* Constant: RESOLUTION_PROPERTIES
* {Array} The properties that are used for calculating resolutions
* information.
*/
RESOLUTION_PROPERTIES: [
'scales', 'resolutions',
'maxScale', 'minScale',
'maxResolution', 'minResolution',
'numZoomLevels', 'maxZoomLevel'
],
/**
* APIProperty: events
* {<OpenLayers.Events>}
*
* Register a listener for a particular event with the following syntax:
* (code)
* layer.events.register(type, obj, listener);
@@ -87,23 +102,6 @@ OpenLayers.Layer = OpenLayers.Class({
* will receive an object with a *map* property referencing the map and
* a *layer* property referencing the layer.
*/
/**
* Constant: RESOLUTION_PROPERTIES
* {Array} The properties that are used for calculating resolutions
* information.
*/
RESOLUTION_PROPERTIES: [
'scales', 'resolutions',
'maxScale', 'minScale',
'maxResolution', 'minResolution',
'numZoomLevels', 'maxZoomLevel'
],
/**
* APIProperty: events
* {<OpenLayers.Events>}
*/
events: null,
/**
@@ -161,13 +159,6 @@ OpenLayers.Layer = OpenLayers.Class({
*/
imageSize: null,
/**
* Property: imageOffset
* {<OpenLayers.Pixel>} For layers with a gutter, the image offset
* represents displacement due to the gutter.
*/
imageOffset: null,
// OPTIONS
/**
@@ -255,8 +246,8 @@ OpenLayers.Layer = OpenLayers.Class({
* APIProperty: maxResolution
* {Float} Default max is 360 deg / 256 px, which corresponds to
* zoom level 0 on gmaps. Specify a different value in the layer
* options if you are not using a geographic projection and
* displaying the whole world.
* options if you are not using the default <OpenLayers.Map.tileSize>
* and displaying the whole world.
*/
maxResolution: null,
@@ -361,10 +352,6 @@ OpenLayers.Layer = OpenLayers.Class({
}
}
if (this.wrapDateLine) {
this.displayOutsideMaxExtent = true;
}
},
/**
@@ -477,8 +464,18 @@ OpenLayers.Layer = OpenLayers.Class({
this.options = {};
}
// allow array for extents
if (newOptions) {
// make sure this.projection references a projection object
if(typeof newOptions.projection == "string") {
newOptions.projection = new OpenLayers.Projection(newOptions.projection);
}
if (newOptions.projection) {
// get maxResolution, units and maxExtent from projection defaults if
// they are not defined already
OpenLayers.Util.applyDefaults(newOptions,
OpenLayers.Projection.defaults[newOptions.projection.getCode()]);
}
// allow array for extents
if (newOptions.maxExtent && !(newOptions.maxExtent instanceof OpenLayers.Bounds)) {
newOptions.maxExtent = new OpenLayers.Bounds(newOptions.maxExtent);
}
@@ -492,12 +489,7 @@ OpenLayers.Layer = OpenLayers.Class({
// add new options to this
OpenLayers.Util.extend(this, newOptions);
// make sure this.projection references a projection object
if(typeof this.projection == "string") {
this.projection = new OpenLayers.Projection(this.projection);
}
// get the units from the projection, if we have a projection
// and it it has units
if(this.projection && this.projection.getUnits()) {
@@ -694,7 +686,7 @@ OpenLayers.Layer = OpenLayers.Class({
/**
* APIMethod: setTileSize
* Set the tile size based on the map size. This also sets layer.imageSize
* and layer.imageOffset for use by Tile.Image.
* or use by Tile.Image.
*
* Parameters:
* size - {<OpenLayers.Size>}
@@ -711,8 +703,6 @@ OpenLayers.Layer = OpenLayers.Class({
// this.name + ": layers with " +
// "gutters need non-null tile sizes");
//}
this.imageOffset = new OpenLayers.Pixel(-this.gutter,
-this.gutter);
this.imageSize = new OpenLayers.Size(tileSize.w + (2*this.gutter),
tileSize.h + (2*this.gutter));
}
@@ -889,6 +879,16 @@ OpenLayers.Layer = OpenLayers.Class({
props.resolutions = this.resolutionsFromScales(props.scales);
}
if(props.resolutions == null) {
var maxExtent = this.maxExtent;
if (!props.maxResolution && maxExtent) {
// maxResolution for default grid sets assumes that at zoom
// level zero, the whole world fits on one tile.
var tileSize = this.tileSize || this.map.getTileSize();
props.maxResolution = Math.max(
maxExtent.getWidth() / tileSize.w,
maxExtent.getHeight() / tileSize.h
);
}
props.resolutions = this.calculateResolutions(props);
}
}

View File

@@ -29,12 +29,6 @@ OpenLayers.Layer.ArcIMS = OpenLayers.Class(OpenLayers.Layer.Grid, {
ServiceName: ''
},
/**
* APIProperty: tileSize
* {<OpenLayers.Size>} Size for tiles. Default is 512x512.
*/
tileSize: null,
/**
* APIProperty: featureCoordSys
* {String} Code for feature coordinate system. Default is "4326".

View File

@@ -67,6 +67,13 @@ OpenLayers.Layer.Bing = OpenLayers.Class(OpenLayers.Layer.XYZ, {
*/
type: "Road",
/**
* APIProperty: culture
* {String} The culture identifier. See http://msdn.microsoft.com/en-us/library/ff701709.aspx
* for the definition and the possible values. Default is "en-US".
*/
culture: "en-US",
/**
* APIProperty: metadataParams
* {Object} Optional url parameters for the Get Imagery Metadata request
@@ -74,6 +81,16 @@ OpenLayers.Layer.Bing = OpenLayers.Class(OpenLayers.Layer.XYZ, {
*/
metadataParams: null,
/** APIProperty: tileOptions
* {Object} optional configuration options for <OpenLayers.Tile> instances
* created by this Layer. Default is
*
* (code)
* {crossOriginKeyword: 'anonymous'}
* (end)
*/
tileOptions: null,
/**
* Constructor: OpenLayers.Layer.Bing
* Create a new Bing layer.
@@ -107,6 +124,9 @@ OpenLayers.Layer.Bing = OpenLayers.Class(OpenLayers.Layer.XYZ, {
var newArgs = [name, null, options];
OpenLayers.Layer.XYZ.prototype.initialize.apply(this, newArgs);
this.tileOptions = OpenLayers.Util.extend({
crossOriginKeyword: 'anonymous'
}, this.options.tileOptions);
this.loadMetadata();
},
@@ -142,13 +162,15 @@ OpenLayers.Layer.Bing = OpenLayers.Class(OpenLayers.Layer.XYZ, {
initLayer: function() {
var res = this.metadata.resourceSets[0].resources[0];
var url = res.imageUrl.replace("{quadkey}", "${quadkey}");
url = url.replace("{culture}", this.culture);
this.url = [];
for (var i=0; i<res.imageUrlSubdomains.length; ++i) {
this.url.push(url.replace("{subdomain}", res.imageUrlSubdomains[i]));
}
this.addOptions({
maxResolution: Math.min(
this.serverResolutions[res.zoomMin], this.maxResolution
this.serverResolutions[res.zoomMin],
this.maxResolution || Number.POSITIVE_INFINITY
),
numZoomLevels: Math.min(
res.zoomMax + 1 - res.zoomMin, this.numZoomLevels

View File

@@ -11,10 +11,15 @@
/**
* Constant: OpenLayers.Layer.Google.v3
*
* Mixin providing functionality specific to the Google Maps API v3. Note that
* this layer configures the google.maps.map object with the "disableDefaultUI"
* option set to true. Using UI controls that the Google Maps API provides is
* not supported by the OpenLayers API.
* Mixin providing functionality specific to the Google Maps API v3 <= v3.6.
* Note that this layer configures the google.maps.map object with the
* "disableDefaultUI" option set to true. Using UI controls that the Google
* Maps API provides is not supported by the OpenLayers API. To use this layer,
* you must include the GMaps API (<= v3.6) in your html:
*
* (code)
* <script src="http://maps.google.com/maps/api/js?v=3.6&amp;sensor=false"></script>
* (end)
*/
OpenLayers.Layer.Google.v3 = {
@@ -25,29 +30,13 @@ OpenLayers.Layer.Google.v3 = {
*
* (code)
* {
* maxExtent: new OpenLayers.Bounds(
* -128 * 156543.03390625,
* -128 * 156543.03390625,
* 128 * 156543.03390625,
* 128 * 156543.03390625
* ),
* sphericalMercator: true,
* maxResolution: 156543.03390625,
* units: "m",
* projection: "EPSG:900913"
* }
* (end)
*/
DEFAULTS: {
maxExtent: new OpenLayers.Bounds(
-128 * 156543.03390625,
-128 * 156543.03390625,
128 * 156543.03390625,
128 * 156543.03390625
),
sphericalMercator: true,
maxResolution: 156543.03390625,
units: "m",
projection: "EPSG:900913"
},

View File

@@ -99,11 +99,12 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
/**
* APIProperty: tileLoadingDelay
* {Integer} - Number of milliseconds before we shift and load
* tiles. Default is 100.
* {Integer} Number of milliseconds before we shift and load
* tiles when panning. Ignored if <OpenLayers.Animation.isNative> is
* true. Default is 85.
*/
tileLoadingDelay: 100,
tileLoadingDelay: 85,
/**
* Property: serverResolutions
* {Array(Number}} This property is documented in subclasses as
@@ -112,11 +113,31 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
serverResolutions: null,
/**
* Property: timerId
* {Number} - The id of the tileLoadingDelay timer.
* Property: moveTimerId
* {Number} The id of the <deferMoveGriddedTiles> timer.
*/
timerId: null,
moveTimerId: null,
/**
* Property: deferMoveGriddedTiles
* {Function} A function that defers execution of <moveGriddedTiles> by
* <tileLoadingDelay>. If <OpenLayers.Animation.isNative> is true, this
* is null and unused.
*/
deferMoveGriddedTiles: null,
/**
* Property: tileQueueId
* {Number} The id of the <drawTileFromQueue> animation.
*/
tileQueueId: null,
/**
* Property: tileQueue
* {Array(<OpenLayers.Tile>)} Tiles queued for drawing.
*/
tileQueue: null,
/**
* Property: backBuffer
* {DOMElement} The back buffer.
@@ -153,6 +174,14 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
*/
backBufferTimerId: null,
/**
* APIProperty: removeBackBufferDelay
* {Number} Delay for removing the backbuffer when all tiles have finished
* loading. Can be set to 0 when no css opacity transitions for the
* olTileImage class are used. Default is 2500.
*/
removeBackBufferDelay: 2500,
/**
* Register a listener for a particular event with the following syntax:
* (code)
@@ -170,7 +199,9 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
* tileloaded - Triggered when each new tile is
* loaded, as a means of progress update to listeners.
* listeners can access 'numLoadingTiles' if they wish to keep
* track of the loading progress.
* track of the loading progress. Listeners are called with an object
* with a tile property as first argument, making the loded tile
* available to the listener.
*/
/**
@@ -187,10 +218,14 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
OpenLayers.Layer.HTTPRequest.prototype.initialize.apply(this,
arguments);
this.grid = [];
this._moveGriddedTiles = OpenLayers.Function.bind(
this.moveGriddedTiles, this
);
this.tileQueue = [];
if (!OpenLayers.Animation.isNative) {
this.deferMoveGriddedTiles = OpenLayers.Function.bind(function() {
this.moveGriddedTiles(true);
this.moveTimerId = null;
}, this);
}
},
/**
@@ -201,10 +236,11 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
* map - {<OpenLayers.Map>} The map.
*/
removeMap: function(map) {
if(this.timerId != null) {
window.clearTimeout(this.timerId);
this.timerId = null;
if (this.moveTimerId !== null) {
window.clearTimeout(this.moveTimerId);
this.moveTimerId = null;
}
this.clearTileQueue();
if(this.backBufferTimerId !== null) {
window.clearTimeout(this.backBufferTimerId);
this.backBufferTimerId = null;
@@ -230,20 +266,20 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
* destroy() on each of them to kill circular references
*/
clearGrid:function() {
this.clearTileQueue();
if (this.grid) {
for(var iRow=0, len=this.grid.length; iRow<len; iRow++) {
var row = this.grid[iRow];
for(var iCol=0, clen=row.length; iCol<clen; iCol++) {
var tile = row[iCol];
this.removeTileMonitoringHooks(tile);
tile.destroy();
this.destroyTile(tile);
}
}
this.grid = [];
this.gridResolution = null;
}
},
/**
* APIMethod: clone
* Create a clone of this layer
@@ -299,7 +335,7 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
// if grid is empty or zoom has changed, we *must* re-tile
var forceReTile = !this.grid.length || zoomChanged;
// total bounds of the tiles
var tilesBounds = this.getTilesBounds();
@@ -371,11 +407,66 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
}
this.initGriddedTiles(bounds);
} else {
this.scheduleMoveGriddedTiles();
this.moveGriddedTiles();
}
}
}
},
/**
* Method: queueTileDraw
* Adds a tile to the animation queue that will draw it.
*
* Parameters:
* evt - {Object} Listener argument of the tile's beforedraw event
*/
queueTileDraw: function(evt) {
var tile = evt.object;
if (!~OpenLayers.Util.indexOf(this.tileQueue, tile)) {
// queue only if not in queue already
this.tileQueue.push(tile);
}
if (!this.tileQueueId) {
this.tileQueueId = OpenLayers.Animation.start(
OpenLayers.Function.bind(this.drawTileFromQueue, this),
null, this.div
);
}
return false;
},
/**
* Method: drawTileFromQueue
* Draws the first tile from the tileQueue, and unqueues that tile
*/
drawTileFromQueue: function() {
if (this.tileQueue.length === 0) {
this.clearTileQueue();
} else {
this.tileQueue.shift().draw(true);
}
},
/**
* Method: clearTileQueue
* Clears the animation queue
*/
clearTileQueue: function() {
OpenLayers.Animation.stop(this.tileQueueId);
this.tileQueueId = null;
this.tileQueue = [];
},
/**
* Method: destroyTile
*
* Parameters:
* tile - {<OpenLayers.Tile>}
*/
destroyTile: function(tile) {
this.removeTileMonitoringHooks(tile);
tile.destroy();
},
/**
* Method: getServerResolution
@@ -565,24 +656,10 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
*/
moveByPx: function(dx, dy) {
if (!this.singleTile) {
this.scheduleMoveGriddedTiles();
this.moveGriddedTiles();
}
},
/**
* Method: scheduleMoveGriddedTiles
* Schedule the move of tiles.
*/
scheduleMoveGriddedTiles: function() {
if (this.timerId != null) {
window.clearTimeout(this.timerId);
}
this.timerId = window.setTimeout(
this._moveGriddedTiles,
this.tileLoadingDelay
);
},
/**
* APIMethod: setTileSize
* Check if we are in singleTile mode and if so, set the size as a ratio
@@ -633,6 +710,7 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
* bounds - {<OpenLayers.Bounds>}
*/
initSingleTile: function(bounds) {
this.clearTileQueue();
//determine new tile bounds
var center = bounds.getCenterLonLat();
@@ -744,6 +822,7 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
* bounds - {<OpenLayers.Bounds>}
*/
initGriddedTiles:function(bounds) {
this.clearTileQueue();
// work out mininum number of rows and columns; this is the number of
// tiles required to cover the viewport plus at least one for panning
@@ -776,7 +855,7 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
var layerContainerDivLeft = parseInt(this.map.layerContainerDiv.style.left);
var layerContainerDivTop = parseInt(this.map.layerContainerDiv.style.top);
var tileData = [], center = this.map.getCenter();
do {
var row = this.grid[rowidx++];
if (!row) {
@@ -810,6 +889,12 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
} else {
tile.moveTo(tileBounds, px, false);
}
var tileCenter = tileBounds.getCenterLonLat();
tileData.push({
tile: tile,
distance: Math.pow(tileCenter.lon - center.lon, 2) +
Math.pow(tileCenter.lat - center.lat, 2)
});
tileoffsetlon += tilelon;
tileoffsetx += this.tileSize.w;
@@ -828,7 +913,12 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
this.gridResolution = this.getServerResolution();
//now actually draw the tiles
this.spiralTileLoad();
tileData.sort(function(a, b) {
return a.distance - b.distance;
});
for (var i=0, ii=tileData.length; i<ii; ++i) {
tileData[i].tile.draw();
}
},
/**
@@ -843,79 +933,6 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
return this.maxExtent;
},
/**
* Method: spiralTileLoad
* Starts at the top right corner of the grid and proceeds in a spiral
* towards the center, adding tiles one at a time to the beginning of a
* queue.
*
* Once all the grid's tiles have been added to the queue, we go back
* and iterate through the queue (thus reversing the spiral order from
* outside-in to inside-out), calling draw() on each tile.
*/
spiralTileLoad: function() {
var tileQueue = [];
var directions = ["right", "down", "left", "up"];
var iRow = 0;
var iCell = -1;
var direction = OpenLayers.Util.indexOf(directions, "right");
var directionsTried = 0;
while( directionsTried < directions.length) {
var testRow = iRow;
var testCell = iCell;
switch (directions[direction]) {
case "right":
testCell++;
break;
case "down":
testRow++;
break;
case "left":
testCell--;
break;
case "up":
testRow--;
break;
}
// if the test grid coordinates are within the bounds of the
// grid, get a reference to the tile.
var tile = null;
if ((testRow < this.grid.length) && (testRow >= 0) &&
(testCell < this.grid[0].length) && (testCell >= 0)) {
tile = this.grid[testRow][testCell];
}
if ((tile != null) && (!tile.queued)) {
//add tile to beginning of queue, mark it as queued.
tileQueue.unshift(tile);
tile.queued = true;
//restart the directions counter and take on the new coords
directionsTried = 0;
iRow = testRow;
iCell = testCell;
} else {
//need to try to load a tile in a different direction
direction = (direction + 1) % 4;
directionsTried++;
}
}
// now we go through and draw the tiles in forward order
for(var i=0, len=tileQueue.length; i<len; i++) {
var tile = tileQueue[i];
tile.draw();
//mark tile as unqueued for the next time (since tiles are reused)
tile.queued = false;
}
},
/**
* APIMethod: addTile
* Create a tile, initialize it, and add it to the layer div.
@@ -928,8 +945,11 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
* {<OpenLayers.Tile>} The added OpenLayers.Tile
*/
addTile: function(bounds, position) {
return new this.tileClass(this, position, bounds, null,
this.tileSize, this.tileOptions);
var tile = new this.tileClass(
this, position, bounds, null, this.tileSize, this.tileOptions
);
tile.events.register("beforedraw", this, this.queueTileDraw);
return tile;
},
/**
@@ -953,19 +973,19 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
tile.onLoadEnd = function() {
this.numLoadingTiles--;
this.events.triggerEvent("tileloaded");
this.events.triggerEvent("tileloaded", {tile: tile});
//if that was the last tile, then trigger a 'loadend' on the layer
if (this.numLoadingTiles == 0) {
if (this.tileQueue.length === 0 && this.numLoadingTiles === 0) {
this.events.triggerEvent("loadend");
if(this.backBuffer) {
// the removal of the back buffer is delayed to prevent flash
// effects due to the animation of tile displaying
this.backBufferTimerId = window.setTimeout(
OpenLayers.Function.bind(this.removeBackBuffer, this),
2500
this.removeBackBufferDelay
);
}
}
}
};
tile.events.register("loadend", this, tile.onLoadEnd);
tile.events.register("unload", this, tile.onLoadEnd);
@@ -991,39 +1011,47 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
/**
* Method: moveGriddedTiles
*
* Parameter:
* deferred - {Boolean} true if this is a deferred call that should not
* be delayed.
*/
moveGriddedTiles: function() {
var shifted = true;
moveGriddedTiles: function(deferred) {
if (!deferred && !OpenLayers.Animation.isNative) {
if (this.moveTimerId != null) {
window.clearTimeout(this.moveTimerId);
}
this.moveTimerId = window.setTimeout(
this.deferMoveGriddedTiles, this.tileLoadingDelay
);
return;
}
var buffer = this.buffer || 1;
var scale = this.getResolutionScale();
var tlLayer = this.grid[0][0].position.clone();
tlLayer.x *= scale;
tlLayer.y *= scale;
tlLayer = tlLayer.add(parseInt(this.div.style.left, 10),
parseInt(this.div.style.top, 10));
var offsetX = parseInt(this.map.layerContainerDiv.style.left);
var offsetY = parseInt(this.map.layerContainerDiv.style.top);
var tlViewPort = tlLayer.add(offsetX, offsetY);
var tileSize = {
w: this.tileSize.w * scale,
h: this.tileSize.h * scale
};
if (tlViewPort.x > -tileSize.w * (buffer - 1)) {
this.shiftColumn(true);
} else if (tlViewPort.x < -tileSize.w * buffer) {
this.shiftColumn(false);
} else if (tlViewPort.y > -tileSize.h * (buffer - 1)) {
this.shiftRow(true);
} else if (tlViewPort.y < -tileSize.h * buffer) {
this.shiftRow(false);
} else {
shifted = false;
}
if (shifted) {
// we may have other row or columns to shift, schedule it
// with a setTimeout, to give the user a chance to sneak
// in moveTo's
this.timerId = window.setTimeout(this._moveGriddedTiles, 0);
while(true) {
var tlViewPort = {
x: (this.grid[0][0].position.x * scale) +
parseInt(this.div.style.left, 10) +
parseInt(this.map.layerContainerDiv.style.left),
y: (this.grid[0][0].position.y * scale) +
parseInt(this.div.style.top, 10) +
parseInt(this.map.layerContainerDiv.style.top)
};
var tileSize = {
w: this.tileSize.w * scale,
h: this.tileSize.h * scale
};
if (tlViewPort.x > -tileSize.w * (buffer - 1)) {
this.shiftColumn(true);
} else if (tlViewPort.x < -tileSize.w * buffer) {
this.shiftColumn(false);
} else if (tlViewPort.y > -tileSize.h * (buffer - 1)) {
this.shiftRow(true);
} else if (tlViewPort.y < -tileSize.h * buffer) {
this.shiftRow(false);
} else {
break;
}
}
},
@@ -1113,8 +1141,7 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
var row = this.grid.pop();
for (var i=0, l=row.length; i<l; i++) {
var tile = row[i];
this.removeTileMonitoringHooks(tile);
tile.destroy();
this.destroyTile(tile);
}
}
@@ -1123,8 +1150,7 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
for (var i=0, l=this.grid.length; i<l; i++) {
var row = this.grid[i];
var tile = row.pop();
this.removeTileMonitoringHooks(tile);
tile.destroy();
this.destroyTile(tile);
}
}
},

View File

@@ -27,10 +27,10 @@ OpenLayers.Layer.MapGuide = OpenLayers.Class(OpenLayers.Layer.Grid, {
/**
* APIProperty: useHttpTile
* {Boolean} use a tile cache exposed directly via a webserver rather than the
* via mapguide server. This does require extra configuration on the Mapguide Server,
* and will only work when singleTile is false. The url for the layer must be set to the
* webserver path rather than the Mapguide mapagent.
* See http://trac.osgeo.org/mapguide/wiki/CodeSamples/Tiles/ServingTilesViaHttp
* via mapguide server. This does require extra configuration on the Mapguide Server,
* and will only work when singleTile is false. The url for the layer must be set to the
* webserver path rather than the Mapguide mapagent.
* See http://trac.osgeo.org/mapguide/wiki/CodeSamples/Tiles/ServingTilesViaHttp
**/
useHttpTile: false,

View File

@@ -63,6 +63,25 @@ OpenLayers.Layer.OSM = OpenLayers.Class(OpenLayers.Layer.XYZ, {
*/
wrapDateLine: true,
/** APIProperty: tileOptions
* {Object} optional configuration options for <OpenLayers.Tile> instances
* created by this Layer. Default is
*
* (code)
* {crossOriginKeyword: 'anonymous'}
* (end)
*
* When using OSM tilesets other than the default ones, it may be
* necessary to set this to
*
* (code)
* {crossOriginKeyword: null}
* (end)
*
* if the server does not send Access-Control-Allow-Origin headers.
*/
tileOptions: null,
/**
* Constructor: OpenLayers.Layer.OSM
*
@@ -73,6 +92,12 @@ OpenLayers.Layer.OSM = OpenLayers.Class(OpenLayers.Layer.XYZ, {
* layer option can be set in this object (e.g.
* <OpenLayers.Layer.Grid.buffer>).
*/
initialize: function(name, url, options) {
OpenLayers.Layer.XYZ.prototype.initialize.apply(this, arguments);
this.tileOptions = OpenLayers.Util.extend({
crossOriginKeyword: 'anonymous'
}, this.options && this.options.tileOptions);
},
/**
* Method: clone

View File

@@ -24,6 +24,9 @@
OpenLayers.Layer.Vector = OpenLayers.Class(OpenLayers.Layer, {
/**
* APIProperty: events
* {<OpenLayers.Events>}
*
* Register a listener for a particular event with the following syntax:
* (code)
* layer.events.register(type, obj, listener);
@@ -36,7 +39,7 @@ OpenLayers.Layer.Vector = OpenLayers.Class(OpenLayers.Layer, {
* object - {Object} A reference to layer.events.object.
* element - {DOMElement} A reference to layer.events.element.
*
* Supported map event types (in addition to those from <OpenLayers.Layer>):
* Supported map event types (in addition to those from <OpenLayers.Layer.events>):
* beforefeatureadded - Triggered before a feature is added. Listeners
* will receive an object with a *feature* property referencing the
* feature to be added. To stop the feature from being added, a

View File

@@ -56,9 +56,11 @@ OpenLayers.Layer.WMS = OpenLayers.Class(OpenLayers.Layer.Grid, {
* Property: yx
* {Object} Keys in this object are EPSG codes for which the axis order
* is to be reversed (yx instead of xy, LatLon instead of LonLat), with
* true as value. This is only relevant for WMS versions >= 1.3.0.
* true as value. This is only relevant for WMS versions >= 1.3.0, and
* only if yx is not set in <OpenLayers.Projection.defaults> for the
* used projection.
*/
yx: {'EPSG:4326': true},
yx: {},
/**
* Constructor: OpenLayers.Layer.WMS
@@ -173,8 +175,9 @@ OpenLayers.Layer.WMS = OpenLayers.Class(OpenLayers.Layer.Grid, {
* {Boolean} true if the axis order is reversed, false otherwise.
*/
reverseAxisOrder: function() {
return (parseFloat(this.params.VERSION) >= 1.3 &&
!!this.yx[this.map.getProjectionObject().getCode()]);
var projCode = this.projection.getCode();
return parseFloat(this.params.VERSION) >= 1.3 &&
!!(this.yx[projCode] || OpenLayers.Projection.defaults[projCode].yx);
},
/**

View File

@@ -72,22 +72,13 @@ OpenLayers.Layer.XYZ = OpenLayers.Class(OpenLayers.Layer.Grid, {
initialize: function(name, url, options) {
if (options && options.sphericalMercator || this.sphericalMercator) {
options = OpenLayers.Util.extend({
maxExtent: new OpenLayers.Bounds(
-128 * 156543.03390625,
-128 * 156543.03390625,
128 * 156543.03390625,
128 * 156543.03390625
),
maxResolution: 156543.03390625,
numZoomLevels: 19,
units: "m",
projection: "EPSG:900913"
projection: "EPSG:900913",
numZoomLevels: 19
}, options);
}
url = url || this.url;
name = name || this.name;
var newArguments = [name, url, {}, options];
OpenLayers.Layer.Grid.prototype.initialize.apply(this, newArguments);
OpenLayers.Layer.Grid.prototype.initialize.apply(this, [
name || this.name, url || this.url, {}, options
]);
},
/**
@@ -157,10 +148,9 @@ OpenLayers.Layer.XYZ = OpenLayers.Class(OpenLayers.Layer.Grid, {
OpenLayers.Util.indexOf(resolutions, res) :
this.getServerZoom() + this.zoomOffset;
var limit = Math.pow(2, z);
if (this.wrapDateLine)
{
x = ((x % limit) + limit) % limit;
if (this.wrapDateLine) {
var limit = Math.pow(2, z);
x = ((x % limit) + limit) % limit;
}
return {'x': x, 'y': y, 'z': z};

View File

@@ -87,12 +87,11 @@ OpenLayers.Layer.Zoomify = OpenLayers.Class(OpenLayers.Layer.Grid, {
initialize: function(name, url, size, options) {
// initilize the Zoomify pyramid for given size
this.initializeZoomify( size );
this.initializeZoomify(size);
var newArguments = [];
newArguments.push(name, url, size, {}, options);
OpenLayers.Layer.Grid.prototype.initialize.apply(this, newArguments);
OpenLayers.Layer.Grid.prototype.initialize.apply(this, [
name, url, size, {}, options
]);
},
/**

View File

@@ -8,6 +8,7 @@
* @requires OpenLayers/Util.js
* @requires OpenLayers/Events.js
* @requires OpenLayers/Tween.js
* @requires OpenLayers/Projection.js
*/
/**
@@ -34,6 +35,9 @@ OpenLayers.Map = OpenLayers.Class({
},
/**
* APIProperty: events
* {<OpenLayers.Events>}
*
* Register a listener for a particular event with the following syntax:
* (code)
* map.events.register(type, obj, listener);
@@ -43,43 +47,42 @@ OpenLayers.Map = OpenLayers.Class({
* properties of this event depends on exactly what happened.
*
* All event objects have at least the following properties:
* - *object* {Object} A reference to map.events.object.
* - *element* {DOMElement} A reference to map.events.element.
* object - {Object} A reference to map.events.object.
* element - {DOMElement} A reference to map.events.element.
*
* Browser events have the following additional properties:
* - *xy* {<OpenLayers.Pixel>} The pixel location of the event (relative
* to the the map viewport).
* - other properties that come with browser events
* xy - {<OpenLayers.Pixel>} The pixel location of the event (relative
* to the the map viewport).
*
* Supported map event types:
* - *preaddlayer* triggered before a layer has been added. The event
* object will include a *layer* property that references the layer
* to be added. When a listener returns "false" the adding will be
* aborted.
* - *addlayer* triggered after a layer has been added. The event object
* will include a *layer* property that references the added layer.
* - *preremovelayer* triggered before a layer has been removed. The event
* object will include a *layer* property that references the layer
* to be removed. When a listener returns "false" the removal will be
* aborted.
* - *removelayer* triggered after a layer has been removed. The event
* object will include a *layer* property that references the removed
* layer.
* - *changelayer* triggered after a layer name change, order change,
* opacity change, params change, visibility change (due to resolution
* thresholds) or attribution change (due to extent change). Listeners
* will receive an event object with *layer* and *property* properties.
* The *layer* property will be a reference to the changed layer. The
* *property* property will be a key to the changed property (name,
* order, opacity, params, visibility or attribution).
* - *movestart* triggered after the start of a drag, pan, or zoom
* - *move* triggered after each drag, pan, or zoom
* - *moveend* triggered after a drag, pan, or zoom completes
* - *zoomend* triggered after a zoom completes
* - *mouseover* triggered after mouseover the map
* - *mouseout* triggered after mouseout the map
* - *mousemove* triggered after mousemove the map
* - *changebaselayer* triggered after the base layer changes
* preaddlayer - triggered before a layer has been added. The event
* object will include a *layer* property that references the layer
* to be added. When a listener returns "false" the adding will be
* aborted.
* addlayer - triggered after a layer has been added. The event object
* will include a *layer* property that references the added layer.
* preremovelayer - triggered before a layer has been removed. The event
* object will include a *layer* property that references the layer
* to be removed. When a listener returns "false" the removal will be
* aborted.
* removelayer - triggered after a layer has been removed. The event
* object will include a *layer* property that references the removed
* layer.
* changelayer - triggered after a layer name change, order change,
* opacity change, params change, visibility change (due to resolution
* thresholds) or attribution change (due to extent change). Listeners
* will receive an event object with *layer* and *property* properties.
* The *layer* property will be a reference to the changed layer. The
* *property* property will be a key to the changed property (name,
* order, opacity, params, visibility or attribution).
* movestart - triggered after the start of a drag, pan, or zoom
* move - triggered after each drag, pan, or zoom
* moveend - triggered after a drag, pan, or zoom completes
* zoomend - triggered after a zoom completes
* mouseover - triggered after mouseover the map
* mouseout - triggered after mouseout the map
* mousemove - triggered after mousemove the map
* changebaselayer - triggered after the base layer changes
*/
/**
@@ -248,17 +251,19 @@ OpenLayers.Map = OpenLayers.Class({
/**
* APIProperty: projection
* {String} Set in the map options to override the default projection
* string this map - also set maxExtent, maxResolution, and
* units if appropriate. Default is "EPSG:4326".
* string this map. When using a projection other than EPSG:4326
* (CRS:84, Geographic) or EPSG:3857 (EPSG:900913, Web Mercator),
* also set maxExtent and maxResolution. Default is "EPSG:4326".
*/
projection: "EPSG:4326",
/**
* APIProperty: units
* {String} The map units. Defaults to 'degrees'. Possible values are
* 'degrees' (or 'dd'), 'm', 'ft', 'km', 'mi', 'inches'.
* {String} The map units. Possible values are 'degrees' (or 'dd'), 'm',
* 'ft', 'km', 'mi', 'inches'. Only required if the projection default
* should be overridden.
*/
units: 'degrees',
units: null,
/**
* APIProperty: resolutions
@@ -271,12 +276,10 @@ OpenLayers.Map = OpenLayers.Class({
/**
* APIProperty: maxResolution
* {Float} Default max is 360 deg / 256 px, which corresponds to
* zoom level 0 on gmaps. Specify a different value in the map
* options if you are not using a geographic projection and
* displaying the whole world.
* {Float} Required if you are not displaying the whole world on a tile
* with the size specified in <tileSize>.
*/
maxResolution: 1.40625,
maxResolution: null,
/**
* APIProperty: minResolution
@@ -342,7 +345,8 @@ OpenLayers.Map = OpenLayers.Class({
/**
* APIProperty: displayProjection
* {<OpenLayers.Projection>} Requires proj4js support.Projection used by
* {<OpenLayers.Projection>} Requires proj4js support for projections other
* than EPSG:4326 or EPSG:900913/EPSG:3857. Projection used by
* several controls to display data to user. If this property is set,
* it will be set on any control which has a null displayProjection
* property at the time the control is added to the map.
@@ -471,8 +475,6 @@ OpenLayers.Map = OpenLayers.Class({
this.tileSize = new OpenLayers.Size(OpenLayers.Map.TILE_WIDTH,
OpenLayers.Map.TILE_HEIGHT);
this.maxExtent = new OpenLayers.Bounds(-180, -90, 180, 90);
this.paddingForPopups = new OpenLayers.Bounds(15, 15, 15, 15);
this.theme = OpenLayers._getScriptLocation() +
@@ -481,6 +483,10 @@ OpenLayers.Map = OpenLayers.Class({
// now override default options
OpenLayers.Util.extend(this, options);
var projCode = this.projection instanceof OpenLayers.Projection ?
this.projection.projCode : this.projection;
OpenLayers.Util.applyDefaults(this, OpenLayers.Projection.defaults[projCode]);
// allow extents to be arrays
if (this.maxExtent && !(this.maxExtent instanceof OpenLayers.Bounds)) {
this.maxExtent = new OpenLayers.Bounds(this.maxExtent);
@@ -571,14 +577,20 @@ OpenLayers.Map = OpenLayers.Class({
}
if (this.controls == null) {
this.controls = [];
if (OpenLayers.Control != null) { // running full or lite?
this.controls = [ new OpenLayers.Control.Navigation(),
new OpenLayers.Control.PanZoom(),
new OpenLayers.Control.ArgParser(),
new OpenLayers.Control.Attribution()
];
} else {
this.controls = [];
if (OpenLayers.Control.Navigation) {
this.controls.push(new OpenLayers.Control.Navigation())
}
if (OpenLayers.Control.PanZoom) {
this.controls.push(new OpenLayers.Control.PanZoom())
}
if (OpenLayers.Control.ArgParser) {
this.controls.push(new OpenLayers.Control.ArgParser())
}
if (OpenLayers.Control.Attribution) {
this.controls.push(new OpenLayers.Control.Attribution())
}
}
}

View File

@@ -845,10 +845,10 @@ OpenLayers.Popup = OpenLayers.Class({
//read the padding settings from css, put them in an OL.Bounds
contentDivPadding = new OpenLayers.Bounds(
OpenLayers.Element.getStyle(this.contentDiv, "padding-left"),
OpenLayers.Element.getStyle(this.contentDiv, "padding-bottom"),
OpenLayers.Element.getStyle(this.contentDiv, "padding-right"),
OpenLayers.Element.getStyle(this.contentDiv, "padding-top")
OpenLayers.Element.getStyle(this.contentDiv, "paddingLeft"),
OpenLayers.Element.getStyle(this.contentDiv, "paddingBottom"),
OpenLayers.Element.getStyle(this.contentDiv, "paddingRight"),
OpenLayers.Element.getStyle(this.contentDiv, "paddingTop")
);
//cache the value

View File

@@ -142,7 +142,7 @@ OpenLayers.Projection = OpenLayers.Class({
/**
* Property: transforms
* Transforms is an object, with from properties, each of which may
* {Object} Transforms is an object, with from properties, each of which may
* have a to property. This allows you to define projections without
* requiring support for proj4js to be included.
*
@@ -162,6 +162,30 @@ OpenLayers.Projection = OpenLayers.Class({
*/
OpenLayers.Projection.transforms = {};
/**
* APIProperty: defaults
* {Object} Defaults for the SRS codes known to OpenLayers (currently
* EPSG:4326, CRS:84, urn:ogc:def:crs:EPSG:6.6:4326, EPSG:900913, EPSG:3857,
* EPSG:102113 and EPSG:102100). Keys are the SRS code, values are units,
* maxExtent (the validity extent for the SRS) and yx (true if this SRS is
* known to have a reverse axis order).
*/
OpenLayers.Projection.defaults = {
"EPSG:4326": {
units: "degrees",
maxExtent: [-180, -90, 180, 90],
yx: true
},
"CRS:84": {
units: "degrees",
maxExtent: [-180, -90, 180, 90]
},
"EPSG:900913": {
units: "m",
maxExtent: [-20037508.34, -20037508.34, 20037508.34, 20037508.34]
}
};
/**
* APIMethod: addTransform
* Set a custom transform method between two projections. Use this method in
@@ -176,6 +200,12 @@ OpenLayers.Projection.transforms = {};
* in place. The original point should be modified.
*/
OpenLayers.Projection.addTransform = function(from, to, method) {
if (method === OpenLayers.Projection.nullTransform) {
var defaults = OpenLayers.Projection.defaults[from];
if (defaults && !OpenLayers.Projection.defaults[to]) {
OpenLayers.Projection.defaults[to] = defaults;
}
}
if(!OpenLayers.Projection.transforms[from]) {
OpenLayers.Projection.transforms[from] = {};
}
@@ -235,12 +265,15 @@ OpenLayers.Projection.nullTransform = function(point) {
};
/**
* Note: Transforms for web mercator <-> EPSG:4326
* Note: Transforms for web mercator <-> geographic
* OpenLayers recognizes EPSG:3857, EPSG:900913, EPSG:102113 and EPSG:102100.
* OpenLayers originally started referring to EPSG:900913 as web mercator.
* The EPSG has declared EPSG:3857 to be web mercator.
* ArcGIS 10 recognizes the EPSG:3857, EPSG:102113, and EPSG:102100 as
* equivalent. See http://blogs.esri.com/Dev/blogs/arcgisserver/archive/2009/11/20/ArcGIS-Online-moving-to-Google-_2F00_-Bing-tiling-scheme_3A00_-What-does-this-mean-for-you_3F00_.aspx#12084
* equivalent. See http://blogs.esri.com/Dev/blogs/arcgisserver/archive/2009/11/20/ArcGIS-Online-moving-to-Google-_2F00_-Bing-tiling-scheme_3A00_-What-does-this-mean-for-you_3F00_.aspx#12084.
* For geographic, OpenLayers recognizes EPSG:4326, CRS:84 and
* urn:ogc:def:crs:EPSG:6.6:4326. OpenLayers also knows about the reverse axis
* order for EPSG:4326.
*/
(function() {
@@ -258,22 +291,31 @@ OpenLayers.Projection.nullTransform = function(point) {
return xy;
}
// list of equivalent codes for web mercator
var codes = ["EPSG:900913", "EPSG:3857", "EPSG:102113", "EPSG:102100"];
var add = OpenLayers.Projection.addTransform;
var same = OpenLayers.Projection.nullTransform;
var i, len, code, other, j;
for (i=0, len=codes.length; i<len; ++i) {
code = codes[i];
add("EPSG:4326", code, forwardMercator);
add(code, "EPSG:4326", inverseMercator);
for (j=i+1; j<len; ++j) {
other = codes[j];
add(code, other, same);
add(other, code, same);
function map(base, codes) {
var add = OpenLayers.Projection.addTransform;
var same = OpenLayers.Projection.nullTransform;
var i, len, code, other, j;
for (i=0, len=codes.length; i<len; ++i) {
code = codes[i];
add(base, code, forwardMercator);
add(code, base, inverseMercator);
for (j=i+1; j<len; ++j) {
other = codes[j];
add(code, other, same);
add(other, code, same);
}
}
}
// list of equivalent codes for web mercator
var mercator = ["EPSG:900913", "EPSG:3857", "EPSG:102113", "EPSG:102100"],
geographic = ["CRS:84", "urn:ogc:def:crs:EPSG:6.6:4326", "EPSG:4326"],
i;
for (i=mercator.length-1; i>=0; --i) {
map(mercator[i], geographic);
}
for (i=geographic.length-1; i>=0; --i) {
map(geographic[i], mercator);
}
})();

View File

@@ -62,12 +62,27 @@ OpenLayers.Protocol.HTTP = OpenLayers.Class(OpenLayers.Protocol, {
scope: null,
/**
* Property: readWithPOST
* APIProperty: readWithPOST
* {Boolean} true if read operations are done with POST requests
* instead of GET, defaults to false.
*/
readWithPOST: false,
/**
* APIProperty: updateWithPOST
* {Boolean} true if update operations are done with POST requests
* defaults to false.
*/
updateWithPOST: false,
/**
* APIProperty: deleteWithPOST
* {Boolean} true if delete operations are done with POST requests
* defaults to false.
* if true, POST data is set to output of format.write().
*/
deleteWithPOST: false,
/**
* Property: wildcarded.
* {Boolean} If true percent signs are added around values
@@ -293,7 +308,8 @@ OpenLayers.Protocol.HTTP = OpenLayers.Class(OpenLayers.Protocol, {
requestType: "update"
});
resp.priv = OpenLayers.Request.PUT({
var method = this.updateWithPOST ? "POST" : "PUT";
resp.priv = OpenLayers.Request[method]({
url: url,
callback: this.createCallback(this.handleUpdate, resp, options),
headers: options.headers,
@@ -344,11 +360,16 @@ OpenLayers.Protocol.HTTP = OpenLayers.Class(OpenLayers.Protocol, {
requestType: "delete"
});
resp.priv = OpenLayers.Request.DELETE({
var method = this.deleteWithPOST ? "POST" : "DELETE";
var requestOptions = {
url: url,
callback: this.createCallback(this.handleDelete, resp, options),
headers: options.headers
});
};
if (this.deleteWithPOST) {
requestOptions.data = this.format.write(feature);
}
resp.priv = OpenLayers.Request[method](requestOptions);
return resp;
},

View File

@@ -415,3 +415,18 @@ OpenLayers.Renderer.defaultSymbolizer = {
labelAlign: 'cm'
};
/**
* Constant: OpenLayers.Renderer.symbol
* Coordinate arrays for well known (named) symbols.
*/
OpenLayers.Renderer.symbol = {
"star": [350,75, 379,161, 469,161, 397,215, 423,301, 350,250, 277,301,
303,215, 231,161, 321,161, 350,75],
"cross": [4,0, 6,0, 6,4, 10,4, 10,6, 6,6, 6,10, 4,10, 4,6, 0,6, 0,4, 4,4,
4,0],
"x": [0,0, 25,0, 50,35, 75,0, 100,0, 65,50, 100,100, 75,100, 50,65, 25,100, 0,100, 35,50, 0,0],
"square": [0,0, 0,1, 1,1, 1,0, 0,0],
"triangle": [0,10, 10,10, 5,0, 0,10]
};

View File

@@ -51,6 +51,12 @@ OpenLayers.Renderer.Canvas = OpenLayers.Class(OpenLayers.Renderer, {
*/
pendingRedraw: false,
/**
* Property: cachedSymbolBounds
* {Object} Internal cache of calculated symbol extents.
*/
cachedSymbolBounds: {},
/**
* Constructor: OpenLayers.Renderer.Canvas
*
@@ -110,8 +116,7 @@ OpenLayers.Renderer.Canvas = OpenLayers.Class(OpenLayers.Renderer, {
* {Boolean} Whether or not the browser supports the renderer class
*/
supported: function() {
var canvas = document.createElement("canvas");
return !!canvas.getContext;
return OpenLayers.CANVAS_SUPPORTED;
},
/**
@@ -284,6 +289,151 @@ OpenLayers.Renderer.Canvas = OpenLayers.Class(OpenLayers.Renderer, {
img.src = style.externalGraphic;
},
/**
* Method: drawNamedSymbol
* Called to draw Well Known Graphic Symbol Name.
* This method is only called by the renderer itself.
*
* Parameters:
* geometry - {<OpenLayers.Geometry>}
* style - {Object}
* featureId - {String}
*/
drawNamedSymbol: function(geometry, style, featureId) {
var x, y, cx, cy, i, symbolBounds, scaling, angle;
var unscaledStrokeWidth;
var deg2rad = Math.PI / 180.0;
var symbol = OpenLayers.Renderer.symbol[style.graphicName];
if (!symbol) {
throw new Error(style.graphicName + ' is not a valid symbol name');
}
if (!symbol.length || symbol.length < 2) return;
var pt = this.getLocalXY(geometry);
var p0 = pt[0];
var p1 = pt[1];
if (isNaN(p0) || isNaN(p1)) return;
// Use rounded line caps
this.canvas.lineCap = "round";
this.canvas.lineJoin = "round";
// Scale and rotate symbols, using precalculated bounds whenever possible.
if (style.graphicName in this.cachedSymbolBounds) {
symbolBounds = this.cachedSymbolBounds[style.graphicName];
} else {
symbolBounds = new OpenLayers.Bounds();
for(i = 0; i < symbol.length; i+=2) {
symbolBounds.extend(new OpenLayers.LonLat(symbol[i], symbol[i+1]));
}
this.cachedSymbolBounds[style.graphicName] = symbolBounds;
}
// Push symbol scaling, translation and rotation onto the transformation stack in reverse order.
// Don't forget to apply all canvas transformations to the hitContext canvas as well(!)
this.canvas.save();
if (this.hitDetection) { this.hitContext.save(); }
// Step 3: place symbol at the desired location
this.canvas.translate(p0,p1);
if (this.hitDetection) { this.hitContext.translate(p0,p1); }
// Step 2a. rotate the symbol if necessary
angle = deg2rad * style.rotation; // will be NaN when style.rotation is undefined.
if (!isNaN(angle)) {
this.canvas.rotate(angle);
if (this.hitDetection) { this.hitContext.rotate(angle); }
}
// // Step 2: scale symbol such that pointRadius equals half the maximum symbol dimension.
scaling = 2.0 * style.pointRadius / Math.max(symbolBounds.getWidth(), symbolBounds.getHeight());
this.canvas.scale(scaling,scaling);
if (this.hitDetection) { this.hitContext.scale(scaling,scaling); }
// Step 1: center the symbol at the origin
cx = symbolBounds.getCenterLonLat().lon;
cy = symbolBounds.getCenterLonLat().lat;
this.canvas.translate(-cx,-cy);
if (this.hitDetection) { this.hitContext.translate(-cx,-cy); }
// Don't forget to scale stroke widths, because they are affected by canvas scale transformations as well(!)
// Alternative: scale symbol coordinates manually, so stroke width scaling is not needed anymore.
unscaledStrokeWidth = style.strokeWidth;
style.strokeWidth = unscaledStrokeWidth / scaling;
if (style.fill !== false) {
this.setCanvasStyle("fill", style);
this.canvas.beginPath();
for (i=0; i<symbol.length; i=i+2) {
x = symbol[i];
y = symbol[i+1];
if (i == 0) this.canvas.moveTo(x,y);
this.canvas.lineTo(x,y);
}
this.canvas.closePath();
this.canvas.fill();
if (this.hitDetection) {
this.setHitContextStyle("fill", featureId, style);
this.hitContext.beginPath();
for (i=0; i<symbol.length; i=i+2) {
x = symbol[i];
y = symbol[i+1];
if (i == 0) this.canvas.moveTo(x,y);
this.hitContext.lineTo(x,y);
}
this.hitContext.closePath();
this.hitContext.fill();
}
}
if (style.stroke !== false) {
this.setCanvasStyle("stroke", style);
this.canvas.beginPath();
for (i=0; i<symbol.length; i=i+2) {
x = symbol[i];
y = symbol[i+1];
if (i == 0) this.canvas.moveTo(x,y);
this.canvas.lineTo(x,y);
}
this.canvas.closePath();
this.canvas.stroke();
}
style.strokeWidth = unscaledStrokeWidth;
this.canvas.restore();
if (this.hitDetection) { this.hitContext.restore(); }
this.setCanvasStyle("reset");
},
/**
* Method: setCanvasStyle
* Prepare the canvas for drawing by setting various global settings.
*
* Parameters:
* type - {String} one of 'stroke', 'fill', or 'reset'
* style - {Object} Symbolizer hash
*/
setCanvasStyle: function(type, style) {
if (type === "fill") {
this.canvas.globalAlpha = style['fillOpacity'];
this.canvas.fillStyle = style['fillColor'];
} else if (type === "stroke") {
this.canvas.globalAlpha = style['strokeOpacity'];
this.canvas.strokeStyle = style['strokeColor'];
this.canvas.lineWidth = style['strokeWidth'];
} else {
this.canvas.globalAlpha = 0;
this.canvas.lineWidth = 1;
}
},
/**
* Method: setCanvasStyle
* Prepare the canvas for drawing by setting various global settings.
@@ -366,6 +516,8 @@ OpenLayers.Renderer.Canvas = OpenLayers.Class(OpenLayers.Renderer, {
if(style.graphic !== false) {
if(style.externalGraphic) {
this.drawExternalGraphic(geometry, style, featureId);
} else if (style.graphicName && (style.graphicName != "circle")) {
this.drawNamedSymbol(geometry, style, featureId);
} else {
var pt = this.getLocalXY(geometry);
var p0 = pt[0];
@@ -634,8 +786,9 @@ OpenLayers.Renderer.Canvas = OpenLayers.Class(OpenLayers.Renderer, {
* layer.
*/
getFeatureIdFromEvent: function(evt) {
var feature;
if (this.hitDetection) {
var featureId, feature;
if (this.hitDetection && this.root.style.display !== "none") {
// this dragging check should go in the feature handler
if (!this.map.dragging) {
var xy = evt.xy;
@@ -645,7 +798,14 @@ OpenLayers.Renderer.Canvas = OpenLayers.Class(OpenLayers.Renderer, {
if (data[3] === 255) { // antialiased
var id = data[2] + (256 * (data[1] + (256 * data[0])));
if (id) {
feature = this.features["OpenLayers.Feature.Vector_" + (id - 1 + this.hitOverflow)][0];
featureId = "OpenLayers.Feature.Vector_" + (id - 1 + this.hitOverflow);
try {
feature = this.features[featureId][0];
} catch(err) {
// Because of antialiasing on the canvas, when the hit location is at a point where the edge of
// one symbol intersects the interior of another symbol, a wrong hit color (and therefore id) results.
// todo: set Antialiasing = 'off' on the hitContext as soon as browsers allow it.
}
}
}
}

View File

@@ -1051,17 +1051,3 @@ OpenLayers.Renderer.Elements = OpenLayers.Class(OpenLayers.Renderer, {
CLASS_NAME: "OpenLayers.Renderer.Elements"
});
/**
* Constant: OpenLayers.Renderer.symbol
* Coordinate arrays for well known (named) symbols.
*/
OpenLayers.Renderer.symbol = {
"star": [350,75, 379,161, 469,161, 397,215, 423,301, 350,250, 277,301,
303,215, 231,161, 321,161, 350,75],
"cross": [4,0, 6,0, 6,4, 10,4, 10,6, 6,6, 6,10, 4,10, 4,6, 0,6, 0,4, 4,4,
4,0],
"x": [0,0, 25,0, 50,35, 75,0, 100,0, 65,50, 100,100, 75,100, 50,65, 25,100, 0,100, 35,50, 0,0],
"square": [0,0, 0,1, 1,1, 1,0, 0,0],
"triangle": [0,10, 10,10, 5,0, 0,10]
};

View File

@@ -0,0 +1,63 @@
/* 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. */
/**
* Namespace: Spherical
* The OpenLayers.Spherical namespace includes utility functions for
* calculations on the basis of a spherical earth (ignoring ellipsoidal
* effects), which is accurate enough for most purposes.
*
* Relevant links:
* * http://www.movable-type.co.uk/scripts/latlong.html
* * http://code.google.com/apis/maps/documentation/javascript/reference.html#spherical
*/
OpenLayers.Spherical = OpenLayers.Spherical || {};
OpenLayers.Spherical.DEFAULT_RADIUS = 6378137;
/**
* APIFunction: computeDistanceBetween
* Computes the distance between two LonLats.
*
* Parameters:
* from - {<OpenLayers.LonLat>} or {Object} Starting point. A LonLat or
* a JavaScript literal with lon lat properties.
* to - {<OpenLayers.LonLat>} or {Object} Ending point. A LonLat or a
* JavaScript literal with lon lat properties.
* radius - {Float} The radius. Optional. Defaults to 6378137 meters.
*
* Returns:
* {Float} The distance in meters.
*/
OpenLayers.Spherical.computeDistanceBetween = function(from, to, radius) {
var R = radius || OpenLayers.Spherical.DEFAULT_RADIUS;
var sinHalfDeltaLon = Math.sin(Math.PI * (to.lon - from.lon) / 360);
var sinHalfDeltaLat = Math.sin(Math.PI * (to.lat - from.lat) / 360);
var a = sinHalfDeltaLat * sinHalfDeltaLat +
sinHalfDeltaLon * sinHalfDeltaLon * Math.cos(Math.PI * from.lat / 180) * Math.cos(Math.PI * to.lat / 180);
return 2 * R * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
};
/**
* APIFunction: computeHeading
* Computes the heading from one LonLat to another LonLat.
*
* Parameters:
* from - {<OpenLayers.LonLat>} or {Object} Starting point. A LonLat or
* a JavaScript literal with lon lat properties.
* to - {<OpenLayers.LonLat>} or {Object} Ending point. A LonLat or a
* JavaScript literal with lon lat properties.
*
* Returns:
* {Float} The heading in degrees.
*/
OpenLayers.Spherical.computeHeading = function(from, to) {
var y = Math.sin(Math.PI * (from.lon - to.lon) / 180) * Math.cos(Math.PI * to.lat / 180);
var x = Math.cos(Math.PI * from.lat / 180) * Math.sin(Math.PI * to.lat / 180) -
Math.sin(Math.PI * from.lat / 180) * Math.cos(Math.PI * to.lat / 180) * Math.cos(Math.PI * (from.lon - to.lon) / 180);
return 180 * Math.atan2(y, x) / Math.PI;
};

View File

@@ -124,9 +124,12 @@ OpenLayers.Strategy.BBOX = OpenLayers.Class(OpenLayers.Strategy, {
* Callback function called on "moveend" or "refresh" layer events.
*
* Parameters:
* options - {Object} An object with a property named "force", this
* property references a boolean value indicating if new data
* must be incondtionally read.
* options - {Object} Optional object whose properties will determine
* the behaviour of this Strategy
*
* Valid options include:
* force - {Boolean} if true, new data must be unconditionally read.
* noAbort - {Boolean} if true, do not abort previous requests.
*/
update: function(options) {
var mapBounds = this.getMapBounds();
@@ -218,7 +221,7 @@ OpenLayers.Strategy.BBOX = OpenLayers.Class(OpenLayers.Strategy, {
* returned by the layer protocol.
*/
triggerRead: function(options) {
if (this.response) {
if (this.response && !(options && options.noAbort === true)) {
this.layer.protocol.abort(this.response);
this.layer.events.triggerEvent("loadend");
}

View File

@@ -20,16 +20,20 @@
OpenLayers.Strategy.Save = OpenLayers.Class(OpenLayers.Strategy, {
/**
* APIProperty: events
* {<OpenLayers.Events>} An events object that handles all
* events on the strategy object.
*
* Register a listener for a particular event with the following syntax:
* (code)
* strategy.events.register(type, obj, listener);
* (end)
*
* Supported event types:
* - *start* Triggered before saving
* - *success* Triggered after a successful transaction
* - *fail* Triggered after a failed transaction
*
* start - Triggered before saving
* success - Triggered after a successful transaction
* fail - Triggered after a failed transaction
*
*/
/**

View File

@@ -23,18 +23,25 @@
*/
OpenLayers.Tile = OpenLayers.Class({
/**
* Supported event types:
* - *loadstart* Triggered when tile loading starts.
* - *loadend* Triggered when tile loading ends.
* - *reload* Triggered when an already loading tile is reloaded.
* - *unload* Triggered before a tile is unloaded.
*/
/**
* APIProperty: events
* {<OpenLayers.Events>} An events object that handles all
* events on the tile.
* events on the tile.
*
* Register a listener for a particular event with the following syntax:
* (code)
* tile.events.register(type, obj, listener);
* (end)
*
* Supported event types:
* beforedraw - Triggered before the tile is drawn. Used to defer
* drawing to an animation queue. To defer drawing, listeners need
* to return false, which will abort drawing. The queue handler needs
* to call <draw>(true) to actually draw the tile.
* loadstart - Triggered when tile loading starts.
* loadend - Triggered when tile loading ends.
* reload - Triggered when an already loading tile is reloaded.
* unload - Triggered before a tile is unloaded.
*/
events: null,
@@ -107,7 +114,7 @@ OpenLayers.Tile = OpenLayers.Class({
* {Boolean} Is the tile loading?
*/
isLoading: false,
/** TBD 3.0 -- remove 'url' from the list of parameters to the constructor.
* there is no need for the base tile class to have a url.
*
@@ -180,15 +187,26 @@ OpenLayers.Tile = OpenLayers.Class({
* it should actually be re-drawn. This is an example implementation
* that can be overridden by subclasses. The minimum thing to do here
* is to call <clear> and return the result from <shouldDraw>.
*
* Parameters:
* deferred - {Boolean} When drawing was aborted by returning false from a
* *beforedraw* listener, the queue manager needs to pass true, so the
* tile will not be cleared and immediately be drawn. Otherwise, the
* tile will be cleared and a *beforedraw* event will be fired.
*
* Returns:
* {Boolean} Whether or not the tile should actually be drawn.
*/
draw: function() {
//clear tile's contents and mark as not drawn
this.clear();
return this.shouldDraw();
draw: function(deferred) {
if (!deferred) {
//clear tile's contents and mark as not drawn
this.clear();
}
var draw = this.shouldDraw();
if (draw && !deferred) {
draw = this.events.triggerEvent("beforedraw") !== false;
}
return draw;
},
/**
@@ -259,10 +277,10 @@ OpenLayers.Tile = OpenLayers.Class({
/**
* Method: clear
* Clear the tile of any bounds/position-related data so that it can
* be reused in a new location. To be implemented by subclasses.
* be reused in a new location.
*/
clear: function(draw) {
// to be implemented by subclasses
// to be extended by subclasses
},
CLASS_NAME: "OpenLayers.Tile"

View File

@@ -6,6 +6,7 @@
/**
* @requires OpenLayers/Tile.js
* @requires OpenLayers/Animation.js
*/
/**
@@ -81,6 +82,23 @@ OpenLayers.Tile.Image = OpenLayers.Class(OpenLayers.Tile, {
*/
maxGetUrlLength: null,
/**
* Property: canvasContext
* {CanvasRenderingContext2D} A canvas context associated with
* the tile image.
*/
canvasContext: null,
/**
* APIProperty: crossOriginKeyword
* The value of the crossorigin keyword to use when loading images. This is
* only relevant when using <getCanvasContext> for tiles from remote
* origins and should be set to either 'anonymous' or 'use-credentials'
* for servers that send Access-Control-Allow-Origin headers with their
* tiles.
*/
crossOriginKeyword: null,
/** TBD 3.0 - reorder the parameters to the init function to remove
* URL. the getUrl() function on the layer gets called on
* each draw(), so no need to specify it here.
@@ -190,11 +208,12 @@ OpenLayers.Tile.Image = OpenLayers.Class(OpenLayers.Tile, {
* code.
*/
positionTile: function() {
var style = this.getTile().style;
var style = this.getTile().style,
size = this.layer.getImageSize(this.bounds);
style.left = this.position.x + "%";
style.top = this.position.y + "%";
style.width = this.size.w + "%";
style.height = this.size.h + "%";
style.width = size.w + "%";
style.height = size.h + "%";
},
/**
@@ -203,6 +222,7 @@ OpenLayers.Tile.Image = OpenLayers.Class(OpenLayers.Tile, {
* it can be reused in a new location.
*/
clear: function() {
OpenLayers.Tile.prototype.clear.apply(this, arguments);
var img = this.imgDiv;
if (img) {
OpenLayers.Event.stopObservingElement(img);
@@ -216,6 +236,7 @@ OpenLayers.Tile.Image = OpenLayers.Class(OpenLayers.Tile, {
}
OpenLayers.Element.removeClass(img, "olImageLoadError");
}
this.canvasContext = null;
},
/**
@@ -236,11 +257,6 @@ OpenLayers.Tile.Image = OpenLayers.Class(OpenLayers.Tile, {
var top = this.layer.gutter / this.layer.tileSize.h * 100;
style.left = -left + "%";
style.top = -top + "%";
style.width = (2 * left + 100) + "%";
style.height = (2 * top + 100) + "%";
} else {
style.width = "100%";
style.height = "100%";
}
style.visibility = "hidden";
style.opacity = 0;
@@ -297,6 +313,9 @@ OpenLayers.Tile.Image = OpenLayers.Class(OpenLayers.Tile, {
} else {
OpenLayers.Event.observe(img, "load", load);
OpenLayers.Event.observe(img, "error", load);
if (img.crossOrigin) {
img.crossOrigin = null;
}
img.src = this.blankImageUrl;
}
}
@@ -314,6 +333,10 @@ OpenLayers.Tile.Image = OpenLayers.Class(OpenLayers.Tile, {
img.style.visibility = 'hidden';
img.style.opacity = 0;
if (url) {
// don't set crossOrigin if the url is a data URL
if (this.crossOriginKeyword && url.substr(0, 5 !== 'data:')) {
img.crossOrigin = this.crossOriginKeyword;
}
img.src = url;
}
},
@@ -366,6 +389,7 @@ OpenLayers.Tile.Image = OpenLayers.Class(OpenLayers.Tile, {
img.style.opacity = this.layer.opacity;
this.isLoading = false;
this.canvasContext = null;
this.events.triggerEvent("loadend");
// IE<7 needs a reflow when the tiles are loaded because of the
@@ -406,6 +430,38 @@ OpenLayers.Tile.Image = OpenLayers.Class(OpenLayers.Tile, {
}
},
/**
* APIMethod: getCanvasContext
* Returns a canvas context associated with the tile image (with
* the image drawn on it).
* Returns undefined if the browser does not support canvas, if
* the tile has no image or if it's currently loading.
*
* The function returns a canvas context instance but the
* underlying canvas is still available in the 'canvas' property:
* (code)
* var context = tile.getCanvasContext();
* if (context) {
* var data = context.canvas.toDataURL('image/jpeg');
* }
* (end)
*
* Returns:
* {Boolean}
*/
getCanvasContext: function() {
if (OpenLayers.CANVAS_SUPPORTED && this.imgDiv && !this.isLoading) {
if (!this.canvasContext) {
var canvas = document.createElement("canvas");
canvas.width = this.size.w;
canvas.height = this.size.h;
this.canvasContext = canvas.getContext("2d");
this.canvasContext.drawImage(this.imgDiv, 0, 0);
}
return this.canvasContext;
}
},
CLASS_NAME: "OpenLayers.Tile.Image"
});

View File

@@ -65,7 +65,11 @@ OpenLayers.Tile.Image.IFrame = {
// And if we had an iframe we also remove the event pane.
if(fromIFrame) {
this.blankImageUrl = this._blankImageUrl;
this.frame.removeChild(this.frame.firstChild);
} else {
this._blankImageUrl = this.blankImageUrl;
this.blankImageUrl = "about:blank";
}
}
}
@@ -85,7 +89,7 @@ OpenLayers.Tile.Image.IFrame = {
style.width = "100%";
style.height = "100%";
style.zIndex = 1;
style.backgroundImage = "url(" + this.blankImageUrl + ")";
style.backgroundImage = "url(" + this._blankImageUrl + ")";
this.frame.appendChild(eventPane);
}
@@ -133,7 +137,7 @@ OpenLayers.Tile.Image.IFrame = {
return OpenLayers.Tile.Image.prototype.getImage.apply(this, arguments);
}
},
/**
* Method: createRequestForm
* Create the html <form> element with width, height, bbox and all

View File

@@ -1,8 +1,9 @@
/* 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.
*
* full text of the license. */
/**
* @requires OpenLayers/BaseTypes/Class.js
* @requires OpenLayers/Animation.js
*/

View File

@@ -1435,6 +1435,15 @@ OpenLayers.IS_GECKO = (function() {
return ua.indexOf("webkit") == -1 && ua.indexOf("gecko") != -1;
})();
/**
* Constant: CANVAS_SUPPORTED
* {Boolean} True if canvas 2d is supported.
*/
OpenLayers.CANVAS_SUPPORTED = (function() {
var elem = document.createElement('canvas');
return !!(elem.getContext && elem.getContext('2d'));
})();
/**
* Constant: BROWSER_NAME
* {String}