function SfmbMapsOL(opts) { var divObject = opts.divObject, polyPointCallback = opts.polyPointCallback, getPolygonCallback = opts.getPolygonCallback, landmarkCallback = opts.landmarkCallback; var map; //never used yet var datasets = new Object(); // global polygon name used between [get/delete/new]polygon functions var polygonName; var selectedMarker; // transform from WGS 1984 (map's projection) var fromProjection = new OpenLayers.Projection("EPSG:4326"); // to Spherical Mercator Projection ("normal" projection) var toProjection = new OpenLayers.Projection("EPSG:900913"); // instantiate the map this.div = divObject; var osm = new OpenLayers.Layer.OSM(); map = new OpenLayers.Map({ div: divObject, // this is if you want to get the tiles from your own server /*layers: [new OpenLayers.Layer.OSM( "OpenStreetMap", 'http://10.120.1.136/osm_tiles/${z}/${x}/${y}.png')], */ layers: [ osm ], controls: [ new OpenLayers.Control.Navigation({ dragPanOptions: { enableKinetic: false, // because the effect if not good, documentDrag: true } }), new OpenLayers.Control.ScaleLine(), new OpenLayers.Control.PanZoomBar() ], center:[0, 0], zoom: 1 }); map.div.oncontextmenu = function noContextMenu(e) { // use this if you want to handle context menu when is // triggered by right click /* if (OpenLayers.Event.isRightClick(e)){ // do something } */ return false; //cancel the right click of brower }; map.events.register('click', map, handleMapClick); function handleMapClick(e) { if (geocodePopup != null) { geocodePopup.destroy(); geocodePopup = null; } var lonlat = map.getLonLatFromViewPortPx(e.xy) .transform(toProjection, fromProjection); if (landmarkCallback) { landmarkCallback({latitude:lonlat.lat, longitude:lonlat.lon}); } // use lonlat // If you are using OpenStreetMap (etc) tiles and want to convert back // to gps coords add the following line :- // lonlat.transform( map.projection,map.displayProjection); // Longitude = lonlat.lon // Latitude = lonlat.lat } // choose renderers // and allow testing of specific renderers via "?renderer=Canvas", etc var renderer = OpenLayers.Util.getParameters(window.location.href).renderer; renderer = (renderer) ? [renderer] : OpenLayers.Layer.Vector.prototype.renderers; // polyline's layer var polysLayer = new OpenLayers.Layer.Vector("Poly"); // polygon's layer var polygonsLayer = new OpenLayers.Layer.Vector("Polygon"); // marker's layer // we can use OpenLayers.Markers but is old and it is still in the lib // because of backwards compatibility. var markersLayer = new OpenLayers.Layer.Vector("Markers", { styleMap: new OpenLayers.StyleMap({'default':{ strokeColor: "#00FF00", strokeOpacity: 1, strokeWidth: 3, fill:true, fillColor: "yellow", fillOpacity: 1, pointRadius: 1, // label with \n linebreaks label : "${name}", labelOutlineColor: "yellow", BackgroundColor: "yellow", externalGraphic: "images/${icon}", graphicWidth:30, graphicHeight:30, graphicOpacity:1, graphicXOffset:-12, graphicYOffset:-20, fontColor: "${favColor}", fontSize: "12px", fontFamily: "Courier New, monospace", fontWeight: "bold", labelAlign: "${align}", labelXOffset: "0", labelYOffset: "22", labelOutlineWidth: 4 }}), renderers: renderer }); // add the three layers to the map map.addLayer(markersLayer); map.addLayer(polygonsLayer); map.addLayer(polysLayer); // control for popup var selectFeature = new OpenLayers.Control.SelectFeature( markersLayer, { onSelect: createPopup, onUnselect: destroyPopup }); function createPopup(feature) { selectedMarker = feature.attributes.id; var FramedCloudCustomized = OpenLayers .Class(OpenLayers.Popup.FramedCloud, { displayClass: "olScrollable olPopup", registerEvents:function() { this.events = new OpenLayers.Events(this); } }); feature.popup = new FramedCloudCustomized("pop", feature.geometry.getBounds().getCenterLonLat(), null, '
'+feature.attributes.description+'
', null, true, function() { controls['selector'].unselectAll(); } ) map.addPopup(feature.popup); } function destroyPopup(feature) { selectedMarker = null; feature.popup.destroy(); feature.popup = null; } // new polygon drawing control var drawFeature = new OpenLayers.Control.DrawFeature( polygonsLayer, OpenLayers.Handler.Polygon); drawFeature.handler.move = emptyMove; // disable animation on drawing function emptyMove(evt) { } drawFeature.handler.dblclick = null; // disable ending with dbl click // callback after every new point added drawFeature.handler.callbacks.point = getPolygonToCallback; function getPolygonToCallback(evt) { var vertices = drawFeature.handler.getGeometry().getVertices(); return getPointsOfFeatureVertices(vertices); } // control for editing polygons var modifyFeature = new OpenLayers.Control.ModifyFeature(polygonsLayer); // callback after every polygon point edited polygonsLayer.events.on({ 'featuremodified': function(evt) { var vertices = evt.feature.geometry.getVertices(); return getPointsOfFeatureVertices(vertices); } }); // get the points when add/edit polygon points function getPointsOfFeatureVertices(vertices) { var points = []; for (var i = 0; i < vertices.length; i++) { var p = new OpenLayers.LonLat(vertices[i].x, vertices[i].y) .transform(toProjection, fromProjection); points.push({latitude: p.lat, longitude: p.lon}); } points = removeDuplicates(points); points = adjust(points); if (polyPointCallback) { polyPointCallback(points); } return points; // [{latitude, longitude}...] } // group the controls var controls = { selector: selectFeature, polygon: drawFeature, modify: modifyFeature, line: new OpenLayers.Control.DrawFeature(polysLayer, OpenLayers.Handler.Path), }; // add some atributes: rotation on edit, create new vertices on editing and // edit only one polygon at a time controls.modify.mode |= OpenLayers.Control.ModifyFeature.ROTATE; controls.modify.createVertices = true; controls.modify.standalone = true; controls.modify.clickout = false; // add controls to map for(var key in controls) { map.addControl(controls[key]); } controls['selector'].activate(); /* Resize the map to specified position; */ SfmbMapsOL.prototype.resize = function(height, width) { this.div.style.height = height + 'px'; this.div.style.width = width + 'px'; map.updateSize(); } /* Put the markers on map @params pointsArray: [{id, latitude, longitude, icon, description}...] setAutozoom: boolean */ SfmbMapsOL.prototype.putPoints = function(pointsArray, setAutozoom) { if (pointsArray.length == 0) { return; } var unselectMarker = undefined; var bounds = new OpenLayers.Bounds(); for (var i = 0; i < pointsArray.length; i++) { var oldPoint = markersLayer.getFeaturesByAttribute( "id", pointsArray[i].id); // test if the marker already exists if (pointsArray[i].id != "" && oldPoint[0] != null && oldPoint[0].attributes.lon == pointsArray[i].longitude && oldPoint[0].attributes.lat == pointsArray[i].latitude) { bounds.extend(oldPoint[0].geometry.getBounds()); // leave the point in peace } else { // remove the marker if (oldPoint[0] != null && pointsArray[i].id != "") { if (pointsArray[i].id == selectedMarker) { unselectMarker = pointsArray[i].id; } this.removePoint(pointsArray[i]); // remove the old point } // create marker var p = pointsArray[i]; var position = new OpenLayers.LonLat(p.longitude, p.latitude) .transform( fromProjection, toProjection); var point = new OpenLayers.Geometry.Point( position.lon, position.lat); var pointFeature = new OpenLayers.Feature.Vector(point); pointFeature.attributes = { id:p.id , name: p.id, favColor: 'black', align: "cm", icon: p.icon ? p.icon : "transparent.png", description: p.description, lat:p.latitude, lon:p.longitude }; markersLayer.addFeatures([pointFeature]); bounds.extend(pointFeature.geometry.getBounds()); if (pointsArray[i].id == "") { markersLayer.destroyFeatures([pointFeature]); } } } if (unselectMarker) { this.openInfoBubble(unselectMarker) unselectMarker = false; } if (setAutozoom) { autozoom(bounds); } } /* Removes all markers */ SfmbMapsOL.prototype.removeAllPoints = function() { selectFeature.unselectAll(); selectFeature.deactivate(); removeAllItems(markersLayer); selectFeature.activate(); } /* Remove marker @params point: {id, latitude, longitude, color, description} Obs: only the id is needed */ SfmbMapsOL.prototype.removePoint = function(point) { var p = markersLayer.getFeaturesByAttribute("id", point.id); if (p[0] != null) { if (p[0].popup != null) { selectFeature.unselect(p[0]); } selectFeature.deactivate(); markersLayer.destroyFeatures([p[0]]); selectFeature.activate(); } } /* Remove points from map @params points: [{id, latitude, longitude, color, description}...] */ SfmbMapsOL.prototype.removePoints = function(points) { if (!points) { return; } for (var i = 0; i < points.length; i++) { this.removePoint(points[i]); } } //to be used with polygons and polylines and markers function removeItem(collection, itemId){ var p = collection.getFeaturesByAttribute("name", itemId); if (p[0] != null) { collection.destroyFeatures([p[0]]); } } //removes all items from collection safely (calls removeItem on each item) function removeAllItems(collection){ collection.destroyFeatures(); } function autozoom(bounds) { map.zoomToExtent(bounds); } SfmbMapsOL.prototype.showLabels = function() { markersLayer.styleMap.styles.default.defaultStyle.label = "${name}"; markersLayer.redraw(); } SfmbMapsOL.prototype.hideLabels = function() { markersLayer.styleMap.styles.default.defaultStyle.label = ''; markersLayer.redraw(); } /* @params points: [{id, latitude, longitude, color, description}...] */ SfmbMapsOL.prototype.putLabels = function(points) { changeLabels(points, "${name}"); } /* @params points: [{id, latitude, longitude, color, description}...] */ SfmbMapsOL.prototype.removeLabels = function(points) { changeLabels(points, ""); } // Add/remove labels of points markers function changeLabels(points, add) { for (var i = 0; i < points.length; i++) { var p = markersLayer.getFeaturesByAttribute("id", points[i].id); if (!p[0]) { continue; } p[0].attributes.name = add ? p[0].attributes.id : ""; } markersLayer.redraw(); } /* @params: lat: latitude - double lon: longitude - double zoom: int */ SfmbMapsOL.prototype.centerZoom = function(lat, lon, zoom) { var center = new OpenLayers.LonLat(lon, lat) .transform( fromProjection, toProjection); map.panTo(center); map.zoomTo(zoom); markersLayer.redraw(); polygonsLayer.redraw(); polysLayer.redraw(); } /* @params mapType: string */ SfmbMapsOL.prototype.setMapType = function(mapType) { // TODO Change layer: maybe Google Maps } SfmbMapsOL.prototype.getMapType = function() { // TODO Change layer: maybe Google Maps return 'OSM'; } /* @params markerName: string */ SfmbMapsOL.prototype.openInfoBubble = function(markerName) { var p = markersLayer.getFeaturesByAttribute("id", markerName); //createPopup(p[0]); selectFeature.unselectAll(); selectFeature.select(p[0]); } /* Add a polygon to map @params name: string color: string points: [{latitude, longitude}...] */ SfmbMapsOL.prototype.setPolygon = function(name, color, points) { var sitePoints = []; // create style var polygonStyle = { fillColor:color, fillOpacity:0.4, strokeColor:color, strokeOpacity:0.9, strokeWidth:0.8 }; // group points for (var i in points) { var coord = points[i]; var point = new OpenLayers.Geometry.Point( coord.longitude, coord.latitude); // transform from WGS 1984 to Spherical Mercator point.transform(fromProjection, toProjection); sitePoints.push(point); } sitePoints.push(sitePoints[0]); var linearRing = new OpenLayers.Geometry.LinearRing(sitePoints); var geometry = new OpenLayers.Geometry.Polygon([linearRing]); var polygonFeature = new OpenLayers.Feature.Vector( geometry, null, polygonStyle); // attributes for keeping name and color in the polygon polygonFeature.attributes = { name:name, color:color } polygonsLayer.addFeatures([polygonFeature]); } /* name is optional. If name == null -> remove all @params name: string */ SfmbMapsOL.prototype.deletePolygon = function(name) { // if polygon is in newPolygon adding mode if (controls['polygon'].active && (name == polygonName || name == undefined)) { drawFeature.handler.cancel(); controls['polygon'].deactivate(); return; } // maybe the polygon is in editing mode controls['modify'].deactivate(); if (name) { removeItem(polygonsLayer, name); } else { removeAllItems(polygonsLayer); } } SfmbMapsOL.prototype.deleteAllPolygons = function() { this.deletePolygon(); } /* Add polyline on map @params setAutozoom: bool color: string thickness: double between 0 and 1 points: [{latitude, longitude}...] name: poly name */ SfmbMapsOL.prototype.setPoly = function(setAutozoom, color, thickness, points, name) { var nameAttr = "default"; if (name) { nameAttr = name; } var sitePoints = []; var polyStyle = { strokeColor:color, strokeOpacity:thickness, strokeWidth:5 }; for (var i in points) { var coord = points[i]; var point = new OpenLayers.Geometry.Point( coord.longitude, coord.latitude); // transform from WGS 1984 to Spherical Mercator point.transform(fromProjection, toProjection); sitePoints.push(point); } var linearRing = new OpenLayers.Geometry.LineString(sitePoints); //var geometry = new OpenLayers.Geometry.Polygon([linearRing]); var polyFeature = new OpenLayers.Feature.Vector( linearRing, null, polyStyle); polyFeature.attributes = { name:nameAttr } polysLayer.addFeatures([polyFeature]); } /* remove all polys @params name: string */ SfmbMapsOL.prototype.deletePoly = function(name) { if (name) { removeItem(polysLayer, name); } else { removeAllItems(polysLayer); } } /* Begin adding new polygon on the map Color is optional @params name: string color:string */ SfmbMapsOL.prototype.newPolygon = function(name, color) { if (!color) { color = blue; } polygonName = name; setStyle(color) setTempStyle(color); controls['polygon'].activate(); } /* Get the polygon info name is optional. If name == null -> remove all @params name: string @return: */ SfmbMapsOL.prototype.getPolygon = function(name) { var polygonArray = []; if (controls['polygon'].active && polygonName == name) { polygonArray = { name:name, color: polygonsLayer .styleMap .styles .default .defaultStyle .fillColor, points: getPolygonLatLongFromGeomString( controls['polygon'].handler.getGeometry())}; } else { if (name) { var p = polygonsLayer.getFeaturesByAttribute("name", name); if (p[0]) { polygonArray = { name:name, color: p[0].attributes.color, points: getPolygonLatLongString(p[0])}; } } else { for (i = 0; i < polygonsLayer.features.length; i++) { f = polygonsLayer.features[i]; polygonArray.push({ name: f.attributes.name, color:f.attributes.color, points:getPolygonLatLongString(f)}); } } } console.log(JSON.stringify(polygonArray)); if (getPolygonCallback) { getPolygonCallback(polygonArray); } return polygonArray; //[{name, color, [{latitude, longitude}...]}...] } function getPolygonLatLongFromGeomString(geometry) { var pointsArray = []; if (!geometry) { return pointsArray; } var points = geometry.components[0].components; for (var i = 0; i < points.length; i++) { var p = new OpenLayers.LonLat(points[i].x, points[i].y) .transform(toProjection, fromProjection); pointsArray.push({latitude: p.lat, longitude: p.lon}); } // [{latitude, longitude}...] return adjust(removeDuplicates(pointsArray)); } function removeDuplicates(array) { return array.reduce(function(a,c) { var dup = _(a).find(function(e){ return e.latitude === c.latitude && e.longitude === c.longitude }); if (!dup) a.push(c); return a; },[]); } function adjust(array) { return array.reduce(function(a, c) { if (c.longitude < -180 || c.longitude > 180) { var newLat = 360 - Math.abs(c.longitude); if (c.longitude >= 0) { newLat = -newLat; } c.longitude = newLat; } a.push(c); return a; }, []); } // get points array function getPolygonLatLongString(polygon) { // [{latitude, longitude}...] return getPolygonLatLongFromGeomString(polygon.geometry); } /* @params: name: string */ SfmbMapsOL.prototype.startEditPolygon = function(name) { var p = polygonsLayer.getFeaturesByAttribute("name", name); if (p[0]) { setTempStyle(p[0].attributes.color); setStyle(p[0].attributes.color) controls['modify'].virtualStyle.fillColor = p[0] .attributes.color; controls['modify'].virtualStyle.strokeColor = p[0] .attributes.color; controls['modify'].activate(); controls['modify'].selectFeature(p[0]); } } function setStyle(color) { polygonsLayer.styleMap.styles.default.defaultStyle.fillColor=color; polygonsLayer.styleMap.styles.default.defaultStyle.fillOpacity=0.4; polygonsLayer.styleMap.styles.default.defaultStyle.strokeColor=color; polygonsLayer.styleMap.styles.default.defaultStyle.strokeOpacity=0.9; polygonsLayer.styleMap.styles.default.defaultStyle.strokeWidth=0.8; } function setTempStyle(color) { polygonsLayer.styleMap.styles.temporary.defaultStyle.fillColor=color; polygonsLayer.styleMap.styles.temporary.defaultStyle.fillOpacity=0.4; polygonsLayer.styleMap.styles.temporary.defaultStyle.strokeColor=color; polygonsLayer.styleMap.styles.temporary.defaultStyle.strokeOpacity=0.9; polygonsLayer.styleMap.styles.temporary.defaultStyle.strokeWidth=0.8; } SfmbMapsOL.prototype.endEditPolygon = function() { // if in add new polygon mode if (controls['polygon'].active) { drawFeature.handler.finishGeometry(); //set attributes for keeping the polygon info polygonsLayer.features[polygonsLayer.features.length - 1] .attributes.name = polygonName; polygonsLayer.features[polygonsLayer.features.length - 1] .attributes.color = polygonsLayer .styleMap .styles .default .defaultStyle .fillColor; controls['polygon'].deactivate(); } controls['modify'].deactivate(); } /* Clear the items from map @params markers: [{id, latitude, longitude, color, description}...] polygons: [[name, color, {latitude, longitude}...]...] polys: [[{latitude, longitude}...]...] */ SfmbMapsOL.prototype.clearFromMap = function(markers, polygons, polys) { // NOT USED } /* Clear all from map */ SfmbMapsOL.prototype.resetAll = function() { this.removeAllPoints(); this.deletePolygon(); this.deletePoly(); } /* @params name: string color: string */ SfmbMapsOL.prototype.changePolygonColor = function(name, color) { var p = polygonsLayer.getFeaturesByAttribute("name", name); if (p[0]) { p[0].style.fillColor = color; p[0].style.strokeColor = color; p[0].attributes.color = color; setStyle(color) setTempStyle(color); controls['modify'].virtualStyle.fillColor = color; controls['modify'].virtualStyle.strokeColor = color; controls['modify'].selectFeature(p[0]); } } /* Geocoding */ SfmbMapsOL.prototype.geocode = function(address){ var query = "http://open.mapquestapi.com/nominatim/v1/search.php?format=json&q=" + address + "&limit=1"; var self = this; $.post(query,function(data,status){ if (status == "success") { if (data != "[]") { self.openSimplePopup(data[0]); } } //alert("Data: " + data + "\nStatus: " + status); }); } var geocodePopup; SfmbMapsOL.prototype.openSimplePopup = function(place){ if (geocodePopup != null) { geocodePopup.destroy(); geocodePopup = null; } var FramedCloudCustomized = OpenLayers .Class(OpenLayers.Popup.FramedCloud, { displayClass: "olScrollable olPopup", registerEvents:function() { this.events = new OpenLayers.Events(this); } }); var position = new OpenLayers.LonLat(place.lon, place.lat) .transform( fromProjection, toProjection); geocodePopup = new FramedCloudCustomized("simple_pop", position, null, '
'+place.display_name+'
', null, true, function() { geocodePopup.destroy(); geocodePopup = null; } ) map.addPopup(geocodePopup); map.panTo(position); //map.zoomTo(13); } SfmbMapsOL.prototype.setMapKind = function() { // TODO } SfmbMapsOL.prototype.getMapKind = function() { return "OSM"; } } var SfmbMaps = SfmbMapsOL;