Is this possible in Google Maps? Drawing a box manually on Google Maps - google-maps

I am working on integrating Google Maps into a web application and I have a question of possibility.
I am using ASP .Net 4.0 as the basis for the code, but i suspect i will have to use JavaScript to achieve most of this, which is. Basically I want to display a bunch of markers on a map from Lat Long locations i have stored in a database, then have the user be able to draw a box on the map with the mouse, then get back the lat long of the four corners of the box.
If anyone knows how i could do this this would be of great help to me!
Thanks

The complexity of the Google Maps API has kept me scared for years. Recently I stumbled upon a jQuery plugin called GMap3 that does a lot of the heavy lifting for you.
I would suggest that after initializing and all that, you print a Javascript block from your .NET code, with something like this:
var markersFromDatabase = [
[60.164967,24.94758],
[59.956495, 10.764599]
//etc. This array should be printed from your serverside code
];
var markersToBeAdded = [];
jQuery.each(markersFromDatabase, function(indexOfItem, valueOfItem){
markersToBeAdded.push({
lat:valueOfItem[0],
lng:valueOfItem[1],
options: {
draggable: false,
icon: "img/your_awesome_icon.png",
title: "This is an icon from my database!"
}
});
});
jQuery("#map_canvas").gmap3(
{ action: 'addMarkers',
markers: markersToBeAdded
}
);
Edit: I realize now that I only answered half of your question. I'm afraid I have no apparent answer to the selection box. I suspect that you can use addRectangle or, in a worst case scenario, addFixPanel that lets you add a transparent <div> over your map canvas (and then trigger mouse events for that).

Here is one way to do it with Google Maps API 3's overlay editable feature.
Google Maps Overlay Editable

If your question is "How to select multiple markers with a rectangle", you can do something like this:
var markers = []; // This array must be filled with your data
var rectangles = [];
var triggeredMarkers = [];
google.maps.event.addListener(drawingManager, 'rectanglecomplete', updateSelection);
function updateSelection(rectangle){
var lat_max = rectangle.getBounds().getNorthEast().lat();
var lat_min = rectangle.getBounds().getSouthWest().lat();
var lng_max = rectangle.getBounds().getNorthEast().lng();
var lng_min = rectangle.getBounds().getSouthWest().lng();
rectangles.push(rectangle);
for(var i=0;i<markers.length;i++){
if((lat_min < markers[i].getPosition().lat() ? (markers[i].getPosition().lat() < lat_max ? true:false):false)
&& (lng_min < markers[i].getPosition().lng() ? (markers[i].getPosition().lng() < lng_max ? true:false):false)){
triggeredMarkers.push(markers[i]);
}
}
}
The rectangles array is used to hold rectangles in order to be able to erase them later.
But if you just want a simple function that handle Polygons, there is this one that really can be helpful for you. It can be used like this:
var markers = [];
var polygones = [];
var triggeredMarkers = [];
google.maps.event.addListener(drawingManager, 'polygoncomplete', updateSelection);
function updateSelection(polygon){
polygones.push(polygon);
for(var i=0;i<markers.length;i++){
if(google.maps.geometry.poly.containsLocation(markers[i].getPosition(),polygon)){
triggeredMarkers.push(markers[i]);
}
}
}
For rectangles and circles there's this answer that can help you.

Related

How to make google map 'fit to markers'?

I am using google-map-react to render maps in my react app.I am displaying dynamic number of markers on the map.I need to fit the view of map so that it just encloses all the markers.I went through this thread but found it a bit complicated.Can anyone please give me an overview of how this can be done?
It happens that I had to do the exact same thing recently. I found that existing libs were more getting on my way than actually helping so I just went with writing my own component.
In case you decide going the same way - here's how to do what you want:
First - you need to get the bounds object enclosing all your markers. Here we assume that this.state.markers contains an array of google.maps.Marker objects
Your component could have the following method to do that:
getObjectsBounds(){
let objectsBounds = new google.maps.LatLngBounds();
Object.values(this.state.markers).map((marker) => {
let lat = parseFloat(marker.getPosition().lat());
let long = parseFloat(marker.getPosition().lng());
let point = new google.maps.LatLng(lat, long);
objectsBounds.extend(point);
});
return objectsBounds;
}
Now we just use fitBounds on the above funtion's return results. Here we assume that this.map is your gmap, i.e. what google.maps.Map( ... your args ... ) returns.
fitBounds(){
let bounds = this.getObjectsBounds();
this.map.fitBounds(bounds);
}

Cesium JS flying to camera.lookAt (Migrating from Google Earth Plugin API lookAt)

Needing some help migrating my flying functionality from the Google Earth plugin to Cesium. Basically in ge I create a lookAt and called setAbstractView like below
var ge = google.earth.createInstance('map3d')
var lookAt = TVV.mapObject.createLookAt('');
lookAt.set(
21.2765107698755,
-157.825362273258,
0,
ge.ALTITUDE_RELATIVE_TO_GROUND,
20.1690873648706,
74.9605580474674,
764.534479411941
);
ge.getView().setAbstractView(lookAt);
That was my code for google earth plugin. In cesium following the migration guides I do:
// fly to code that works with cesium (but a little bit off)
viewer.camera.flyTo({
destination : Cesium.Cartesian3.fromDegrees(-157.825362273258, 21.2765107698755, 764.534479411941),
orientation : {
heading : Cesium.Math.toRadians(20.1690873648706),
pitch : Cesium.Math.toRadians(74.9605580474674 - 90.0),
roll: 0
}
})
That code goes to almost the right place. I have to drag it down over to the right to see my placemark that I previously set (so the view is not exactly what it was in Google earth).
So I tried this code I also found.
// code that works with cesium
var center = Cesium.Cartesian3.fromDegrees(-157.825362273258, 21.2765107698755);
var heading = Cesium.Math.toRadians(20.1690873648706);
var pitch = Cesium.Math.toRadians(74.9605580474674);
var range = 764.534479411941;
viwer.camera.lookAt(center, new Cesium.HeadingPitchRange(heading, pitch, range));
That code looks MUCH closer to the previous google earth plugin view. However, of course, it does not fly the camera to the view. It only sets the view right away.
My question is, how can I fly the camera to the lookAt view in cesium, taking advantage of my lat, lng, heading, pitch, and range values?
Here are the relevant API docs from GE and Cesium should you find them useful.
GE createLookAt
https://developers.google.com/earth/documentation/reference/interface_g_e_plugin.html#a82f1b3618531a6bfab793b04c76a43e7
GE Camera Control (search for "Panning to an absolute location")
https://developers.google.com/earth/documentation/camera_control
Cesium lookAt
https://cesiumjs.org/Cesium/Build/Documentation/Camera.html#lookAt
Cesium flyTo
https://cesiumjs.org/Cesium/Build/Documentation/Camera.html#flyTo
I also found this but was unsure about how to integrate it. If anybody could provide a codepen/jsfiddle or something of the like that would be greatly appreciated!
https://groups.google.com/forum/#!topic/cesium-dev/r5rddMUeS80
Thanks to Hannah Pinkos from the Cesium Forum for the answer.
After creating an entity and using values for heading, pitch(tilt), and range from the google earth plugin, you can fly to the entity with an offset...
var heading = Cesium.Math.toRadians(20.1690873648706g);
var pitch = Cesium.Math.toRadians(74.9605580474674 - 90);
var range = 764.534479411941;
TVV.mapObject.flyTo(entity, {
offset: new Cesium.HeadingPitchRange(heading, pitch, range)
});

Cesium - Applying color filter to ImageryLayer

Has anyone attempted to do this? As far as I can tell from the documentation, there doesn't seem to be a built in function for achieving this. Does anyone know if this is possible? Is it, possibly, a feature that the authors might intend to add to the platform?
The ImageryLayer documentation shows how to control brightness, contrast, hue, saturation, and gamma correction.
To get a globe with a solid color, you can remove the imagery layers like so:
var viewer = new Cesium.Viewer('cesiumContainer', {
baseLayerPicker: false
});
var globe = viewer.scene.globe;
globe.imageryLayers.removeAll();
globe.baseColor = Cesium.Color.LIGHTSLATEGRAY;
A "minimalist map" (as you mention in the comments) is something you would probably need to get from a custom imagery provider. You may want to check out Stamen Maps for some examples of this. In particular, note their "Toner" map comes in a number of sub-varieties, any of which can be selected in Cesium.
For example, to try the "Toner Background" version, you would use:
var viewer = new Cesium.Viewer('cesiumContainer', {
baseLayerPicker: false,
imageryProvider: Cesium.createOpenStreetMapImageryProvider({
url : 'https://stamen-tiles.a.ssl.fastly.net/toner-background/',
credit : 'Map tiles by Stamen Design, under CC BY 3.0. Data by OpenStreetMap, under CC BY SA.'
})
});
EDIT: #EmmanuelBuckski (OP) took this idea and ran with it, mixing the above two techniques together to produce a result that looks really nice! Check it out:
var viewer = new Cesium.Viewer('cesiumContainer', {
baseLayerPicker: false
});
var globe = viewer.scene.globe;
globe.imageryLayers.removeAll();
globe.baseColor = Cesium.Color.fromCssColorString('#f3f3f3');
var tonerLayer = globe.imageryLayers.addImageryProvider(
Cesium.createOpenStreetMapImageryProvider({
url : 'https://stamen-tiles.a.ssl.fastly.net/toner-background/',
credit : 'Map tiles by Stamen Design, under CC BY 3.0. Data by OpenStreetMap, under CC BY SA.'
})
);
tonerLayer.alpha = 0.1;

Imitating Mouse click - point with known coordinates on a fusion table layer - google maps

I have been making a script using a fusion table's layer in google maps.
I am using geocoder and get the coordinates of a point that I need.
I put a script that changes the style of a polygon from the fusion table when you click on it, using the google.maps.event.addListener(layer, "click", function(e) {});
I would like to use the same function that I call in the case of a click on the layer, but this time with a click with the coordinates that I got.
I have tried google.maps.event.trigger(map, 'click', {latLng: new google.maps.LatLng(42.701487,26.772308)});
As well as the example here > Google Fusion Table Double Click (dblClick)
I have tried changing map with layer...
I am sorry if my question is quite stupid, but I have tried many options.
P.S. I have seen many post about getting the info from the table, but I do not need that. I want to change the style of the KML element in the selected row, so I do not see it happening by a query.
Here is the model of my script:
function initialize()
{
geocoder = new google.maps.Geocoder();
map = new google.maps.Map(document.getElementById("map_canvas"),myOptions);
layer = new google.maps.FusionTablesLayer({
suppressInfoWindows:true,
map : map,
query : {
select: 'Местоположение',
from: '12ZoroPjIfBR4J-XwM6Rex7LmfhzCDJc9_vyG5SM'
}
});
google.maps.event.addListener(layer, "click", function(e) {
SmeniStilRaionni(layer,e);
marker.setMap(null);
});
}
function SmeniStilRaionni(layer,e)
{
...
}
function showAddress(address)
{
geocoder.geocode( { 'address': address}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
var point = results[0].geometry.location;
//IMITATE THE CLICK
}
});
}
In response to geocodezip
This way you hide all the other elements... I do not wish that. It is like if I want to change the border of the selected element. And I do not wish for a new layer.
In the function that I use now I push the style of the options of the layer and then set the option. I use the e from google.maps.event.addListener(layer, "click", function(e)); by inserting e.row['Name'].value inside the where rule.
I would like to ask you if there is any info on the e variable in google.maps.event.addListener(layer, "click", function(e));
I found out how to get the results I wanted:
For my query after I get the point I use this:
var queryText ="SELECT 'Районен съд','Окръжен съд','Апелативен съд','Местоположение' FROM "+FusionTableID+" WHERE ST_INTERSECTS(\'Местоположение\', CIRCLE(LATLNG(" + point.toUrlValue(6) + "),0.5));";
queryText = encodeURIComponent(queryText);
document.getElementById("vij query").innerHTML = queryText;
var query = new google.visualization.Query('http://www.google.com/fusiontables/gvizdata?tq=' + queryText);
And then I get these results:
var rsyd = response.getDataTable().getValue(0,0);
var osyd = response.getDataTable().getValue(0,1);
var apsyd = response.getDataTable().getValue(0,2);
And then, I use the following:
where: "'Районен съд' = '"+rsyd+"'",
Which is the same as:
where: "'Районен съд' = '"+e.row['Районен съд'].value+"'",
in the click function.
This is a working solution for my problem.
But still, I cannot find a way to Imitate a Mouse click.
The issue is this: the data(row) for the layers will be requested via AJAX when you click on a layer.
In theory it's possible to select a geometry(polygon) by a given LatLng, the geometry-library has a method for this: google.maps.geometry.poly.containsLocation().
Unfortunately the FusionTableAPI does not support such queries(ST_CONTAINS), you cannot select a row by supplying a LatLng and selecting the rows where the geometry contains the LatLng.
So what you can do: create a copy of the table that contains the columns needed to select a row(Община...the distinct value, and Местоположение.... the geometry). This copy may be requested via AJAX, but when the FusionTable will not be modified anymore I would suggest to use a hardcoded copy.
What to do now when you want to simulate the click:
Iterate over all rows of the copy, use the mentioned containsLocation()-method to check if the geometry(Местоположение) contains the LatLng and when it does apply the query by using the value of the distinct column Община .
Of course it would take some time to check all the geometries, but the FusionTable is not very large, it should be a possible approach in your case.
Here is a demo: http://jsfiddle.net/doktormolle/sSwj3/
The size of the stored data is approximately 500kb, you should store the data in an external script, so they may be cached.
You may notice that the highligthning of the selected layer will be much faster when triggered via the links, because there will no data be requested via AJAX. When the highlightning of the selected feature is the only thing you need you may ommit the observation of the layer-click completely and observe the map-click instead. Use the returned LatLng to retrieve the selected row from the data and set the style:
Demo: http://jsfiddle.net/doktormolle/swdX8/

Not able to edit Polygon after editable option as true also in Drawing Manager of Google Maps v3

I have tried to draw Polygon using Drawing Manager and send the Polygon Coordinates to PHP script(to store in Database).
1)i have coded editable option as 'true' for polygon. But i am not to
edit the polygon.I am not to find what i did wrong?
2)Also i try to get
Polygon paths using getPaths method..it is returned as array..How do i
check this coordinates are correct. If i put in alert in displays as
'Object[] Object'.Please help me to solve these problems.
You need to set the drawing mode to true (to enable map interactions). the following code will do the trick :)
google.maps.event.addListener(drawingManager, 'polygoncomplete', function(polygon) {
drawingManager.setDrawingMode(null);
});
with regards to the 2nd part im currently working on that now. use console.log instead of alert.
For the path:
var thisPath=polygon.getPath();
for(i=0;i<thisPath.length;i++){
var latlng=thisPath.getAt(i);
pathString= pathString+', '+ latlng.lat()+' - '+ latlng.lng()+'\n'
}
alert (pathString);
For part 2, sharingStuff code would work, I preferred for the path to be a json object,
vertices = this.polygon.getPath();
var points = [];
// Iterate over the vertices.
if(this.polygon.getMap() == null){
return false;
}
for (var i =0; i < vertices.length; i++) {
var xy = vertices.getAt(i);
points.push(xy.lat() +"," + xy.lng());
}
return JSON.stringify({points: points});
either method is fine, just thought I'd give you another option. :)