Google Maps API Drawing Rectangle - google-maps-api-3

This is the meat of the code I am using and I am not getting errors, but I am not seeing the points that are in the area of the rectangle. Any help would be appreciated:
`enter code here`/** #this {google.maps.Rectangle} */
function showNewRect(event) {
var ne = rectangle.getBounds().getNorthEast();
var sw = rectangle.getBounds().getSouthWest();
google.maps.event.addlistener(rectangle, "bounds_changed", function(){
document.getElementById("map-selected").innerHTML=rectangle.getBounds();
var rectA = (ne*sw);
})
}
function listSelected () {
var inside = $.map( sites, function ( s ) {
var d;
if ( ( (d = google.maps.geometry.poly.containsLocation( s.position )) <= rectA ) )
return s.location + ' ('+(Math.round(d/100)/10)+' km)';
$('#map-selected').html( inside.sort().join('') );
});
}
google.maps.event.addListener(drawingManager, 'rectanglecomplete', function( rectangle ) {
selectedArea = rectangle;
listSelected();
google.maps.event.addListener(rectangle, 'center_changed', listSelected);
google.maps.event.addListener(rectangle, 'bounds_changed', listSelected);I am working with the Google maps API and I have a map I am drawing on with a rectangle. I need to have a user draw the rectangle, and on the map there will be predefined locations, that when the rectangle crosses the locations there will be details of each location put into a list.
This is an example:
http://hmoodesigns.com/ksi/
I have an example using the circle draw tool, which I can get to work fine, but the rectangle tool I have not been able to have this identify the points on the map.
How can I check for these points without having a predefined rectangle on the page?
Thanks,

When the Rectangle has been drawn iterate over the locations and use the method contains() of the Rectangle's bounds to test if the LatLng's are within the bounds of the Rectangle

Related

Google maps expand limitation of rectangle boundary

Please find the google mapsApi documentation https://developers.google.com/maps/documentation/javascript/shapes#editable
Please zoomout to world view and then expand the region selection towards right in single attempt. At some point you could observe that the selection became unstable and it selects entirely different section of the world.
By default the rectangle selection tool seems to look for shortest possible path to complete the shape. This creates a strange behavior when attempting to draw a very very large region.
I wanted to click and drag a very large region that covered a large geography. I was dragging West to East. Once the size of the object was very large, the selection reserved and was covering a completely different section of the world.
I attempt to expand a boundary to include the entire world. When the boundary goes far enough, again the region appears to be the minimal/smaller area.
Expected behavior was the selector to continue expanding in the direction the user intends. In this case I would expect the selector to continue its west to east expansion.
https://developers.google.com/maps/documentation/javascript/shapes#editable
var bounds = {north: 44.599, south: 44.490, east: -78.443, west: -78.649 }; // Define a rectangle and set its editable property to true. var rectangle = new google.maps.Rectangle({bounds: bounds, editable: true});
Please tries to expands rectangle to further right
Is there a solution to resolve the scenario mentioned?
Please let me know if further details required.
As I said in my comment, when you drag it "too far", the rectangle left and right coordinates (longitude) get inverted.
In other words, if you drag it too far to the right, right will become left and left will be where you dragged the right side to. And the opposite in the other direction. So by comparing where was the left with where is the right or vice-versa, you can detect if your rectangle left and right got inverted and invert it again... This way you can achieve what you want.
And of course if you drag the right side further to the right than where the left was (or the other way around), it will reset, as you can't have a rectangle overlapping itself around the globe.
The UI can be a bit confusing though, as you can see the rectangle lines get inverted but you can't do much about that.
var map;
function initialize() {
var mapOptions = {
center: new google.maps.LatLng(0, 0),
zoom: 2,
zoomControl: false
};
map = new google.maps.Map(document.getElementById('map-canvas'), mapOptions);
// Set origin bounds
var originBounds = new google.maps.LatLngBounds(
new google.maps.LatLng(-20, -100),
new google.maps.LatLng(20, 20)
);
// Get left/right coords
var left = originBounds.getSouthWest().lng();
var right = originBounds.getNorthEast().lng();
// Create editable rectangle
var rectangle = new google.maps.Rectangle({
bounds: originBounds,
fillColor: 'white',
fillOpacity: .5,
editable: true,
map: map
});
// Check for rectangle bounds changed
google.maps.event.addListener(rectangle, 'bounds_changed', function() {
// Get currents bounds and left/right coords
var newBounds = rectangle.getBounds();
var newLeft = newBounds.getSouthWest().lng();
var newRight = newBounds.getNorthEast().lng();
if ((newRight === left) || (newLeft === right)) {
// User dragged "too far" left or right and rectangle got inverted
// Invert left and right coordinates
rectangle.setBounds(invertBounds(newBounds));
}
// Reset current left and right
left = rectangle.getBounds().getSouthWest().lng();
right = rectangle.getBounds().getNorthEast().lng();
});
}
function invertBounds(bounds) {
// Invert the rectangle bounds
var invertedBounds = new google.maps.LatLngBounds(
new google.maps.LatLng(bounds.getNorthEast().lat(), bounds.getNorthEast().lng()),
new google.maps.LatLng(bounds.getSouthWest().lat(), bounds.getSouthWest().lng())
);
return invertedBounds;
}
initialize();
#map-canvas {
height: 150px;
}
<div id="map-canvas"></div>
<script src="https://maps.googleapis.com/maps/api/js"></script>

How to dynamically alter point radius and style of JSON path in d3?

I need help in dynamically "highlighting" cities on a world map, created using D3 and geoJSON.
I'm working on a spinning globe with 295 city-markers on it. Every 300 millisec, one of these cities need to "be highlighted", meaning 1) change its color and 2) increase its radius (and then stay that way). This gist shows the visual so far: gist example
Steps taken so far:
1) I started with "circle" elements in d3: highlighting was easily done by changing their class (and using CSS styles) and radius. However: the circles remained visible on the "backside" of the globe...
2) To solve the "no circles on back of earth" problem, this post showed me that JSON paths would help: http://bl.ocks.org/PatrickStotz/1f19b3e4cb848100ffd7.
I have now rewritten the code with these paths, and there is correct clipping of the markers on the back of the earth, but now I am stuck in dynamically accessing the radius and style of each city...
Question about changing the radius:
I understand that using path.pointRadius() I can alter the radius of the city markers. However, I want to do this dynamically (every 300msec), and only on a subselection of the markers each time. And that's where I get stuck...
Question about changing the style:
Also I would like to change the color, but assigning styles to the paths confuses me about how to access the JSON "Point" and "path" elements...
Code snippet showing my failed CSS styles attempt:
svg.append('g')
.selectAll("path")
.data(data,function(d,i){ return d.id })
.enter()
.append("path")
.datum(function(d) {
return {
type: "Point",
coordinates: [d.lon, d.lat],
class: "nohighlight" //MY ATTEMPT AT CHANGING CLASS... Not working...
}; })
.attr("class","city") //this class is assigned to the "correct" paths. Can I access them individually??
.attr("d", pathproj);
Code snippet showing the time loop in which the highlighting needs to happen:
//Highlighting the cities one by one:
var city_idx = 0; //data.id starts at 1
//Every 300 msec: highlight a new city:
var city_play = setInterval(function() {
city_idx++;
var filtered = data.filter(function(d) {
return d.id === city_idx;
});
// CHANGE CLASS?
// CHANGE RADIUS?
//Stop when all cities are highlighted
if(city_idx>=geo_data.length){
clearInterval(city_play) //terminates calls to update function within setInterval function.
};
}, 300); // end timer city play setInterval
Full code in block builder:
blockbuilder - globe and city markers
Please do let me know if I can clarify further!
We can do it this way:
To all path belonging to cities give a class
.selectAll("path")
.data(data,function(d,i){ return d.id })
.enter()
.append("path")
.classed("city", true) <--- so all cities point will have class city
Next in the timer block change radius and class dynamically like this:
var city_play = setInterval(function() {
city_idx++;
// Control the radius of ALL circles!
pathproj.pointRadius(function(d,i) {
//your biz logic
if (i < city_idx){
return 4
} else
return 2
});
// CHANGE CLASS?
// CHANGE RADIUS?
//select all elements with class city
d3.selectAll(".city").attr("class",
function(d, i){
if (i < city_idx){
return "city highlight"
} else
return "city"
}).attr("d", pathproj)
var len = d3.selectAll(".city").data().length;
console.log(city_idx, len)
//Stop when all cities are highlighted
if(city_idx>=len){
clearInterval(city_play) //terminates calls to update function within setInterval function.
};
}, 300);
working code here

Restrict panning and zoom on Here Maps 3.0

I generated a map with Here maps JS Api 3.0. I want to restrict the zoom to a min/max value and the panning to a given rectangle. Is there a way to do that?
for example:
map.setMinZoom(4);
map.setMaxZoom(14);
map.setPanRestriction(rectangle);
I am guessing you're trying to restrict the viewport to where you now have you image overlay...
The easiest way is to listen to view model and and viewport updates similar the other example:
Custom map overlay heremaps js api v3
Now you can look at the map's center coordinate and see if it is within the boundaries you wish to display. If not, set it to within the boundaries. Something along those lines may work for you:
var bounds = new H.geo.Rect(45, -45, -45, 45);
map.getViewModel().addEventListener('sync', function() {
var center = map.getCenter(),
adjustLat,
adjustLng;
if (!bounds.containsPoint(center)) {
if (center.lat > bounds.getTop()) {
adjustLat = bounds.getTop();
} else if (center.lat < bounds.getBottom()) {
adjustLat = bounds.getBottom();
} else {
adjustLat = center.lat;
}
if (center.lng < bounds.getLeft()) {
adjustLng = bounds.getLeft();
} else if (center.lng > bounds.getRight()) {
adjustLng = bounds.getRight();
} else {
adjustLng = center.lng;
}
map.setCenter({
lat: adjustLat,
lng: adjustLng
});
}
});
//Debug code to visualize where your restriction is
map.addObject(new H.map.Rect(bounds));

How to get the fillColor of overlay shapes in Google maps?

Look at this code: a is an object we save a circle overlay inside. In Google maps we can get type{polygon, circle, rectangle, marker, polyline} or center{circle}, etc. Imagine you create a circle on the map. How can you get something like this:
a.fillColor = circle.fillColor;
<script>
function getProprties()
{
var a = {};
a.type = circle.type;
a.center = circle.center;
a.redius = circle.radius;
}
</script>
You should be able to use this, using the get function available on all MVCObjects
a.fillColor = circle.get('fillColor');

Multiple marker selection within a box in leaflet

I need to select multiple markers in a map. Something like this: Box/Rectangle Draw Selection in Google Maps but with Leaflet and OSM.
I think it could be done by modifying the zoom box that appears when you shift click and drag in an OSM map, but I don't know how to do it.
Edit:
I rewrote the _onMouseUp function, as L. Sanna suggested and ended up with something like this:
_onMouseUp: function (e) {
this._finish();
var map = this._map,
layerPoint = map.mouseEventToLayerPoint(e);
if (this._startLayerPoint.equals(layerPoint)) { return; }
var bounds = new L.LatLngBounds(
map.layerPointToLatLng(this._startLayerPoint),
map.layerPointToLatLng(layerPoint));
var t=0;
var selected = new Array();
for (var i = 0; i < addressPoints.length; i++) {
var a = addressPoints[i];
pt = new L.LatLng(a[0], a[1]);
if (bounds.contains(pt) == true) {
selected[t] = a[2];
t++;
}
}
alert(selected.join('\n'))
},
I think it could be easy modificating the zoom box that appears when
you shift clic and drag in an osm map, but I don't know how to do it
Good idea. The zoom Box is actually a functionality of leaflet.
Here is the code.
Just rewrite the _onMouseUp function to fit your needs.
Have you tried something like this?
markers is an array of L.latLng() coordinates
map.on("boxzoomend", function(e) {
for (var i = 0; i < markers.length; i++) {
if (e.boxZoomBounds.contains(markers[i].getLatLng())) {
console.log(markers[i]);
}
}
});
Not enough points to comment, but in order to override the _onMouseUp function like OP posted in their edit, the leaflet tutorial gives a good explanation. Additionally, this post was very helpful and walks you through every step.
A bit late to the party but it's also possible to achieve this using the leaflet-editable plugin.
// start drawing a rectangle
function startSelection() {
const rect = new L.Draw.Rectangle(this.map);
rect.enable();
this.map.on('draw:created', (e) => {
// the rectangle will not be added to the map unless you
// explicitly add it as a layer
// get the bounds of the rect and check if your points
// are contained in it
});
}
Benefits of using this method
Allow selection with any shape (polygon, circle, path, etc.)
Allow selection using a button/programmatically (does not require holding down the shift key, which may be unknown to some users).
Does not change the zoom box functionality

Resources