Bachir Soussi Chiadmi 1bc61b12ad first import
2015-04-08 11:40:19 +02:00

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);