diff options
Diffstat (limited to 'ishtar_common/static/gis/js')
-rw-r--r-- | ishtar_common/static/gis/js/OLMapWidget.js | 246 |
1 files changed, 246 insertions, 0 deletions
diff --git a/ishtar_common/static/gis/js/OLMapWidget.js b/ishtar_common/static/gis/js/OLMapWidget.js new file mode 100644 index 000000000..7102b0bf8 --- /dev/null +++ b/ishtar_common/static/gis/js/OLMapWidget.js @@ -0,0 +1,246 @@ +/* global ol */ + +var GeometryTypeControl = function(opt_options) { + 'use strict'; + // Map control to switch type when geometry type is unknown + var options = opt_options || {}; + + var element = document.createElement('div'); + element.className = 'switch-type type-' + options.type + ' ol-control ol-unselectable'; + if (options.active) { + element.className += " type-active"; + } + + var self = this; + var switchType = function(e) { + e.preventDefault(); + if (options.widget.currentGeometryType !== self) { + options.widget.map.removeInteraction(options.widget.interactions.draw); + options.widget.interactions.draw = new ol.interaction.Draw({ + features: options.widget.featureCollection, + type: options.type + }); + options.widget.map.addInteraction(options.widget.interactions.draw); + var className = options.widget.currentGeometryType.element.className.replace(/ type-active/g, ''); + options.widget.currentGeometryType.element.className = className; + options.widget.currentGeometryType = self; + element.className += " type-active"; + } + }; + + element.addEventListener('click', switchType, false); + element.addEventListener('touchstart', switchType, false); + + ol.control.Control.call(this, { + element: element + }); +}; + +// custom Ishtar - inherits not available anymore on new ol +// ol.inherits(GeometryTypeControl, ol.control.Control); +var ol_ext_inherits = function(child, parent) { + child.prototype = Object.create(parent.prototype); + child.prototype.constructor = child; +}; +ol_ext_inherits(GeometryTypeControl, ol.control.Control); +// end custom Ishtar + + +// TODO: allow deleting individual features (#8972) +(function() { + 'use strict'; + var jsonFormat = new ol.format.GeoJSON(); + + function MapWidget(options) { + this.map = null; + this.interactions = {draw: null, modify: null}; + this.typeChoices = false; + this.ready = false; + + // Default options + this.options = { + default_lat: 0, + default_lon: 0, + default_zoom: 12, + is_collection: options.geom_name.indexOf('Multi') > -1 || options.geom_name.indexOf('Collection') > -1 + }; + + // Altering using user-provided options + for (var property in options) { + if (options.hasOwnProperty(property)) { + this.options[property] = options[property]; + } + } + if (!options.base_layer) { + this.options.base_layer = new ol.layer.Tile({source: new ol.source.OSM()}); + } + + this.map = this.createMap(); + this.featureCollection = new ol.Collection(); + this.featureOverlay = new ol.layer.Vector({ + map: this.map, + source: new ol.source.Vector({ + features: this.featureCollection, + useSpatialIndex: false // improve performance + }), + updateWhileAnimating: true, // optional, for instant visual feedback + updateWhileInteracting: true // optional, for instant visual feedback + }); + + // Populate and set handlers for the feature container + var self = this; + this.featureCollection.on('add', function(event) { + var feature = event.element; + feature.on('change', function() { + self.serializeFeatures(); + }); + if (self.ready) { + self.serializeFeatures(); + if (!self.options.is_collection) { + self.disableDrawing(); // Only allow one feature at a time + } + } + }); + + var initial_value = document.getElementById(this.options.id).value; + if (initial_value) { + var features = jsonFormat.readFeatures('{"type": "Feature", "geometry": ' + initial_value + '}'); + var extent = ol.extent.createEmpty(); + features.forEach(function(feature) { + this.featureOverlay.getSource().addFeature(feature); + ol.extent.extend(extent, feature.getGeometry().getExtent()); + }, this); + // Center/zoom the map + this.map.getView().fit(extent, {maxZoom: this.options.default_zoom}); + } else { + this.map.getView().setCenter(this.defaultCenter()); + } + this.createInteractions(); + if (initial_value && !this.options.is_collection) { + this.disableDrawing(); + } + this.ready = true; + } + + MapWidget.prototype.createMap = function() { + // custom Ishtar + var layers = [this.options.base_layer]; + if (this.options.layers) layers = this.options.layers; + var options = { + target: this.options.map_id, + layers: layers, + view: new ol.View({ + zoom: this.options.default_zoom + }) + }; + if (this.options.controls) options["controls"] = this.options.controls; + // end custom Ishtar + var map = new ol.Map(options); + return map; + }; + + MapWidget.prototype.createInteractions = function() { + // Initialize the modify interaction + this.interactions.modify = new ol.interaction.Modify({ + features: this.featureCollection, + deleteCondition: function(event) { + return ol.events.condition.shiftKeyOnly(event) && + ol.events.condition.singleClick(event); + } + }); + + // Initialize the draw interaction + var geomType = this.options.geom_name; + if (geomType === "Unknown" || geomType === "GeometryCollection") { + // Default to Point, but create icons to switch type + geomType = "Point"; + this.currentGeometryType = new GeometryTypeControl({widget: this, type: "Point", active: true}); + this.map.addControl(this.currentGeometryType); + this.map.addControl(new GeometryTypeControl({widget: this, type: "LineString", active: false})); + this.map.addControl(new GeometryTypeControl({widget: this, type: "Polygon", active: false})); + this.typeChoices = true; + } + this.interactions.draw = new ol.interaction.Draw({ + features: this.featureCollection, + type: geomType + }); + + this.map.addInteraction(this.interactions.draw); + this.map.addInteraction(this.interactions.modify); + }; + + MapWidget.prototype.defaultCenter = function() { + var center = [this.options.default_lon, this.options.default_lat]; + if (this.options.map_srid) { + return ol.proj.transform(center, 'EPSG:4326', this.map.getView().getProjection()); + } + return center; + }; + + MapWidget.prototype.enableDrawing = function() { + this.interactions.draw.setActive(true); + if (this.typeChoices) { + // Show geometry type icons + var divs = document.getElementsByClassName("switch-type"); + for (var i = 0; i !== divs.length; i++) { + divs[i].style.visibility = "visible"; + } + } + }; + + MapWidget.prototype.disableDrawing = function() { + if (this.interactions.draw) { + this.interactions.draw.setActive(false); + if (this.typeChoices) { + // Hide geometry type icons + var divs = document.getElementsByClassName("switch-type"); + for (var i = 0; i !== divs.length; i++) { + divs[i].style.visibility = "hidden"; + } + } + } + }; + + MapWidget.prototype.clearFeatures = function() { + this.featureCollection.clear(); + // Empty textarea widget + document.getElementById(this.options.id).value = ''; + this.enableDrawing(); + }; + + MapWidget.prototype.serializeFeatures = function() { + // Three use cases: GeometryCollection, multigeometries, and single geometry + var geometry = null; + var features = this.featureOverlay.getSource().getFeatures(); + if (this.options.is_collection) { + if (this.options.geom_name === "GeometryCollection") { + var geometries = []; + for (var i = 0; i < features.length; i++) { + geometries.push(features[i].getGeometry()); + } + geometry = new ol.geom.GeometryCollection(geometries); + } else { + geometry = features[0].getGeometry().clone(); + for (var j = 1; j < features.length; j++) { + switch (geometry.getType()) { + case "MultiPoint": + geometry.appendPoint(features[j].getGeometry().getPoint(0)); + break; + case "MultiLineString": + geometry.appendLineString(features[j].getGeometry().getLineString(0)); + break; + case "MultiPolygon": + geometry.appendPolygon(features[j].getGeometry().getPolygon(0)); + } + } + } + } else { + if (features[0]) { + geometry = features[0].getGeometry(); + } + } + document.getElementById(this.options.id).value = jsonFormat.writeGeometry(geometry); + }; + + window.MapWidget = MapWidget; +})(); |