/**
|
* @requires OpenLayers/BaseTypes/Class.js
|
* @requires OpenLayers/Util.js
|
* @requires OpenLayers/Control.js
|
* @requires OpenLayers/Format.js
|
* @requires OpenLayers/Request.js
|
* @requires OpenLayers/Layer/WMS.js
|
* @requires OpenLayers/Layer/MapServer.js
|
* @requires OpenLayers/Tile.js
|
* @requires OpenLayers/Request/XMLHttpRequest.js
|
* @requires OpenLayers/Layer/Vector.js
|
* @requires OpenLayers/Layer/Markers.js
|
* @requires OpenLayers/Console.js
|
* @requires OpenLayers/Lang.js
|
* @requires OpenLayers/Feature.js
|
* @requires OpenLayers/Layer/EventPane.js
|
* @requires OpenLayers/Layer/FixedZoomLevels.js
|
* @requires OpenLayers/Layer/SphericalMercator.js
|
* @requires OpenLayers/Protocol.js
|
* @requires OpenLayers/Format/JSON.js
|
* @requires OpenLayers/Format/WKT.js
|
* @requires OpenLayers/Format/XML.js
|
* @requires OpenLayers/Geometry.js
|
* @requires OpenLayers/Renderer/Elements.js
|
* @requires OpenLayers/Popup/Anchored.js
|
* @requires Rico/Corner.js
|
*/
|
|
/**
|
* About: Deprecated
|
* The deprecated.js script includes all methods, properties, and constructors
|
* that are not supported as part of the long-term API. If you use any of
|
* these, you have to explicitly include this script in your application.
|
*
|
* For example:
|
* (code)
|
* <script src="deprecated.js" type="text/javascript"></script>
|
* (end)
|
*
|
* You are strongly encouraged to avoid using deprecated functionality. The
|
* documentation here should point you to the supported alternatives.
|
*/
|
|
/**
|
* Namespace: OpenLayers.Class
|
*/
|
|
/**
|
* Property: isPrototype
|
* *Deprecated*. This is no longer needed and will be removed at 3.0.
|
*/
|
OpenLayers.Class.isPrototype = function () {};
|
|
/**
|
* APIFunction: OpenLayers.create
|
* *Deprecated*. Old method to create an OpenLayers style class. Use the
|
* <OpenLayers.Class> constructor instead.
|
*
|
* Returns:
|
* An OpenLayers class
|
*/
|
OpenLayers.Class.create = function() {
|
return function() {
|
if (arguments && arguments[0] != OpenLayers.Class.isPrototype) {
|
this.initialize.apply(this, arguments);
|
}
|
};
|
};
|
|
/**
|
* APIFunction: inherit
|
* *Deprecated*. Old method to inherit from one or more OpenLayers style
|
* classes. Use the <OpenLayers.Class> constructor instead.
|
*
|
* Parameters:
|
* class - One or more classes can be provided as arguments
|
*
|
* Returns:
|
* An object prototype
|
*/
|
OpenLayers.Class.inherit = function (P) {
|
var C = function() {
|
P.call(this);
|
};
|
var newArgs = [C].concat(Array.prototype.slice.call(arguments));
|
OpenLayers.inherit.apply(null, newArgs);
|
return C.prototype;
|
};
|
|
/**
|
* Namespace: OpenLayers.Util
|
*/
|
|
/**
|
* Function: clearArray
|
* *Deprecated*. This function will disappear in 3.0.
|
* Please use "array.length = 0" instead.
|
*
|
* Parameters:
|
* array - {Array}
|
*/
|
OpenLayers.Util.clearArray = function(array) {
|
OpenLayers.Console.warn(
|
OpenLayers.i18n(
|
"methodDeprecated", {'newMethod': 'array = []'}
|
)
|
);
|
array.length = 0;
|
};
|
|
/**
|
* Function: setOpacity
|
* *Deprecated*. This function has been deprecated. Instead, please use
|
* <OpenLayers.Util.modifyDOMElement>
|
* or
|
* <OpenLayers.Util.modifyAlphaImageDiv>
|
*
|
* Set the opacity of a DOM Element
|
* Note that for this function to work in IE, elements must "have layout"
|
* according to:
|
* http://msdn.microsoft.com/workshop/author/dhtml/reference/properties/haslayout.asp
|
*
|
* Parameters:
|
* element - {DOMElement} Set the opacity on this DOM element
|
* opacity - {Float} Opacity value (0.0 - 1.0)
|
*/
|
OpenLayers.Util.setOpacity = function(element, opacity) {
|
OpenLayers.Util.modifyDOMElement(element, null, null, null,
|
null, null, null, opacity);
|
};
|
|
/**
|
* Function: safeStopPropagation
|
* *Deprecated*. This function has been deprecated. Please use directly
|
* <OpenLayers.Event.stop> passing 'true' as the 2nd
|
* argument (preventDefault)
|
*
|
* Safely stop the propagation of an event *without* preventing
|
* the default browser action from occurring.
|
*
|
* Parameters:
|
* evt - {Event}
|
*/
|
OpenLayers.Util.safeStopPropagation = function(evt) {
|
OpenLayers.Event.stop(evt, true);
|
};
|
|
/**
|
* Function: getArgs
|
* *Deprecated*. Will be removed in 3.0. Please use instead
|
* <OpenLayers.Util.getParameters>
|
*
|
* Parameters:
|
* url - {String} Optional url used to extract the query string.
|
* If null, query string is taken from page location.
|
*
|
* Returns:
|
* {Object} An object of key/value pairs from the query string.
|
*/
|
OpenLayers.Util.getArgs = function(url) {
|
OpenLayers.Console.warn(
|
OpenLayers.i18n(
|
"methodDeprecated", {'newMethod': 'OpenLayers.Util.getParameters'}
|
)
|
);
|
return OpenLayers.Util.getParameters(url);
|
};
|
|
/**
|
* Maintain existing definition of $.
|
*
|
* The use of our $-method is deprecated and the mapping of
|
* OpenLayers.Util.getElement will eventually be removed. Do not depend on
|
* window.$ being defined by OpenLayers.
|
*/
|
if(typeof window.$ === "undefined") {
|
window.$ = OpenLayers.Util.getElement;
|
}
|
|
/**
|
* Namespace: OpenLayers.Ajax
|
*/
|
|
/**
|
* Function: OpenLayers.nullHandler
|
* @param {} request
|
*/
|
OpenLayers.nullHandler = function(request) {
|
OpenLayers.Console.userError(OpenLayers.i18n("unhandledRequest", {'statusText':request.statusText}));
|
};
|
|
/**
|
* APIFunction: OpenLayers.loadURL
|
* Background load a document.
|
* *Deprecated*. Use <OpenLayers.Request.GET> method instead.
|
*
|
* Parameters:
|
* uri - {String} URI of source doc
|
* params - {String} or {Object} GET params. Either a string in the form
|
* "?hello=world&foo=bar" (do not forget the leading question mark)
|
* or an object in the form {'hello': 'world', 'foo': 'bar}
|
* caller - {Object} object which gets callbacks
|
* onComplete - {Function} Optional callback for success. The callback
|
* will be called with this set to caller and will receive the request
|
* object as an argument. Note that if you do not specify an onComplete
|
* function, <OpenLayers.nullHandler> will be called (which pops up a
|
* user friendly error message dialog).
|
* onFailure - {Function} Optional callback for failure. In the event of
|
* a failure, the callback will be called with this set to caller and will
|
* receive the request object as an argument. Note that if you do not
|
* specify an onComplete function, <OpenLayers.nullHandler> will be called
|
* (which pops up a user friendly error message dialog).
|
*
|
* Returns:
|
* {<OpenLayers.Request.XMLHttpRequest>} The request object. To abort loading,
|
* call request.abort().
|
*/
|
OpenLayers.loadURL = function(uri, params, caller,
|
onComplete, onFailure) {
|
|
if(typeof params == 'string') {
|
params = OpenLayers.Util.getParameters(params);
|
}
|
var success = (onComplete) ? onComplete : OpenLayers.nullHandler;
|
var failure = (onFailure) ? onFailure : OpenLayers.nullHandler;
|
|
return OpenLayers.Request.GET({
|
url: uri, params: params,
|
success: success, failure: failure, scope: caller
|
});
|
};
|
|
/**
|
* Function: OpenLayers.parseXMLString
|
* Parse XML into a doc structure
|
*
|
* Parameters:
|
* text - {String}
|
*
|
* Returns:
|
* {?} Parsed AJAX Responsev
|
*/
|
OpenLayers.parseXMLString = function(text) {
|
|
//MS sucks, if the server is bad it dies
|
var index = text.indexOf('<');
|
if (index > 0) {
|
text = text.substring(index);
|
}
|
|
var ajaxResponse = OpenLayers.Util.Try(
|
function() {
|
var xmldom = new ActiveXObject('Microsoft.XMLDOM');
|
xmldom.loadXML(text);
|
return xmldom;
|
},
|
function() {
|
return new DOMParser().parseFromString(text, 'text/xml');
|
},
|
function() {
|
var req = new XMLHttpRequest();
|
req.open("GET", "data:" + "text/xml" +
|
";charset=utf-8," + encodeURIComponent(text), false);
|
if (req.overrideMimeType) {
|
req.overrideMimeType("text/xml");
|
}
|
req.send(null);
|
return req.responseXML;
|
}
|
);
|
|
return ajaxResponse;
|
};
|
|
OpenLayers.Ajax = {
|
|
/**
|
* Method: emptyFunction
|
*/
|
emptyFunction: function () {},
|
|
/**
|
* Method: getTransport
|
*
|
* Returns:
|
* {Object} Transport mechanism for whichever browser we're in, or false if
|
* none available.
|
*/
|
getTransport: function() {
|
return OpenLayers.Util.Try(
|
function() {return new XMLHttpRequest();},
|
function() {return new ActiveXObject('Msxml2.XMLHTTP');},
|
function() {return new ActiveXObject('Microsoft.XMLHTTP');}
|
) || false;
|
},
|
|
/**
|
* Property: activeRequestCount
|
* {Integer}
|
*/
|
activeRequestCount: 0
|
};
|
|
/**
|
* Namespace: OpenLayers.Ajax.Responders
|
* {Object}
|
*/
|
OpenLayers.Ajax.Responders = {
|
|
/**
|
* Property: responders
|
* {Array}
|
*/
|
responders: [],
|
|
/**
|
* Method: register
|
*
|
* Parameters:
|
* responderToAdd - {?}
|
*/
|
register: function(responderToAdd) {
|
for (var i = 0; i < this.responders.length; i++){
|
if (responderToAdd == this.responders[i]){
|
return;
|
}
|
}
|
this.responders.push(responderToAdd);
|
},
|
|
/**
|
* Method: unregister
|
*
|
* Parameters:
|
* responderToRemove - {?}
|
*/
|
unregister: function(responderToRemove) {
|
OpenLayers.Util.removeItem(this.reponders, responderToRemove);
|
},
|
|
/**
|
* Method: dispatch
|
*
|
* Parameters:
|
* callback - {?}
|
* request - {?}
|
* transport - {?}
|
*/
|
dispatch: function(callback, request, transport) {
|
var responder;
|
for (var i = 0; i < this.responders.length; i++) {
|
responder = this.responders[i];
|
|
if (responder[callback] &&
|
typeof responder[callback] == 'function') {
|
try {
|
responder[callback].apply(responder,
|
[request, transport]);
|
} catch (e) {}
|
}
|
}
|
}
|
};
|
|
OpenLayers.Ajax.Responders.register({
|
/**
|
* Function: onCreate
|
*/
|
onCreate: function() {
|
OpenLayers.Ajax.activeRequestCount++;
|
},
|
|
/**
|
* Function: onComplete
|
*/
|
onComplete: function() {
|
OpenLayers.Ajax.activeRequestCount--;
|
}
|
});
|
|
/**
|
* Class: OpenLayers.Ajax.Base
|
*/
|
OpenLayers.Ajax.Base = OpenLayers.Class({
|
|
/**
|
* Constructor: OpenLayers.Ajax.Base
|
*
|
* Parameters:
|
* options - {Object}
|
*/
|
initialize: function(options) {
|
this.options = {
|
method: 'post',
|
asynchronous: true,
|
contentType: 'application/xml',
|
parameters: ''
|
};
|
OpenLayers.Util.extend(this.options, options || {});
|
|
this.options.method = this.options.method.toLowerCase();
|
|
if (typeof this.options.parameters == 'string') {
|
this.options.parameters =
|
OpenLayers.Util.getParameters(this.options.parameters);
|
}
|
}
|
});
|
|
/**
|
* Class: OpenLayers.Ajax.Request
|
* *Deprecated*. Use <OpenLayers.Request> method instead.
|
*
|
* Inherit:
|
* - <OpenLayers.Ajax.Base>
|
*/
|
OpenLayers.Ajax.Request = OpenLayers.Class(OpenLayers.Ajax.Base, {
|
|
/**
|
* Property: _complete
|
*
|
* {Boolean}
|
*/
|
_complete: false,
|
|
/**
|
* Constructor: OpenLayers.Ajax.Request
|
*
|
* Parameters:
|
* url - {String}
|
* options - {Object}
|
*/
|
initialize: function(url, options) {
|
OpenLayers.Ajax.Base.prototype.initialize.apply(this, [options]);
|
|
if (OpenLayers.ProxyHost && OpenLayers.String.startsWith(url, "http")) {
|
url = OpenLayers.ProxyHost + encodeURIComponent(url);
|
}
|
|
this.transport = OpenLayers.Ajax.getTransport();
|
this.request(url);
|
},
|
|
/**
|
* Method: request
|
*
|
* Parameters:
|
* url - {String}
|
*/
|
request: function(url) {
|
this.url = url;
|
this.method = this.options.method;
|
var params = OpenLayers.Util.extend({}, this.options.parameters);
|
|
if (this.method != 'get' && this.method != 'post') {
|
// simulate other verbs over post
|
params['_method'] = this.method;
|
this.method = 'post';
|
}
|
|
this.parameters = params;
|
|
if (params = OpenLayers.Util.getParameterString(params)) {
|
// when GET, append parameters to URL
|
if (this.method == 'get') {
|
this.url += ((this.url.indexOf('?') > -1) ? '&' : '?') + params;
|
} else if (/Konqueror|Safari|KHTML/.test(navigator.userAgent)) {
|
params += '&_=';
|
}
|
}
|
try {
|
var response = new OpenLayers.Ajax.Response(this);
|
if (this.options.onCreate) {
|
this.options.onCreate(response);
|
}
|
|
OpenLayers.Ajax.Responders.dispatch('onCreate',
|
this,
|
response);
|
|
this.transport.open(this.method.toUpperCase(),
|
this.url,
|
this.options.asynchronous);
|
|
if (this.options.asynchronous) {
|
window.setTimeout(
|
OpenLayers.Function.bind(this.respondToReadyState, this, 1),
|
10);
|
}
|
|
this.transport.onreadystatechange =
|
OpenLayers.Function.bind(this.onStateChange, this);
|
this.setRequestHeaders();
|
|
this.body = this.method == 'post' ?
|
(this.options.postBody || params) : null;
|
this.transport.send(this.body);
|
|
// Force Firefox to handle ready state 4 for synchronous requests
|
if (!this.options.asynchronous &&
|
this.transport.overrideMimeType) {
|
this.onStateChange();
|
}
|
} catch (e) {
|
this.dispatchException(e);
|
}
|
},
|
|
/**
|
* Method: onStateChange
|
*/
|
onStateChange: function() {
|
var readyState = this.transport.readyState;
|
if (readyState > 1 && !((readyState == 4) && this._complete)) {
|
this.respondToReadyState(this.transport.readyState);
|
}
|
},
|
|
/**
|
* Method: setRequestHeaders
|
*/
|
setRequestHeaders: function() {
|
var headers = {
|
'X-Requested-With': 'XMLHttpRequest',
|
'Accept': 'text/javascript, text/html, application/xml, text/xml, */*',
|
'OpenLayers': true
|
};
|
|
if (this.method == 'post') {
|
headers['Content-type'] = this.options.contentType +
|
(this.options.encoding ? '; charset=' + this.options.encoding : '');
|
|
/* Force "Connection: close" for older Mozilla browsers to work
|
* around a bug where XMLHttpRequest sends an incorrect
|
* Content-length header. See Mozilla Bugzilla #246651.
|
*/
|
if (this.transport.overrideMimeType &&
|
(navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005) {
|
headers['Connection'] = 'close';
|
}
|
}
|
// user-defined headers
|
if (typeof this.options.requestHeaders == 'object') {
|
var extras = this.options.requestHeaders;
|
|
if (typeof extras.push == 'function') {
|
for (var i = 0, length = extras.length; i < length; i += 2) {
|
headers[extras[i]] = extras[i+1];
|
}
|
} else {
|
for (var i in extras) {
|
headers[i] = extras[i];
|
}
|
}
|
}
|
|
for (var name in headers) {
|
this.transport.setRequestHeader(name, headers[name]);
|
}
|
},
|
|
/**
|
* Method: success
|
*
|
* Returns:
|
* {Boolean} -
|
*/
|
success: function() {
|
var status = this.getStatus();
|
return !status || (status >=200 && status < 300);
|
},
|
|
/**
|
* Method: getStatus
|
*
|
* Returns:
|
* {Integer} - Status
|
*/
|
getStatus: function() {
|
try {
|
return this.transport.status || 0;
|
} catch (e) {
|
return 0;
|
}
|
},
|
|
/**
|
* Method: respondToReadyState
|
*
|
* Parameters:
|
* readyState - {?}
|
*/
|
respondToReadyState: function(readyState) {
|
var state = OpenLayers.Ajax.Request.Events[readyState];
|
var response = new OpenLayers.Ajax.Response(this);
|
|
if (state == 'Complete') {
|
try {
|
this._complete = true;
|
(this.options['on' + response.status] ||
|
this.options['on' + (this.success() ? 'Success' : 'Failure')] ||
|
OpenLayers.Ajax.emptyFunction)(response);
|
} catch (e) {
|
this.dispatchException(e);
|
}
|
|
var contentType = response.getHeader('Content-type');
|
}
|
|
try {
|
(this.options['on' + state] ||
|
OpenLayers.Ajax.emptyFunction)(response);
|
OpenLayers.Ajax.Responders.dispatch('on' + state,
|
this,
|
response);
|
} catch (e) {
|
this.dispatchException(e);
|
}
|
|
if (state == 'Complete') {
|
// avoid memory leak in MSIE: clean up
|
this.transport.onreadystatechange = OpenLayers.Ajax.emptyFunction;
|
}
|
},
|
|
/**
|
* Method: getHeader
|
*
|
* Parameters:
|
* name - {String} Header name
|
*
|
* Returns:
|
* {?} - response header for the given name
|
*/
|
getHeader: function(name) {
|
try {
|
return this.transport.getResponseHeader(name);
|
} catch (e) {
|
return null;
|
}
|
},
|
|
/**
|
* Method: dispatchException
|
* If the optional onException function is set, execute it
|
* and then dispatch the call to any other listener registered
|
* for onException.
|
*
|
* If no optional onException function is set, we suspect that
|
* the user may have also not used
|
* OpenLayers.Ajax.Responders.register to register a listener
|
* for the onException call. To make sure that something
|
* gets done with this exception, only dispatch the call if there
|
* are listeners.
|
*
|
* If you explicitly want to swallow exceptions, set
|
* request.options.onException to an empty function (function(){})
|
* or register an empty function with <OpenLayers.Ajax.Responders>
|
* for onException.
|
*
|
* Parameters:
|
* exception - {?}
|
*/
|
dispatchException: function(exception) {
|
var handler = this.options.onException;
|
if(handler) {
|
// call options.onException and alert any other listeners
|
handler(this, exception);
|
OpenLayers.Ajax.Responders.dispatch('onException', this, exception);
|
} else {
|
// check if there are any other listeners
|
var listener = false;
|
var responders = OpenLayers.Ajax.Responders.responders;
|
for (var i = 0; i < responders.length; i++) {
|
if(responders[i].onException) {
|
listener = true;
|
break;
|
}
|
}
|
if(listener) {
|
// call all listeners
|
OpenLayers.Ajax.Responders.dispatch('onException', this, exception);
|
} else {
|
// let the exception through
|
throw exception;
|
}
|
}
|
}
|
});
|
|
/**
|
* Property: Events
|
* {Array(String)}
|
*/
|
OpenLayers.Ajax.Request.Events =
|
['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];
|
|
/**
|
* Class: OpenLayers.Ajax.Response
|
*/
|
OpenLayers.Ajax.Response = OpenLayers.Class({
|
|
/**
|
* Property: status
|
*
|
* {Integer}
|
*/
|
status: 0,
|
|
|
/**
|
* Property: statusText
|
*
|
* {String}
|
*/
|
statusText: '',
|
|
/**
|
* Constructor: OpenLayers.Ajax.Response
|
*
|
* Parameters:
|
* request - {Object}
|
*/
|
initialize: function(request) {
|
this.request = request;
|
var transport = this.transport = request.transport,
|
readyState = this.readyState = transport.readyState;
|
|
if ((readyState > 2 &&
|
!(!!(window.attachEvent && !window.opera))) ||
|
readyState == 4) {
|
this.status = this.getStatus();
|
this.statusText = this.getStatusText();
|
this.responseText = transport.responseText == null ?
|
'' : String(transport.responseText);
|
}
|
|
if(readyState == 4) {
|
var xml = transport.responseXML;
|
this.responseXML = xml === undefined ? null : xml;
|
}
|
},
|
|
/**
|
* Method: getStatus
|
*/
|
getStatus: OpenLayers.Ajax.Request.prototype.getStatus,
|
|
/**
|
* Method: getStatustext
|
*
|
* Returns:
|
* {String} - statusText
|
*/
|
getStatusText: function() {
|
try {
|
return this.transport.statusText || '';
|
} catch (e) {
|
return '';
|
}
|
},
|
|
/**
|
* Method: getHeader
|
*/
|
getHeader: OpenLayers.Ajax.Request.prototype.getHeader,
|
|
/**
|
* Method: getResponseHeader
|
*
|
* Returns:
|
* {?} - response header for given name
|
*/
|
getResponseHeader: function(name) {
|
return this.transport.getResponseHeader(name);
|
}
|
});
|
|
|
/**
|
* Function: getElementsByTagNameNS
|
*
|
* Parameters:
|
* parentnode - {?}
|
* nsuri - {?}
|
* nsprefix - {?}
|
* tagname - {?}
|
*
|
* Returns:
|
* {?}
|
*/
|
OpenLayers.Ajax.getElementsByTagNameNS = function(parentnode, nsuri,
|
nsprefix, tagname) {
|
var elem = null;
|
if (parentnode.getElementsByTagNameNS) {
|
elem = parentnode.getElementsByTagNameNS(nsuri, tagname);
|
} else {
|
elem = parentnode.getElementsByTagName(nsprefix + ':' + tagname);
|
}
|
return elem;
|
};
|
|
|
/**
|
* Function: serializeXMLToString
|
* Wrapper function around XMLSerializer, which doesn't exist/work in
|
* IE/Safari. We need to come up with a way to serialize in those browser:
|
* for now, these browsers will just fail. #535, #536
|
*
|
* Parameters:
|
* xmldom {XMLNode} xml dom to serialize
|
*
|
* Returns:
|
* {?}
|
*/
|
OpenLayers.Ajax.serializeXMLToString = function(xmldom) {
|
var serializer = new XMLSerializer();
|
var data = serializer.serializeToString(xmldom);
|
return data;
|
};
|
|
/**
|
* Namespace: OpenLayers.Element
|
*/
|
OpenLayers.Util.extend(OpenLayers.Element, {
|
|
/**
|
* APIFunction: hide
|
* *Deprecated*. Hide element(s) passed in
|
*
|
* Parameters:
|
* element - {DOMElement} Actually user can pass any number of elements
|
*/
|
hide: function() {
|
OpenLayers.Console.warn(OpenLayers.i18n("methodDeprecated", {
|
newMethod: "element.style.display = 'none';"
|
}));
|
|
for (var i=0, len=arguments.length; i<len; i++) {
|
var element = OpenLayers.Util.getElement(arguments[i]);
|
if (element) {
|
element.style.display = 'none';
|
}
|
}
|
},
|
|
/**
|
* APIFunction: show
|
* *Deprecated*. Show element(s) passed in
|
*
|
* Parameters:
|
* element - {DOMElement} Actually user can pass any number of elements
|
*/
|
show: function() {
|
OpenLayers.Console.warn(OpenLayers.i18n("methodDeprecated", {
|
newMethod: "element.style.display = '';"
|
}));
|
|
for (var i=0, len=arguments.length; i<len; i++) {
|
var element = OpenLayers.Util.getElement(arguments[i]);
|
if (element) {
|
element.style.display = '';
|
}
|
}
|
},
|
|
/**
|
* APIFunction: getDimensions
|
* *Deprecated*. Returns dimensions of the element passed in.
|
*
|
* Parameters:
|
* element - {DOMElement}
|
*
|
* Returns:
|
* {Object} Object with 'width' and 'height' properties which are the
|
* dimensions of the element passed in.
|
*/
|
getDimensions: function(element) {
|
element = OpenLayers.Util.getElement(element);
|
if (OpenLayers.Element.getStyle(element, 'display') != 'none') {
|
return {width: element.offsetWidth, height: element.offsetHeight};
|
}
|
|
// All *Width and *Height properties give 0 on elements with display none,
|
// so enable the element temporarily
|
var els = element.style;
|
var originalVisibility = els.visibility;
|
var originalPosition = els.position;
|
var originalDisplay = els.display;
|
els.visibility = 'hidden';
|
els.position = 'absolute';
|
els.display = '';
|
var originalWidth = element.clientWidth;
|
var originalHeight = element.clientHeight;
|
els.display = originalDisplay;
|
els.position = originalPosition;
|
els.visibility = originalVisibility;
|
return {width: originalWidth, height: originalHeight};
|
}
|
|
});
|
|
if (!String.prototype.startsWith) {
|
/**
|
* APIMethod: String.startsWith
|
* *Deprecated*. Whether or not a string starts with another string.
|
*
|
* Parameters:
|
* sStart - {String} The string we're testing for.
|
*
|
* Returns:
|
* {Boolean} Whether or not this string starts with the string passed in.
|
*/
|
String.prototype.startsWith = function(sStart) {
|
OpenLayers.Console.warn(OpenLayers.i18n("methodDeprecated",
|
{'newMethod':'OpenLayers.String.startsWith'}));
|
return OpenLayers.String.startsWith(this, sStart);
|
};
|
}
|
|
if (!String.prototype.contains) {
|
/**
|
* APIMethod: String.contains
|
* *Deprecated*. Whether or not a string contains another string.
|
*
|
* Parameters:
|
* str - {String} The string that we're testing for.
|
*
|
* Returns:
|
* {Boolean} Whether or not this string contains with the string passed in.
|
*/
|
String.prototype.contains = function(str) {
|
OpenLayers.Console.warn(OpenLayers.i18n("methodDeprecated",
|
{'newMethod':'OpenLayers.String.contains'}));
|
return OpenLayers.String.contains(this, str);
|
};
|
}
|
|
if (!String.prototype.trim) {
|
/**
|
* APIMethod: String.trim
|
* *Deprecated*. Removes leading and trailing whitespace characters from a string.
|
*
|
* Returns:
|
* {String} A trimmed version of the string - all leading and
|
* trailing spaces removed
|
*/
|
String.prototype.trim = function() {
|
OpenLayers.Console.warn(OpenLayers.i18n("methodDeprecated",
|
{'newMethod':'OpenLayers.String.trim'}));
|
return OpenLayers.String.trim(this);
|
};
|
}
|
|
if (!String.prototype.camelize) {
|
/**
|
* APIMethod: String.camelize
|
* *Deprecated*. Camel-case a hyphenated string.
|
* Ex. "chicken-head" becomes "chickenHead", and
|
* "-chicken-head" becomes "ChickenHead".
|
*
|
* Returns:
|
* {String} The string, camelized
|
*/
|
String.prototype.camelize = function() {
|
OpenLayers.Console.warn(OpenLayers.i18n("methodDeprecated",
|
{'newMethod':'OpenLayers.String.camelize'}));
|
return OpenLayers.String.camelize(this);
|
};
|
}
|
|
if (!Function.prototype.bind) {
|
/**
|
* APIMethod: Function.bind
|
* *Deprecated*. Bind a function to an object.
|
* Method to easily create closures with 'this' altered.
|
*
|
* Parameters:
|
* object - {Object} the this parameter
|
*
|
* Returns:
|
* {Function} A closure with 'this' altered to the first
|
* argument.
|
*/
|
Function.prototype.bind = function() {
|
OpenLayers.Console.warn(OpenLayers.i18n("methodDeprecated",
|
{'newMethod':'OpenLayers.Function.bind'}));
|
// new function takes the same arguments with this function up front
|
Array.prototype.unshift.apply(arguments, [this]);
|
return OpenLayers.Function.bind.apply(null, arguments);
|
};
|
}
|
|
if (!Function.prototype.bindAsEventListener) {
|
/**
|
* APIMethod: Function.bindAsEventListener
|
* *Deprecated*. Bind a function to an object, and configure it to receive the
|
* event object as first parameter when called.
|
*
|
* Parameters:
|
* object - {Object} A reference to this.
|
*
|
* Returns:
|
* {Function}
|
*/
|
Function.prototype.bindAsEventListener = function(object) {
|
OpenLayers.Console.warn(OpenLayers.i18n("methodDeprecated",
|
{'newMethod':'OpenLayers.Function.bindAsEventListener'}));
|
return OpenLayers.Function.bindAsEventListener(this, object);
|
};
|
}
|
|
// FIXME: Remove this in 3.0. In 3.0, Event.stop will no longer be provided
|
// by OpenLayers.
|
if (window.Event) {
|
OpenLayers.Util.applyDefaults(window.Event, OpenLayers.Event);
|
} else {
|
var Event = OpenLayers.Event;
|
}
|
|
/**
|
* Namespace: OpenLayers.Tile
|
*/
|
OpenLayers.Util.extend(OpenLayers.Tile.prototype, {
|
/**
|
* Method: getBoundsFromBaseLayer
|
* Take the pixel locations of the corner of the tile, and pass them to
|
* the base layer and ask for the location of those pixels, so that
|
* displaying tiles over Google works fine.
|
*
|
* Parameters:
|
* position - {<OpenLayers.Pixel>}
|
*
|
* Returns:
|
* bounds - {<OpenLayers.Bounds>}
|
*/
|
getBoundsFromBaseLayer: function(position) {
|
var msg = OpenLayers.i18n('reprojectDeprecated',
|
{'layerName':this.layer.name});
|
OpenLayers.Console.warn(msg);
|
var topLeft = this.layer.map.getLonLatFromLayerPx(position);
|
var bottomRightPx = position.clone();
|
bottomRightPx.x += this.size.w;
|
bottomRightPx.y += this.size.h;
|
var bottomRight = this.layer.map.getLonLatFromLayerPx(bottomRightPx);
|
// Handle the case where the base layer wraps around the date line.
|
// Google does this, and it breaks WMS servers to request bounds in
|
// that fashion.
|
if (topLeft.lon > bottomRight.lon) {
|
if (topLeft.lon < 0) {
|
topLeft.lon = -180 - (topLeft.lon+180);
|
} else {
|
bottomRight.lon = 180+bottomRight.lon+180;
|
}
|
}
|
var bounds = new OpenLayers.Bounds(topLeft.lon,
|
bottomRight.lat,
|
bottomRight.lon,
|
topLeft.lat);
|
return bounds;
|
}
|
});
|
|
/**
|
* Class: OpenLayers.Control.MouseDefaults
|
* This class is DEPRECATED in 2.4 and will be removed by 3.0.
|
* If you need this functionality, use <OpenLayers.Control.Navigation>
|
* instead!!!
|
*
|
* Inherits from:
|
* - <OpenLayers.Control>
|
*/
|
OpenLayers.Control.MouseDefaults = OpenLayers.Class(OpenLayers.Control, {
|
|
/** WARNING WARNING WARNING!!!
|
This class is DEPRECATED in 2.4 and will be removed by 3.0.
|
If you need this functionality, use Control.Navigation instead!!! */
|
|
/**
|
* Property: performedDrag
|
* {Boolean}
|
*/
|
performedDrag: false,
|
|
/**
|
* Property: wheelObserver
|
* {Function}
|
*/
|
wheelObserver: null,
|
|
/**
|
* Constructor: OpenLayers.Control.MouseDefaults
|
*/
|
initialize: function() {
|
OpenLayers.Control.prototype.initialize.apply(this, arguments);
|
},
|
|
/**
|
* APIMethod: destroy
|
*/
|
destroy: function() {
|
|
if (this.handler) {
|
this.handler.destroy();
|
}
|
this.handler = null;
|
|
this.map.events.un({
|
"click": this.defaultClick,
|
"dblclick": this.defaultDblClick,
|
"mousedown": this.defaultMouseDown,
|
"mouseup": this.defaultMouseUp,
|
"mousemove": this.defaultMouseMove,
|
"mouseout": this.defaultMouseOut,
|
scope: this
|
});
|
|
//unregister mousewheel events specifically on the window and document
|
OpenLayers.Event.stopObserving(window, "DOMMouseScroll",
|
this.wheelObserver);
|
OpenLayers.Event.stopObserving(window, "mousewheel",
|
this.wheelObserver);
|
OpenLayers.Event.stopObserving(document, "mousewheel",
|
this.wheelObserver);
|
this.wheelObserver = null;
|
|
OpenLayers.Control.prototype.destroy.apply(this, arguments);
|
},
|
|
/**
|
* Method: draw
|
*/
|
draw: function() {
|
this.map.events.on({
|
"click": this.defaultClick,
|
"dblclick": this.defaultDblClick,
|
"mousedown": this.defaultMouseDown,
|
"mouseup": this.defaultMouseUp,
|
"mousemove": this.defaultMouseMove,
|
"mouseout": this.defaultMouseOut,
|
scope: this
|
});
|
|
this.registerWheelEvents();
|
|
},
|
|
/**
|
* Method: registerWheelEvents
|
*/
|
registerWheelEvents: function() {
|
|
this.wheelObserver = OpenLayers.Function.bindAsEventListener(
|
this.onWheelEvent, this
|
);
|
|
//register mousewheel events specifically on the window and document
|
OpenLayers.Event.observe(window, "DOMMouseScroll", this.wheelObserver);
|
OpenLayers.Event.observe(window, "mousewheel", this.wheelObserver);
|
OpenLayers.Event.observe(document, "mousewheel", this.wheelObserver);
|
},
|
|
/**
|
* Method: defaultClick
|
*
|
* Parameters:
|
* evt - {Event}
|
*
|
* Returns:
|
* {Boolean}
|
*/
|
defaultClick: function (evt) {
|
if (!OpenLayers.Event.isLeftClick(evt)) {
|
return;
|
}
|
var notAfterDrag = !this.performedDrag;
|
this.performedDrag = false;
|
return notAfterDrag;
|
},
|
|
/**
|
* Method: defaultDblClick
|
*
|
* Parameters:
|
* evt - {Event}
|
*/
|
defaultDblClick: function (evt) {
|
var newCenter = this.map.getLonLatFromViewPortPx( evt.xy );
|
this.map.setCenter(newCenter, this.map.zoom + 1);
|
OpenLayers.Event.stop(evt);
|
return false;
|
},
|
|
/**
|
* Method: defaultMouseDown
|
*
|
* Parameters:
|
* evt - {Event}
|
*/
|
defaultMouseDown: function (evt) {
|
if (!OpenLayers.Event.isLeftClick(evt)) {
|
return;
|
}
|
this.mouseDragStart = evt.xy.clone();
|
this.performedDrag = false;
|
if (evt.shiftKey) {
|
this.map.div.style.cursor = "crosshair";
|
this.zoomBox = OpenLayers.Util.createDiv('zoomBox',
|
this.mouseDragStart,
|
null,
|
null,
|
"absolute",
|
"2px solid red");
|
this.zoomBox.style.backgroundColor = "white";
|
this.zoomBox.style.filter = "alpha(opacity=50)"; // IE
|
this.zoomBox.style.opacity = "0.50";
|
this.zoomBox.style.fontSize = "1px";
|
this.zoomBox.style.zIndex = this.map.Z_INDEX_BASE["Popup"] - 1;
|
this.map.viewPortDiv.appendChild(this.zoomBox);
|
}
|
document.onselectstart = OpenLayers.Function.False;
|
OpenLayers.Event.stop(evt);
|
},
|
|
/**
|
* Method: defaultMouseMove
|
*
|
* Parameters:
|
* evt - {Event}
|
*/
|
defaultMouseMove: function (evt) {
|
// record the mouse position, used in onWheelEvent
|
this.mousePosition = evt.xy.clone();
|
|
if (this.mouseDragStart != null) {
|
if (this.zoomBox) {
|
var deltaX = Math.abs(this.mouseDragStart.x - evt.xy.x);
|
var deltaY = Math.abs(this.mouseDragStart.y - evt.xy.y);
|
this.zoomBox.style.width = Math.max(1, deltaX) + "px";
|
this.zoomBox.style.height = Math.max(1, deltaY) + "px";
|
if (evt.xy.x < this.mouseDragStart.x) {
|
this.zoomBox.style.left = evt.xy.x+"px";
|
}
|
if (evt.xy.y < this.mouseDragStart.y) {
|
this.zoomBox.style.top = evt.xy.y+"px";
|
}
|
} else {
|
var deltaX = this.mouseDragStart.x - evt.xy.x;
|
var deltaY = this.mouseDragStart.y - evt.xy.y;
|
var size = this.map.getSize();
|
var newXY = new OpenLayers.Pixel(size.w / 2 + deltaX,
|
size.h / 2 + deltaY);
|
var newCenter = this.map.getLonLatFromViewPortPx( newXY );
|
this.map.setCenter(newCenter, null, true);
|
this.mouseDragStart = evt.xy.clone();
|
this.map.div.style.cursor = "move";
|
}
|
this.performedDrag = true;
|
}
|
},
|
|
/**
|
* Method: defaultMouseUp
|
*
|
* Parameters:
|
* evt - {<OpenLayers.Event>}
|
*/
|
defaultMouseUp: function (evt) {
|
if (!OpenLayers.Event.isLeftClick(evt)) {
|
return;
|
}
|
if (this.zoomBox) {
|
this.zoomBoxEnd(evt);
|
} else {
|
if (this.performedDrag) {
|
this.map.setCenter(this.map.center);
|
}
|
}
|
document.onselectstart=null;
|
this.mouseDragStart = null;
|
this.map.div.style.cursor = "";
|
},
|
|
/**
|
* Method: defaultMouseOut
|
*
|
* Parameters:
|
* evt - {Event}
|
*/
|
defaultMouseOut: function (evt) {
|
if (this.mouseDragStart != null &&
|
OpenLayers.Util.mouseLeft(evt, this.map.viewPortDiv)) {
|
if (this.zoomBox) {
|
this.removeZoomBox();
|
}
|
this.mouseDragStart = null;
|
}
|
},
|
|
|
/**
|
* Method: defaultWheelUp
|
* User spun scroll wheel up
|
*
|
*/
|
defaultWheelUp: function(evt) {
|
if (this.map.getZoom() <= this.map.getNumZoomLevels()) {
|
this.map.setCenter(this.map.getLonLatFromPixel(evt.xy),
|
this.map.getZoom() + 1);
|
}
|
},
|
|
/**
|
* Method: defaultWheelDown
|
* User spun scroll wheel down
|
*/
|
defaultWheelDown: function(evt) {
|
if (this.map.getZoom() > 0) {
|
this.map.setCenter(this.map.getLonLatFromPixel(evt.xy),
|
this.map.getZoom() - 1);
|
}
|
},
|
|
/**
|
* Method: zoomBoxEnd
|
* Zoombox function.
|
*/
|
zoomBoxEnd: function(evt) {
|
if (this.mouseDragStart != null) {
|
if (Math.abs(this.mouseDragStart.x - evt.xy.x) > 5 ||
|
Math.abs(this.mouseDragStart.y - evt.xy.y) > 5) {
|
var start = this.map.getLonLatFromViewPortPx( this.mouseDragStart );
|
var end = this.map.getLonLatFromViewPortPx( evt.xy );
|
var top = Math.max(start.lat, end.lat);
|
var bottom = Math.min(start.lat, end.lat);
|
var left = Math.min(start.lon, end.lon);
|
var right = Math.max(start.lon, end.lon);
|
var bounds = new OpenLayers.Bounds(left, bottom, right, top);
|
this.map.zoomToExtent(bounds);
|
} else {
|
var end = this.map.getLonLatFromViewPortPx( evt.xy );
|
this.map.setCenter(new OpenLayers.LonLat(
|
(end.lon),
|
(end.lat)
|
), this.map.getZoom() + 1);
|
}
|
this.removeZoomBox();
|
}
|
},
|
|
/**
|
* Method: removeZoomBox
|
* Remove the zoombox from the screen and nullify our reference to it.
|
*/
|
removeZoomBox: function() {
|
this.map.viewPortDiv.removeChild(this.zoomBox);
|
this.zoomBox = null;
|
},
|
|
|
/**
|
* Mouse ScrollWheel code thanks to http://adomas.org/javascript-mouse-wheel/
|
*/
|
|
|
/**
|
* Method: onWheelEvent
|
* Catch the wheel event and handle it xbrowserly
|
*
|
* Parameters:
|
* e - {Event}
|
*/
|
onWheelEvent: function(e){
|
|
// first determine whether or not the wheeling was inside the map
|
var inMap = false;
|
var elem = OpenLayers.Event.element(e);
|
while(elem != null) {
|
if (this.map && elem == this.map.div) {
|
inMap = true;
|
break;
|
}
|
elem = elem.parentNode;
|
}
|
|
if (inMap) {
|
|
var delta = 0;
|
if (!e) {
|
e = window.event;
|
}
|
if (e.wheelDelta) {
|
delta = e.wheelDelta/120;
|
if (window.opera && window.opera.version() < 9.2) {
|
delta = -delta;
|
}
|
} else if (e.detail) {
|
delta = -e.detail / 3;
|
}
|
if (delta) {
|
// add the mouse position to the event because mozilla has a bug
|
// with clientX and clientY (see https://bugzilla.mozilla.org/show_bug.cgi?id=352179)
|
// getLonLatFromViewPortPx(e) returns wrong values
|
e.xy = this.mousePosition;
|
|
if (delta < 0) {
|
this.defaultWheelDown(e);
|
} else {
|
this.defaultWheelUp(e);
|
}
|
}
|
|
//only wheel the map, not the window
|
OpenLayers.Event.stop(e);
|
}
|
},
|
|
CLASS_NAME: "OpenLayers.Control.MouseDefaults"
|
});
|
|
/**
|
* Class: OpenLayers.Control.MouseToolbar
|
* This class is DEPRECATED in 2.4 and will be removed by 3.0.
|
* If you need this functionality, use <OpenLayers.Control.NavToolbar>
|
* instead!!!
|
*/
|
OpenLayers.Control.MouseToolbar = OpenLayers.Class(
|
OpenLayers.Control.MouseDefaults, {
|
|
/**
|
* Property: mode
|
*/
|
mode: null,
|
/**
|
* Property: buttons
|
*/
|
buttons: null,
|
|
/**
|
* APIProperty: direction
|
* {String} 'vertical' or 'horizontal'
|
*/
|
direction: "vertical",
|
|
/**
|
* Property: buttonClicked
|
* {String}
|
*/
|
buttonClicked: null,
|
|
/**
|
* Constructor: OpenLayers.Control.MouseToolbar
|
*
|
* Parameters:
|
* position - {<OpenLayers.Pixel>}
|
* direction - {String}
|
*/
|
initialize: function(position, direction) {
|
OpenLayers.Control.prototype.initialize.apply(this, arguments);
|
this.position = new OpenLayers.Pixel(OpenLayers.Control.MouseToolbar.X,
|
OpenLayers.Control.MouseToolbar.Y);
|
if (position) {
|
this.position = position;
|
}
|
if (direction) {
|
this.direction = direction;
|
}
|
this.measureDivs = [];
|
},
|
|
/**
|
* APIMethod: destroy
|
*/
|
destroy: function() {
|
for( var btnId in this.buttons) {
|
var btn = this.buttons[btnId];
|
btn.map = null;
|
btn.events.destroy();
|
}
|
OpenLayers.Control.MouseDefaults.prototype.destroy.apply(this,
|
arguments);
|
},
|
|
/**
|
* Method: draw
|
*/
|
draw: function() {
|
OpenLayers.Control.prototype.draw.apply(this, arguments);
|
OpenLayers.Control.MouseDefaults.prototype.draw.apply(this, arguments);
|
this.buttons = {};
|
var sz = new OpenLayers.Size(28,28);
|
var centered = new OpenLayers.Pixel(OpenLayers.Control.MouseToolbar.X,0);
|
this._addButton("zoombox", "drag-rectangle-off.png", "drag-rectangle-on.png", centered, sz, "Shift->Drag to zoom to area");
|
centered = centered.add((this.direction == "vertical" ? 0 : sz.w), (this.direction == "vertical" ? sz.h : 0));
|
this._addButton("pan", "panning-hand-off.png", "panning-hand-on.png", centered, sz, "Drag the map to pan.");
|
centered = centered.add((this.direction == "vertical" ? 0 : sz.w), (this.direction == "vertical" ? sz.h : 0));
|
this.switchModeTo("pan");
|
|
return this.div;
|
},
|
|
/**
|
* Method: _addButton
|
*/
|
_addButton:function(id, img, activeImg, xy, sz, title) {
|
var imgLocation = OpenLayers.Util.getImageLocation(img);
|
var activeImgLocation = OpenLayers.Util.getImageLocation(activeImg);
|
// var btn = new ol.AlphaImage("_"+id, imgLocation, xy, sz);
|
var btn = OpenLayers.Util.createAlphaImageDiv(
|
"OpenLayers_Control_MouseToolbar_" + id,
|
xy, sz, imgLocation, "absolute");
|
|
//we want to add the outer div
|
this.div.appendChild(btn);
|
btn.imgLocation = imgLocation;
|
btn.activeImgLocation = activeImgLocation;
|
|
btn.events = new OpenLayers.Events(this, btn, null, true);
|
btn.events.on({
|
"mousedown": this.buttonDown,
|
"mouseup": this.buttonUp,
|
"dblclick": OpenLayers.Event.stop,
|
scope: this
|
});
|
btn.action = id;
|
btn.title = title;
|
btn.alt = title;
|
btn.map = this.map;
|
|
//we want to remember/reference the outer div
|
this.buttons[id] = btn;
|
return btn;
|
},
|
|
/**
|
* Method: buttonDown
|
*
|
* Parameters:
|
* evt - {Event}
|
*/
|
buttonDown: function(evt) {
|
if (!OpenLayers.Event.isLeftClick(evt)) {
|
return;
|
}
|
this.buttonClicked = evt.element.action;
|
OpenLayers.Event.stop(evt);
|
},
|
|
/**
|
* Method: buttonUp
|
*
|
* Parameters:
|
* evt - {Event}
|
*/
|
buttonUp: function(evt) {
|
if (!OpenLayers.Event.isLeftClick(evt)) {
|
return;
|
}
|
if (this.buttonClicked != null) {
|
if (this.buttonClicked == evt.element.action) {
|
this.switchModeTo(evt.element.action);
|
}
|
OpenLayers.Event.stop(evt);
|
this.buttonClicked = null;
|
}
|
},
|
|
/**
|
* Method: defaultDblClick
|
*
|
* Parameters:
|
* evt - {Event}
|
*/
|
defaultDblClick: function (evt) {
|
this.switchModeTo("pan");
|
this.performedDrag = false;
|
var newCenter = this.map.getLonLatFromViewPortPx( evt.xy );
|
this.map.setCenter(newCenter, this.map.zoom + 1);
|
OpenLayers.Event.stop(evt);
|
return false;
|
},
|
|
/**
|
* Method: defaultMouseDown
|
*
|
* Parameters:
|
* evt - {Event}
|
*/
|
defaultMouseDown: function (evt) {
|
if (!OpenLayers.Event.isLeftClick(evt)) {
|
return;
|
}
|
this.mouseDragStart = evt.xy.clone();
|
this.performedDrag = false;
|
this.startViaKeyboard = false;
|
if (evt.shiftKey && this.mode !="zoombox") {
|
this.switchModeTo("zoombox");
|
this.startViaKeyboard = true;
|
} else if (evt.altKey && this.mode !="measure") {
|
this.switchModeTo("measure");
|
} else if (!this.mode) {
|
this.switchModeTo("pan");
|
}
|
|
switch (this.mode) {
|
case "zoombox":
|
this.map.div.style.cursor = "crosshair";
|
this.zoomBox = OpenLayers.Util.createDiv('zoomBox',
|
this.mouseDragStart,
|
null,
|
null,
|
"absolute",
|
"2px solid red");
|
this.zoomBox.style.backgroundColor = "white";
|
this.zoomBox.style.filter = "alpha(opacity=50)"; // IE
|
this.zoomBox.style.opacity = "0.50";
|
this.zoomBox.style.fontSize = "1px";
|
this.zoomBox.style.zIndex = this.map.Z_INDEX_BASE["Popup"] - 1;
|
this.map.viewPortDiv.appendChild(this.zoomBox);
|
this.performedDrag = true;
|
break;
|
case "measure":
|
var distance = "";
|
if (this.measureStart) {
|
var measureEnd = this.map.getLonLatFromViewPortPx(this.mouseDragStart);
|
distance = OpenLayers.Util.distVincenty(this.measureStart, measureEnd);
|
distance = Math.round(distance * 100) / 100;
|
distance = distance + "km";
|
this.measureStartBox = this.measureBox;
|
}
|
this.measureStart = this.map.getLonLatFromViewPortPx(this.mouseDragStart);;
|
this.measureBox = OpenLayers.Util.createDiv(null,
|
this.mouseDragStart.add(
|
-2-parseInt(this.map.layerContainerDiv.style.left),
|
-2-parseInt(this.map.layerContainerDiv.style.top)),
|
null,
|
null,
|
"absolute");
|
this.measureBox.style.width="4px";
|
this.measureBox.style.height="4px";
|
this.measureBox.style.fontSize = "1px";
|
this.measureBox.style.backgroundColor="red";
|
this.measureBox.style.zIndex = this.map.Z_INDEX_BASE["Popup"] - 1;
|
this.map.layerContainerDiv.appendChild(this.measureBox);
|
if (distance) {
|
this.measureBoxDistance = OpenLayers.Util.createDiv(null,
|
this.mouseDragStart.add(
|
-2-parseInt(this.map.layerContainerDiv.style.left),
|
2-parseInt(this.map.layerContainerDiv.style.top)),
|
null,
|
null,
|
"absolute");
|
|
this.measureBoxDistance.innerHTML = distance;
|
this.measureBoxDistance.style.zIndex = this.map.Z_INDEX_BASE["Popup"] - 1;
|
this.map.layerContainerDiv.appendChild(this.measureBoxDistance);
|
this.measureDivs.push(this.measureBoxDistance);
|
}
|
this.measureBox.style.zIndex = this.map.Z_INDEX_BASE["Popup"] - 1;
|
this.map.layerContainerDiv.appendChild(this.measureBox);
|
this.measureDivs.push(this.measureBox);
|
break;
|
default:
|
this.map.div.style.cursor = "move";
|
break;
|
}
|
document.onselectstart = OpenLayers.Function.False;
|
OpenLayers.Event.stop(evt);
|
},
|
|
/**
|
* Method: switchModeTo
|
*
|
* Parameters:
|
* mode - {String}
|
*/
|
switchModeTo: function(mode) {
|
if (mode != this.mode) {
|
|
|
if (this.mode && this.buttons[this.mode]) {
|
OpenLayers.Util.modifyAlphaImageDiv(this.buttons[this.mode], null, null, null, this.buttons[this.mode].imgLocation);
|
}
|
if (this.mode == "measure" && mode != "measure") {
|
for(var i=0, len=this.measureDivs.length; i<len; i++) {
|
if (this.measureDivs[i]) {
|
this.map.layerContainerDiv.removeChild(this.measureDivs[i]);
|
}
|
}
|
this.measureDivs = [];
|
this.measureStart = null;
|
}
|
this.mode = mode;
|
if (this.buttons[mode]) {
|
OpenLayers.Util.modifyAlphaImageDiv(this.buttons[mode], null, null, null, this.buttons[mode].activeImgLocation);
|
}
|
switch (this.mode) {
|
case "zoombox":
|
this.map.div.style.cursor = "crosshair";
|
break;
|
default:
|
this.map.div.style.cursor = "";
|
break;
|
}
|
|
}
|
},
|
|
/**
|
* Method: leaveMode
|
*/
|
leaveMode: function() {
|
this.switchModeTo("pan");
|
},
|
|
/**
|
* Method: defaultMouseMove
|
*
|
* Parameters:
|
* evt - {Event}
|
*/
|
defaultMouseMove: function (evt) {
|
if (this.mouseDragStart != null) {
|
switch (this.mode) {
|
case "zoombox":
|
var deltaX = Math.abs(this.mouseDragStart.x - evt.xy.x);
|
var deltaY = Math.abs(this.mouseDragStart.y - evt.xy.y);
|
this.zoomBox.style.width = Math.max(1, deltaX) + "px";
|
this.zoomBox.style.height = Math.max(1, deltaY) + "px";
|
if (evt.xy.x < this.mouseDragStart.x) {
|
this.zoomBox.style.left = evt.xy.x+"px";
|
}
|
if (evt.xy.y < this.mouseDragStart.y) {
|
this.zoomBox.style.top = evt.xy.y+"px";
|
}
|
break;
|
default:
|
var deltaX = this.mouseDragStart.x - evt.xy.x;
|
var deltaY = this.mouseDragStart.y - evt.xy.y;
|
var size = this.map.getSize();
|
var newXY = new OpenLayers.Pixel(size.w / 2 + deltaX,
|
size.h / 2 + deltaY);
|
var newCenter = this.map.getLonLatFromViewPortPx( newXY );
|
this.map.setCenter(newCenter, null, true);
|
this.mouseDragStart = evt.xy.clone();
|
}
|
this.performedDrag = true;
|
}
|
},
|
|
/**
|
* Method: defaultMouseUp
|
*
|
* Parameters:
|
* evt - {Event}
|
*/
|
defaultMouseUp: function (evt) {
|
if (!OpenLayers.Event.isLeftClick(evt)) {
|
return;
|
}
|
switch (this.mode) {
|
case "zoombox":
|
this.zoomBoxEnd(evt);
|
if (this.startViaKeyboard) {
|
this.leaveMode();
|
}
|
break;
|
case "pan":
|
if (this.performedDrag) {
|
this.map.setCenter(this.map.center);
|
}
|
}
|
document.onselectstart = null;
|
this.mouseDragStart = null;
|
this.map.div.style.cursor = "default";
|
},
|
|
/**
|
* Method: defaultMouseOut
|
*
|
* Parameters:
|
* evt - {Event}
|
*/
|
defaultMouseOut: function (evt) {
|
if (this.mouseDragStart != null
|
&& OpenLayers.Util.mouseLeft(evt, this.map.viewPortDiv)) {
|
if (this.zoomBox) {
|
this.removeZoomBox();
|
if (this.startViaKeyboard) {
|
this.leaveMode();
|
}
|
}
|
this.mouseDragStart = null;
|
this.map.div.style.cursor = "default";
|
}
|
},
|
|
/**
|
* Method: defaultClick
|
*
|
* Parameters:
|
* evt - {Event}
|
*/
|
defaultClick: function (evt) {
|
if (this.performedDrag) {
|
this.performedDrag = false;
|
return false;
|
}
|
},
|
|
CLASS_NAME: "OpenLayers.Control.MouseToolbar"
|
});
|
|
OpenLayers.Control.MouseToolbar.X = 6;
|
OpenLayers.Control.MouseToolbar.Y = 300;
|
|
/**
|
* Class: OpenLayers.Layer.Grid
|
*/
|
|
OpenLayers.Util.extend(OpenLayers.Layer.Grid.prototype, {
|
|
/**
|
* Method: getGridBounds
|
* Deprecated. This function will be removed in 3.0. Please use
|
* getTilesBounds() instead.
|
*
|
* Returns:
|
* {<OpenLayers.Bounds>} A Bounds object representing the bounds of all the
|
* currently loaded tiles (including those partially or not at all seen
|
* onscreen)
|
*/
|
getGridBounds: function() {
|
var msg = "The getGridBounds() function is deprecated. It will be " +
|
"removed in 3.0. Please use getTilesBounds() instead.";
|
OpenLayers.Console.warn(msg);
|
return this.getTilesBounds();
|
}
|
});
|
|
/**
|
* Class: OpenLayers.Format.XML
|
*/
|
OpenLayers.Util.extend(OpenLayers.Format.XML.prototype, {
|
|
/**
|
* APIMethod: concatChildValues
|
* *Deprecated*. Use <getChildValue> instead.
|
*
|
* Concatenate the value of all child nodes if any exist, or return an
|
* optional default string. Returns an empty string if no children
|
* exist and no default value is supplied. Not optimized for large
|
* numbers of child nodes.
|
*
|
* Parameters:
|
* node - {DOMElement} The element used to look for child values.
|
* def - {String} Optional string to return in the event that no
|
* child exist.
|
*
|
* Returns:
|
* {String} The concatenated value of all child nodes of the given node.
|
*/
|
concatChildValues: function(node, def) {
|
var value = "";
|
var child = node.firstChild;
|
var childValue;
|
while(child) {
|
childValue = child.nodeValue;
|
if(childValue) {
|
value += childValue;
|
}
|
child = child.nextSibling;
|
}
|
if(value == "" && def != undefined) {
|
value = def;
|
}
|
return value;
|
}
|
|
});
|
|
/**
|
* Class: OpenLayers.Layer.WMS.Post
|
* Instances of OpenLayers.Layer.WMS.Post are used to retrieve data from OGC
|
* Web Mapping Services via HTTP-POST (application/x-www-form-urlencoded).
|
* Create a new WMS layer with the <OpenLayers.Layer.WMS.Post> constructor.
|
*
|
* *Deprecated*. Instead of this layer, use <OpenLayers.Layer.WMS> with
|
* <OpenLayers.Tile.Image.maxGetUrlLength> configured in the layer's
|
* <OpenLayers.Layer.WMS.tileOptions>.
|
*
|
* Inherits from:
|
* - <OpenLayers.Layer.WMS>
|
*/
|
OpenLayers.Layer.WMS.Post = OpenLayers.Class(OpenLayers.Layer.WMS, {
|
|
/**
|
* APIProperty: unsupportedBrowsers
|
* {Array} Array with browsers, which should use the HTTP-GET protocol
|
* instead of HTTP-POST for fetching tiles from a WMS .
|
* Defaults to ["mozilla", "firefox", "opera"], because Opera is not able
|
* to show transparent images in IFrames and Firefox/Mozilla has some ugly
|
* effects of viewport-shaking when panning the map. Both browsers, Opera
|
* and Firefox/Mozilla, have no problem with long urls, which is the reason
|
* for using POST instead of GET. The strings to pass to this array are
|
* the ones returned by <OpenLayers.BROWSER_NAME>.
|
*/
|
unsupportedBrowsers: ["mozilla", "firefox", "opera"],
|
|
/**
|
* Property: SUPPORTED_TRANSITIONS
|
* {Array}
|
* no supported transitions for this type of layer, because it is not
|
* possible to modify the initialized tiles (iframes)
|
*/
|
SUPPORTED_TRANSITIONS: [],
|
|
/**
|
* Property: usePost
|
* {Boolean}
|
*/
|
usePost: null,
|
|
/**
|
* Constructor: OpenLayers.Layer.WMS.Post
|
* Creates a new WMS layer object.
|
*
|
* Example:
|
* (code)
|
* var wms = new OpenLayers.Layer.WMS.Post(
|
* "NASA Global Mosaic",
|
* "http://wms.jpl.nasa.gov/wms.cgi",
|
* {layers: "modis, global_mosaic"});
|
* (end)
|
*
|
* Parameters:
|
* name - {String} A name for the layer
|
* url - {String} Base url for the WMS
|
* (e.g. http://wms.jpl.nasa.gov/wms.cgi)
|
* params - {Object} An object with key/value pairs representing the
|
* GetMap query string parameters and parameter values.
|
* options - {Object} Hashtable of extra options to tag onto the layer.
|
*/
|
initialize: function(name, url, params, options) {
|
var newArguments = [];
|
newArguments.push(name, url, params, options);
|
OpenLayers.Layer.WMS.prototype.initialize.apply(this, newArguments);
|
|
this.usePost = OpenLayers.Util.indexOf(
|
this.unsupportedBrowsers, OpenLayers.BROWSER_NAME) == -1;
|
},
|
|
/**
|
* Method: addTile
|
* addTile creates a tile, initializes it and adds it as iframe to the
|
* layer div.
|
*
|
* Parameters:
|
* bounds - {<OpenLayers.Bounds>}
|
* position - {<OpenLayers.Pixel>}
|
*
|
* Returns:
|
* {<OpenLayers.Tile.Image.IFrame>} The added OpenLayers.Tile.Image.IFrame
|
*/
|
addTile: function(bounds,position) {
|
return new OpenLayers.Tile.Image(
|
this, position, bounds, null, this.tileSize, {
|
maxGetUrlLength: this.usePost ? 0 : null
|
});
|
},
|
|
CLASS_NAME: 'OpenLayers.Layer.WMS.Post'
|
});
|
|
/**
|
* Class: OpenLayers.Layer.WMS.Untiled
|
* *Deprecated*. To be removed in 3.0. Instead use OpenLayers.Layer.WMS and
|
* pass the option 'singleTile' as true.
|
*
|
* Inherits from:
|
* - <OpenLayers.Layer.WMS>
|
*/
|
OpenLayers.Layer.WMS.Untiled = OpenLayers.Class(OpenLayers.Layer.WMS, {
|
|
/**
|
* APIProperty: singleTile
|
* {singleTile} Always true for untiled.
|
*/
|
singleTile: true,
|
|
/**
|
* Constructor: OpenLayers.Layer.WMS.Untiled
|
*
|
* Parameters:
|
* name - {String}
|
* url - {String}
|
* params - {Object}
|
* options - {Object}
|
*/
|
initialize: function(name, url, params, options) {
|
OpenLayers.Layer.WMS.prototype.initialize.apply(this, arguments);
|
|
var msg = "The OpenLayers.Layer.WMS.Untiled class is deprecated and " +
|
"will be removed in 3.0. Instead, you should use the " +
|
"normal OpenLayers.Layer.WMS class, passing it the option " +
|
"'singleTile' as true.";
|
OpenLayers.Console.warn(msg);
|
},
|
|
/**
|
* Method: clone
|
* Create a clone of this layer
|
*
|
* Returns:
|
* {<OpenLayers.Layer.WMS.Untiled>} An exact clone of this layer
|
*/
|
clone: function (obj) {
|
|
if (obj == null) {
|
obj = new OpenLayers.Layer.WMS.Untiled(this.name,
|
this.url,
|
this.params,
|
this.getOptions());
|
}
|
|
//get all additions from superclasses
|
obj = OpenLayers.Layer.WMS.prototype.clone.apply(this, [obj]);
|
|
// copy/set any non-init, non-simple values here
|
|
return obj;
|
},
|
|
CLASS_NAME: "OpenLayers.Layer.WMS.Untiled"
|
});
|
|
/**
|
* Class: OpenLayers.Layer.MapServer.Untiled
|
* *Deprecated*. To be removed in 3.0. Instead use OpenLayers.Layer.MapServer
|
* and pass the option 'singleTile' as true.
|
*
|
* Inherits from:
|
* - <OpenLayers.Layer.MapServer>
|
*/
|
OpenLayers.Layer.MapServer.Untiled = OpenLayers.Class(OpenLayers.Layer.MapServer, {
|
|
/**
|
* APIProperty: singleTile
|
* {singleTile} Always true for untiled.
|
*/
|
singleTile: true,
|
|
/**
|
* Constructor: OpenLayers.Layer.MapServer.Untiled
|
*
|
* Parameters:
|
* name - {String}
|
* url - {String}
|
* params - {Object}
|
* options - {Object}
|
*/
|
initialize: function(name, url, params, options) {
|
OpenLayers.Layer.MapServer.prototype.initialize.apply(this, arguments);
|
|
var msg = "The OpenLayers.Layer.MapServer.Untiled class is deprecated and " +
|
"will be removed in 3.0. Instead, you should use the " +
|
"normal OpenLayers.Layer.MapServer class, passing it the option " +
|
"'singleTile' as true.";
|
OpenLayers.Console.warn(msg);
|
},
|
|
/**
|
* Method: clone
|
* Create a clone of this layer
|
*
|
* Returns:
|
* {<OpenLayers.Layer.MapServer.Untiled>} An exact clone of this layer
|
*/
|
clone: function (obj) {
|
|
if (obj == null) {
|
obj = new OpenLayers.Layer.MapServer.Untiled(this.name,
|
this.url,
|
this.params,
|
this.getOptions());
|
}
|
|
//get all additions from superclasses
|
obj = OpenLayers.Layer.MapServer.prototype.clone.apply(this, [obj]);
|
|
// copy/set any non-init, non-simple values here
|
|
return obj;
|
},
|
|
CLASS_NAME: "OpenLayers.Layer.MapServer.Untiled"
|
});
|
|
/**
|
* Class: OpenLayers.Tile.WFS
|
* Instances of OpenLayers.Tile.WFS are used to manage the image tiles
|
* used by various layers. Create a new image tile with the
|
* <OpenLayers.Tile.WFS> constructor.
|
*
|
* Inherits from:
|
* - <OpenLayers.Tile>
|
*/
|
OpenLayers.Tile.WFS = OpenLayers.Class(OpenLayers.Tile, {
|
|
/**
|
* Property: features
|
* {Array(<OpenLayers.Feature>)} list of features in this tile
|
*/
|
features: null,
|
|
/**
|
* Property: url
|
* {String}
|
*/
|
url: null,
|
|
/**
|
* Property: request
|
* {<OpenLayers.Request.XMLHttpRequest>}
|
*/
|
request: null,
|
|
/** TBD 3.0 - reorder the parameters to the init function to put URL
|
* as last, so we can continue to call tile.initialize()
|
* without changing the arguments.
|
*
|
* Constructor: OpenLayers.Tile.WFS
|
* Constructor for a new <OpenLayers.Tile.WFS> instance.
|
*
|
* Parameters:
|
* layer - {<OpenLayers.Layer>} layer that the tile will go in.
|
* position - {<OpenLayers.Pixel>}
|
* bounds - {<OpenLayers.Bounds>}
|
* url - {<String>}
|
* size - {<OpenLayers.Size>}
|
*/
|
initialize: function(layer, position, bounds, url, size) {
|
OpenLayers.Tile.prototype.initialize.apply(this, arguments);
|
this.url = url;
|
this.features = [];
|
},
|
|
/**
|
* APIMethod: destroy
|
* nullify references to prevent circular references and memory leaks
|
*/
|
destroy: function() {
|
OpenLayers.Tile.prototype.destroy.apply(this, arguments);
|
this.destroyAllFeatures();
|
this.features = null;
|
this.url = null;
|
if(this.request) {
|
this.request.abort();
|
//this.request.destroy();
|
this.request = null;
|
}
|
},
|
|
/**
|
* Method: clear
|
* Clear the tile of any bounds/position-related data so that it can
|
* be reused in a new location.
|
*/
|
clear: function() {
|
this.destroyAllFeatures();
|
},
|
|
/**
|
* Method: draw
|
* Check that a tile should be drawn, and load features for it.
|
*/
|
draw:function() {
|
if (OpenLayers.Tile.prototype.draw.apply(this, arguments)) {
|
if (this.isLoading) {
|
//if already loading, send 'reload' instead of 'loadstart'.
|
this.events.triggerEvent("reload");
|
} else {
|
this.isLoading = true;
|
this.events.triggerEvent("loadstart");
|
}
|
this.loadFeaturesForRegion(this.requestSuccess);
|
}
|
},
|
|
/**
|
* Method: loadFeaturesForRegion
|
* Abort any pending requests and issue another request for data.
|
*
|
* Input are function pointers for what to do on success and failure.
|
*
|
* Parameters:
|
* success - {function}
|
* failure - {function}
|
*/
|
loadFeaturesForRegion:function(success, failure) {
|
if(this.request) {
|
this.request.abort();
|
}
|
this.request = OpenLayers.Request.GET({
|
url: this.url,
|
success: success,
|
failure: failure,
|
scope: this
|
});
|
},
|
|
/**
|
* Method: requestSuccess
|
* Called on return from request succcess. Adds results via
|
* layer.addFeatures in vector mode, addResults otherwise.
|
*
|
* Parameters:
|
* request - {<OpenLayers.Request.XMLHttpRequest>}
|
*/
|
requestSuccess:function(request) {
|
if (this.features) {
|
var doc = request.responseXML;
|
if (!doc || !doc.documentElement) {
|
doc = request.responseText;
|
}
|
if (this.layer.vectorMode) {
|
this.layer.addFeatures(this.layer.formatObject.read(doc));
|
} else {
|
var xml = new OpenLayers.Format.XML();
|
if (typeof doc == "string") {
|
doc = xml.read(doc);
|
}
|
var resultFeatures = xml.getElementsByTagNameNS(
|
doc, "http://www.opengis.net/gml", "featureMember"
|
);
|
this.addResults(resultFeatures);
|
}
|
}
|
if (this.events) {
|
this.events.triggerEvent("loadend");
|
}
|
|
//request produced with success, we can delete the request object.
|
//this.request.destroy();
|
this.request = null;
|
},
|
|
/**
|
* Method: addResults
|
* Construct new feature via layer featureClass constructor, and add to
|
* this.features.
|
*
|
* Parameters:
|
* results - {Object}
|
*/
|
addResults: function(results) {
|
for (var i=0; i < results.length; i++) {
|
var feature = new this.layer.featureClass(this.layer,
|
results[i]);
|
this.features.push(feature);
|
}
|
},
|
|
|
/**
|
* Method: destroyAllFeatures
|
* Iterate through and call destroy() on each feature, removing it from
|
* the local array
|
*/
|
destroyAllFeatures: function() {
|
while(this.features.length > 0) {
|
var feature = this.features.shift();
|
feature.destroy();
|
}
|
},
|
|
CLASS_NAME: "OpenLayers.Tile.WFS"
|
}
|
);
|
|
/**
|
* Class: OpenLayers.Feature.WFS
|
* WFS handling class, for use as a featureClass on the WFS layer for handling
|
* 'point' WFS types. Good for subclassing when creating a custom WFS like
|
* XML application.
|
*
|
* Inherits from:
|
* - <OpenLayers.Feature>
|
*/
|
OpenLayers.Feature.WFS = OpenLayers.Class(OpenLayers.Feature, {
|
|
/**
|
* Constructor: OpenLayers.Feature.WFS
|
* Create a WFS feature.
|
*
|
* Parameters:
|
* layer - {<OpenLayers.Layer>}
|
* xmlNode - {XMLNode}
|
*/
|
initialize: function(layer, xmlNode) {
|
var newArguments = arguments;
|
var data = this.processXMLNode(xmlNode);
|
newArguments = new Array(layer, data.lonlat, data);
|
OpenLayers.Feature.prototype.initialize.apply(this, newArguments);
|
this.createMarker();
|
this.layer.addMarker(this.marker);
|
},
|
|
/**
|
* Method: destroy
|
* nullify references to prevent circular references and memory leaks
|
*/
|
destroy: function() {
|
if (this.marker != null) {
|
this.layer.removeMarker(this.marker);
|
}
|
OpenLayers.Feature.prototype.destroy.apply(this, arguments);
|
},
|
|
/**
|
* Method: processXMLNode
|
* When passed an xmlNode, parses it for a GML point, and passes
|
* back an object describing that point.
|
*
|
* For subclasses of Feature.WFS, this is the feature to change.
|
*
|
* Parameters:
|
* xmlNode - {XMLNode}
|
*
|
* Returns:
|
* {Object} Data Object with 'id', 'lonlat', and private properties set
|
*/
|
processXMLNode: function(xmlNode) {
|
//this should be overridden by subclasses
|
// must return an Object with 'id' and 'lonlat' values set
|
var point = OpenLayers.Ajax.getElementsByTagNameNS(xmlNode, "http://www.opengis.net/gml", "gml", "Point");
|
var text = OpenLayers.Util.getXmlNodeValue(OpenLayers.Ajax.getElementsByTagNameNS(point[0], "http://www.opengis.net/gml","gml", "coordinates")[0]);
|
var floats = text.split(",");
|
return {lonlat: new OpenLayers.LonLat(parseFloat(floats[0]),
|
parseFloat(floats[1])),
|
id: null};
|
|
},
|
|
CLASS_NAME: "OpenLayers.Feature.WFS"
|
});
|
|
|
/**
|
* Class: OpenLayers.Layer.WFS
|
* *Deprecated*. To be removed in 3.0. Instead use OpenLayers.Layer.Vector
|
* with a Protocol.WFS and one or more Strategies.
|
*
|
* Inherits from:
|
* - <OpenLayers.Layer.Vector>
|
* - <OpenLayers.Layer.Markers>
|
*/
|
OpenLayers.Layer.WFS = OpenLayers.Class(
|
OpenLayers.Layer.Vector, OpenLayers.Layer.Markers, {
|
|
/**
|
* APIProperty: isBaseLayer
|
* {Boolean} WFS layer is not a base layer by default.
|
*/
|
isBaseLayer: false,
|
|
/**
|
* Property: tile
|
* {<OpenLayers.Tile.WFS>}
|
*/
|
tile: null,
|
|
/**
|
* APIProperty: ratio
|
* {Float} The ratio property determines the size of the serverside query
|
* relative to the map viewport size. By default, we load an area twice
|
* as big as the map, to allow for panning without immediately reload.
|
* Setting this to 1 will cause the area of the WFS request to match
|
* the map area exactly. It is recommended to set this to some number
|
* at least slightly larger than 1, otherwise accidental clicks can
|
* cause a data reload, by moving the map only 1 pixel.
|
*/
|
ratio: 2,
|
|
/**
|
* Property: DEFAULT_PARAMS
|
* {Object} Hashtable of default key/value parameters
|
*/
|
DEFAULT_PARAMS: { service: "WFS",
|
version: "1.0.0",
|
request: "GetFeature"
|
},
|
|
/**
|
* APIProperty: featureClass
|
* {<OpenLayers.Feature>} If featureClass is defined, an old-style markers
|
* based WFS layer is created instead of a new-style vector layer. If
|
* sent, this should be a subclass of OpenLayers.Feature
|
*/
|
featureClass: null,
|
|
/**
|
* APIProperty: format
|
* {<OpenLayers.Format>} The format you want the data to be parsed with.
|
* Must be passed in the constructor. Should be a class, not an instance.
|
* This option can only be used if no featureClass is passed / vectorMode
|
* is false: if a featureClass is passed, then this parameter is ignored.
|
*/
|
format: null,
|
|
/**
|
* Property: formatObject
|
* {<OpenLayers.Format>} Internally created/managed format object, used by
|
* the Tile to parse data.
|
*/
|
formatObject: null,
|
|
/**
|
* APIProperty: formatOptions
|
* {Object} Hash of options which should be passed to the format when it is
|
* created. Must be passed in the constructor.
|
*/
|
formatOptions: null,
|
|
/**
|
* Property: vectorMode
|
* {Boolean} Should be calculated automatically. Determines whether the
|
* layer is in vector mode or marker mode.
|
*/
|
vectorMode: true,
|
|
/**
|
* APIProperty: encodeBBOX
|
* {Boolean} Should the BBOX commas be encoded? The WMS spec says 'no',
|
* but some services want it that way. Default false.
|
*/
|
encodeBBOX: false,
|
|
/**
|
* APIProperty: extractAttributes
|
* {Boolean} Should the WFS layer parse attributes from the retrieved
|
* GML? Defaults to false. If enabled, parsing is slower, but
|
* attributes are available in the attributes property of
|
* layer features.
|
*/
|
extractAttributes: false,
|
|
/**
|
* Constructor: OpenLayers.Layer.WFS
|
*
|
* Parameters:
|
* name - {String}
|
* url - {String}
|
* params - {Object}
|
* options - {Object} Hashtable of extra options to tag onto the layer
|
*/
|
initialize: function(name, url, params, options) {
|
if (options == undefined) { options = {}; }
|
|
if (options.featureClass ||
|
!OpenLayers.Layer.Vector ||
|
!OpenLayers.Feature.Vector) {
|
this.vectorMode = false;
|
}
|
|
// Uppercase params
|
params = OpenLayers.Util.upperCaseObject(params);
|
|
// Turn off error reporting, browsers like Safari may work
|
// depending on the setup, and we don't want an unneccesary alert.
|
OpenLayers.Util.extend(options, {'reportError': false});
|
var newArguments = [];
|
newArguments.push(name, options);
|
OpenLayers.Layer.Vector.prototype.initialize.apply(this, newArguments);
|
if (!this.renderer || !this.vectorMode) {
|
this.vectorMode = false;
|
if (!options.featureClass) {
|
options.featureClass = OpenLayers.Feature.WFS;
|
}
|
OpenLayers.Layer.Markers.prototype.initialize.apply(this,
|
newArguments);
|
}
|
|
if (this.params && this.params.typename && !this.options.typename) {
|
this.options.typename = this.params.typename;
|
}
|
|
if (!this.options.geometry_column) {
|
this.options.geometry_column = "the_geom";
|
}
|
|
this.params = OpenLayers.Util.applyDefaults(
|
params,
|
OpenLayers.Util.upperCaseObject(this.DEFAULT_PARAMS)
|
);
|
this.url = url;
|
},
|
|
|
/**
|
* APIMethod: destroy
|
*/
|
destroy: function() {
|
if (this.vectorMode) {
|
OpenLayers.Layer.Vector.prototype.destroy.apply(this, arguments);
|
} else {
|
OpenLayers.Layer.Markers.prototype.destroy.apply(this, arguments);
|
}
|
if (this.tile) {
|
this.tile.destroy();
|
}
|
this.tile = null;
|
|
this.ratio = null;
|
this.featureClass = null;
|
this.format = null;
|
|
if (this.formatObject && this.formatObject.destroy) {
|
this.formatObject.destroy();
|
}
|
this.formatObject = null;
|
|
this.formatOptions = null;
|
this.vectorMode = null;
|
this.encodeBBOX = null;
|
this.extractAttributes = null;
|
},
|
|
/**
|
* Method: setMap
|
*
|
* Parameters:
|
* map - {<OpenLayers.Map>}
|
*/
|
setMap: function(map) {
|
if (this.vectorMode) {
|
OpenLayers.Layer.Vector.prototype.setMap.apply(this, arguments);
|
|
var options = {
|
'extractAttributes': this.extractAttributes
|
};
|
|
OpenLayers.Util.extend(options, this.formatOptions);
|
if (this.map && !this.projection.equals(this.map.getProjectionObject())) {
|
options.externalProjection = this.projection;
|
options.internalProjection = this.map.getProjectionObject();
|
}
|
|
this.formatObject = this.format ? new this.format(options) : new OpenLayers.Format.GML(options);
|
} else {
|
OpenLayers.Layer.Markers.prototype.setMap.apply(this, arguments);
|
}
|
},
|
|
/**
|
* Method: moveTo
|
*
|
* Parameters:
|
* bounds - {<OpenLayers.Bounds>}
|
* zoomChanged - {Boolean}
|
* dragging - {Boolean}
|
*/
|
moveTo:function(bounds, zoomChanged, dragging) {
|
if (this.vectorMode) {
|
OpenLayers.Layer.Vector.prototype.moveTo.apply(this, arguments);
|
} else {
|
OpenLayers.Layer.Markers.prototype.moveTo.apply(this, arguments);
|
}
|
|
// don't load wfs features while dragging, wait for drag end
|
if (dragging) {
|
// TBD try to hide the vector layer while dragging
|
// this.setVisibility(false);
|
// this will probably help for panning performances
|
return false;
|
}
|
|
if ( zoomChanged ) {
|
if (this.vectorMode) {
|
this.renderer.clear();
|
}
|
}
|
|
//DEPRECATED - REMOVE IN 3.0
|
// don't load data if current zoom level doesn't match
|
if (this.options.minZoomLevel) {
|
OpenLayers.Console.warn(OpenLayers.i18n('minZoomLevelError'));
|
|
if (this.map.getZoom() < this.options.minZoomLevel) {
|
return null;
|
}
|
}
|
|
if (bounds == null) {
|
bounds = this.map.getExtent();
|
}
|
|
var firstRendering = (this.tile == null);
|
|
//does the new bounds to which we need to move fall outside of the
|
// current tile's bounds?
|
var outOfBounds = (!firstRendering &&
|
!this.tile.bounds.containsBounds(bounds));
|
|
if (zoomChanged || firstRendering || (!dragging && outOfBounds)) {
|
//determine new tile bounds
|
var center = bounds.getCenterLonLat();
|
var tileWidth = bounds.getWidth() * this.ratio;
|
var tileHeight = bounds.getHeight() * this.ratio;
|
var tileBounds =
|
new OpenLayers.Bounds(center.lon - (tileWidth / 2),
|
center.lat - (tileHeight / 2),
|
center.lon + (tileWidth / 2),
|
center.lat + (tileHeight / 2));
|
|
//determine new tile size
|
var tileSize = this.map.getSize();
|
tileSize.w = tileSize.w * this.ratio;
|
tileSize.h = tileSize.h * this.ratio;
|
|
//determine new position (upper left corner of new bounds)
|
var ul = new OpenLayers.LonLat(tileBounds.left, tileBounds.top);
|
var pos = this.map.getLayerPxFromLonLat(ul);
|
|
//formulate request url string
|
var url = this.getFullRequestString();
|
|
var params = null;
|
|
// Cant combine "filter" and "BBOX". This is a cheap hack to help
|
// people out who can't migrate to the WFS protocol immediately.
|
var filter = this.params.filter || this.params.FILTER;
|
if (filter) {
|
params = {FILTER: filter};
|
}
|
else {
|
params = {BBOX: this.encodeBBOX ? tileBounds.toBBOX()
|
: tileBounds.toArray()};
|
}
|
|
if (this.map && !this.projection.equals(this.map.getProjectionObject())) {
|
var projectedBounds = tileBounds.clone();
|
projectedBounds.transform(this.map.getProjectionObject(),
|
this.projection);
|
if (!filter){
|
params.BBOX = this.encodeBBOX ? projectedBounds.toBBOX()
|
: projectedBounds.toArray();
|
}
|
}
|
|
url += "&" + OpenLayers.Util.getParameterString(params);
|
|
if (!this.tile) {
|
this.tile = new OpenLayers.Tile.WFS(this, pos, tileBounds,
|
url, tileSize);
|
this.addTileMonitoringHooks(this.tile);
|
this.tile.draw();
|
} else {
|
if (this.vectorMode) {
|
this.destroyFeatures();
|
this.renderer.clear();
|
} else {
|
this.clearMarkers();
|
}
|
this.removeTileMonitoringHooks(this.tile);
|
this.tile.destroy();
|
|
this.tile = null;
|
this.tile = new OpenLayers.Tile.WFS(this, pos, tileBounds,
|
url, tileSize);
|
this.addTileMonitoringHooks(this.tile);
|
this.tile.draw();
|
}
|
}
|
},
|
|
/**
|
* Method: addTileMonitoringHooks
|
* This function takes a tile as input and adds the appropriate hooks to
|
* the tile so that the layer can keep track of the loading tile
|
* (making sure to check that the tile is always the layer's current
|
* tile before taking any action).
|
*
|
* Parameters:
|
* tile - {<OpenLayers.Tile>}
|
*/
|
addTileMonitoringHooks: function(tile) {
|
tile.onLoadStart = function() {
|
//if this is the the layer's current tile, then trigger
|
// a 'loadstart'
|
if (this == this.layer.tile) {
|
this.layer.events.triggerEvent("loadstart");
|
}
|
};
|
tile.events.register("loadstart", tile, tile.onLoadStart);
|
|
tile.onLoadEnd = function() {
|
//if this is the the layer's current tile, then trigger
|
// a 'tileloaded' and 'loadend'
|
if (this == this.layer.tile) {
|
this.layer.events.triggerEvent("tileloaded");
|
this.layer.events.triggerEvent("loadend");
|
}
|
};
|
tile.events.register("loadend", tile, tile.onLoadEnd);
|
tile.events.register("unload", tile, tile.onLoadEnd);
|
},
|
|
/**
|
* Method: removeTileMonitoringHooks
|
* This function takes a tile as input and removes the tile hooks
|
* that were added in addTileMonitoringHooks()
|
*
|
* Parameters:
|
* tile - {<OpenLayers.Tile>}
|
*/
|
removeTileMonitoringHooks: function(tile) {
|
tile.unload();
|
tile.events.un({
|
"loadstart": tile.onLoadStart,
|
"loadend": tile.onLoadEnd,
|
"unload": tile.onLoadEnd,
|
scope: tile
|
});
|
},
|
|
/**
|
* Method: onMapResize
|
* Call the onMapResize method of the appropriate parent class.
|
*/
|
onMapResize: function() {
|
if(this.vectorMode) {
|
OpenLayers.Layer.Vector.prototype.onMapResize.apply(this,
|
arguments);
|
} else {
|
OpenLayers.Layer.Markers.prototype.onMapResize.apply(this,
|
arguments);
|
}
|
},
|
|
/**
|
* Method: display
|
* Call the display method of the appropriate parent class.
|
*/
|
display: function() {
|
if(this.vectorMode) {
|
OpenLayers.Layer.Vector.prototype.display.apply(this,
|
arguments);
|
} else {
|
OpenLayers.Layer.Markers.prototype.display.apply(this,
|
arguments);
|
}
|
},
|
|
/**
|
* APIMethod: mergeNewParams
|
* Modify parameters for the layer and redraw.
|
*
|
* Parameters:
|
* newParams - {Object}
|
*/
|
mergeNewParams:function(newParams) {
|
var upperParams = OpenLayers.Util.upperCaseObject(newParams);
|
var newArguments = [upperParams];
|
return OpenLayers.Layer.HTTPRequest.prototype.mergeNewParams.apply(this,
|
newArguments);
|
},
|
|
/**
|
* APIMethod: clone
|
*
|
* Parameters:
|
* obj - {Object}
|
*
|
* Returns:
|
* {<OpenLayers.Layer.WFS>} An exact clone of this OpenLayers.Layer.WFS
|
*/
|
clone: function (obj) {
|
|
if (obj == null) {
|
obj = new OpenLayers.Layer.WFS(this.name,
|
this.url,
|
this.params,
|
this.getOptions());
|
}
|
|
//get all additions from superclasses
|
if (this.vectorMode) {
|
obj = OpenLayers.Layer.Vector.prototype.clone.apply(this, [obj]);
|
} else {
|
obj = OpenLayers.Layer.Markers.prototype.clone.apply(this, [obj]);
|
}
|
|
// copy/set any non-init, non-simple values here
|
|
return obj;
|
},
|
|
/**
|
* APIMethod: getFullRequestString
|
* combine the layer's url with its params and these newParams.
|
*
|
* Add the SRS parameter from 'projection' -- this is probably
|
* more eloquently done via a setProjection() method, but this
|
* works for now and always.
|
*
|
* Parameters:
|
* newParams - {Object}
|
* altUrl - {String} Use this as the url instead of the layer's url
|
*/
|
getFullRequestString:function(newParams, altUrl) {
|
var projectionCode = this.projection.getCode() || this.map.getProjection();
|
this.params.SRS = (projectionCode == "none") ? null : projectionCode;
|
|
return OpenLayers.Layer.Grid.prototype.getFullRequestString.apply(
|
this, arguments);
|
},
|
|
/**
|
* APIMethod: commit
|
* Write out the data to a WFS server.
|
*/
|
commit: function() {
|
if (!this.writer) {
|
var options = {};
|
if (this.map && !this.projection.equals(this.map.getProjectionObject())) {
|
options.externalProjection = this.projection;
|
options.internalProjection = this.map.getProjectionObject();
|
}
|
|
this.writer = new OpenLayers.Format.WFS(options,this);
|
}
|
|
var data = this.writer.write(this.features);
|
|
OpenLayers.Request.POST({
|
url: this.url,
|
data: data,
|
success: this.commitSuccess,
|
failure: this.commitFailure,
|
scope: this
|
});
|
},
|
|
/**
|
* Method: commitSuccess
|
* Called when the Ajax request returns a response
|
*
|
* Parameters:
|
* response - {XmlNode} from server
|
*/
|
commitSuccess: function(request) {
|
var response = request.responseText;
|
if (response.indexOf('SUCCESS') != -1) {
|
this.commitReport(OpenLayers.i18n("commitSuccess", {'response':response}));
|
|
for(var i = 0; i < this.features.length; i++) {
|
this.features[i].state = null;
|
}
|
// TBD redraw the layer or reset the state of features
|
// foreach features: set state to null
|
} else if (response.indexOf('FAILED') != -1 ||
|
response.indexOf('Exception') != -1) {
|
this.commitReport(OpenLayers.i18n("commitFailed", {'response':response}));
|
}
|
},
|
|
/**
|
* Method: commitFailure
|
* Called when the Ajax request fails
|
*
|
* Parameters:
|
* response - {XmlNode} from server
|
*/
|
commitFailure: function(request) {},
|
|
/**
|
* APIMethod: commitReport
|
* Called with a 'success' message if the commit succeeded, otherwise
|
* a failure message, and the full request text as a second parameter.
|
* Override this function to provide custom transaction reporting.
|
*
|
* string - {String} reporting string
|
* response - {String} full XML response
|
*/
|
commitReport: function(string, response) {
|
OpenLayers.Console.userError(string);
|
},
|
|
|
/**
|
* APIMethod: refresh
|
* Refreshes all the features of the layer
|
*/
|
refresh: function() {
|
if (this.tile) {
|
if (this.vectorMode) {
|
this.renderer.clear();
|
this.features.length = 0;
|
} else {
|
this.clearMarkers();
|
this.markers.length = 0;
|
}
|
this.tile.draw();
|
}
|
},
|
|
/**
|
* APIMethod: getDataExtent
|
* Calculates the max extent which includes all of the layer data.
|
*
|
* Returns:
|
* {<OpenLayers.Bounds>}
|
*/
|
getDataExtent: function () {
|
var extent;
|
//get all additions from superclasses
|
if (this.vectorMode) {
|
extent = OpenLayers.Layer.Vector.prototype.getDataExtent.apply(this);
|
} else {
|
extent = OpenLayers.Layer.Markers.prototype.getDataExtent.apply(this);
|
}
|
|
return extent;
|
},
|
|
/**
|
* APIMethod: setOpacity
|
* Call the setOpacity method of the appropriate parent class to set the
|
* opacity.
|
*
|
* Parameters:
|
* opacity - {Float}
|
*/
|
setOpacity: function (opacity) {
|
if (this.vectorMode) {
|
OpenLayers.Layer.Vector.prototype.setOpacity.apply(this, [opacity]);
|
} else {
|
OpenLayers.Layer.Markers.prototype.setOpacity.apply(this, [opacity]);
|
}
|
},
|
|
CLASS_NAME: "OpenLayers.Layer.WFS"
|
});
|
|
/**
|
* Class: OpenLayers.Layer.VirtualEarth
|
* *Deprecated*. Use <OpenLayers.Layer.Bing> instead.
|
*
|
* Instances of OpenLayers.Layer.VirtualEarth are used to display the data from
|
* the Bing Maps AJAX Control (see e.g.
|
* http://msdn.microsoft.com/library/bb429619.aspx). Create a VirtualEarth
|
* layer with the <OpenLayers.Layer.VirtualEarth> constructor.
|
*
|
* Inherits from:
|
* - <OpenLayers.Layer.EventPane>
|
* - <OpenLayers.Layer.FixedZoomLevels>
|
*/
|
OpenLayers.Layer.VirtualEarth = OpenLayers.Class(
|
OpenLayers.Layer.EventPane,
|
OpenLayers.Layer.FixedZoomLevels, {
|
|
/**
|
* Constant: MIN_ZOOM_LEVEL
|
* {Integer} 1
|
*/
|
MIN_ZOOM_LEVEL: 1,
|
|
/**
|
* Constant: MAX_ZOOM_LEVEL
|
* {Integer} 19
|
*/
|
MAX_ZOOM_LEVEL: 19,
|
|
/**
|
* Constant: RESOLUTIONS
|
* {Array(Float)} Hardcode these resolutions so that they are more closely
|
* tied with the standard wms projection
|
*/
|
RESOLUTIONS: [
|
1.40625,
|
0.703125,
|
0.3515625,
|
0.17578125,
|
0.087890625,
|
0.0439453125,
|
0.02197265625,
|
0.010986328125,
|
0.0054931640625,
|
0.00274658203125,
|
0.001373291015625,
|
0.0006866455078125,
|
0.00034332275390625,
|
0.000171661376953125,
|
0.0000858306884765625,
|
0.00004291534423828125,
|
0.00002145767211914062,
|
0.00001072883605957031,
|
0.00000536441802978515
|
],
|
|
/**
|
* APIProperty: type
|
* {VEMapType}
|
*/
|
type: null,
|
|
/**
|
* APIProperty: wrapDateLine
|
* {Boolean} Allow user to pan forever east/west. Default is true.
|
* Setting this to false only restricts panning if
|
* <sphericalMercator> is true.
|
*/
|
wrapDateLine: true,
|
|
/**
|
* APIProperty: sphericalMercator
|
* {Boolean} Should the map act as a mercator-projected map? This will
|
* cause all interactions with the map to be in the actual map
|
* projection, which allows support for vector drawing, overlaying
|
* other maps, etc.
|
*/
|
sphericalMercator: false,
|
|
/**
|
* APIProperty: animationEnabled
|
* {Boolean} If set to true, the transition between zoom levels will be
|
* animated. Set to false to match the zooming experience of other
|
* layer types. Default is true.
|
*/
|
animationEnabled: true,
|
|
/**
|
* Constructor: OpenLayers.Layer.VirtualEarth
|
* Creates a new instance of a OpenLayers.Layer.VirtualEarth. If you use an
|
* instance of OpenLayers.Layer.VirtualEarth in you map, you should set
|
* the <OpenLayers.Map> option restrictedExtent to a meaningful value,
|
* e.g.:
|
* (code)
|
* var map = new OpenLayers.Map( 'map', {
|
* // other map options
|
* restrictedExtent : OpenLayers.Bounds(-20037508, -20037508, 20037508, 20037508)
|
* } );
|
*
|
* var veLayer = new OpenLayers.Layer.VirtualEarth (
|
* "Virtual Earth Layer"
|
* );
|
*
|
* map.addLayer( veLayer );
|
* (end)
|
*
|
* Parameters:
|
* name - {String}
|
* options - {Object}
|
*/
|
initialize: function(name, options) {
|
OpenLayers.Layer.EventPane.prototype.initialize.apply(this, arguments);
|
OpenLayers.Layer.FixedZoomLevels.prototype.initialize.apply(this,
|
arguments);
|
if(this.sphericalMercator) {
|
OpenLayers.Util.extend(this, OpenLayers.Layer.SphericalMercator);
|
this.initMercatorParameters();
|
}
|
},
|
|
/**
|
* Method: loadMapObject
|
*/
|
loadMapObject:function() {
|
|
// create div and set to same size as map
|
var veDiv = OpenLayers.Util.createDiv(this.name);
|
var sz = this.map.getSize();
|
veDiv.style.width = sz.w + "px";
|
veDiv.style.height = sz.h + "px";
|
this.div.appendChild(veDiv);
|
|
try { // crash prevention
|
this.mapObject = new VEMap(this.name);
|
} catch (e) { }
|
|
if (this.mapObject != null) {
|
try { // this is to catch a Mozilla bug without falling apart
|
|
// The fourth argument is whether the map is 'fixed' -- not
|
// draggable. See:
|
// http://blogs.msdn.com/virtualearth/archive/2007/09/28/locking-a-virtual-earth-map.aspx
|
//
|
this.mapObject.LoadMap(null, null, this.type, true);
|
this.mapObject.AttachEvent("onmousedown", OpenLayers.Function.True);
|
|
} catch (e) { }
|
this.mapObject.HideDashboard();
|
if(typeof this.mapObject.SetAnimationEnabled == "function") {
|
this.mapObject.SetAnimationEnabled(this.animationEnabled);
|
}
|
}
|
|
//can we do smooth panning? this is an unpublished method, so we need
|
// to be careful
|
if ( !this.mapObject ||
|
!this.mapObject.vemapcontrol ||
|
!this.mapObject.vemapcontrol.PanMap ||
|
(typeof this.mapObject.vemapcontrol.PanMap != "function")) {
|
|
this.dragPanMapObject = null;
|
}
|
|
},
|
|
/**
|
* Method: onMapResize
|
*/
|
onMapResize: function() {
|
this.mapObject.Resize(this.map.size.w, this.map.size.h);
|
},
|
|
/**
|
* APIMethod: getWarningHTML
|
*
|
* Returns:
|
* {String} String with information on why layer is broken, how to get
|
* it working.
|
*/
|
getWarningHTML:function() {
|
return OpenLayers.i18n(
|
"getLayerWarning", {'layerType':'VE', 'layerLib':'VirtualEarth'}
|
);
|
},
|
|
|
|
/************************************
|
* *
|
* MapObject Interface Controls *
|
* *
|
************************************/
|
|
|
// Get&Set Center, Zoom
|
|
/**
|
* APIMethod: setMapObjectCenter
|
* Set the mapObject to the specified center and zoom
|
*
|
* Parameters:
|
* center - {Object} MapObject LonLat format
|
* zoom - {int} MapObject zoom format
|
*/
|
setMapObjectCenter: function(center, zoom) {
|
this.mapObject.SetCenterAndZoom(center, zoom);
|
},
|
|
/**
|
* APIMethod: getMapObjectCenter
|
*
|
* Returns:
|
* {Object} The mapObject's current center in Map Object format
|
*/
|
getMapObjectCenter: function() {
|
return this.mapObject.GetCenter();
|
},
|
|
/**
|
* APIMethod: dragPanMapObject
|
*
|
* Parameters:
|
* dX - {Integer}
|
* dY - {Integer}
|
*/
|
dragPanMapObject: function(dX, dY) {
|
this.mapObject.vemapcontrol.PanMap(dX, -dY);
|
},
|
|
/**
|
* APIMethod: getMapObjectZoom
|
*
|
* Returns:
|
* {Integer} The mapObject's current zoom, in Map Object format
|
*/
|
getMapObjectZoom: function() {
|
return this.mapObject.GetZoomLevel();
|
},
|
|
|
// LonLat - Pixel Translation
|
|
/**
|
* APIMethod: getMapObjectLonLatFromMapObjectPixel
|
*
|
* Parameters:
|
* moPixel - {Object} MapObject Pixel format
|
*
|
* Returns:
|
* {Object} MapObject LonLat translated from MapObject Pixel
|
*/
|
getMapObjectLonLatFromMapObjectPixel: function(moPixel) {
|
//the conditional here is to test if we are running the v6 of VE
|
return (typeof VEPixel != 'undefined')
|
? this.mapObject.PixelToLatLong(moPixel)
|
: this.mapObject.PixelToLatLong(moPixel.x, moPixel.y);
|
},
|
|
/**
|
* APIMethod: getMapObjectPixelFromMapObjectLonLat
|
*
|
* Parameters:
|
* moLonLat - {Object} MapObject LonLat format
|
*
|
* Returns:
|
* {Object} MapObject Pixel transtlated from MapObject LonLat
|
*/
|
getMapObjectPixelFromMapObjectLonLat: function(moLonLat) {
|
return this.mapObject.LatLongToPixel(moLonLat);
|
},
|
|
|
/************************************
|
* *
|
* MapObject Primitives *
|
* *
|
************************************/
|
|
|
// LonLat
|
|
/**
|
* APIMethod: getLongitudeFromMapObjectLonLat
|
*
|
* Parameters:
|
* moLonLat - {Object} MapObject LonLat format
|
*
|
* Returns:
|
* {Float} Longitude of the given MapObject LonLat
|
*/
|
getLongitudeFromMapObjectLonLat: function(moLonLat) {
|
return this.sphericalMercator ?
|
this.forwardMercator(moLonLat.Longitude, moLonLat.Latitude).lon :
|
moLonLat.Longitude;
|
},
|
|
/**
|
* APIMethod: getLatitudeFromMapObjectLonLat
|
*
|
* Parameters:
|
* moLonLat - {Object} MapObject LonLat format
|
*
|
* Returns:
|
* {Float} Latitude of the given MapObject LonLat
|
*/
|
getLatitudeFromMapObjectLonLat: function(moLonLat) {
|
return this.sphericalMercator ?
|
this.forwardMercator(moLonLat.Longitude, moLonLat.Latitude).lat :
|
moLonLat.Latitude;
|
},
|
|
/**
|
* APIMethod: getMapObjectLonLatFromLonLat
|
*
|
* Parameters:
|
* lon - {Float}
|
* lat - {Float}
|
*
|
* Returns:
|
* {Object} MapObject LonLat built from lon and lat params
|
*/
|
getMapObjectLonLatFromLonLat: function(lon, lat) {
|
var veLatLong;
|
if(this.sphericalMercator) {
|
var lonlat = this.inverseMercator(lon, lat);
|
veLatLong = new VELatLong(lonlat.lat, lonlat.lon);
|
} else {
|
veLatLong = new VELatLong(lat, lon);
|
}
|
return veLatLong;
|
},
|
|
// Pixel
|
|
/**
|
* APIMethod: getXFromMapObjectPixel
|
*
|
* Parameters:
|
* moPixel - {Object} MapObject Pixel format
|
*
|
* Returns:
|
* {Integer} X value of the MapObject Pixel
|
*/
|
getXFromMapObjectPixel: function(moPixel) {
|
return moPixel.x;
|
},
|
|
/**
|
* APIMethod: getYFromMapObjectPixel
|
*
|
* Parameters:
|
* moPixel - {Object} MapObject Pixel format
|
*
|
* Returns:
|
* {Integer} Y value of the MapObject Pixel
|
*/
|
getYFromMapObjectPixel: function(moPixel) {
|
return moPixel.y;
|
},
|
|
/**
|
* APIMethod: getMapObjectPixelFromXY
|
*
|
* Parameters:
|
* x - {Integer}
|
* y - {Integer}
|
*
|
* Returns:
|
* {Object} MapObject Pixel from x and y parameters
|
*/
|
getMapObjectPixelFromXY: function(x, y) {
|
//the conditional here is to test if we are running the v6 of VE
|
return (typeof VEPixel != 'undefined') ? new VEPixel(x, y)
|
: new Msn.VE.Pixel(x, y);
|
},
|
|
CLASS_NAME: "OpenLayers.Layer.VirtualEarth"
|
});
|
|
/*
|
* Copyright 2007, Google Inc.
|
*
|
* Redistribution and use in source and binary forms, with or without
|
* modification, are permitted provided that the following conditions are met:
|
*
|
* 1. Redistributions of source code must retain the above copyright notice,
|
* this list of conditions and the following disclaimer.
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
* this list of conditions and the following disclaimer in the documentation
|
* and/or other materials provided with the distribution.
|
* 3. Neither the name of Google Inc. nor the names of its contributors may be
|
* used to endorse or promote products derived from this software without
|
* specific prior written permission.
|
*
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
*
|
* Sets up google.gears.*, which is *the only* supported way to access Gears.
|
*
|
* Circumvent this file at your own risk!
|
*
|
* In the future, Gears may automatically define google.gears.* without this
|
* file. Gears may use these objects to transparently fix bugs and compatibility
|
* issues. Applications that use the code below will continue to work seamlessly
|
* when that happens.
|
*/
|
|
(function() {
|
// We are already defined. Hooray!
|
if (window.google && google.gears) {
|
return;
|
}
|
|
var factory = null;
|
|
// Firefox
|
if (typeof GearsFactory != 'undefined') {
|
factory = new GearsFactory();
|
} else {
|
// IE
|
try {
|
factory = new ActiveXObject('Gears.Factory');
|
// privateSetGlobalObject is only required and supported on WinCE.
|
if (factory.getBuildInfo().indexOf('ie_mobile') != -1) {
|
factory.privateSetGlobalObject(this);
|
}
|
} catch (e) {
|
// Safari
|
if ((typeof navigator.mimeTypes != 'undefined')
|
&& navigator.mimeTypes["application/x-googlegears"]) {
|
factory = document.createElement("object");
|
factory.style.display = "none";
|
factory.width = 0;
|
factory.height = 0;
|
factory.type = "application/x-googlegears";
|
document.documentElement.appendChild(factory);
|
}
|
}
|
}
|
|
// *Do not* define any objects if Gears is not installed. This mimics the
|
// behavior of Gears defining the objects in the future.
|
if (!factory) {
|
return;
|
}
|
|
// Now set up the objects, being careful not to overwrite anything.
|
//
|
// Note: In Internet Explorer for Windows Mobile, you can't add properties to
|
// the window object. However, global objects are automatically added as
|
// properties of the window object in all browsers.
|
if (!window.google) {
|
google = {};
|
}
|
|
if (!google.gears) {
|
google.gears = {factory: factory};
|
}
|
})();
|
|
/**
|
* Class: OpenLayers.Protocol.SQL
|
* Abstract SQL protocol class. Not to be instantiated directly. Use
|
* one of the SQL protocol subclasses instead.
|
*
|
* Inherits from:
|
* - <OpenLayers.Protocol>
|
*/
|
OpenLayers.Protocol.SQL = OpenLayers.Class(OpenLayers.Protocol, {
|
|
/**
|
* APIProperty: databaseName
|
* {String}
|
*/
|
databaseName: 'ol',
|
|
/**
|
* APIProperty: tableName
|
* Name of the database table into which Features should be saved.
|
*/
|
tableName: "ol_vector_features",
|
|
/**
|
* Property: postReadFiltering
|
* {Boolean} Whether the filter (if there's one) must be applied after
|
* the features have been read from the database; for example the
|
* BBOX strategy passes the read method a BBOX spatial filter, if
|
* postReadFiltering is true every feature read from the database
|
* will go through the BBOX spatial filter, which can be costly;
|
* defaults to true.
|
*/
|
postReadFiltering: true,
|
|
/**
|
* Constructor: OpenLayers.Protocol.SQL
|
*/
|
initialize: function(options) {
|
OpenLayers.Protocol.prototype.initialize.apply(this, [options]);
|
},
|
|
/**
|
* APIMethod: destroy
|
* Clean up the protocol.
|
*/
|
destroy: function() {
|
OpenLayers.Protocol.prototype.destroy.apply(this);
|
},
|
|
/**
|
* APIMethod: supported
|
* This should be overridden by specific subclasses
|
*
|
* Returns:
|
* {Boolean} Whether or not the browser supports the SQL backend
|
*/
|
supported: function() {
|
return false;
|
},
|
|
/**
|
* Method: evaluateFilter
|
* If postReadFiltering is true evaluate the filter against the feature
|
* and return the result of the evaluation, otherwise return true.
|
*
|
* Parameters:
|
* {<OpenLayers.Feature.Vector>} The feature.
|
* {<OpenLayers.Filter>} The filter.
|
*
|
* Returns:
|
* {Boolean} true if postReadFiltering if false, the result of the
|
* filter evaluation otherwise.
|
*/
|
evaluateFilter: function(feature, filter) {
|
return filter && this.postReadFiltering ?
|
filter.evaluate(feature) : true;
|
},
|
|
CLASS_NAME: "OpenLayers.Protocol.SQL"
|
});
|
|
/**
|
* Class: OpenLayers.Protocol.SQL.Gears
|
* This Protocol stores feature in the browser via the Gears Database module
|
* <http://code.google.com/apis/gears/api_database.html>.
|
*
|
* The main advantage is that all the read, create, update and delete operations
|
* can be done offline.
|
*
|
* Inherits from:
|
* - <OpenLayers.Protocol.SQL>
|
*/
|
OpenLayers.Protocol.SQL.Gears = OpenLayers.Class(OpenLayers.Protocol.SQL, {
|
|
/**
|
* Property: FID_PREFIX
|
* {String}
|
*/
|
FID_PREFIX: '__gears_fid__',
|
|
/**
|
* Property: NULL_GEOMETRY
|
* {String}
|
*/
|
NULL_GEOMETRY: '__gears_null_geometry__',
|
|
/**
|
* Property: NULL_FEATURE_STATE
|
* {String}
|
*/
|
NULL_FEATURE_STATE: '__gears_null_feature_state__',
|
|
/**
|
* Property: jsonParser
|
* {<OpenLayers.Format.JSON>}
|
*/
|
jsonParser: null,
|
|
/**
|
* Property: wktParser
|
* {<OpenLayers.Format.WKT>}
|
*/
|
wktParser: null,
|
|
/**
|
* Property: fidRegExp
|
* {RegExp} Regular expression to know whether a feature was
|
* created in offline mode.
|
*/
|
fidRegExp: null,
|
|
/**
|
* Property: saveFeatureState
|
* {Boolean} Whether to save the feature state (<OpenLayers.State>)
|
* into the database, defaults to true.
|
*/
|
saveFeatureState: true,
|
|
/**
|
* Property: typeOfFid
|
* {String} The type of the feature identifier, either "number" or
|
* "string", defaults to "string".
|
*/
|
typeOfFid: "string",
|
|
/**
|
* Property: db
|
* {GearsDatabase}
|
*/
|
db: null,
|
|
/**
|
* Constructor: OpenLayers.Protocol.SQL.Gears
|
*/
|
initialize: function(options) {
|
if (!this.supported()) {
|
return;
|
}
|
OpenLayers.Protocol.SQL.prototype.initialize.apply(this, [options]);
|
this.jsonParser = new OpenLayers.Format.JSON();
|
this.wktParser = new OpenLayers.Format.WKT();
|
|
this.fidRegExp = new RegExp('^' + this.FID_PREFIX);
|
this.initializeDatabase();
|
|
|
},
|
|
/**
|
* Method: initializeDatabase
|
*/
|
initializeDatabase: function() {
|
this.db = google.gears.factory.create('beta.database');
|
this.db.open(this.databaseName);
|
this.db.execute(
|
"CREATE TABLE IF NOT EXISTS " + this.tableName +
|
" (fid TEXT UNIQUE, geometry TEXT, properties TEXT," +
|
" state TEXT)");
|
},
|
|
/**
|
* APIMethod: destroy
|
* Clean up the protocol.
|
*/
|
destroy: function() {
|
this.db.close();
|
this.db = null;
|
|
this.jsonParser = null;
|
this.wktParser = null;
|
|
OpenLayers.Protocol.SQL.prototype.destroy.apply(this);
|
},
|
|
/**
|
* APIMethod: supported
|
* Determine whether a browser supports Gears
|
*
|
* Returns:
|
* {Boolean} The browser supports Gears
|
*/
|
supported: function() {
|
return !!(window.google && google.gears);
|
},
|
|
/**
|
* APIMethod: read
|
* Read all features from the database and return a
|
* <OpenLayers.Protocol.Response> instance. If the options parameter
|
* contains a callback attribute, the function is called with the response
|
* as a parameter.
|
*
|
* Parameters:
|
* options - {Object} Optional object for configuring the request; it
|
* can have the {Boolean} property "noFeatureStateReset" which
|
* specifies if the state of features read from the Gears
|
* database must be reset to null, if "noFeatureStateReset"
|
* is undefined or false then each feature's state is reset
|
* to null, if "noFeatureStateReset" is true the feature state
|
* is preserved.
|
*
|
* Returns:
|
* {<OpenLayers.Protocol.Response>} An <OpenLayers.Protocol.Response>
|
* object.
|
*/
|
read: function(options) {
|
OpenLayers.Protocol.prototype.read.apply(this, arguments);
|
options = OpenLayers.Util.applyDefaults(options, this.options);
|
|
var feature, features = [];
|
var rs = this.db.execute("SELECT * FROM " + this.tableName);
|
while (rs.isValidRow()) {
|
feature = this.unfreezeFeature(rs);
|
if (this.evaluateFilter(feature, options.filter)) {
|
if (!options.noFeatureStateReset) {
|
feature.state = null;
|
}
|
features.push(feature);
|
}
|
rs.next();
|
}
|
rs.close();
|
|
var resp = new OpenLayers.Protocol.Response({
|
code: OpenLayers.Protocol.Response.SUCCESS,
|
requestType: "read",
|
features: features
|
});
|
|
if (options && options.callback) {
|
options.callback.call(options.scope, resp);
|
}
|
|
return resp;
|
},
|
|
/**
|
* Method: unfreezeFeature
|
*
|
* Parameters:
|
* row - {ResultSet}
|
*
|
* Returns:
|
* {<OpenLayers.Feature.Vector>}
|
*/
|
unfreezeFeature: function(row) {
|
var feature;
|
var wkt = row.fieldByName('geometry');
|
if (wkt == this.NULL_GEOMETRY) {
|
feature = new OpenLayers.Feature.Vector();
|
} else {
|
feature = this.wktParser.read(wkt);
|
}
|
|
feature.attributes = this.jsonParser.read(
|
row.fieldByName('properties'));
|
|
feature.fid = this.extractFidFromField(row.fieldByName('fid'));
|
|
var state = row.fieldByName('state');
|
if (state == this.NULL_FEATURE_STATE) {
|
state = null;
|
}
|
feature.state = state;
|
|
return feature;
|
},
|
|
/**
|
* Method: extractFidFromField
|
*
|
* Parameters:
|
* field - {String}
|
*
|
* Returns
|
* {String} or {Number} The fid.
|
*/
|
extractFidFromField: function(field) {
|
if (!field.match(this.fidRegExp) && this.typeOfFid == "number") {
|
field = parseFloat(field);
|
}
|
return field;
|
},
|
|
/**
|
* APIMethod: create
|
* Create new features into the database.
|
*
|
* Parameters:
|
* features - {Array({<OpenLayers.Feature.Vector>})} or
|
* {<OpenLayers.Feature.Vector>} The features to create in
|
* the database.
|
* options - {Object} Optional object for configuring the request.
|
*
|
* Returns:
|
* {<OpenLayers.Protocol.Response>} An <OpenLayers.Protocol.Response>
|
* object.
|
*/
|
create: function(features, options) {
|
options = OpenLayers.Util.applyDefaults(options, this.options);
|
|
var resp = this.createOrUpdate(features);
|
resp.requestType = "create";
|
|
if (options && options.callback) {
|
options.callback.call(options.scope, resp);
|
}
|
|
return resp;
|
},
|
|
/**
|
* APIMethod: update
|
* Construct a request updating modified feature.
|
*
|
* Parameters:
|
* features - {Array({<OpenLayers.Feature.Vector>})} or
|
* {<OpenLayers.Feature.Vector>} The features to update in
|
* the database.
|
* options - {Object} Optional object for configuring the request.
|
*
|
* Returns:
|
* {<OpenLayers.Protocol.Response>} An <OpenLayers.Protocol.Response>
|
* object.
|
*/
|
update: function(features, options) {
|
options = OpenLayers.Util.applyDefaults(options, this.options);
|
|
var resp = this.createOrUpdate(features);
|
resp.requestType = "update";
|
|
if (options && options.callback) {
|
options.callback.call(options.scope, resp);
|
}
|
|
return resp;
|
},
|
|
/**
|
* Method: createOrUpdate
|
* Construct a request for updating or creating features in the
|
* database.
|
*
|
* Parameters:
|
* features - {Array({<OpenLayers.Feature.Vector>})} or
|
* {<OpenLayers.Feature.Vector>} The feature to create or update
|
* in the database.
|
*
|
* Returns:
|
* {<OpenLayers.Protocol.Response>} An <OpenLayers.Protocol.Response>
|
* object.
|
*/
|
createOrUpdate: function(features) {
|
if (!(OpenLayers.Util.isArray(features))) {
|
features = [features];
|
}
|
|
var i, len = features.length, feature;
|
var insertedFeatures = new Array(len);
|
|
for (i = 0; i < len; i++) {
|
feature = features[i];
|
var params = this.freezeFeature(feature);
|
this.db.execute(
|
"REPLACE INTO " + this.tableName +
|
" (fid, geometry, properties, state)" +
|
" VALUES (?, ?, ?, ?)",
|
params);
|
|
var clone = feature.clone();
|
clone.fid = this.extractFidFromField(params[0]);
|
insertedFeatures[i] = clone;
|
}
|
|
return new OpenLayers.Protocol.Response({
|
code: OpenLayers.Protocol.Response.SUCCESS,
|
features: insertedFeatures,
|
reqFeatures: features
|
});
|
},
|
|
/**
|
* Method: freezeFeature
|
*
|
* Parameters:
|
* feature - {<OpenLayers.Feature.Vector>}
|
* state - {String} The feature state to store in the database.
|
*
|
* Returns:
|
* {Array}
|
*/
|
freezeFeature: function(feature) {
|
// 2 notes:
|
// - fid might not be a string
|
// - getFeatureStateForFreeze needs the feature fid to it's stored
|
// in the feature here
|
feature.fid = feature.fid != null ?
|
"" + feature.fid : OpenLayers.Util.createUniqueID(this.FID_PREFIX);
|
|
var geometry = feature.geometry != null ?
|
feature.geometry.toString() : this.NULL_GEOMETRY;
|
|
var properties = this.jsonParser.write(feature.attributes);
|
|
var state = this.getFeatureStateForFreeze(feature);
|
|
return [feature.fid, geometry, properties, state];
|
},
|
|
/**
|
* Method: getFeatureStateForFreeze
|
* Get the state of the feature to store into the database.
|
*
|
* Parameters:
|
* feature - {<OpenLayers.Feature.Vector>} The feature.
|
*
|
* Returns
|
* {String} The state
|
*/
|
getFeatureStateForFreeze: function(feature) {
|
var state;
|
if (!this.saveFeatureState) {
|
state = this.NULL_FEATURE_STATE;
|
} else if (this.createdOffline(feature)) {
|
// if the feature was created in offline mode, its
|
// state must remain INSERT
|
state = OpenLayers.State.INSERT;
|
} else {
|
state = feature.state;
|
}
|
return state;
|
},
|
|
/**
|
* APIMethod: delete
|
* Delete features from the database.
|
*
|
* Parameters:
|
* features - {Array({<OpenLayers.Feature.Vector>})} or
|
* {<OpenLayers.Feature.Vector>}
|
* options - {Object} Optional object for configuring the request.
|
* This object is modified and should not be reused.
|
*
|
* Returns:
|
* {<OpenLayers.Protocol.Response>} An <OpenLayers.Protocol.Response>
|
* object.
|
*/
|
"delete": function(features, options) {
|
if (!(OpenLayers.Util.isArray(features))) {
|
features = [features];
|
}
|
|
options = OpenLayers.Util.applyDefaults(options, this.options);
|
|
var i, len, feature;
|
for (i = 0, len = features.length; i < len; i++) {
|
feature = features[i];
|
|
// if saveFeatureState is set to true and if the feature wasn't created
|
// in offline mode we don't delete it in the database but just update
|
// it state column
|
if (this.saveFeatureState && !this.createdOffline(feature)) {
|
var toDelete = feature.clone();
|
toDelete.fid = feature.fid;
|
if (toDelete.geometry) {
|
toDelete.geometry.destroy();
|
toDelete.geometry = null;
|
}
|
toDelete.state = feature.state;
|
this.createOrUpdate(toDelete);
|
} else {
|
this.db.execute(
|
"DELETE FROM " + this.tableName +
|
" WHERE fid = ?", [feature.fid]);
|
}
|
}
|
|
var resp = new OpenLayers.Protocol.Response({
|
code: OpenLayers.Protocol.Response.SUCCESS,
|
requestType: "delete",
|
reqFeatures: features
|
});
|
|
if (options && options.callback) {
|
options.callback.call(options.scope, resp);
|
}
|
|
return resp;
|
},
|
|
/**
|
* Method: createdOffline
|
* Returns true if the feature had a feature id when it was created in
|
* the Gears database, false otherwise; this is determined by
|
* checking the form of the feature's fid value.
|
*
|
* Parameters:
|
* feature - {<OpenLayers.Feature.Vector>}
|
*
|
* Returns:
|
* {Boolean}
|
*/
|
createdOffline: function(feature) {
|
return (typeof feature.fid == "string" &&
|
!!(feature.fid.match(this.fidRegExp)));
|
},
|
|
/**
|
* APIMethod: commit
|
* Go over the features and for each take action
|
* based on the feature state. Possible actions are create,
|
* update and delete.
|
*
|
* Parameters:
|
* features - {Array({<OpenLayers.Feature.Vector>})}
|
* options - {Object} Object whose possible keys are "create", "update",
|
* "delete", "callback" and "scope", the values referenced by the
|
* first three are objects as passed to the "create", "update", and
|
* "delete" methods, the value referenced by the "callback" key is
|
* a function which is called when the commit operation is complete
|
* using the scope referenced by the "scope" key.
|
*
|
* Returns:
|
* {Array({<OpenLayers.Protocol.Response>})} An array of
|
* <OpenLayers.Protocol.Response> objects, one per request made
|
* to the database.
|
*/
|
commit: function(features, options) {
|
var opt, resp = [], nRequests = 0, nResponses = 0;
|
|
function callback(resp) {
|
if (++nResponses < nRequests) {
|
resp.last = false;
|
}
|
this.callUserCallback(options, resp);
|
}
|
|
var feature, toCreate = [], toUpdate = [], toDelete = [];
|
for (var i = features.length - 1; i >= 0; i--) {
|
feature = features[i];
|
switch (feature.state) {
|
case OpenLayers.State.INSERT:
|
toCreate.push(feature);
|
break;
|
case OpenLayers.State.UPDATE:
|
toUpdate.push(feature);
|
break;
|
case OpenLayers.State.DELETE:
|
toDelete.push(feature);
|
break;
|
}
|
}
|
if (toCreate.length > 0) {
|
nRequests++;
|
opt = OpenLayers.Util.applyDefaults(
|
{"callback": callback, "scope": this},
|
options.create
|
);
|
resp.push(this.create(toCreate, opt));
|
}
|
if (toUpdate.length > 0) {
|
nRequests++;
|
opt = OpenLayers.Util.applyDefaults(
|
{"callback": callback, "scope": this},
|
options.update
|
);
|
resp.push(this.update(toUpdate, opt));
|
}
|
if (toDelete.length > 0) {
|
nRequests++;
|
opt = OpenLayers.Util.applyDefaults(
|
{"callback": callback, "scope": this},
|
options["delete"]
|
);
|
resp.push(this["delete"](toDelete, opt));
|
}
|
|
return resp;
|
},
|
|
/**
|
* Method: clear
|
* Removes all rows of the table.
|
*/
|
clear: function() {
|
this.db.execute("DELETE FROM " + this.tableName);
|
},
|
|
/**
|
* Method: callUserCallback
|
* This method is called from within commit each time a request is made
|
* to the database, it is responsible for calling the user-supplied
|
* callbacks.
|
*
|
* Parameters:
|
* options - {Object} The map of options passed to the commit call.
|
* resp - {<OpenLayers.Protocol.Response>}
|
*/
|
callUserCallback: function(options, resp) {
|
var opt = options[resp.requestType];
|
if (opt && opt.callback) {
|
opt.callback.call(opt.scope, resp);
|
}
|
if (resp.last && options.callback) {
|
options.callback.call(options.scope);
|
}
|
},
|
|
CLASS_NAME: "OpenLayers.Protocol.SQL.Gears"
|
});
|
|
/**
|
* Class: OpenLayers.Layer.Yahoo
|
*
|
* Inherits from:
|
* - <OpenLayers.Layer.EventPane>
|
* - <OpenLayers.Layer.FixedZoomLevels>
|
*/
|
OpenLayers.Layer.Yahoo = OpenLayers.Class(
|
OpenLayers.Layer.EventPane, OpenLayers.Layer.FixedZoomLevels, {
|
|
/**
|
* Constant: MIN_ZOOM_LEVEL
|
* {Integer} 0
|
*/
|
MIN_ZOOM_LEVEL: 0,
|
|
/**
|
* Constant: MAX_ZOOM_LEVEL
|
* {Integer} 17
|
*/
|
MAX_ZOOM_LEVEL: 17,
|
|
/**
|
* Constant: RESOLUTIONS
|
* {Array(Float)} Hardcode these resolutions so that they are more closely
|
* tied with the standard wms projection
|
*/
|
RESOLUTIONS: [
|
1.40625,
|
0.703125,
|
0.3515625,
|
0.17578125,
|
0.087890625,
|
0.0439453125,
|
0.02197265625,
|
0.010986328125,
|
0.0054931640625,
|
0.00274658203125,
|
0.001373291015625,
|
0.0006866455078125,
|
0.00034332275390625,
|
0.000171661376953125,
|
0.0000858306884765625,
|
0.00004291534423828125,
|
0.00002145767211914062,
|
0.00001072883605957031
|
],
|
|
/**
|
* APIProperty: type
|
* {YahooMapType}
|
*/
|
type: null,
|
|
/**
|
* APIProperty: wrapDateLine
|
* {Boolean} Allow user to pan forever east/west. Default is true.
|
* Setting this to false only restricts panning if
|
* <sphericalMercator> is true.
|
*/
|
wrapDateLine: true,
|
|
/**
|
* APIProperty: sphericalMercator
|
* {Boolean} Should the map act as a mercator-projected map? This will
|
* cause all interactions with the map to be in the actual map projection,
|
* which allows support for vector drawing, overlaying other maps, etc.
|
*/
|
sphericalMercator: false,
|
|
/**
|
* Constructor: OpenLayers.Layer.Yahoo
|
*
|
* Parameters:
|
* name - {String}
|
* options - {Object}
|
*/
|
initialize: function(name, options) {
|
OpenLayers.Layer.EventPane.prototype.initialize.apply(this, arguments);
|
OpenLayers.Layer.FixedZoomLevels.prototype.initialize.apply(this,
|
arguments);
|
if(this.sphericalMercator) {
|
OpenLayers.Util.extend(this, OpenLayers.Layer.SphericalMercator);
|
this.initMercatorParameters();
|
}
|
},
|
|
/**
|
* Method: loadMapObject
|
*/
|
loadMapObject:function() {
|
try { //do not crash!
|
var size = this.getMapObjectSizeFromOLSize(this.map.getSize());
|
this.mapObject = new YMap(this.div, this.type, size);
|
this.mapObject.disableKeyControls();
|
this.mapObject.disableDragMap();
|
|
//can we do smooth panning? (moveByXY is not an API function)
|
if ( !this.mapObject.moveByXY ||
|
(typeof this.mapObject.moveByXY != "function" ) ) {
|
|
this.dragPanMapObject = null;
|
}
|
} catch(e) {}
|
},
|
|
/**
|
* Method: onMapResize
|
*
|
*/
|
onMapResize: function() {
|
try {
|
var size = this.getMapObjectSizeFromOLSize(this.map.getSize());
|
this.mapObject.resizeTo(size);
|
} catch(e) {}
|
},
|
|
|
/**
|
* APIMethod: setMap
|
* Overridden from EventPane because we need to remove this yahoo event
|
* pane which prohibits our drag and drop, and we can only do this
|
* once the map has been loaded and centered.
|
*
|
* Parameters:
|
* map - {<OpenLayers.Map>}
|
*/
|
setMap: function(map) {
|
OpenLayers.Layer.EventPane.prototype.setMap.apply(this, arguments);
|
|
this.map.events.register("moveend", this, this.fixYahooEventPane);
|
},
|
|
/**
|
* Method: fixYahooEventPane
|
* The map has been centered, so the mysterious yahoo eventpane has been
|
* added. we remove it so that it doesnt mess with *our* event pane.
|
*/
|
fixYahooEventPane: function() {
|
var yahooEventPane = OpenLayers.Util.getElement("ygddfdiv");
|
if (yahooEventPane != null) {
|
if (yahooEventPane.parentNode != null) {
|
yahooEventPane.parentNode.removeChild(yahooEventPane);
|
}
|
this.map.events.unregister("moveend", this,
|
this.fixYahooEventPane);
|
}
|
},
|
|
/**
|
* APIMethod: getWarningHTML
|
*
|
* Returns:
|
* {String} String with information on why layer is broken, how to get
|
* it working.
|
*/
|
getWarningHTML:function() {
|
return OpenLayers.i18n(
|
"getLayerWarning", {'layerType':'Yahoo', 'layerLib':'Yahoo'}
|
);
|
},
|
|
/********************************************************/
|
/* */
|
/* Translation Functions */
|
/* */
|
/* The following functions translate GMaps and OL */
|
/* formats for Pixel, LonLat, Bounds, and Zoom */
|
/* */
|
/********************************************************/
|
|
|
//
|
// TRANSLATION: MapObject Zoom <-> OpenLayers Zoom
|
//
|
|
/**
|
* APIMethod: getOLZoomFromMapObjectZoom
|
*
|
* Parameters:
|
* gZoom - {Integer}
|
*
|
* Returns:
|
* {Integer} An OpenLayers Zoom level, translated from the passed in gZoom
|
* Returns null if null value is passed in.
|
*/
|
getOLZoomFromMapObjectZoom: function(moZoom) {
|
var zoom = null;
|
if (moZoom != null) {
|
zoom = OpenLayers.Layer.FixedZoomLevels.prototype.getOLZoomFromMapObjectZoom.apply(this, [moZoom]);
|
zoom = 18 - zoom;
|
}
|
return zoom;
|
},
|
|
/**
|
* APIMethod: getMapObjectZoomFromOLZoom
|
*
|
* Parameters:
|
* olZoom - {Integer}
|
*
|
* Returns:
|
* {Integer} A MapObject level, translated from the passed in olZoom
|
* Returns null if null value is passed in
|
*/
|
getMapObjectZoomFromOLZoom: function(olZoom) {
|
var zoom = null;
|
if (olZoom != null) {
|
zoom = OpenLayers.Layer.FixedZoomLevels.prototype.getMapObjectZoomFromOLZoom.apply(this, [olZoom]);
|
zoom = 18 - zoom;
|
}
|
return zoom;
|
},
|
|
/************************************
|
* *
|
* MapObject Interface Controls *
|
* *
|
************************************/
|
|
|
// Get&Set Center, Zoom
|
|
/**
|
* APIMethod: setMapObjectCenter
|
* Set the mapObject to the specified center and zoom
|
*
|
* Parameters:
|
* center - {Object} MapObject LonLat format
|
* zoom - {int} MapObject zoom format
|
*/
|
setMapObjectCenter: function(center, zoom) {
|
this.mapObject.drawZoomAndCenter(center, zoom);
|
},
|
|
/**
|
* APIMethod: getMapObjectCenter
|
*
|
* Returns:
|
* {Object} The mapObject's current center in Map Object format
|
*/
|
getMapObjectCenter: function() {
|
return this.mapObject.getCenterLatLon();
|
},
|
|
/**
|
* APIMethod: dragPanMapObject
|
*
|
* Parameters:
|
* dX - {Integer}
|
* dY - {Integer}
|
*/
|
dragPanMapObject: function(dX, dY) {
|
this.mapObject.moveByXY({
|
'x': -dX,
|
'y': dY
|
});
|
},
|
|
/**
|
* APIMethod: getMapObjectZoom
|
*
|
* Returns:
|
* {Integer} The mapObject's current zoom, in Map Object format
|
*/
|
getMapObjectZoom: function() {
|
return this.mapObject.getZoomLevel();
|
},
|
|
|
// LonLat - Pixel Translation
|
|
/**
|
* APIMethod: getMapObjectLonLatFromMapObjectPixel
|
*
|
* Parameters:
|
* moPixel - {Object} MapObject Pixel format
|
*
|
* Returns:
|
* {Object} MapObject LonLat translated from MapObject Pixel
|
*/
|
getMapObjectLonLatFromMapObjectPixel: function(moPixel) {
|
return this.mapObject.convertXYLatLon(moPixel);
|
},
|
|
/**
|
* APIMethod: getMapObjectPixelFromMapObjectLonLat
|
*
|
* Parameters:
|
* moLonLat - {Object} MapObject LonLat format
|
*
|
* Returns:
|
* {Object} MapObject Pixel transtlated from MapObject LonLat
|
*/
|
getMapObjectPixelFromMapObjectLonLat: function(moLonLat) {
|
return this.mapObject.convertLatLonXY(moLonLat);
|
},
|
|
|
/************************************
|
* *
|
* MapObject Primitives *
|
* *
|
************************************/
|
|
|
// LonLat
|
|
/**
|
* APIMethod: getLongitudeFromMapObjectLonLat
|
*
|
* Parameters:
|
* moLonLat - {Object} MapObject LonLat format
|
*
|
* Returns:
|
* {Float} Longitude of the given MapObject LonLat
|
*/
|
getLongitudeFromMapObjectLonLat: function(moLonLat) {
|
return this.sphericalMercator ?
|
this.forwardMercator(moLonLat.Lon, moLonLat.Lat).lon :
|
moLonLat.Lon;
|
},
|
|
/**
|
* APIMethod: getLatitudeFromMapObjectLonLat
|
*
|
* Parameters:
|
* moLonLat - {Object} MapObject LonLat format
|
*
|
* Returns:
|
* {Float} Latitude of the given MapObject LonLat
|
*/
|
getLatitudeFromMapObjectLonLat: function(moLonLat) {
|
return this.sphericalMercator ?
|
this.forwardMercator(moLonLat.Lon, moLonLat.Lat).lat :
|
moLonLat.Lat;
|
},
|
|
/**
|
* APIMethod: getMapObjectLonLatFromLonLat
|
*
|
* Parameters:
|
* lon - {Float}
|
* lat - {Float}
|
*
|
* Returns:
|
* {Object} MapObject LonLat built from lon and lat params
|
*/
|
getMapObjectLonLatFromLonLat: function(lon, lat) {
|
var yLatLong;
|
if(this.sphericalMercator) {
|
var lonlat = this.inverseMercator(lon, lat);
|
yLatLong = new YGeoPoint(lonlat.lat, lonlat.lon);
|
} else {
|
yLatLong = new YGeoPoint(lat, lon);
|
}
|
return yLatLong;
|
},
|
|
// Pixel
|
|
/**
|
* APIMethod: getXFromMapObjectPixel
|
*
|
* Parameters:
|
* moPixel - {Object} MapObject Pixel format
|
*
|
* Returns:
|
* {Integer} X value of the MapObject Pixel
|
*/
|
getXFromMapObjectPixel: function(moPixel) {
|
return moPixel.x;
|
},
|
|
/**
|
* APIMethod: getYFromMapObjectPixel
|
*
|
* Parameters:
|
* moPixel - {Object} MapObject Pixel format
|
*
|
* Returns:
|
* {Integer} Y value of the MapObject Pixel
|
*/
|
getYFromMapObjectPixel: function(moPixel) {
|
return moPixel.y;
|
},
|
|
/**
|
* APIMethod: getMapObjectPixelFromXY
|
*
|
* Parameters:
|
* x - {Integer}
|
* y - {Integer}
|
*
|
* Returns:
|
* {Object} MapObject Pixel from x and y parameters
|
*/
|
getMapObjectPixelFromXY: function(x, y) {
|
return new YCoordPoint(x, y);
|
},
|
|
// Size
|
|
/**
|
* APIMethod: getMapObjectSizeFromOLSize
|
*
|
* Parameters:
|
* olSize - {<OpenLayers.Size>}
|
*
|
* Returns:
|
* {Object} MapObject Size from olSize parameter
|
*/
|
getMapObjectSizeFromOLSize: function(olSize) {
|
return new YSize(olSize.w, olSize.h);
|
},
|
|
CLASS_NAME: "OpenLayers.Layer.Yahoo"
|
});
|
|
/**
|
* Class: OpenLayers.Layer.GML
|
* Create a vector layer by parsing a GML file. The GML file is
|
* passed in as a parameter.
|
* *Deprecated*. To be removed in 3.0. Instead use OpenLayers.Layer.Vector
|
* with Protocol.HTTP and Strategy.Fixed. Provide the protocol with a
|
* format parameter to get the parser you want for your data.
|
*
|
* Inherits from:
|
* - <OpenLayers.Layer.Vector>
|
*/
|
OpenLayers.Layer.GML = OpenLayers.Class(OpenLayers.Layer.Vector, {
|
|
/**
|
* Property: loaded
|
* {Boolean} Flag for whether the GML data has been loaded yet.
|
*/
|
loaded: false,
|
|
/**
|
* APIProperty: format
|
* {<OpenLayers.Format>} The format you want the data to be parsed with.
|
*/
|
format: null,
|
|
/**
|
* APIProperty: formatOptions
|
* {Object} Hash of options which should be passed to the format when it is
|
* created. Must be passed in the constructor.
|
*/
|
formatOptions: null,
|
|
/**
|
* Constructor: OpenLayers.Layer.GML
|
* Load and parse a single file on the web, according to the format
|
* provided via the 'format' option, defaulting to GML.
|
*
|
* Parameters:
|
* name - {String}
|
* url - {String} URL of a GML file.
|
* options - {Object} Hashtable of extra options to tag onto the layer.
|
*/
|
initialize: function(name, url, options) {
|
var newArguments = [];
|
newArguments.push(name, options);
|
OpenLayers.Layer.Vector.prototype.initialize.apply(this, newArguments);
|
this.url = url;
|
},
|
|
/**
|
* APIMethod: setVisibility
|
* Set the visibility flag for the layer and hide/show&redraw accordingly.
|
* Fire event unless otherwise specified
|
* GML will be loaded if the layer is being made visible for the first
|
* time.
|
*
|
* Parameters:
|
* visible - {Boolean} Whether or not to display the layer
|
* (if in range)
|
* noEvent - {Boolean}
|
*/
|
setVisibility: function(visibility, noEvent) {
|
OpenLayers.Layer.Vector.prototype.setVisibility.apply(this, arguments);
|
if(this.visibility && !this.loaded){
|
// Load the GML
|
this.loadGML();
|
}
|
},
|
|
/**
|
* Method: moveTo
|
* If layer is visible and GML has not been loaded, load GML, then load GML
|
* and call OpenLayers.Layer.Vector.moveTo() to redraw at the new location.
|
*
|
* Parameters:
|
* bounds - {Object}
|
* zoomChanged - {Object}
|
* minor - {Object}
|
*/
|
moveTo:function(bounds, zoomChanged, minor) {
|
OpenLayers.Layer.Vector.prototype.moveTo.apply(this, arguments);
|
// Wait until initialisation is complete before loading GML
|
// otherwise we can get a race condition where the root HTML DOM is
|
// loaded after the GML is paited.
|
// See http://trac.openlayers.org/ticket/404
|
if(this.visibility && !this.loaded){
|
this.loadGML();
|
}
|
},
|
|
/**
|
* Method: loadGML
|
*/
|
loadGML: function() {
|
if (!this.loaded) {
|
this.events.triggerEvent("loadstart");
|
OpenLayers.Request.GET({
|
url: this.url,
|
success: this.requestSuccess,
|
failure: this.requestFailure,
|
scope: this
|
});
|
this.loaded = true;
|
}
|
},
|
|
/**
|
* Method: setUrl
|
* Change the URL and reload the GML
|
*
|
* Parameters:
|
* url - {String} URL of a GML file.
|
*/
|
setUrl:function(url) {
|
this.url = url;
|
this.destroyFeatures();
|
this.loaded = false;
|
this.loadGML();
|
},
|
|
/**
|
* Method: requestSuccess
|
* Process GML after it has been loaded.
|
* Called by initialize() and loadUrl() after the GML has been loaded.
|
*
|
* Parameters:
|
* request - {String}
|
*/
|
requestSuccess:function(request) {
|
var doc = request.responseXML;
|
|
if (!doc || !doc.documentElement) {
|
doc = request.responseText;
|
}
|
|
var options = {};
|
|
OpenLayers.Util.extend(options, this.formatOptions);
|
if (this.map && !this.projection.equals(this.map.getProjectionObject())) {
|
options.externalProjection = this.projection;
|
options.internalProjection = this.map.getProjectionObject();
|
}
|
|
var gml = this.format ? new this.format(options) : new OpenLayers.Format.GML(options);
|
this.addFeatures(gml.read(doc));
|
this.events.triggerEvent("loadend");
|
},
|
|
/**
|
* Method: requestFailure
|
* Process a failed loading of GML.
|
* Called by initialize() and loadUrl() if there was a problem loading GML.
|
*
|
* Parameters:
|
* request - {String}
|
*/
|
requestFailure: function(request) {
|
OpenLayers.Console.userError('Error in loading GML file ' + this.url);
|
this.events.triggerEvent("loadend");
|
},
|
|
CLASS_NAME: "OpenLayers.Layer.GML"
|
});
|
|
/**
|
* Class: OpenLayers.Geometry.Rectangle
|
* This class is *not supported*, and probably isn't what you're looking for.
|
* Instead, most users probably want something like:
|
* (code)
|
* var poly = new OpenLayers.Bounds(0,0,10,10).toGeometry();
|
* (end)
|
* This will create a rectangular Polygon geometry.
|
*
|
* Inherits:
|
* - <OpenLayers.Geometry>
|
*/
|
|
OpenLayers.Geometry.Rectangle = OpenLayers.Class(OpenLayers.Geometry, {
|
|
/**
|
* Property: x
|
* {Float}
|
*/
|
x: null,
|
|
/**
|
* Property: y
|
* {Float}
|
*/
|
y: null,
|
|
/**
|
* Property: width
|
* {Float}
|
*/
|
width: null,
|
|
/**
|
* Property: height
|
* {Float}
|
*/
|
height: null,
|
|
/**
|
* Constructor: OpenLayers.Geometry.Rectangle
|
*
|
* Parameters:
|
* points - {Array(<OpenLayers.Geometry.Point>)}
|
*/
|
initialize: function(x, y, width, height) {
|
OpenLayers.Geometry.prototype.initialize.apply(this, arguments);
|
|
this.x = x;
|
this.y = y;
|
|
this.width = width;
|
this.height = height;
|
},
|
|
/**
|
* Method: calculateBounds
|
* Recalculate the bounds for the geometry.
|
*/
|
calculateBounds: function() {
|
this.bounds = new OpenLayers.Bounds(this.x, this.y,
|
this.x + this.width,
|
this.y + this.height);
|
},
|
|
|
/**
|
* APIMethod: getLength
|
*
|
* Returns:
|
* {Float} The length of the geometry
|
*/
|
getLength: function() {
|
var length = (2 * this.width) + (2 * this.height);
|
return length;
|
},
|
|
/**
|
* APIMethod: getArea
|
*
|
* Returns:
|
* {Float} The area of the geometry
|
*/
|
getArea: function() {
|
var area = this.width * this.height;
|
return area;
|
},
|
|
CLASS_NAME: "OpenLayers.Geometry.Rectangle"
|
});
|
|
/**
|
* Class: OpenLayers.Renderer.NG
|
*
|
* Inherits from:
|
* - <OpenLayers.Renderer.Elements>
|
*/
|
OpenLayers.Renderer.NG = OpenLayers.Class(OpenLayers.Renderer.Elements, {
|
|
/**
|
* Constant: labelNodeType
|
* {String} The node type for text label containers. To be defined by
|
* subclasses.
|
*/
|
labelNodeType: null,
|
|
/**
|
* Constructor: OpenLayers.Renderer.NG
|
*
|
* Parameters:
|
* containerID - {String}
|
* options - {Object} options for this renderer. Supported options are:
|
* * yOrdering - {Boolean} Whether to use y-ordering
|
* * zIndexing - {Boolean} Whether to use z-indexing. Will be ignored
|
* if yOrdering is set to true.
|
*/
|
|
/**
|
* Method: updateDimensions
|
* To be extended by subclasses - here we set positioning related styles
|
* on HTML elements, subclasses have to do the same for renderer specific
|
* elements (e.g. viewBox, width and height of the rendererRoot)
|
*
|
* Parameters:
|
* zoomChanged - {Boolean} Has the zoom changed? If so, subclasses may have
|
* to update feature styles/dimensions.
|
*/
|
updateDimensions: function(zoomChanged) {
|
var mapExtent = this.map.getExtent();
|
var renderExtent = mapExtent.scale(3);
|
this.setExtent(renderExtent, true);
|
var res = this.getResolution();
|
var div = this.rendererRoot.parentNode;
|
var layerLeft = parseFloat(div.parentNode.style.left);
|
var layerTop = parseFloat(div.parentNode.style.top);
|
div.style.left = ((renderExtent.left - mapExtent.left) / res - layerLeft) + "px";
|
div.style.top = ((mapExtent.top - renderExtent.top) / res - layerTop) + "px";
|
},
|
|
/**
|
* Method: resize
|
*/
|
setSize: function() {
|
this.map.getExtent() && this.updateDimensions();
|
},
|
|
/**
|
* Method: drawFeature
|
* Draw the feature. The optional style argument can be used
|
* to override the feature's own style. This method should only
|
* be called from layer.drawFeature().
|
*
|
* Parameters:
|
* feature - {<OpenLayers.Feature.Vector>}
|
* style - {<Object>}
|
*
|
* Returns:
|
* {Boolean} true if the feature has been drawn completely, false if not,
|
* undefined if the feature had no geometry
|
*/
|
drawFeature: function(feature, style) {
|
if(style == null) {
|
style = feature.style;
|
}
|
if (feature.geometry) {
|
var rendered = this.drawGeometry(feature.geometry, style, feature.id);
|
if(rendered !== false && style.label) {
|
var location = feature.geometry.getCentroid();
|
this.drawText(feature.id, style, location);
|
} else {
|
this.removeText(feature.id);
|
}
|
return rendered;
|
}
|
},
|
|
/**
|
* Method: drawText
|
* Function for drawing text labels.
|
* This method is only called by the renderer itself.
|
*
|
* Parameters:
|
* featureId - {String|DOMElement}
|
* style - {Object}
|
* location - {<OpenLayers.Geometry.Point>}, will be modified inline
|
*
|
* Returns:
|
* {DOMElement} container holding the text label (to be populated by
|
* subclasses)
|
*/
|
drawText: function(featureId, style, location) {
|
var label;
|
if (typeof featureId !== "string") {
|
label = featureId;
|
} else {
|
label = this.nodeFactory(featureId + this.LABEL_ID_SUFFIX, this.labelNodeType);
|
label._featureId = featureId;
|
}
|
label._style = style;
|
label._x = location.x;
|
label._y = location.y;
|
if(style.labelXOffset || style.labelYOffset) {
|
var xOffset = isNaN(style.labelXOffset) ? 0 : style.labelXOffset;
|
var yOffset = isNaN(style.labelYOffset) ? 0 : style.labelYOffset;
|
var res = this.getResolution();
|
location.move(xOffset*res, yOffset*res);
|
}
|
|
if(label.parentNode !== this.textRoot) {
|
this.textRoot.appendChild(label);
|
}
|
|
return label;
|
},
|
|
CLASS_NAME: "OpenLayers.Renderer.NG"
|
});
|
|
// Monkey-patching Layer.Vector for Renderer.NG support
|
(function() {
|
var moveTo = OpenLayers.Layer.Vector.prototype.moveTo;
|
OpenLayers.Layer.Vector.prototype.moveTo = function(bounds, zoomChanged, dragging) {
|
if (OpenLayers.Renderer.NG && this.renderer instanceof OpenLayers.Renderer.NG) {
|
OpenLayers.Layer.prototype.moveTo.apply(this, arguments);
|
dragging || this.renderer.updateDimensions(zoomChanged);
|
if (!this.drawn) {
|
this.drawn = true;
|
var feature;
|
for(var i=0, len=this.features.length; i<len; i++) {
|
this.renderer.locked = (i !== (len - 1));
|
feature = this.features[i];
|
this.drawFeature(feature);
|
}
|
}
|
} else {
|
moveTo.apply(this, arguments);
|
}
|
}
|
var redraw = OpenLayers.Layer.Vector.prototype.redraw;
|
OpenLayers.Layer.Vector.prototype.redraw = function() {
|
if (OpenLayers.Renderer.NG && this.renderer instanceof OpenLayers.Renderer.NG) {
|
this.drawn = false;
|
}
|
redraw.apply(this, arguments);
|
}
|
})();
|
|
/**
|
* Class: OpenLayers.Renderer.SVG2
|
*
|
* Inherits from:
|
* - <OpenLayers.Renderer.NG>
|
*/
|
OpenLayers.Renderer.SVG2 = OpenLayers.Class(OpenLayers.Renderer.NG, {
|
|
/**
|
* Property: xmlns
|
* {String}
|
*/
|
xmlns: "http://www.w3.org/2000/svg",
|
|
/**
|
* Property: xlinkns
|
* {String}
|
*/
|
xlinkns: "http://www.w3.org/1999/xlink",
|
|
/**
|
* Property: symbolMetrics
|
* {Object} Cache for symbol metrics according to their svg coordinate
|
* space. This is an object keyed by the symbol's id, and values are
|
* an object with size, x and y properties.
|
*/
|
symbolMetrics: null,
|
|
/**
|
* Constant: labelNodeType
|
* {String} The node type for text label containers.
|
*/
|
labelNodeType: "g",
|
|
/**
|
* Constructor: OpenLayers.Renderer.SVG2
|
*
|
* Parameters:
|
* containerID - {String}
|
*/
|
initialize: function(containerID) {
|
if (!this.supported()) {
|
return;
|
}
|
OpenLayers.Renderer.Elements.prototype.initialize.apply(this,
|
arguments);
|
|
this.symbolMetrics = {};
|
},
|
|
/**
|
* APIMethod: supported
|
*
|
* Returns:
|
* {Boolean} Whether or not the browser supports the SVG renderer
|
*/
|
supported: function() {
|
var svgFeature = "http://www.w3.org/TR/SVG11/feature#";
|
return (document.implementation &&
|
(document.implementation.hasFeature("org.w3c.svg", "1.0") ||
|
document.implementation.hasFeature(svgFeature + "SVG", "1.1") ||
|
document.implementation.hasFeature(svgFeature + "BasicStructure", "1.1") ));
|
},
|
|
/**
|
* Method: updateDimensions
|
*
|
* Parameters:
|
* zoomChanged - {Boolean}
|
*/
|
updateDimensions: function(zoomChanged) {
|
OpenLayers.Renderer.NG.prototype.updateDimensions.apply(this, arguments);
|
|
var res = this.getResolution();
|
|
var width = this.extent.getWidth();
|
var height = this.extent.getHeight();
|
|
var extentString = [
|
this.extent.left,
|
-this.extent.top,
|
width,
|
height
|
].join(" ");
|
this.rendererRoot.setAttributeNS(null, "viewBox", extentString);
|
this.rendererRoot.setAttributeNS(null, "width", width / res);
|
this.rendererRoot.setAttributeNS(null, "height", height / res);
|
|
if (zoomChanged === true) {
|
// update styles for the new resolution
|
var i, len;
|
var nodes = this.vectorRoot.childNodes;
|
for (i=0, len=nodes.length; i<len; ++i) {
|
this.setStyle(nodes[i]);
|
}
|
var textNodes = this.textRoot.childNodes;
|
var label;
|
for (i=0, len=textNodes.length; i<len; ++i) {
|
label = textNodes[i];
|
this.drawText(label, label._style,
|
new OpenLayers.Geometry.Point(label._x, label._y)
|
);
|
}
|
}
|
},
|
|
/**
|
* Method: getNodeType
|
*
|
* Parameters:
|
* geometry - {<OpenLayers.Geometry>}
|
* style - {Object}
|
*
|
* Returns:
|
* {String} The corresponding node type for the specified geometry
|
*/
|
getNodeType: function(geometry, style) {
|
var nodeType = null;
|
switch (geometry.CLASS_NAME) {
|
case "OpenLayers.Geometry.Point":
|
if (style.externalGraphic) {
|
nodeType = "image";
|
} else if (this.isComplexSymbol(style.graphicName)) {
|
nodeType = "svg";
|
} else {
|
nodeType = "circle";
|
}
|
break;
|
case "OpenLayers.Geometry.Rectangle":
|
nodeType = "rect";
|
break;
|
case "OpenLayers.Geometry.LineString":
|
nodeType = "polyline";
|
break;
|
case "OpenLayers.Geometry.LinearRing":
|
nodeType = "polygon";
|
break;
|
case "OpenLayers.Geometry.Polygon":
|
case "OpenLayers.Geometry.Curve":
|
nodeType = "path";
|
break;
|
default:
|
break;
|
}
|
return nodeType;
|
},
|
|
/**
|
* Method: setStyle
|
* Use to set all the style attributes to a SVG node.
|
*
|
* Takes care to adjust stroke width and point radius to be
|
* resolution-relative
|
*
|
* Parameters:
|
* node - {SVGDomElement} An SVG element to decorate
|
* style - {Object}
|
* options - {Object} Currently supported options include
|
* 'isFilled' {Boolean} and
|
* 'isStroked' {Boolean}
|
*/
|
setStyle: function(node, style, options) {
|
style = style || node._style;
|
options = options || node._options;
|
var resolution = this.getResolution();
|
var r = node._radius;
|
var widthFactor = resolution;
|
if (node._geometryClass == "OpenLayers.Geometry.Point" && r) {
|
node.style.visibility = "";
|
if (style.graphic === false) {
|
node.style.visibility = "hidden";
|
} else if (style.externalGraphic) {
|
|
if (style.graphicTitle) {
|
node.setAttributeNS(null, "title", style.graphicTitle);
|
//Standards-conformant SVG
|
// Prevent duplicate nodes. See issue https://github.com/openlayers/openlayers/issues/92
|
var titleNode = node.getElementsByTagName("title");
|
if (titleNode.length > 0) {
|
titleNode[0].firstChild.textContent = style.graphicTitle;
|
} else {
|
var label = this.nodeFactory(null, "title");
|
label.textContent = style.graphicTitle;
|
node.appendChild(label);
|
}
|
}
|
if (style.graphicWidth && style.graphicHeight) {
|
node.setAttributeNS(null, "preserveAspectRatio", "none");
|
}
|
var width = style.graphicWidth || style.graphicHeight;
|
var height = style.graphicHeight || style.graphicWidth;
|
width = width ? width : style.pointRadius*2;
|
height = height ? height : style.pointRadius*2;
|
width *= resolution;
|
height *= resolution;
|
|
var xOffset = (style.graphicXOffset != undefined) ?
|
style.graphicXOffset * resolution : -(0.5 * width);
|
var yOffset = (style.graphicYOffset != undefined) ?
|
style.graphicYOffset * resolution : -(0.5 * height);
|
|
var opacity = style.graphicOpacity || style.fillOpacity;
|
|
node.setAttributeNS(null, "x", node._x + xOffset);
|
node.setAttributeNS(null, "y", node._y + yOffset);
|
node.setAttributeNS(null, "width", width);
|
node.setAttributeNS(null, "height", height);
|
node.setAttributeNS(this.xlinkns, "href", style.externalGraphic);
|
node.setAttributeNS(null, "style", "opacity: "+opacity);
|
node.onclick = OpenLayers.Renderer.SVG2.preventDefault;
|
} else if (this.isComplexSymbol(style.graphicName)) {
|
// the symbol viewBox is three times as large as the symbol
|
var offset = style.pointRadius * 3 * resolution;
|
var size = offset * 2;
|
var src = this.importSymbol(style.graphicName);
|
widthFactor = this.symbolMetrics[src.id].size * 3 / size * resolution;
|
|
// remove the node from the dom before we modify it. This
|
// prevents various rendering issues in Safari and FF
|
var parent = node.parentNode;
|
var nextSibling = node.nextSibling;
|
if(parent) {
|
parent.removeChild(node);
|
}
|
|
// The more appropriate way to implement this would be use/defs,
|
// but due to various issues in several browsers, it is safer to
|
// copy the symbols instead of referencing them.
|
// See e.g. ticket http://trac.osgeo.org/openlayers/ticket/2985
|
// and this email thread
|
// http://osgeo-org.1803224.n2.nabble.com/Select-Control-Ctrl-click-on-Feature-with-a-graphicName-opens-new-browser-window-tc5846039.html
|
node.firstChild && node.removeChild(node.firstChild);
|
node.appendChild(src.firstChild.cloneNode(true));
|
node.setAttributeNS(null, "viewBox", src.getAttributeNS(null, "viewBox"));
|
|
node.setAttributeNS(null, "width", size);
|
node.setAttributeNS(null, "height", size);
|
node.setAttributeNS(null, "x", node._x - offset);
|
node.setAttributeNS(null, "y", node._y - offset);
|
|
// now that the node has all its new properties, insert it
|
// back into the dom where it was
|
if(nextSibling) {
|
parent.insertBefore(node, nextSibling);
|
} else if(parent) {
|
parent.appendChild(node);
|
}
|
} else {
|
node.setAttributeNS(null, "r", style.pointRadius * resolution);
|
}
|
|
var rotation = style.rotation;
|
if (rotation !== undefined || node._rotation !== undefined) {
|
node._rotation = rotation;
|
rotation |= 0;
|
if (node.nodeName !== "svg") {
|
node.setAttributeNS(null, "transform",
|
["rotate(", rotation, node._x, node._y, ")"].join(" ")
|
);
|
} else {
|
var metrics = this.symbolMetrics[src.id];
|
node.firstChild.setAttributeNS(null, "transform",
|
["rotate(", rotation, metrics.x, metrics.y, ")"].join(" ")
|
);
|
}
|
}
|
}
|
|
if (options.isFilled) {
|
node.setAttributeNS(null, "fill", style.fillColor);
|
node.setAttributeNS(null, "fill-opacity", style.fillOpacity);
|
} else {
|
node.setAttributeNS(null, "fill", "none");
|
}
|
|
if (options.isStroked) {
|
node.setAttributeNS(null, "stroke", style.strokeColor);
|
node.setAttributeNS(null, "stroke-opacity", style.strokeOpacity);
|
node.setAttributeNS(null, "stroke-width", style.strokeWidth * widthFactor);
|
node.setAttributeNS(null, "stroke-linecap", style.strokeLinecap || "round");
|
// Hard-coded linejoin for now, to make it look the same as in VML.
|
// There is no strokeLinejoin property yet for symbolizers.
|
node.setAttributeNS(null, "stroke-linejoin", "round");
|
style.strokeDashstyle && node.setAttributeNS(null,
|
"stroke-dasharray", this.dashStyle(style, widthFactor));
|
} else {
|
node.setAttributeNS(null, "stroke", "none");
|
}
|
|
if (style.pointerEvents) {
|
node.setAttributeNS(null, "pointer-events", style.pointerEvents);
|
}
|
|
if (style.cursor != null) {
|
node.setAttributeNS(null, "cursor", style.cursor);
|
}
|
|
return node;
|
},
|
|
/**
|
* Method: dashStyle
|
*
|
* Parameters:
|
* style - {Object}
|
* widthFactor - {Number}
|
*
|
* Returns:
|
* {String} A SVG compliant 'stroke-dasharray' value
|
*/
|
dashStyle: function(style, widthFactor) {
|
var w = style.strokeWidth * widthFactor;
|
var str = style.strokeDashstyle;
|
switch (str) {
|
case 'solid':
|
return 'none';
|
case 'dot':
|
return [widthFactor, 4 * w].join();
|
case 'dash':
|
return [4 * w, 4 * w].join();
|
case 'dashdot':
|
return [4 * w, 4 * w, widthFactor, 4 * w].join();
|
case 'longdash':
|
return [8 * w, 4 * w].join();
|
case 'longdashdot':
|
return [8 * w, 4 * w, widthFactor, 4 * w].join();
|
default:
|
var parts = OpenLayers.String.trim(str).split(/\s+/g);
|
for (var i=0, ii=parts.length; i<ii; i++) {
|
parts[i] = parts[i] * widthFactor;
|
}
|
return parts.join();
|
}
|
},
|
|
/**
|
* Method: createNode
|
*
|
* Parameters:
|
* type - {String} Kind of node to draw
|
* id - {String} Id for node
|
*
|
* Returns:
|
* {DOMElement} A new node of the given type and id
|
*/
|
createNode: function(type, id) {
|
var node = document.createElementNS(this.xmlns, type);
|
if (id) {
|
node.setAttributeNS(null, "id", id);
|
}
|
return node;
|
},
|
|
/**
|
* Method: nodeTypeCompare
|
*
|
* Parameters:
|
* node - {SVGDomElement} An SVG element
|
* type - {String} Kind of node
|
*
|
* Returns:
|
* {Boolean} Whether or not the specified node is of the specified type
|
*/
|
nodeTypeCompare: function(node, type) {
|
return (type == node.nodeName);
|
},
|
|
/**
|
* Method: createRenderRoot
|
*
|
* Returns:
|
* {DOMElement} The specific render engine's root element
|
*/
|
createRenderRoot: function() {
|
return this.nodeFactory(this.container.id + "_svgRoot", "svg");
|
},
|
|
/**
|
* Method: createRoot
|
*
|
* Parameters:
|
* suffix - {String} suffix to append to the id
|
*
|
* Returns:
|
* {DOMElement}
|
*/
|
createRoot: function(suffix) {
|
return this.nodeFactory(this.container.id + suffix, "g");
|
},
|
|
/**
|
* Method: createDefs
|
*
|
* Returns:
|
* {DOMElement} The element to which we'll add the symbol definitions
|
*/
|
createDefs: function() {
|
var defs = this.nodeFactory(this.container.id + "_defs", "defs");
|
this.rendererRoot.appendChild(defs);
|
return defs;
|
},
|
|
/**************************************
|
* *
|
* GEOMETRY DRAWING FUNCTIONS *
|
* *
|
**************************************/
|
|
/**
|
* Method: drawPoint
|
* This method is only called by the renderer itself.
|
*
|
* Parameters:
|
* node - {DOMElement}
|
* geometry - {<OpenLayers.Geometry>}
|
*
|
* Returns:
|
* {DOMElement} or false if the renderer could not draw the point
|
*/
|
drawPoint: function(node, geometry) {
|
return this.drawCircle(node, geometry, 1);
|
},
|
|
/**
|
* Method: drawCircle
|
* This method is only called by the renderer itself.
|
*
|
* Parameters:
|
* node - {DOMElement}
|
* geometry - {<OpenLayers.Geometry>}
|
* radius - {Float}
|
*
|
* Returns:
|
* {DOMElement} or false if the renderer could not draw the circle
|
*/
|
drawCircle: function(node, geometry, radius) {
|
var x = geometry.x;
|
var y = -geometry.y;
|
node.setAttributeNS(null, "cx", x);
|
node.setAttributeNS(null, "cy", y);
|
node._x = x;
|
node._y = y;
|
node._radius = radius;
|
return node;
|
},
|
|
/**
|
* Method: drawLineString
|
* This method is only called by the renderer itself.
|
*
|
* Parameters:
|
* node - {DOMElement}
|
* geometry - {<OpenLayers.Geometry>}
|
*
|
* Returns:
|
* {DOMElement} or null if the renderer could not draw all components of
|
* the linestring, or false if nothing could be drawn
|
*/
|
drawLineString: function(node, geometry) {
|
var path = this.getComponentsString(geometry.components);
|
node.setAttributeNS(null, "points", path);
|
return node;
|
},
|
|
/**
|
* Method: drawLinearRing
|
* This method is only called by the renderer itself.
|
*
|
* Parameters:
|
* node - {DOMElement}
|
* geometry - {<OpenLayers.Geometry>}
|
*
|
* Returns:
|
* {DOMElement} or null if the renderer could not draw all components
|
* of the linear ring, or false if nothing could be drawn
|
*/
|
drawLinearRing: function(node, geometry) {
|
var path = this.getComponentsString(geometry.components);
|
node.setAttributeNS(null, "points", path);
|
return node;
|
},
|
|
/**
|
* Method: drawPolygon
|
* This method is only called by the renderer itself.
|
*
|
* Parameters:
|
* node - {DOMElement}
|
* geometry - {<OpenLayers.Geometry>}
|
*
|
* Returns:
|
* {DOMElement} or null if the renderer could not draw all components
|
* of the polygon, or false if nothing could be drawn
|
*/
|
drawPolygon: function(node, geometry) {
|
var d = [];
|
var draw = true;
|
var complete = true;
|
var linearRingResult, path;
|
for (var j=0, len=geometry.components.length; j<len; j++) {
|
d.push("M");
|
path = this.getComponentsString(
|
geometry.components[j].components, " ");
|
d.push(path);
|
}
|
d.push("z");
|
node.setAttributeNS(null, "d", d.join(" "));
|
node.setAttributeNS(null, "fill-rule", "evenodd");
|
return node;
|
},
|
|
/**
|
* Method: drawRectangle
|
* This method is only called by the renderer itself.
|
*
|
* Parameters:
|
* node - {DOMElement}
|
* geometry - {<OpenLayers.Geometry>}
|
*
|
* Returns:
|
* {DOMElement} or false if the renderer could not draw the rectangle
|
*/
|
drawRectangle: function(node, geometry) {
|
node.setAttributeNS(null, "x", geometry.x);
|
node.setAttributeNS(null, "y", -geometry.y);
|
node.setAttributeNS(null, "width", geometry.width);
|
node.setAttributeNS(null, "height", geometry.height);
|
return node;
|
},
|
|
/**
|
* Method: drawText
|
* Function for drawing text labels.
|
* This method is only called by the renderer itself.
|
*
|
* Parameters:
|
* featureId - {String|DOMElement}
|
* style - {Object}
|
* location - {<OpenLayers.Geometry.Point>}, will be modified inline
|
*
|
* Returns:
|
* {DOMElement} container holding the text label
|
*/
|
drawText: function(featureId, style, location) {
|
var g = OpenLayers.Renderer.NG.prototype.drawText.apply(this, arguments);
|
var text = g.firstChild ||
|
this.nodeFactory(featureId + this.LABEL_ID_SUFFIX + "_text", "text");
|
|
var res = this.getResolution();
|
text.setAttributeNS(null, "x", location.x / res);
|
text.setAttributeNS(null, "y", - location.y / res);
|
g.setAttributeNS(null, "transform", "scale(" + res + ")");
|
|
if (style.fontColor) {
|
text.setAttributeNS(null, "fill", style.fontColor);
|
}
|
if (style.fontOpacity) {
|
text.setAttributeNS(null, "opacity", style.fontOpacity);
|
}
|
if (style.fontFamily) {
|
text.setAttributeNS(null, "font-family", style.fontFamily);
|
}
|
if (style.fontSize) {
|
text.setAttributeNS(null, "font-size", style.fontSize);
|
}
|
if (style.fontWeight) {
|
text.setAttributeNS(null, "font-weight", style.fontWeight);
|
}
|
if (style.fontStyle) {
|
text.setAttributeNS(null, "font-style", style.fontStyle);
|
}
|
if (style.labelSelect === true) {
|
text.setAttributeNS(null, "pointer-events", "visible");
|
text._featureId = featureId;
|
} else {
|
text.setAttributeNS(null, "pointer-events", "none");
|
}
|
var align = style.labelAlign || OpenLayers.Renderer.defaultSymbolizer.labelAlign;
|
text.setAttributeNS(null, "text-anchor",
|
OpenLayers.Renderer.SVG2.LABEL_ALIGN[align[0]] || "middle");
|
|
if (OpenLayers.IS_GECKO === true) {
|
text.setAttributeNS(null, "dominant-baseline",
|
OpenLayers.Renderer.SVG2.LABEL_ALIGN[align[1]] || "central");
|
}
|
|
var labelRows = style.label.split('\n');
|
var numRows = labelRows.length;
|
while (text.childNodes.length > numRows) {
|
text.removeChild(text.lastChild);
|
}
|
for (var i = 0; i < numRows; i++) {
|
var tspan = text.childNodes[i] ||
|
this.nodeFactory(featureId + this.LABEL_ID_SUFFIX + "_tspan_" + i, "tspan");
|
if (style.labelSelect === true) {
|
tspan._featureId = featureId;
|
}
|
if (OpenLayers.IS_GECKO === false) {
|
tspan.setAttributeNS(null, "baseline-shift",
|
OpenLayers.Renderer.SVG2.LABEL_VSHIFT[align[1]] || "-35%");
|
}
|
tspan.setAttribute("x", location.x / res);
|
if (i == 0) {
|
var vfactor = OpenLayers.Renderer.SVG2.LABEL_VFACTOR[align[1]];
|
if (vfactor == null) {
|
vfactor = -.5;
|
}
|
tspan.setAttribute("dy", (vfactor*(numRows-1)) + "em");
|
} else {
|
tspan.setAttribute("dy", "1em");
|
}
|
tspan.textContent = (labelRows[i] === '') ? ' ' : labelRows[i];
|
if (!tspan.parentNode) {
|
text.appendChild(tspan);
|
}
|
}
|
|
if (!text.parentNode) {
|
g.appendChild(text);
|
}
|
|
return g;
|
},
|
|
/**
|
* Method: getComponentString
|
*
|
* Parameters:
|
* components - {Array(<OpenLayers.Geometry.Point>)} Array of points
|
* separator - {String} character between coordinate pairs. Defaults to ","
|
*
|
* Returns:
|
* {Object} hash with properties "path" (the string created from the
|
* components and "complete" (false if the renderer was unable to
|
* draw all components)
|
*/
|
getComponentsString: function(components, separator) {
|
var len = components.length;
|
var strings = new Array(len);
|
for (var i=0; i<len; i++) {
|
strings[i] = this.getShortString(components[i]);
|
}
|
|
return strings.join(separator || ",");
|
},
|
|
/**
|
* Method: getShortString
|
*
|
* Parameters:
|
* point - {<OpenLayers.Geometry.Point>}
|
*
|
* Returns:
|
* {String} or false if point is outside the valid range
|
*/
|
getShortString: function(point) {
|
return point.x + "," + (-point.y);
|
},
|
|
/**
|
* Method: importSymbol
|
* add a new symbol definition from the rendererer's symbol hash
|
*
|
* Parameters:
|
* graphicName - {String} name of the symbol to import
|
*
|
* Returns:
|
* {DOMElement} - the imported symbol
|
*/
|
importSymbol: function (graphicName) {
|
if (!this.defs) {
|
// create svg defs tag
|
this.defs = this.createDefs();
|
}
|
var id = this.container.id + "-" + graphicName;
|
|
// check if symbol already exists in the defs
|
var existing = document.getElementById(id);
|
if (existing != null) {
|
return existing;
|
}
|
|
var symbol = OpenLayers.Renderer.symbol[graphicName];
|
if (!symbol) {
|
throw new Error(graphicName + ' is not a valid symbol name');
|
}
|
|
var symbolNode = this.nodeFactory(id, "symbol");
|
var node = this.nodeFactory(null, "polygon");
|
symbolNode.appendChild(node);
|
var symbolExtent = new OpenLayers.Bounds(
|
Number.MAX_VALUE, Number.MAX_VALUE, 0, 0);
|
|
var points = [];
|
var x,y;
|
for (var i=0, len=symbol.length; i<len; i=i+2) {
|
x = symbol[i];
|
y = symbol[i+1];
|
symbolExtent.left = Math.min(symbolExtent.left, x);
|
symbolExtent.bottom = Math.min(symbolExtent.bottom, y);
|
symbolExtent.right = Math.max(symbolExtent.right, x);
|
symbolExtent.top = Math.max(symbolExtent.top, y);
|
points.push(x, ",", y);
|
}
|
|
node.setAttributeNS(null, "points", points.join(" "));
|
|
var width = symbolExtent.getWidth();
|
var height = symbolExtent.getHeight();
|
// create a viewBox three times as large as the symbol itself,
|
// to allow for strokeWidth being displayed correctly at the corners.
|
var viewBox = [symbolExtent.left - width,
|
symbolExtent.bottom - height, width * 3, height * 3];
|
symbolNode.setAttributeNS(null, "viewBox", viewBox.join(" "));
|
this.symbolMetrics[id] = {
|
size: Math.max(width, height),
|
x: symbolExtent.getCenterLonLat().lon,
|
y: symbolExtent.getCenterLonLat().lat
|
};
|
|
this.defs.appendChild(symbolNode);
|
return symbolNode;
|
},
|
|
/**
|
* Method: getFeatureIdFromEvent
|
*
|
* Parameters:
|
* evt - {Object} An <OpenLayers.Event> object
|
*
|
* Returns:
|
* {String} A feature id or undefined.
|
*/
|
getFeatureIdFromEvent: function(evt) {
|
var featureId = OpenLayers.Renderer.Elements.prototype.getFeatureIdFromEvent.apply(this, arguments);
|
if(!featureId) {
|
var target = evt.target;
|
featureId = target.parentNode && target != this.rendererRoot ?
|
target.parentNode._featureId : undefined;
|
}
|
return featureId;
|
},
|
|
CLASS_NAME: "OpenLayers.Renderer.SVG2"
|
});
|
|
/**
|
* Constant: OpenLayers.Renderer.SVG2.LABEL_ALIGN
|
* {Object}
|
*/
|
OpenLayers.Renderer.SVG2.LABEL_ALIGN = {
|
"l": "start",
|
"r": "end",
|
"b": "bottom",
|
"t": "hanging"
|
};
|
|
/**
|
* Constant: OpenLayers.Renderer.SVG2.LABEL_VSHIFT
|
* {Object}
|
*/
|
OpenLayers.Renderer.SVG2.LABEL_VSHIFT = {
|
// according to
|
// http://www.w3.org/Graphics/SVG/Test/20061213/htmlObjectHarness/full-text-align-02-b.html
|
// a baseline-shift of -70% shifts the text exactly from the
|
// bottom to the top of the baseline, so -35% moves the text to
|
// the center of the baseline.
|
"t": "-70%",
|
"b": "0"
|
};
|
|
/**
|
* Constant: OpenLayers.Renderer.SVG2.LABEL_VFACTOR
|
* {Object}
|
*/
|
OpenLayers.Renderer.SVG2.LABEL_VFACTOR = {
|
"t": 0,
|
"b": -1
|
};
|
|
/**
|
* Function: OpenLayers.Renderer.SVG2.preventDefault
|
* Used to prevent default events (especially opening images in a new tab on
|
* ctrl-click) from being executed for externalGraphic and graphicName symbols
|
*/
|
OpenLayers.Renderer.SVG2.preventDefault = function(e) {
|
e.preventDefault && e.preventDefault();
|
};
|
|
/**
|
* Class: OpenLayers.Popup.AnchoredBubble
|
* This class is *deprecated*. Use {<OpenLayers.Popup.Anchored>} and
|
* round corners using CSS3's border-radius property.
|
*
|
* Inherits from:
|
* - <OpenLayers.Popup.Anchored>
|
*/
|
OpenLayers.Popup.AnchoredBubble = OpenLayers.Class(OpenLayers.Popup.Anchored, {
|
|
/**
|
* Property: rounded
|
* {Boolean} Has the popup been rounded yet?
|
*/
|
rounded: false,
|
|
/**
|
* Constructor: OpenLayers.Popup.AnchoredBubble
|
*
|
* Parameters:
|
* id - {String}
|
* lonlat - {<OpenLayers.LonLat>}
|
* contentSize - {<OpenLayers.Size>}
|
* contentHTML - {String}
|
* anchor - {Object} Object to which we'll anchor the popup. Must expose
|
* a 'size' (<OpenLayers.Size>) and 'offset' (<OpenLayers.Pixel>)
|
* (Note that this is generally an <OpenLayers.Icon>).
|
* closeBox - {Boolean}
|
* closeBoxCallback - {Function} Function to be called on closeBox click.
|
*/
|
initialize:function(id, lonlat, contentSize, contentHTML, anchor, closeBox,
|
closeBoxCallback) {
|
|
this.padding = new OpenLayers.Bounds(
|
0, OpenLayers.Popup.AnchoredBubble.CORNER_SIZE,
|
0, OpenLayers.Popup.AnchoredBubble.CORNER_SIZE
|
);
|
OpenLayers.Popup.Anchored.prototype.initialize.apply(this, arguments);
|
},
|
|
/**
|
* Method: draw
|
*
|
* Parameters:
|
* px - {<OpenLayers.Pixel>}
|
*
|
* Returns:
|
* {DOMElement} Reference to a div that contains the drawn popup.
|
*/
|
draw: function(px) {
|
|
OpenLayers.Popup.Anchored.prototype.draw.apply(this, arguments);
|
|
this.setContentHTML();
|
|
//set the popup color and opacity
|
this.setBackgroundColor();
|
this.setOpacity();
|
|
return this.div;
|
},
|
|
/**
|
* Method: updateRelativePosition
|
* The popup has been moved to a new relative location, in which case
|
* we will want to re-do the rico corners.
|
*/
|
updateRelativePosition: function() {
|
this.setRicoCorners();
|
},
|
|
/**
|
* APIMethod: setSize
|
*
|
* Parameters:
|
* contentSize - {<OpenLayers.Size>} the new size for the popup's
|
* contents div (in pixels).
|
*/
|
setSize:function(contentSize) {
|
OpenLayers.Popup.Anchored.prototype.setSize.apply(this, arguments);
|
|
this.setRicoCorners();
|
},
|
|
/**
|
* APIMethod: setBackgroundColor
|
*
|
* Parameters:
|
* color - {String}
|
*/
|
setBackgroundColor:function(color) {
|
if (color != undefined) {
|
this.backgroundColor = color;
|
}
|
|
if (this.div != null) {
|
if (this.contentDiv != null) {
|
this.div.style.background = "transparent";
|
OpenLayers.Rico.Corner.changeColor(this.groupDiv,
|
this.backgroundColor);
|
}
|
}
|
},
|
|
/**
|
* APIMethod: setOpacity
|
*
|
* Parameters:
|
* opacity - {float}
|
*/
|
setOpacity:function(opacity) {
|
OpenLayers.Popup.Anchored.prototype.setOpacity.call(this, opacity);
|
|
if (this.div != null) {
|
if (this.groupDiv != null) {
|
OpenLayers.Rico.Corner.changeOpacity(this.groupDiv,
|
this.opacity);
|
}
|
}
|
},
|
|
/**
|
* Method: setBorder
|
* Always sets border to 0. Bubble Popups can not have a border.
|
*
|
* Parameters:
|
* border - {Integer}
|
*/
|
setBorder:function(border) {
|
this.border = 0;
|
},
|
|
/**
|
* Method: setRicoCorners
|
* Update RICO corners according to the popup's current relative postion.
|
*/
|
setRicoCorners:function() {
|
|
var corners = this.getCornersToRound(this.relativePosition);
|
var options = {corners: corners,
|
color: this.backgroundColor,
|
bgColor: "transparent",
|
blend: false};
|
|
if (!this.rounded) {
|
OpenLayers.Rico.Corner.round(this.div, options);
|
this.rounded = true;
|
} else {
|
OpenLayers.Rico.Corner.reRound(this.groupDiv, options);
|
//set the popup color and opacity
|
this.setBackgroundColor();
|
this.setOpacity();
|
}
|
},
|
|
/**
|
* Method: getCornersToRound
|
*
|
* Returns:
|
* {String} The proper corners string ("tr tl bl br") for rico to round.
|
*/
|
getCornersToRound:function() {
|
|
var corners = ['tl', 'tr', 'bl', 'br'];
|
|
//we want to round all the corners _except_ the opposite one.
|
var corner = OpenLayers.Bounds.oppositeQuadrant(this.relativePosition);
|
OpenLayers.Util.removeItem(corners, corner);
|
|
return corners.join(" ");
|
},
|
|
CLASS_NAME: "OpenLayers.Popup.AnchoredBubble"
|
});
|
|
/**
|
* Constant: CORNER_SIZE
|
* {Integer} 5. Border space for the RICO corners.
|
*/
|
OpenLayers.Popup.AnchoredBubble.CORNER_SIZE = 5;
|