I'm trying to create a website for vehicles localization on map, but i have some problem with openlayers.
This is my first time with OL…
What I would do is:
– add and update features (my vehicles) on map. DONE
– follow only vehicles visible on screen. DONE
– add and update popup on map. PARTIAL 1
– add clustering options. NO
– remove and add features in run time. PARTIAL 2
I have a series of functions called by runtime engine for updating values.
PARTIAL 1 Popup is shown correclt
popup is shown correctly but what I want to do is update it values and position when vehicle is updated (function drawPosition) – only if popup is active –
STRATEGY
I am a little bit confused about clustering mode.
Now I have a series of png with different color (which represent the status of vehicles).
I would create groups of icons with same color, visibles only by at some zoom level.
Is it possible to create a vector (circles with different color) to represent clusters if I used PNG icons as markers?
Or i must create a big PNG that represent the cluster?
PARTIAL 2
A user can change vehicles shown on map with a jquery dialog.
JS call: pulisiMappa() to clean map from all features and call again drawPosition() to add vehicles choosed by user.
It works great but with my code i lose something.
I don't know if with destroyFeatures() I lose the event.register on l_elements (my vector layer) or I lose something about SelectFeature
Where's the problem?
this is my code:
var map; var justLoaded = 0 var points = []; var storico = { path: null, pos: null, pts: [], viaggio: { viaggio: null, start: null, stop: null} }; var eventPoints = []; var select_feature_control; var l_elements, m_osm, m_google_str, m_google_sat, m_google_ril, m_google_satH, m_ovi, m_base, m_base_et; // WGS84 -> PTV_MERCATOR OpenLayers.Projection.addTransform("EPSG:4326", "PTV_MERCATOR", function (point) { var RPI = Math.PI * 6371000.0; var x = point.x * RPI / 180; var y = Math.log(Math.tan((90 + lat) * Math.PI / 360)) / (Math.PI / 180); y = y * RPI / 180; point.x = x; point.y = y; }); // PTV_MERCATOR -> WGS84 OpenLayers.Projection.addTransform("PTV_MERCATOR", "EPSG:4326", function (point) { var RPI = Math.PI * 6371000.0; var lon = (point.x / RPI) * 180; var lat = (point.y / RPI) * 180; lat = 180 / Math.PI * (2 * Math.atan(Math.exp(lat * Math.PI / 180)) - Math.PI / 2); point.x = lon; point.y = lat; }); function initMap() { map = new OpenLayers.Map({ div: "mapContainer", projection: new OpenLayers.Projection("EPSG:4326"), displayProjection: new OpenLayers.Projection("EPSG:4326"), controls: [ new OpenLayers.Control.Attribution(), new OpenLayers.Control.TouchNavigation({ dragPanOptions: { interval: 100, enableKinetic: true } }), new OpenLayers.Control.ScaleLine({}), new OpenLayers.Control.LayerSwitcher(), new OpenLayers.Control.NavToolbar(), new OpenLayers.Control.KeyboardDefaults({ autoActivate: true }) ], units: "m", numZoomLevels: 20, maxResolution: 9783.939619140625, /*156543.0399,*/ minResolution: 0.5971642833948135, maxExtent: new OpenLayers.Bounds(-19900000.0, -7300000.0, 19900000.0, 18600000.0), restrictExtent: new OpenLayers.Bounds(-19900000.0, -7300000.0, 19900000.0, 18600000.0) }); var style = new OpenLayers.Style({ pointRadius: "${radius}", fillColor: "#ffcc66", fillOpacity: 0.8, strokeColor: "#cc6633", strokeWidth: 2, strokeOpacity: 0.8, externalGraphic: "${icona_elemento}", graphicWidth: 38, graphicHeight: 38, rotation: "${angle}", fillOpacity: 1, graphicZIndex: 10, label: "${nome_elemento}", labelAlign: "cb", labelYOffset: -24, fontOpacity: 1, fontWeight: 600, fontColor: "#000", fontSize: "10px", fontFamily: "\"Lucida Grande\", \"Lucida Sans Unicode\", Helvetica, Arial, Verdana, sans-serif" }, { context: { externalGraphic: null, radius: function (feature) { return Math.min(feature.attributes.count, 7) + 3; } } }); m_osm = new OpenLayers.Layer.OSM(); m_google_ril = new OpenLayers.Layer.Google("Google Rillievo",{ type: google.maps.MapTypeId.TERRAIN }); m_google_str = new OpenLayers.Layer.Google("Google Stradale", { numZoomLevels: 20, isBaseLayer: true, sphericalMercator: true }); m_google_satH = new OpenLayers.Layer.Google("Google Satellite Ibrida",{ type: google.maps.MapTypeId.HYBRID, numZoomLevels: 20 }); m_google_sat = new OpenLayers.Layer.Google("Google Satellite", { type: google.maps.MapTypeId.SATELLITE, numZoomLevels: 20, sphericalMercator:true }); m_ovi = new OpenLayers.Layer.XYZ("Nokia Ovi Maps", ["http://a.maptile.maps.svc.ovi.com/maptiler/maptile/newest/normal.day/${z}/${x}/${y}/256/png8", "http://b.maptile.maps.svc.ovi.com/maptiler/maptile/newest/normal.day/${z}/${x}/${y}/256/png8"], { transitionEffect: 'resize', sphericalMercator: true, numZoomLevels: 18 }); l_elements = new OpenLayers.Layer.Vector("Veicoli", { styleMap: new OpenLayers.StyleMap({ "default": style, "select": { cursor: "hand", graphicWidth: 40, graphicHeight: 40, graphicZIndex: 11, fillColor: "#8aeeef", strokeColor: "#32a8a9" } }), /* strategies: [ new OpenLayers.Strategy.Refresh(), new OpenLayers.Strategy.Cluster() ],*/ renders: ['canvas', 'SVG', 'VML'], rendererOptions: { zIndexing: true } } ); map.addLayers([m_osm, m_google_str, m_google_sat, m_ovi, m_google_ril, m_google_satH, l_elements]); //setto il clip rect e lo zoom var curClipRect = parent.getCartografiaClipRect(); var myClipRect = { left: curClipRect.left / 100000, top: curClipRect.top / 100000, right: curClipRect.right / 100000, bottom: curClipRect.bottom / 100000 } var theRect = new OpenLayers.Bounds(); theRect.extend(new OpenLayers.LonLat(myClipRect.left, myClipRect.top).transform(new OpenLayers.Projection("EPSG:4326"), map.getProjectionObject())); theRect.extend(new OpenLayers.LonLat(myClipRect.right, myClipRect.bottom).transform(new OpenLayers.Projection("EPSG:4326"), map.getProjectionObject())); theRect.toBBOX(); map.zoomToExtent(theRect, true); select_feature_control = new OpenLayers.Control.SelectFeature(l_elements, { multiple: false, toggle: true, hover: false }); map.addControl(select_feature_control); select_feature_control.activate(); l_elements.events.on({ 'featureselected': function (evt) { var feature = evt.feature; popup = new OpenLayers.Popup.FramedCloud("featurePopup", feature.geometry.getBounds().getCenterLonLat(), new OpenLayers.Size(280, 63), feature.attributes.description, null, true, select_feature_control.unselect(feature)); feature.popup = popup; popup.feature = feature; map.addPopup(popup, true); $('a[id$="_bubbleDetail"]').click(function () { var myid = this.id.replace("_bubbleDetail", ""); if (parent.$("#cruscotto").dialog("isOpen") == false) { parent.$("#cruscotto").dialog("open"); } parent.$(".box_container").not("#" + myid + "_boxContainer").removeClass("active"); parent.$("#" + myid + "_boxContainer").addClass("active"); parent.handleBubbleDetail(myid); map.removePopup(feature.popup); feature.popup.destroy(); feature.popup = null; }); }, 'featureunselected': function (evt) { var feature = evt.feature; if (feature.popup) { map.removePopup(feature.popup); feature.popup.destroy(); feature.popup = null; } } }); justLoaded = 1; parent.rebuildScene(); parent.setMapLoaded(); if (parent.document.location.href.indexOf("listaveicoli") >= 0) { map.events.register('zoomend', this, changeZoomHandler); map.events.register('moveend', this, changeZoomHandler); } } function drawPosition(posInfo) { // new feature if (points["_" + posInfo.id] == undefined) { var newPos = new OpenLayers.Feature.Vector(); var obj = { id: posInfo.id, follow: posInfo.follow, newpos: 1, _pt: newPos, _lb: null, loaded: 0 }; points["_" + posInfo.id] = obj; } if (posInfo.ico.indexOf("old_style")) { var colore = posInfo.ico.split("_"); if (parseInt(posInfo.dir) 0) pts = pts + ","; pts = pts + myId; } else points[pos].follow = 0; } } var todo = 1; parent.setMezziToFollow(pts); }; /* ----------------------------------------------------------------------------------------------------------------------------- */ //map clean function pulisciMappa() { for (var myId in points) { var tmpInfo = { id: myId.replace("_", "") } removePosition(tmpInfo); } points = []; // deleteViaggio(); // deletePosizioneStorico(); // deleteStorico(); // deleteEventi(); } //remove features function removePosition(posInfo) { //id veicolo var myId = posInfo.id; var _punto = points["_" + posInfo.id]._pt; if (points["_" + posInfo.id].loaded == 1) { l_elements.destroyFeatures(_punto); } points["_" + posInfo.id]._pt = null; points["_" + posInfo.id]._lb = null; points["_" + posInfo.id].loaded = 0; }
I'll hope everything is clear 😉
EDIT 1: about partial 1 and 2…
it's me again..
Thanks Aragon, with your code now I can update popup content and its position.
I added this code to drawPosition() function:
if(map.popups.length > 0) { if(_punto.id == map.popups[0].id) { map.popups[0].setContentHTML(posInfo.bubble); map.popups[0].lonlat.lon = pointCoord.x; map.popups[0].lonlat.lat = pointCoord.y; map.popups[0].updatePosition(); } }
and everything works fine.
Now I m trying to fix the "event listner" on features when I update vehicles to show.
When I select some vehicles from a jquery dialog, a backend function cleans the vector layer (l_elements) and when layer is clean, there is a "for" cycle that make a call of drawPosition() to add a new feature for every vehicle selected.
Everything works good except the "event listener" over this features.
If I click on every features nothing happens.. 🙁
I have this code in init() function:
select_feature_control = new OpenLayers.Control.SelectFeature(l_elements, { multiple: false, toggle: true, hover: false }); map.addControl(select_feature_control); select_feature_control.activate(); l_elements.events.on( { 'featureselected': function (evt) { alert("ciao"); var feature = evt.feature; popup = new OpenLayers.Popup.FramedCloud("featurePopup", feature.geometry.getBounds().getCenterLonLat(), new OpenLayers.Size(280, 63), feature.attributes.description, null, true, select_feature_control.unselect(feature)); feature.popup = popup; popup.feature = feature; popup.id = feature.id; map.addPopup(popup, true); $('a[id$="_bubbleDetail"]').click(function () { var myid = this.id.replace("_bubbleDetail", ""); if (parent.$("#cruscotto").dialog("isOpen") == false) { parent.$("#cruscotto").dialog("open"); } parent.$(".box_container").not("#" + myid + "_boxContainer").removeClass("active"); parent.$("#" + myid + "_boxContainer").addClass("active"); parent.handleBubbleDetail(myid); map.removePopup(feature.popup); feature.popup.destroy(); feature.popup = null; }); }, 'featureunselected': function (evt) { var feature = evt.feature; if (feature.popup) { map.removePopup(feature.popup); feature.popup.destroy(); feature.popup = null; } } });
Should I move it in drawPosition function?
EDIT 2:
PARTIAL 2 is solved:
I made this changes to my code:
drawPosition()
//_punto.id = posInfo.id; _punto.attributes = { angle: posInfo.dir, title: posInfo.label, id: posInfo.id, description: posInfo.bubble, icona_elemento: icona_elemento, nome_elemento: posInfo.label };
init()
'featureselected': function (evt) { var feature = evt.feature; popup = new OpenLayers.Popup.FramedCloud("featurePopup", feature.geometry.getBounds().getCenterLonLat(), new OpenLayers.Size(280, 63), feature.attributes.description, null, true, select_feature_control.unselect(feature)); feature.popup = popup; popup.feature = feature; popup.id = feature.attributes.id; map.addPopup(popup, true); },
And everything works good 😉
So..
– partial 1 is ok
– partial 2 is now ok
Best Answer
you can catch your opened(active) popup with this way:
you can change so update its content:
you can show or hide your popup:
you can update position of your popup:
for openlayers cluster you should check out Cluster Strategy Example here. Only one thing you should do is that define fillColor or externalGraphic for your cluster.
As the last question, i dont understand very well what you want? but try to use removeFeatures instead of destroyFeatures....
i hope it helps you...