394 lines
13 KiB
JavaScript
394 lines
13 KiB
JavaScript
/*jslint white: false */
|
|
/*jslint forin: true */
|
|
/*global OpenLayers Drupal $ document jQuery window */
|
|
|
|
/**
|
|
* @file
|
|
* This file holds the main javascript API for OpenLayers. It is
|
|
* responsable for loading and displaying the map.
|
|
*
|
|
* @ingroup openlayers
|
|
*/
|
|
|
|
/**
|
|
* This is a workaround for a bug involving IE and VML support.
|
|
* See the Drupal Book page describing this problem:
|
|
* http://drupal.org/node/613002
|
|
*/
|
|
|
|
document.namespaces;
|
|
|
|
(function($) {
|
|
|
|
Drupal.settings.openlayers = {};
|
|
Drupal.settings.openlayers.maps = {};
|
|
|
|
/**
|
|
* Minimal OpenLayers map bootstrap.
|
|
* All additional operations occur in additional Drupal behaviors.
|
|
*/
|
|
Drupal.behaviors.openlayers = {
|
|
'attach': function(context, settings) {
|
|
if (typeof(Drupal.settings.openlayers) === 'object' &&
|
|
Drupal.settings.openlayers.maps &&
|
|
!$(context).data('openlayers')) {
|
|
$('.openlayers-map:not(.openlayers-processed)').each(function() {
|
|
// By setting the stop_render variable to TRUE, this will
|
|
// halt the render process. If set, one could remove this setting
|
|
// then call Drupal.attachBehaviors again to get it started
|
|
var map_id = $(this).attr('id');
|
|
if (Drupal.settings.openlayers.maps[map_id] && Drupal.settings.openlayers.maps[map_id].stop_render != true) {
|
|
var map = Drupal.settings.openlayers.maps[map_id];
|
|
$(this).addClass('openlayers-processed');
|
|
|
|
// Use try..catch for error handling.
|
|
try {
|
|
// Set OpenLayers language based on document language,
|
|
// rather than browser language
|
|
OpenLayers.Lang.setCode($('html').attr('lang'));
|
|
|
|
$(this)
|
|
// @TODO: move this into markup in theme function, doing this dynamically is a waste.
|
|
.css('width', map.width)
|
|
.css('height', map.height);
|
|
|
|
var options = {};
|
|
// This is necessary because the input JSON cannot contain objects
|
|
options.projection = new OpenLayers.Projection('EPSG:' + map.projection);
|
|
options.displayProjection = new OpenLayers.Projection('EPSG:' + map.displayProjection);
|
|
|
|
// TODO: work around this scary code
|
|
if (map.projection === '900913') {
|
|
options.maxExtent = new OpenLayers.Bounds(
|
|
-20037508.34, -20037508.34, 20037508.34, 20037508.34);
|
|
options.units = "m";
|
|
}
|
|
if (map.projection === '4326') {
|
|
options.maxExtent = new OpenLayers.Bounds(-180, -90, 180, 90);
|
|
}
|
|
|
|
options.maxResolution = 'auto'; // 1.40625;
|
|
options.controls = [];
|
|
|
|
// Change image, CSS, and proxy paths if specified
|
|
if (map.image_path) {
|
|
OpenLayers.ImgPath = Drupal.openlayers.relatePath(map.image_path,
|
|
Drupal.settings.basePath);
|
|
}
|
|
if (map.css_path) {
|
|
options.theme = Drupal.openlayers.relatePath(map.css_path,
|
|
Drupal.settings.basePath);
|
|
}
|
|
if (map.proxy_host) {
|
|
OpenLayers.ProxyHost = Drupal.openlayers.relatePath(map.proxy_host,
|
|
Drupal.settings.basePath);
|
|
}
|
|
|
|
// Initialize openlayers map
|
|
var openlayers = new OpenLayers.Map(map.id, options);
|
|
|
|
// Run the layer addition first
|
|
Drupal.openlayers.addLayers(map, openlayers);
|
|
|
|
// Attach data to map DOM object
|
|
$(this).data('openlayers', {'map': map, 'openlayers': openlayers});
|
|
|
|
// Finally, attach behaviors
|
|
Drupal.attachBehaviors(this);
|
|
|
|
if ($.browser.msie) {
|
|
Drupal.openlayers.redrawVectors();
|
|
}
|
|
}
|
|
catch (e) {
|
|
var errorMessage = e.name + ': ' + e.message;
|
|
if (typeof console != 'undefined') {
|
|
console.log(errorMessage);
|
|
}
|
|
else {
|
|
$(this).text('Error during map rendering: ' + errorMessage);
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Collection of helper methods.
|
|
*/
|
|
Drupal.openlayers = {
|
|
// Determine path based on format.
|
|
'relatePath': function(path, basePath) {
|
|
// Check for a full URL or an absolute path.
|
|
if (path.indexOf('://') >= 0 || path.indexOf('/') == 0) {
|
|
return path;
|
|
}
|
|
else {
|
|
return basePath + path;
|
|
}
|
|
},
|
|
/*
|
|
* Redraw Vectors.
|
|
* This is necessary because various version of IE cannot draw vectors on
|
|
* $(document).ready()
|
|
*/
|
|
'redrawVectors': function() {
|
|
$(window).load(
|
|
function() {
|
|
var map;
|
|
for (map in Drupal.settings.openlayers.maps) {
|
|
$.each($('#' + map).data('openlayers')
|
|
.openlayers.getLayersByClass('OpenLayers.Layer.Vector'),
|
|
function(i, layer) {
|
|
layer.redraw();
|
|
}
|
|
);
|
|
}
|
|
}
|
|
);
|
|
},
|
|
/**
|
|
* Add layers to the map
|
|
*
|
|
* @param map Drupal settings object for the map.
|
|
* @param openlayers OpenLayers Map Object.
|
|
*/
|
|
'addLayers': function(map, openlayers) {
|
|
|
|
var sorted = [];
|
|
for (var name in map.layers) {
|
|
sorted.push({'name': name, 'weight': map.layers[name].weight, 'isBaseLayer': map.layers[name].isBaseLayer });
|
|
}
|
|
|
|
sorted.sort(function(a, b) {
|
|
var x = parseInt(a.weight, 10), y = parseInt(b.weight, 10);
|
|
return ((a.isBaseLayer && x < y) ? -1 : ((b.isBaseLayer || x > y) ? 1 : 0));
|
|
});
|
|
|
|
for (var i = 0; i < sorted.length; ++i) {
|
|
var layer,
|
|
name = sorted[i].name,
|
|
options = map.layers[name];
|
|
|
|
// Add reference to our layer ID
|
|
options.drupalID = name;
|
|
// Ensure that the layer handler is available
|
|
if (options.layer_handler !== undefined &&
|
|
Drupal.openlayers.layer[options.layer_handler] !== undefined) {
|
|
var layer = Drupal.openlayers.layer[options.layer_handler](map.layers[name].title, map, options);
|
|
|
|
layer.visibility = !!(!map.layer_activated || map.layer_activated[name]);
|
|
|
|
if (layer.isBaseLayer === false) {
|
|
layer.displayInLayerSwitcher = (!map.layer_switcher || map.layer_switcher[name]);
|
|
}
|
|
|
|
if (map.center.wrapdateline === '1') {
|
|
// TODO: move into layer specific settings
|
|
layer.wrapDateLine = true;
|
|
}
|
|
|
|
openlayers.addLayer(layer);
|
|
}
|
|
}
|
|
|
|
openlayers.setBaseLayer(openlayers.getLayersBy('drupalID', map.default_layer)[0]);
|
|
|
|
// Set the restricted extent if wanted.
|
|
// Prevents the map from being panned outside of a specfic bounding box.
|
|
if (typeof map.center.restrict !== 'undefined' && map.center.restrict.restrictextent) {
|
|
openlayers.restrictedExtent = OpenLayers.Bounds.fromString(
|
|
map.center.restrict.restrictedExtent);
|
|
}
|
|
|
|
// Zoom & center
|
|
if (map.center.initial) {
|
|
var center = OpenLayers.LonLat.fromString(map.center.initial.centerpoint).transform(
|
|
new OpenLayers.Projection('EPSG:4326'),
|
|
new OpenLayers.Projection('EPSG:' + map.projection));
|
|
var zoom = parseInt(map.center.initial.zoom, 10);
|
|
openlayers.setCenter(center, zoom, false, false);
|
|
}
|
|
},
|
|
/**
|
|
* Abstraction of OpenLayer's feature adding syntax to work with Drupal output.
|
|
* Ideally this should be rolled into the PHP code, because we don't want to manually
|
|
* parse WKT
|
|
*/
|
|
'addFeatures': function(map, layer, features) {
|
|
var newFeatures = [];
|
|
|
|
// Go through features
|
|
for (var key in features) {
|
|
var feature = features[key];
|
|
var newFeatureObject = this.objectFromFeature(feature);
|
|
|
|
// If we have successfully extracted geometry add additional
|
|
// properties and queue it for addition to the layer
|
|
if (newFeatureObject) {
|
|
var newFeatureSet = [];
|
|
|
|
// Check to see if it is a new feature, or an array of new features.
|
|
if (typeof(newFeatureObject[0]) === 'undefined') {
|
|
newFeatureSet[0] = newFeatureObject;
|
|
}
|
|
else {
|
|
newFeatureSet = newFeatureObject;
|
|
}
|
|
|
|
// Go through new features
|
|
for (var i in newFeatureSet) {
|
|
var newFeature = newFeatureSet[i];
|
|
|
|
// Transform the geometry if the 'projection' property is different from the map projection
|
|
if (feature.projection) {
|
|
if (feature.projection !== map.projection) {
|
|
var featureProjection = new OpenLayers.Projection('EPSG:' + feature.projection);
|
|
var mapProjection = new OpenLayers.Projection('EPSG:' + map.projection);
|
|
newFeature.geometry.transform(featureProjection, mapProjection);
|
|
}
|
|
}
|
|
|
|
// Add attribute data
|
|
if (feature.attributes) {
|
|
// Attributes belong to features, not single component geometries
|
|
// of them. But we're creating a geometry for each component for
|
|
// better performance and clustering support. Let's call these
|
|
// "pseudofeatures".
|
|
//
|
|
// In order to identify the real feature each geometry belongs to
|
|
// we then add a 'fid' parameter to the "pseudofeature".
|
|
// NOTE: 'drupalFID' is only unique within a single layer.
|
|
newFeature.attributes = feature.attributes;
|
|
newFeature.data = feature.attributes;
|
|
newFeature.drupalFID = key;
|
|
}
|
|
|
|
// Add style information
|
|
if (feature.style) {
|
|
newFeature.style = jQuery.extend({},
|
|
OpenLayers.Feature.Vector.style['default'],
|
|
feature.style);
|
|
}
|
|
|
|
// Push new features
|
|
newFeatures.push(newFeature);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Add new features if there are any
|
|
if (newFeatures.length !== 0) {
|
|
layer.addFeatures(newFeatures);
|
|
}
|
|
},
|
|
|
|
'getStyleMap': function(map, layername) {
|
|
if (map.styles) {
|
|
var stylesAdded = {};
|
|
|
|
// Grab and map base styles.
|
|
for (var style in map.styles) {
|
|
stylesAdded[style] = new OpenLayers.Style(map.styles[style]);
|
|
}
|
|
|
|
// Implement layer-specific styles. First default, then select.
|
|
if (map.layer_styles !== undefined && map.layer_styles[layername]) {
|
|
var style = map.layer_styles[layername];
|
|
stylesAdded['default'] = new OpenLayers.Style(map.styles[style]);
|
|
}
|
|
if (map.layer_styles_select !== undefined && map.layer_styles_select[layername]) {
|
|
var style = map.layer_styles_select[layername];
|
|
stylesAdded['select'] = new OpenLayers.Style(map.styles[style]);
|
|
}
|
|
|
|
return new OpenLayers.StyleMap(stylesAdded);
|
|
}
|
|
else {
|
|
return new OpenLayers.StyleMap({
|
|
'default': new OpenLayers.Style({
|
|
pointRadius: 5,
|
|
fillColor: '#ffcc66',
|
|
strokeColor: '#ff9933',
|
|
strokeWidth: 4,
|
|
fillOpacity: 0.5
|
|
}),
|
|
'select': new OpenLayers.Style({
|
|
fillColor: '#66ccff',
|
|
strokeColor: '#3399ff'
|
|
})
|
|
});
|
|
}
|
|
},
|
|
|
|
'objectFromFeature': function(feature) {
|
|
var wktFormat = new OpenLayers.Format.WKT();
|
|
// Extract geometry either from wkt property or lon/lat properties
|
|
if (feature.wkt) {
|
|
return wktFormat.read(feature.wkt);
|
|
}
|
|
else if (feature.lon) {
|
|
return wktFormat.read('POINT(' + feature.lon + ' ' + feature.lat + ')');
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Add Behavior.
|
|
*
|
|
* This is a wrapper around adding behaviors for OpenLayers.
|
|
* a module does not have to use this, but it helps cut
|
|
* down on code.
|
|
*
|
|
* @param id
|
|
* The identifier of the behavior that is attached to
|
|
* the map.
|
|
* @param attach
|
|
* The callback function for the attach part of the
|
|
* Drupal behavior.
|
|
* @param detach
|
|
* The callback function for the detach part of the
|
|
* Drupal behavior.
|
|
*/
|
|
'addBehavior': function(id, attach, detach) {
|
|
// Add as a Drupal behavior. Add a prefix, just to be safe.
|
|
Drupal.behaviors['openlayers_auto_' + id] = {
|
|
attach: function (context, settings) {
|
|
var data = $(context).data('openlayers');
|
|
|
|
// Ensure that there is a map and that the appropriate
|
|
// behavior exists. Need "data &&" to avoid js crash
|
|
// when data is empty
|
|
var localBehavior = data && data.map.behaviors[id];
|
|
|
|
// Ensure scope in the attach callback
|
|
var that = this;
|
|
if (localBehavior) {
|
|
$(context).once('openlayers-' + id, function () {
|
|
attach.apply(that, [data, data.map.behaviors[id], context, settings]);
|
|
});
|
|
}
|
|
},
|
|
// Maybe we need a little more handling here.
|
|
detach: detach
|
|
};
|
|
},
|
|
|
|
/**
|
|
* Add Control.
|
|
*
|
|
* This is a wrapper around adding controls to maps. It
|
|
* is not needed but saves some code.
|
|
*/
|
|
'addControl': function(openlayers, controlName, options) {
|
|
var control = new OpenLayers.Control[controlName](options);
|
|
openlayers.addControl(control);
|
|
control.activate();
|
|
return control;
|
|
}
|
|
};
|
|
|
|
Drupal.openlayers.layer = {};
|
|
})(jQuery);
|