I have a model in javascript which has latitude and longitude value. I have to find a feature on the map by the ID of the element and update it's location and several other properties. My code looks like this:
function updateCoordinate(item) {
var features = source.getFeatures();
var featureToUpdate;
// find feature by custom property
for(var i=0; i< features.length; i++) {
if (features[i].get('ID') == item.ID) {
featureToUpdate = features[i];
break;
}
}
// get lon, lat from input item
var lon = item.Coordinate.Longitude;
var lat = item.Coordinate.Latitude;
// update geometry (not working)
featureToUpdate.set('Geometry', new ol.geom.Point(getPointFromLongLat(lon, lat)));
// update custom properties (working)
featureToUpdate.set('MapMarkerTitle', item.Title);
// ...
}
function getPointFromLongLat (long, lat) {
return ol.proj.transform([long, lat], 'EPSG:4326', 'EPSG:3857')
}
Am I doing something wrong? Is there a better way for this? Is there a better way to find feature by custom property?
By custom poperty I mean that the feature is getting initiated like this:
var fea = new ol.Feature({
geometry: new ol.geom.Point(getPointFromLongLat(lon, lat)),
MapMarkerTitle : 'AAA',
// ...
})
source.addFeatures([fea]);
The custom properties are getting updated but the coordinate doesn't seem to update. Will the feature be redrawn after updating position? The label is however redrawn so I think yes.
UPDATE
After some debugging I found out that, I mispelled the 'geometry' property with uppercase.
Actually:
featureToUpdate.set('geometry', new ol.geom.Point(getPointFromLongLat(lon, lat)));
does set the new position and update the location right away. I would still like to know if what I am doing is the good way or there is better. Thanks!
You can simplify it to:
function updateCoordinate(item) {
var featureToUpdate = source.getFeatureById(item.ID);
var coord = getPointFromLongLat(item.Coordinate.Longitude, item.Coordinate.Latitude);
featureToUpdate.getGeometry().setCoordinates(coord);
featureToUpdate.set('MapMarkerTitle', item.Title);
}
Related
I have quite a few Tile Layers in my map, and they are all organized into different groups (sometimes they are even nested).
I see in API there's a getLayer() method to retrieve the layer a Vector feature belongs to, and a getLayerGroup() to retrieve all groups associated with a Map.
However, I could not find anything on getting the layerGroup a layer is associated with.
Lets'say I have this situation:
var myGroup = new LayerGroup();
var myLayer = new TileLayer();
myGroup.getLayers().insertAt(0, myLayer);
Is there a way to get myGroup from myLayer?
To get the parent group of a layer would need to write your own search function, something like
function searchGroups(group, layer) {
var result;
var layers = group.getLayers().getArray();
for (var i = 0; i < layer.length; i++) {
if (layers[i] === layer) {
result = group;
} else if (layers[i] instanceof LayerGroup) {
result = searchGroup(layers[i], layer)
}
if (result) {
break;
}
}
return result;
}
then call
var myGroup = searchGroups(map.getLayerGroup(), mylayer);
The getLayers() function you linked only works for a select interaction, you cannot determine from a random feature which layer it belongs to (and it could be in more than one) without a similar search of the features in each vector layer source.
I realize this question has already been answered, but alternatively, you also have the properties attribute for your layers, so you could add an array of group names to the layer itself. For example:
let parent_group = "parent_group";
let sub_group = "sub_group";
let group = new LayerGroup({
name: parent_group,
layers: [
new LayerGroup({
name: sub_group,
layers: [
new TileLayer() {
properties: [
parent_group,
sub_group
]
}
]
})
]
})
Then it's just a matter of looking up the layer name and looking up its properties array - probably a bit more cumbersome to setup initially, but it would save having to recursively search through layerGroups.
My map contains multiple features, the ids for all these features are stored in an array: featureIds.
My application contains a button which toggles the visibililty of some of the features.
I am working on a JavaScript function reCenter() to follow this toggling. This function "zooms" out and refits the map view in accordance to the bounds of features which are now visible.
function reCenter() {
// new array for visible features
var visibleFeatures = [];
// retrieve the features which are visible and put them into the new array
for (var i = 0; i < featureIds.length; i++) {
if (map.getLayoutProperty(featureIds[i], "visibility") == "visible") {
visibleFeatures.push(map.queryRenderedFeatures(featureIds[i]));
}
}
// new array to store coordinates
coordinates = [];
// push coordinates for each visible feature to coordinates array
for (var j = 0; j < visibleFeatures.length; j++) {
coordinates.push(coord.geometry.coordinates);
}
// do fit as shown here : https://docs.mapbox.com/mapbox-gl-js/example/zoomto-linestring/
var bounds = coordinates.reduce(function (bounds, coord) {
return bounds.extend(coord);
}, new mapboxgl.LngLatBounds(coordinates[0], coordinates[0]));
map.fitBounds(bounds, {
padding: 20
});
}
Despite implementing the above and following the guidance provided at https://docs.mapbox.com/mapbox-gl-js/example/zoomto-linestring/. I receive the following error: TypeError: this._sw is undefined
How can one best dyanmically retrieve all coordinates of visibile features and pass them into map.fitBounds()?
Get all your features and create a FeatureCollection and with bbox function from Turf.js get the bounds of the FeatureCollection. here is how I do that:
note: use toWgs84 if your coordinates are not wgs84.
const features = [
{
type: 'Feature',
geometry: {
type: 'Polygon',
coordinates: [
[your_feature_s_coordinates],
[...],
]
}
},
{another feature}
]
const FeatureCollection = {
type: "FeatureCollection",
features: features
};
map.fitBounds(bbox(toWgs84(FeatureCollection)));
Try Turf.js: js is an open-source JavaScript library used for spatial analysis.
And it provide's a method bbox (http://turfjs.org/docs/#bbox)
It take's some set of feature's and will automatically calculate bbox for you. and set that final bbox to fitbounds.
and there's a similar question asked earlier:
Mapbox GL JS getBounds()/fitBounds()
I'm trying to get the Paths of a polygon, and then set them to another polygon like that.
newpoly = new google.maps.Polygon({
paths:poly.getPaths()
});
Isn't this suppose to work ? It gives me this error in the console.
Invalid value for constructor parameter 0: [object Object]
Try adding the following before you instantiate the polygon object
var triangleCoords = [
new google.maps.LatLng(25.774252, -80.190262),
new google.maps.LatLng(18.466465, -66.118292),
new google.maps.LatLng(32.321384, -64.75737),
new google.maps.LatLng(25.774252, -80.190262)
];
Now use you code and replace the poly.getPaths() - Assuming the rest of your code works.
newpoly = new google.maps.Polygon({
paths:triangleCoords //there are probably more method to add here
});
If it works then you know there is something wrong with poly.getPaths(). Use this as reference https://developers.google.com/maps/documentation/javascript/overlays#PolygonOptions.
Remember that we can only use the code that was provide to formulate an solution.
It would help if you can show the code for poly object and if poly.getPaths() return anything. All I can recomand si to debug it in detail like this:
Do you hace any error if you comment paths:poly:Paths();
Console.log(poly); return a google map polygon?
Console.log(poly.getPaths()) return an array of paths?
If yes, you can try to create an array from poly.getPaths then pass it to newpoly.
Get the coords of first polygon this way (assuming that the two polygons were already created):
//store polygon path
var vertices = firstPolygon.getPath();
// Iterate over the vertices.
pathOfFirstPolygon = [];
for (var i =0; i < vertices.getLength(); i++) {
var xy = vertices.getAt(i);
item = {};
item["lat"] = xy.lat();
item["lng"] = xy.lng();
pathOfFirstPolygon.push(item);
};
//Set path of the second polygon
secondPolygon.setPath(pathOfFirstPolygon);
I have a map with various markers and i need to be able to draw a rectangle on the map and select the markers which are within the rectangle bounds.
So far i have found some great info here: How to get markers inside an area selected by mouse drag?
I have implemented the keymapzoom plugin ok. like so
$('#dispatcher').gmap3({action:'get'}).enableKeyDragZoom({
boxStyle: {
border: "dashed black",
//backgroundColor: "red",
opacity: 0.5
},
paneStyle: {
backgroundColor: "gray",
opacity: 0.2
}
});
var dz = $('#dispatcher').gmap3({action:'get'}).getDragZoomObject();
google.maps.event.addListener(dz, 'dragend', function (bnds) {
alert(bnds);
});
This gives me the following
((lat,long),(lat,long)) format from the alert(bnds);
I need to know how i can now check if any markers are within this?
I already have an object that is storing the markers for another reason. like:
markers[name] = {};
markers[name].lat = lati;
markers[name].lng = longi;
which might be useful?
I don't understand how to use the GLatLngBounds and containsLatLng(latlng:GLatLng) as suggested.
Your question is tagged with the v3 version of the Maps API, so I'll assume you are using that version (which you should as v2 is deprecated). Note that some classes and methods are named different than in your question.
Bounds are represented with the LatLngBounds class. You can perform the contains method on an instance of that class to determine if a point lies within those bounds.
If you have an object with all your markers, you can loop through them and check each marker, for example:
var bounds = new google.maps.LatLngBounds(sw, ne);
for (var a in markers) {
if (bounds.contains(new google.maps.LatLng(markers[a].lat, markers[a].lng)) {
// marker is within bounds
}
}
On a side note, I would store the LatLng object in the markers object when creating them. That way you don't have to create them wherever you need.
Box/Rectangle Draw Selection in Google Maps
This was my solution..
google.maps.event.addListener(dz, 'dragend', function(e) { //important listener
for(var i = 0; i < markers.length; i++){ // looping through my Markers Collection
if(e.contains(markers[i].position))
console.log("Marker"+ i +" - matched");
}
});
I have a connection to a database(db). I am getting the lon, lat and name from the db and stroing them:
while ($row_ChartRS = mysql_fetch_array($sql1))
{
$latitude=$row_ChartRS['latitude'];
$longitude=$row_ChartRS['longitude'];
$bus_name =$row_ChartRS['short_name'];
//echo $latitude.'--'.$longitude.'<br>';
echo $bus_name;
I then create a map to display the data. The markers are working fine for all lat, lon locations. Code:
function init()
{
projLonLat = new OpenLayers.Projection("EPSG:4326"); // WGS 1984
projMercator = new OpenLayers.Projection("EPSG:900913"); // Spherical Mercator
overviewMap = new OpenLayers.Control.OverviewMap();
//adding scale ruler
scale = new OpenLayers.Control.ScaleLine();
scale.geodesic = true; // get the scale projection right, at least on small
map = new OpenLayers.Map('demoMap',
{ controls: [ new OpenLayers.Control.Navigation(), // direct panning via mouse drag
new OpenLayers.Control.Attribution(), // attribution text
new OpenLayers.Control.MousePosition(), // where am i?
new OpenLayers.Control.LayerSwitcher(), // switch between layers
new OpenLayers.Control.PanZoomBar(), // larger navigation control
scale,
overviewMap // overview map
]
}
);
map.addLayer(new OpenLayers.Layer.OSM.Mapnik("Mapnik"));
map.addLayer(new OpenLayers.Layer.OSM.Osmarender("Osmarender"));
//Create an explicit OverviewMap object and maximize its size after adding it to the map so that it shows
//as activated by default.
overviewMap.maximizeControl();
//Adding a marker
markers = new OpenLayers.Layer.Markers("Vehicles");
map.addLayer(markers);
vectorLayer = new OpenLayers.Layer.Vector('Routes');
map.addLayer(vectorLayer);
for (k in Locations)
{
//adding a popup for the marker
var feature = new OpenLayers.Feature(markers, new OpenLayers.LonLat(Locations[k].lon, Locations[k].lat).transform(projLonLat,projMercator));
//true to close the box
feature.closeBox = true;
feature.popupClass = new OpenLayers.Class(OpenLayers.Popup.AnchoredBubble,
{
//create the size of the box
'autoSize': true,
'maxSize': new OpenLayers.Size(100,100)
});
//add info into box
for (z in names)
{
feature.data.popup = new OpenLayers.Feature(new OpenLayers.LonLat(names[z]).transform(projLonLat,projMercator));
}
//puts a scroll button on box to scroll down to txt
//feature.data.overflow = "auto";
marker = feature.createMarker();
marker.display(true);
markerClick = function (evt) {
if (this.popup == null) {
this.popup = this.createPopup(this.closeBox);
map.addPopup(this.popup);
this.popup.show();
} else {
this.popup.toggle();
}
currentPopup = this.popup;
OpenLayers.Event.stop(evt);
};
marker.events.register("mousedown", feature, markerClick);
markers.addMarker(marker);
map.setCenter(new OpenLayers.LonLat(Locations[k].lon, Locations[k].lat).transform(projLonLat,projMercator), zoom);
var lonLat1 = new OpenLayers.LonLat(Locations[k].lon,Locations[k].lat).transform(new OpenLayers.Projection('EPSG:4326'), map.getProjectionObject());
var pos2=new OpenLayers.Geometry.Point(lonLat1.lon,lonLat1.lat);
points1.push(pos2);
//Uncomment to put boxes in when map opens
//feature.popup = feature.createPopup(feature.closeBox);
//map.addPopup(feature.popup);
//feature.popup.show()
}
var lineString = new OpenLayers.Geometry.LineString(points1);
var lineFeature = new OpenLayers.Feature.Vector(lineString,'',style_green);
vectorLayer.addFeatures([lineFeature]);
map.setCenter(lonLat1,zoom);
} //function
However the name in the popup marker is the same for all markers. i.e. the last name pulled from the db. Can anyone please help with this - I have spent 3 full days trying to fix it!
Thanks in advance!
A few comments:
The PHP code you’ve posted is completely irrelevant, since it’s not seen to be used anywhere.
The objects names and Locations aren’t declared anywhere in the code you posted. What do they contain?
In the code quoted below, you’re creating multiple new Feature objects, but you assign them all to the same property (thereby overwriting that property each time). Is that intentional?
//add info into box
for (z in names) {
feature.data.popup = new OpenLayers.Feature(new OpenLayers.LonLat(names[z]).transform(projLonLat,projMercator));
}
Edit:
This does appear to be where it’s going wrong. You should remove the for...z loop, and replace it with the following code:
//add info into box
feature.data.popup = new OpenLayers.Feature(new OpenLayers.LonLat(names[k]).transform(projLonLat,projMercator));
Since in PHP, you’re using the same index ($v) to fill both arrays, it makes sense to use the same index to read them in javascript...
Aside from that, using the for...in loop on Javascript arrays is not considered good practice, for a number of reasons. It’s better to use the following:
for (k = 0; k < Locations.length; k += 1) {
// your code
}
i had the same problem , and i solve it ...
the problem is overwrite
you don't have to loop inside your function , do the loop for function for example:
function init(z)
{
feature.data.popup = new OpenLayers.Feature(new OpenLayers.LonLat(names[z]).transform(projLonLat,projMercator));
}
for (z in names)
{
init(z)
}