How to plot shapefiles on Bing Map - gis

How can I use shapefile(.shp) with bing maps without using any third party reference?
I just want to use bing maps api library to perform this action.
So suggest me how can i achieve this?
I have tried something with bing maps which is described below..
Here is my code :
$.ajax({
type: "POST",
url: "GISFunctions.asmx/GetShapeFileData",
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (data, textStatus, jqXHR) {
var response = data.d;
for (var i = 0; i < response.length; i++) {
var polygonGeometry = response[i];
var vertices = new Array();
var numCoordinates = polygonGeometry.length;
for (var j = 0; j < numCoordinates; j++) {
var CoOrdinates = polygonGeometry[j];
var x = CoOrdinates[1];
var y = CoOrdinates[0];
vertices[j] = new Microsoft.Maps.Location(x, y);
}
var polygoncolor = new Microsoft.Maps.Color(100, 100, 0, 100);
var polygon = new Microsoft.Maps.Polygon(vertices, { fillColor: polygoncolor, strokeColor: polygoncolor });
// Add the shape to the map
map.entities.push(polygon);
}
},
error: function (xhr, status, error) {
alert(xhr.responseText);
}
});
"GISFunctions.asmx/GetShapeFileData" is my web service method. It fetches data from shapefile. Reads shapefile's records one by one and fetches co-ordinates for each record's polygon.
In above Jquery Ajax function, i have differentiated my data and created array which contains vertices for my polygon and then according to below link, i am trying to map these polygons on Bing Map
http://msdn.microsoft.com/en-us/library/gg427604.aspx
When i go through static data then i can easily plot one polygon on Bing Map.. But when i try to create these polygons dynamically then my above code doesn't work.
It doesn't plot any polygon on map and also don't give my error..
I am new to GIS functions so kindly suggest me right direction..

I wrote a couple blog posts on how to import ShapeFiles into Bing Maps. Try taking a look at these:
http://www.bing.com/blogs/site_blogs/b/maps/archive/2012/09/06/esri-shapefiles-and-bing-maps.aspx
http://www.bing.com/blogs/site_blogs/b/maps/archive/2012/09/12/esri-shapefiles-and-bing-maps-wpf.aspx
http://www.bing.com/blogs/site_blogs/b/maps/archive/2013/06/18/how-to-load-spatial-data-from-sqlite-in-a-windows-store-app.aspx

Related

How to reset coordinates into an Ajax call after having initialized a map?

I inserted a map on my webpage by using the Leaflet library. What I want to do is to show a map zoomed on a specific region according to which city the user types into a text field.
I firstly initialized my map on my JS file:
function initMaps(){
map = L.map('leaflet').setView([0, 0], 13);
L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 18,
'attribution': 'Map data © OpenStreetMap contributors'
}).addTo(map);
}
My javascript code also has an Ajax call.
What I want to do now is to reset the coordinates on the Ajax call.
I wrote the following:
var readCoordinates = function(){
$.ajax({
url: "https://nominatim.openstreetmap.org/search?q=" + encodeURIComponent($("#inlineFormInputCitta").val()) + "+Italy&format=geocodejson",
dataType: "json",
success: function (data) {
setTimeout(function () {
for (let i = 0; i < data.features.length; i++) {
let coordinate = data.features[i].geometry.coordinates;
console.log(coordinate);
map.setView(coordinate, 13);
console.log("ajax and for loop have been activated");
console.log(coordinate.geometry.coordinates);
};
$("#ristoranti").prop("disabled", false);
}, 1000);
}
});
};
The API I'm referring to in the URL is the following: https://nominatim.openstreetmap.org/search?q=Roma%20Italy&format=geocodejson
What I did is trying to reset the coordinates here: map.setView(coordinate, 13);
after having cycled the elements in the JSON object, see the following:
for (let i = 0; i < data.features.length; i++) {
let coordinate = data.features[i].geometry.coordinates;
I may display several coordinates in the console, see the following:
That's because in the JSON file I get through the API request there are several:
The result of this is the following map, which isn't zoomed anywhere:
Which coordinates should I take in order to display that specific region?
EDIT - - -
I changed the code because I'm trying to get a specific subobject, i.e. the one in the screen below (which has "type" = "city"):
The new snippet is the one below, where I add an if statement:
var readCoordinates = function(){
$.ajax({
url: "https://nominatim.openstreetmap.org/search?q=" + encodeURIComponent($("#inlineFormInputCitta").val()) + "+Italy&format=geocodejson",
dataType: "json",
success: function (data) {
setTimeout(function() {
for (let i = 0; i < data.features.length; i++) {
debugger;
let type = data.features[i].properties.geocoding.type;
if( $(type).val() === "city") {
let coordinate = data.features[i].geometry.coordinates;
let lng = coordinate[0];
let lat = coordinate[1];
map.setView([lng, lat], 13);
console.log("ajax and for loop have been activated");
console.log(coordinate);}
};
$("#ristoranti").prop("disabled", false);
}, 1000);
}
});
};
I'm doing the debugger and get many undefined values:
I would do something like that:
if (typeof data.features[0] !== 'undefined') {
let coordinate = data.features[0].geometry.coordinates;
var latlng = L.latLng(coordinate.reverse());
map.flyTo(latlng, 12)
}
Be sure to have something in your array
Get data from the first item since it should be the correct one in most case
Create a latlng with those coordinates. Be careful, sometime you need to reverse the array to have the correct position.
Use flyTo to have a smooth transition to your coordinates. 12 is the zoom level
You don't need to loop over the data since you need only one position. You can replace the for with that.
You're having two problems here:
The response from the Nominatim API is returning several search results, each of them in one GeoJSON Feature inside the response FeatureCollection. It's up to you to choose which search result you want to focus in the map (the first?), or let the user do so.
You're not aware that GeoJSON uses longitude-latitude (or x-y) coordinates, whereas Leaflet uses latitude-longitude (or y-x)

Drawing polygons with WKT - XML file using OpenLayers

I have this XML file created with PHP and Mysql:
How can I use this to draw all the polygons using OpenLayers? I did some research and found examples with WKT, but in those examples they used just one polygon:
var feature = format.readFeature(
'POLYGON((10.689697265625 -25.0927734375, 34.595947265625 ' +
'-20.1708984375, 38.814697265625 -35.6396484375, 13.502197265625 ' +
'-39.1552734375, 10.689697265625 -25.0927734375))');
I want to draw all the polygons to create a thematic map based on the "Area" data.
Just parse your XML and iterate over the marker tags. Something like this:
var xml = new OpenLayers.Format.XML(),
wkt = new OpenLayers.Format.WKT(),
vectorLayer = new OpenLayers.Layer.Vector('features'),
doc, markers, i, feature;
OpenLayers.Request.GET({
url: "features.xml",
success: function(request) {
doc = xml.read(request.responseText);
markers = doc.documentElement.getElementsByTagName('marker');
for (i = 0; i < markers.length; i++) {
feature = wkt.read(markers[i].attributes.geometry.nodeValue);
vectorLayer.addFeatures([feature]);
}
}
});
Edit: If you are using OpenLayers 3, try the following:
var wkt = new ol.format.WKT(),
vectorLayer,
source,
features = [],
feature,
markers;
//make sure that jQuery is included
$.ajax('features.xml').then(function(response) {
var markers = response.getElementsByTagName('marker');
for (var i = 0; i < markers.length; i++) {
feature = wkt.readFeature(markers[i].attributes.geometry.nodeValue);
features.push(feature);
}
source = new ol.source.Vector({
features: features
});
vectorLayer = new ol.layer.Vector({
source: source
});
});

How to change Bing Map code to Google Map code

Good day,
Does anyone have an idea of how to change a bing map to google map api code. I have found a very useful code on line that is coded using bing maps and would like to change it to work with google maps. if found the code here: http://blogs.msdn.com/b/crm/archive/2011/01/19/custom-charting-capabilities-in-microsoft-dynamics-crm-2011.aspx
Code below:
<html>
<head>
<title>Accounts on Bing Maps</title>
<script type="text/javascript" src="http://ecn.dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=6.3"></script>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script type="text/javascript" src="ClientGlobalContext.js.aspx"></script>
<script type="text/javascript">
var map;
// Function to construct key-value pairs from a query string.
function getParametersFromQuery(query) {
var parametersDictionary = new Array();
var parameters = query.split('&');
for (var i = 0; i < parameters.length; i++) {
var keyAndValue = parameters[i].split('=');
parametersDictionary[unescape(keyAndValue[0])] = unescape(keyAndValue[1]);
}
return parametersDictionary;
}
// Function that makes a GET request to the CRM REST end-point, and invokes a callback with the results.
function retrieveFromCrmRestApi(url, callback) {
$.ajax({
type: "GET",
url: GetGlobalContext().getServerUrl() + "/XRMServices/2011/OrganizationData.svc" + url,
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (data) {
callback(data.d);
}
});
}
// Function that retrieves the corresponding CRM chart, and invokes the callback when successful.
function loadChartFromCrm(callback) {
var parameters = getParametersFromQuery(window.location.search.substring(1));
parameters = getParametersFromQuery(parameters["data"]);
var id = parameters["visid"].substr(1, 36);
var type = parameters["vistype"];
var url = (type == "1111" ? "/SavedQueryVisualizationSet" : "/UserQueryVisualizationSet")
+ "(guid'" + id + "')?$select=DataDescription,PresentationDescription";
retrieveFromCrmRestApi(url, callback);
}
var locations = new Array();
function plotAccountLocations(accounts) {
if (accounts.length > 0) {
var account = accounts.pop();
var address = account.Address1_City + ', ' + account.Address1_Country;
map.Find(null, address, null, null, 0, 1, false, false, false, false,
function (shapeLayer, results, places, moreResults, error) {
if (null != places && places.length > 0) {
var place = places[0];
var newShape = new VEShape(VEShapeType.Pushpin, place.LatLong);
newShape.SetTitle(account.Name);
newShape.SetDescription(address);
locations.push(newShape);
}
// When we have found (or not found) the current account,
// recursively call the same function to find the next one.
plotAccountLocations(accounts);
});
}
else {
var shapeLayer = new VEShapeLayer();
map.AddShapeLayer(shapeLayer);
shapeLayer.AddShape(locations);
}
}
function loadAccountsFromCrm(dataDescription) {
var url = "/AccountSet?$select=Address1_Country,Address1_City,Name";
if (null != dataDescription) {
// Filter accounts based on country specified in data description.
url += "&$filter=Address1_Country eq '" + dataDescription + "'";
}
retrieveFromCrmRestApi(url,
function (data) {
var results = data["results"];
var accounts = new Array();
for (resultKey in results) {
accounts.push(results[resultKey]);
}
// Once accounts are retrieved from CRM Server, plot their locations on map.
plotAccountLocations(accounts);
}
);
}
function getMap(presentationDescription) {
// Set center and zoom defaults.
var center = null;
var zoom = 4;
if (null != presentationDescription) {
// Calculate map-center and zoom from the presentation description.
var arguments = presentationDescription.split(',');
if (arguments.length > 1) {
center = new VELatLong(arguments[0], arguments[1]);
}
if (arguments.length > 2) {
zoom = arguments[2];
}
}
map = new VEMap("map");
map.LoadMap(center, zoom, VEMapStyle.Road, true, VEMapMode.Mode2D, false, 0);
window.onresize = function (event) { map.Resize(document.body.clientWidth, document.body.clientHeight); };
window.onresize(null);
}
function loadMap() {
// First, get the chart object from CRM Server.
loadChartFromCrm(
function (chart) {
// Once we have retrieved the chart, format the map based on the chart's presentation description.
getMap(chart.PresentationDescription);
// Get Accounts from CRM Server based on the chart's data description, and plot them on the map.
loadAccountsFromCrm(chart.DataDescription);
}
);
}
</script>
</head>
<body onload="loadMap()">
<div id="map"></div>
</body>
</html>
There is no easy out of the box solution for what you are looking for.
Google API has many differences. For example, the Google API leaves keeping track of map children to the programmer (you). There is no means of looping through the map controls like there is with the Bing API. This means that your solution for saving the map content and re-displaying it will be a little different.
Although, since both API's are done via javascript, all you need to do is convert your functionality according to their documentation;
Geocoding Sample
Simple Map Initialization
Adding Shapes
Adding Markers (pushpin)

GeoXml3 parse fusion table layer of kml (points) into Google Maps

I have a kml of points loaded into fusion table layer. I want to parse the data to une map.fitBounds on the layer extent using geoxml3, but thats not functionning. This exactly code below is working with KML polygons but not with KML points layer.
Code:
var queryText = encodeURIComponent("SELECT * FROM 1CNJWjLDYgBkJGZVslJ67Fak4DyqadEFuIabzQ60 ");
var query = new google.visualization.Query('http://www.google.com/fusiontables/gvizdata?tq=' + queryText);
query.send(zoomTo);
}
function zoomTo(response) {
if (!response) {
alert('no response');
return;
}
if (response.isError()) {
alert('Error in query: ' + response.getMessage() + ' ' + response.getDetailedMessage());
return;
}
FTresponse = response;
//for more information on the response object, see the documentation
//http://code.google.com/apis/visualization/documentation/reference.html#QueryResponse
numRows = response.getDataTable().getNumberOfRows();
numCols = response.getDataTable().getNumberOfColumns();
var geoXml = new geoXML3.parser();
var bounds = new google.maps.LatLngBounds();
for (var i = 0; i < numCols; i++){
if (FTresponse.getDataTable().getColumnLabel(i) == 'geometry') {
var ColIndex = i;
}
}
if (!ColIndex){
alert('Geometry column "geometry" not found.')
}
for (var i = 0; i < numRows; i++){
var kml = FTresponse.getDataTable().getValue(i,ColIndex);
geoXml.parseKmlString("<Placemark>"+kml+"</Placemark>");
bounds.union(geoXml.docs[i].bounds);
}
map.fitBounds(bounds);
}
The parse method should not be used for parsing KML strings from FusionTables (the parseKmlString method is for doing that).
var kml = FTresponse.getDataTable().getValue(i,ColIndex);
geoXml.parseKmlString("<Placemark>"+kml+"</Placemark>");
Note: the KML fragments stored in FusionTables do not include the <Placemark> tags which geoxml3 looks for, that is why they are added to the string passed to geoxml3.
The GViz query response has a 500 row limit (that doesn't seem to be documented anywhere I could find, the best I could find was this reference to it, but the documentation has moved since then).
Looks like you are going to run into that limitation with your table, to overcome that use the FusionTables API v1.0, that returns GeoJSON, not KML (so you will no longer need geoxml3).
example that decodes KML "Points" from FusionTables using GViz and geoxml3 (table contains less than 500 points)
example of parsing markers from Fusion Tables using the Fusion Tables API v1.0

Latitude and longitude can find zip code?

I am using Google geocoder for lat and lon and my question is, is there a way you can find out zipcode with latitude and longitude?
It's good to note that Google Maps has a new version since this solultion was presented.
Reference: https://developers.google.com/maps/documentation/geocoding/?csw=1#ReverseGeocoding
Here's an updated example for Google Maps v3. It makes use of the Address Components that JIssak mentions above. I should note that there is no fallback. If it fails to find a zip code, it does nothing. This may or may not be important to your script.
var latlng = new google.maps.LatLng(p.coords.latitude, p.coords.longitude);
geocoder = new google.maps.Geocoder();
geocoder.geocode({'latLng': latlng}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
if (results[0]) {
for (j = 0; j < results[0].address_components.length; j++) {
if (results[0].address_components[j].types[0] == 'postal_code')
alert("Zip Code: " + results[0].address_components[j].short_name);
}
}
} else {
alert("Geocoder failed due to: " + status);
}
});
I think what you are looking for is the address_components[] in the results array. Maybe something like this would work, just typing the below so it might have errors in it but I think you will get the idea.
http://code.google.com/apis/maps/documentation/geocoding/#Results
function (request, response) {
geocoder.geocode({ 'address': request.term, 'latLng': centLatLng, 'region': 'US' }, function (results, status) {
response($.map(results, function (item) {
return {
item.address_components.postal_code;//This is what you want to look at
}
}
[Removed non-working solution for google - see #hblackorby's solution.]
Here's a version that uses openstreetmap.org, much simpler than google's api - coffeescript, then javascript:
getZip = (cb) ->
# try to populate zip from geolocation/google geocode api
if document.location.protocol == 'http:' && navigator.geolocation?
navigator.geolocation.getCurrentPosition (pos) ->
coords = pos.coords
url = "http://nominatim.openstreetmap.org/reverse?format=json&lat=#{ coords.latitude }&lon=#{ coords.longitude }&addressdetails=1"
$.ajax({
url: url,
dataType: 'jsonp',
jsonp: 'json_callback',
cache: true,
}).success (data) ->
cb(data.address.postcode)
Here's the compiled javascript:
getZip = function(cb) {
if (document.location.protocol === 'http:' && (navigator.geolocation != null)) {
return navigator.geolocation.getCurrentPosition(function(pos) {
var coords, url;
coords = pos.coords;
url = "http://nominatim.openstreetmap.org/reverse?format=json&lat=" + coords.latitude + "&lon=" + coords.longitude + "&addressdetails=1";
return $.ajax({
url: url,
dataType: 'jsonp',
jsonp: 'json_callback',
cache: true
}).success(function(data) {
return cb(data.address.postcode);
});
});
}
};
Use it like this:
getZip(function(zipcode){ console.log("zip code found:" + zipcode); });
Yahoo's PlaceFinder API provides a good wat to lookup location data by lat/lng:
http://developer.yahoo.com/geo/placefinder/
Here's an example url that they use:
http://where.yahooapis.com/geocode?q=38.898717,+-77.035974&gflags=R
It would seem so:
Source: Google Maps API Service
Geocoding is the process of converting addresses (like "1600
Amphitheatre Parkway, Mountain View, CA") into geographic coordinates
(like latitude 37.423021 and longitude -122.083739), which you can use
to place markers or position the map. The Google Geocoding API
provides a direct way to access a geocoder via an HTTP request.
Additionally, the service allows you to perform the converse operation
(turning coordinates into addresses); this process is known as
"reverse geocoding."
You should also check out this documentation which has some sample code:
Reverse Geocoding
I made a generic function to look for the type that you want. Not always the address_component has zipcode, country, etc and if they do not always are in the same index. Sometimes your array is lenght 8, 6 or whatever. I did it in Typescript, just change a few things to make it vanilla JS.
getPlaceTypeValue(addressComponents: Places[], type: string): string {
let value = null;
for (const [i] of addressComponents.entries()) {
if (addressComponents[i].types.includes(type)) {
value = addressComponents[i].long_name;
break;
}
}
return value;
}
OR
getPlaceTypeValue(addressComponents: any[], type: string): string {
return (addressComponents.find(({ types }) => types.includes(type)) || {}).long_name || null;
}
Example of usage:
this.placesService.getPlaceTypeValue(address.address_components, 'postal_code');
this.placesService.getPlaceTypeValue(address.address_components, 'country');