Does "Here" maps support country highlighting, something like in the following example: https://google-developers.appspot.com/chart/interactive/docs/gallery/geochart_06d031f6a0bf088f1320a975cdefa0e3.frame
There is no library support for Choropleth maps (which is what I think you are after), but it is possible to create one using jQuery + HERE Maps if you have access to a KML file holding the boundaries of the countries or regions you need.
Updated WKT solution now available
Access to KML shapes is no longer required, since the Geocoder API now offers an IncludeShapes attribute which returns the shape of a country in WKT format. A WKT parser can be found here.
A simple WKT choropleth example can be found here.
KML Solution
Hint: try something like http://geocommons.com/overlays/119819 - Country borders are a political minefield, and this is probably the reason why HERE doesn't do this sort of thing directly.
The problem falls into four parts:
Asynchronously load but do not parse a KML document to read in the "countries of the world"
Manipulate the KML to remove unwanted countries, alter the intensity of colours and so on.
Taking the <Document> element only call nokia.maps.kml.Manager.parse() to transfrom your modified KML into mapObjects and place them on the map.
By default the KML will display an Infobubble when a <PlaceMark> is clicked, an additional listener is required if you want to get the Infobubble to display on hover as in the example you linked to.
Here is an example screenshot, it just highlights countries beginning with "A" or "B" but you should get the idea:
The code is as follows (use your own app id and token):
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>KML Country color test</title>
<meta http-equiv="X-UA-Compatible" content="IE=7; IE=EmulateIE9"/>
<meta http-equiv="content-type" content="text/html; charset=UTF-8"/>
<script type="text/javascript" charset="UTF-8" src="http://api.maps.nokia.com/2.2.3/jsl.js?with=all"></script>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
</head>
<body>
<div style="height:800px" id="mapContainer"></div>
<script type="text/javascript" id="exampleJsSource">
nokia.Settings.set( "appId", "YOUR APP ID");
nokia.Settings.set( "authenticationToken", "YOUR TOKEN");
// Get the DOM node to which we will append the map
var mapContainer = document.getElementById("mapContainer");
var infoBubbles = new nokia.maps.map.component.InfoBubbles();
// Create a map inside the map container DOM node
var map = new nokia.maps.map.Display(mapContainer, {
center: [0, 0],
zoomLevel: 3,
components: [
// We add the behavior component to allow panning / zooming of the map
new nokia.maps.map.component.Behavior(),new nokia.maps.map.component.TypeSelector(),new nokia.maps.map.component.ZoomBar(),
infoBubbles
]
});
map.addListener("mouseover", function (evt) {
var coord = map.pixelToGeo(evt.targetX, evt.targetY);
var objects = map.getObjectsAt( evt.targetX, evt.targetY) ;
for(var i=0;i<objects.length;i++){
var object=objects[i];
if(object instanceof nokia.maps.map.Polygon ){
object.dispatch( new nokia.maps.dom.Event({type: "click", target: object}));
evt.stopImmediatePropagation();
}
}
});
var kml = new nokia.maps.kml.Manager();
var resultSet;
var container = new nokia.maps.map.Container();
var doc;
// We define a callback function for parsing kml file,
// and then push the parsing result to map display
var onParsed = function (kmlManager) {
//console.debug("onParsed");
var
boundingBox;
// KML file was successfully loaded
if (kmlManager.state == "finished") {
// KML file was successfully parsed
resultSet = new nokia.maps.kml.component.KMLResultSet( kmlManager.kmlDocument, map);
// Add the container to the map's object collection so it will be rendered onto the map.
map.objects.add(container = resultSet.create());
}
};
// Add an observer to kml manager
kml.addObserver("state", onParsed);
function err (){
alert("An Error has occurred.");
}
function parseXml(xml)
{
$(xml).find("Placemark").each(function(){
var countryName = $(this).children("name").text();
/* YOU CAN MANIPULATE STUFF HERE.
var newName = document.createElement('name');
newName.appendChild(document.createTextNode(" Additional Text" ));
var newDesc = document.createElement('description');
newDesc.appendChild(document.createTextNode(countryName));
$(this).children("name").replaceWith(newName);
$(this).children("description").replaceWith(newDesc);*/
if (countryName.indexOf("A")!= 0 && countryName.indexOf("B")!= 0 ){
$(this).remove();
}
});
doc = xml.getElementsByTagName('Document')[0];
kml.parse( doc);
}
// doc-simple-limited is my KML file of country borders.
$.ajax({
type: "GET",
url: "../doc-simple-limited.kml" ,
dataType: "xml",
success: parseXml,
error : err
});
</script>
<body>
</html>
Related
I am using google maps in my asp.net project. When I type some address, i get suggestions, I pick one of them and map is shown related to that address. This works fine. But I want that user types address in a custom textbox on page 1 and i take that input and populate maps textbox on page 2 as well as show map on page 2 related to address.
here is how I am doing it
$(document).ready(function() {
// Empty the value on page load
$("#formattedAddress").val("");
// variable to indicate whether or not enter has been pressed on the input
var enterPressedInForm = false;
var input = document.getElementById("inputName");
var options = {
componentRestrictions: {country: 'uk'}
};
autocomplete = new google.maps.places.Autocomplete(input, options);
$("#formName").submit(function(e) {
// Only submit the form if information has been stored in our hidden input
return $("#formattedAddress").val().length > 0;
});
$("#inputName").bind("keypress", function(e) {
if(e.keyCode == 13) {
// Note that simply triggering the 'place_changed' event in here would not suffice, as this would just create an object with the name as typed in the input field, and no other information, as that has still not been retrieved at this point.
// We change this variable to indicate that enter has been pressed in our input field
enterPressedInForm = true;
}
});
// This event seems to fire twice when pressing enter on a search result. The first time getPlace() is undefined, and the next time it has the data. This is why the following logic has been added.
google.maps.event.addListener(autocomplete, 'place_changed', function () {
// If getPlace() is not undefined (so if it exists), store the formatted_address (or whatever data is relevant to you) in the hidden input.
if(autocomplete.getPlace() !== undefined) {
$("#formattedAddress").val(autocomplete.getPlace().formatted_address);
}
// If enter has been pressed, submit the form.
if(enterPressedInForm) {
$("#formName").submit();
}
});
});
Regards,
Asif Hameed
You can send variables to other pages (or the same page) with the hashtag. Anything to the right hand side of the # is ignored by the server, but can be read/set by javascript.
Like on page 1 you have
25
50
This value can be read by page2, like this:
var pos = location.hash.substr(1);
Here is an example with your form
page1.htm
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Page 1 - type address</title>
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script>
$( function() {
$('#formName').on('submit', function(e) {
// read address
var address = $('#formattedAddress').val();
// add hash to page 2
window.location = 'page2.htm#' + address;
// prevent real submit
e.preventDefault();
return false;
});
});
</script>
</head>
<body>
<form id="formName">
<input id="formattedAddress" placeholder="Enter address"/>
<input type="submit" value="submit" />
</form>
</body>
</html>
page2.htm
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Page 2 - populate map</title>
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script>
$( function() {
if(location.hash) {
var address = location.hash.substr(1);
$('#test').html(address);
}
});
</script>
</head>
<body>
<div id="test"></div>
</body>
</html>
Tell me if you have difficulties applying this to a Google Maps webpage.
Try out passing coordinates to page2.
like "page2.htm#50.24/4.45" =>
var variables = location.hash.substr(1);
var position = variables.split('/');
var lat = Number(position[0]);
var lng = Number(position[1]);
Or pass the search string. That should work too.
I am trying to instantiate a Google Places Autocomplete input within an Angular 2 component. I use this code to do it:
loadGoogle() {
let autocomplete = new google.maps.places.Autocomplete((this.ref.nativeElement), { types: ['geocode'] });
let that = this
//add event listener to google autocomplete and capture address input
google.maps.event.addListener(autocomplete, 'place_changed', function() {
let place = autocomplete.getPlace();
that.place = place;
that.placesearch = jQuery('#pac-input').val();
});
autocomplete.addListener()
}
Normally, I believe, I would use the callback function provided by the Google API to ensure that it is loaded before this function runs, but I do not have access to it within a component's scope. I am able to load the autocomplete input 90% of the time, but on slower connections I sometimes error out with
google is not defined
Has anyone figured out how to ensure the Google API is loaded within a component before instantiating.
Not sure whether this will help, but I just use a simple script tag in my index.html to load Google API and I never get any error. I believe you do the same as well. I post my codes here, hope it helps.
Note: I use Webpack to load other scripts, except for Google Map API.
<html>
<head>
<base href="/">
<title>Let's Go Holiday</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Google Map -->
<script type="text/javascript" src="https://maps.googleapis.com/maps/api/js?key=<your-key>&libraries=places"></script>
</head>
<body>
<my-app>Loading...</my-app>
</body>
</html>
And then in your component:
...
declare var google: any;
export class SearchBoxComponent implements OnInit {
ngOnInit() {
// Initialize the search box and autocomplete
let searchBox: any = document.getElementById('search-box');
let options = {
types: [
// return only geocoding results, rather than business results.
'geocode',
],
componentRestrictions: { country: 'my' }
};
var autocomplete = new google.maps.places.Autocomplete(searchBox, options);
// Add listener to the place changed event
autocomplete.addListener('place_changed', () => {
let place = autocomplete.getPlace();
let lat = place.geometry.location.lat();
let lng = place.geometry.location.lng();
let address = place.formatted_address;
this.placeChanged(lat, lng, address);
});
}
...
}
I used it the same way as explained above but as per google page speed i was getting this suggestion,
Remove render-blocking JavaScript:
http://maps.googleapis.com/…es=geometry,places®ion=IN&language=en
So i changed my implementation,
<body>
<app-root></app-root>
<script src="http://maps.googleapis.com/maps/api/js?client=xxxxx2&libraries=geometry,places®ion=IN&language=en" async></script>
</body>
/* Now in my component.ts */
triggerGoogleBasedFn(){
let _this = this;
let interval = setInterval(() => {
if(window['google']){
_this.getPlaces();
clearInterval(interval);
}
},300)
}
You can do one more thing, emit events once the value(google) is received,& trigger your google task
inside them.
Inside a infoBubble Google map I have added a function, but the first time the infoBubble is opened, the code not work, and if I open a second infoBubble or close the first and reopen, the code work.
Please help.
This is my page
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Documento senza titolo</title>
<script type="text/javascript" src="https://maps.googleapis.com/maps/api/js?v=3.20&sensor=false"></script>
<script type="text/javascript" src="js/jquery.js"></script>
<script type="text/javascript" src="js/infobubble.js"></script>
<script>
var infoBubble = new InfoBubble();
var infowindow = new google.maps.InfoWindow();
var map;
function initialize() {
var config = {
el: 'map',
lat: 40.2329,
lon: -3.42,
zoom: 10,
type: google.maps.MapTypeId.ROADMAP
};
var data = [
['Giorgio Rossi', 40.15, -3.42, '1' ],
['Marta Bianchi', 40.25, -3.42, '2'],
['Carlo Verdi', 40.15, -3.62, '3'],
['Mario Giallo', 40.25, -3.62, '4'],
];
var map = new google.maps.Map(document.getElementById(config.el), {
zoom: config.zoom,
scrollwheel: false,
center: new google.maps.LatLng(config.lat, config.lon),
mapTypeId: config.type
});
var markers = [];
var i ;
for (i = 0; i < data.length; i++) {
var marker = new google.maps.Marker({
position: new google.maps.LatLng(data[i][1], data[i][2]),
map: map
});
marker.info = '<div id="'+data[i][3]+ '">'+data[i][0]+ '</div>';
marker.html = '<div style="padding:25px"><a class="testClass" href="javascript:;" > My Friend '+data[i][3]+'</a> </div>';
google.maps.event.addListener(marker , 'click', function(){
infoBubble.setContent(this.html);
infoBubble.open(map, this);
var prova = this.info;
var found = $(prova).attr('id');
google.maps.event.addListenerOnce(infoBubble, 'domready', function () {
$(".testClass").click(function () {
alert(found);
})
});
});
}
}
google.maps.event.addDomListener(window, 'load', initialize);
</script>
</head>
<body>
<div id="map" style="width:700px; height:500px"></div>
</body>
</html>
As you can see from this SO question and the accepted answer
your issue is related to a bug in the infobubble.js code.
More specifically, the placement of the domready trigger was in the wrong part of the code, prior to the asynchronouse setMap() call, instead of after the infobubble elements are added to the DOM in the onAdd() function (which is called after the setMap() function).
What this means is that on your FIRST marker click, at domready event, the elements hadn't yet been added to the DOM - but they were a few milliseconds later - which is why the 2nd marker click worked.
I fixed the domready placement in infobubble.js and created a pull request which has been accepted and is now merged into the official code.
If you update your infobubble.js to the latest commit (use the non-minified for the moment) you'll probably see that your issue is resolved.
Non-working JS Fiddle here using the old code.
Working JS Fiddle here using the new code.
I created a custom XML structure for my Map Points. The structure looks like the code below. I'm wanting to read the points in and put them on the map accordingly with a popup window when clicked and a specific marker icon. I would appreciate any help.
MapPoints.xml
<MapPoints>
<MapPoint PointID="1">
<LocationName></LocationName>
<LocationAddress></LocationAddress>
<LocationURL></LocationURL>
<LocationExt></LocationExt>
<LocationFax></LocationFax>
<LocationLat></LocationLat>
<LocationLong></LocationLong>
<LocationMarker></LocationMarker>
</MapPoint>
<MapPoint PointID="2">
<LocationName></LocationName>
<LocationAddress></LocationAddress>
<LocationURL></LocationURL>
<LocationExt></LocationExt>
<LocationFax></LocationFax>
<LocationLat></LocationLat>
<LocationLong></LocationLong>
<LocationMarker></LocationMarker>
</MapPoint>
<MapPoint PointID="3">
<LocationName></LocationName>
<LocationAddress></LocationAddress>
<LocationURL></LocationURL>
<LocationExt></LocationExt>
<LocationFax></LocationFax>
<LocationLat></LocationLat>
<LocationLong></LocationLong>
<LocationMarker></LocationMarker>
</MapPoint>
<MapPoint PointID="4">
<LocationName></LocationName>
<LocationAddress></LocationAddress>
<LocationURL></LocationURL>
<LocationExt></LocationExt>
<LocationFax></LocationFax>
<LocationLat></LocationLat>
<LocationLong></LocationLong>
<LocationMarker></LocationMarker>
</MapPoint>
</MapPoints>
There are lots of examples that parse xml in the "Mike Williams Google Maps API v2 tutorial" format using attributes, here is one.
To use your "custom" format, you will need to replace this line (to look for "MapPoint" rather than "marker"):
var markers = xmlDoc.documentElement.getElementsByTagName("marker");
and these lines:
var lat = parseFloat(markers[i].getAttribute("lat"));
var lng = parseFloat(markers[i].getAttribute("lng"));
var point = new google.maps.LatLng(lat,lng);
var html = markers[i].getAttribute("html");
var label = markers[i].getAttribute("label");
// create the marker
var marker = createMarker(point,label,html);
With code that parses the element content out of your xml.
To get the element content you will need to do something like:
var lat = parseFloat(nodeValue(markers[i].getElementsByTagName("LocationLat")[0]));
Where nodeValue (borrowed from geoxml3) is:
//nodeValue: Extract the text value of a DOM node, with leading and trailing whitespace trimmed
geoXML3.nodeValue = function(node) {
var retStr="";
if (!node) {
return '';
}
if(node.nodeType==3||node.nodeType==4||node.nodeType==2){
retStr+=node.nodeValue;
}else if(node.nodeType==1||node.nodeType==9||node.nodeType==11){
for(var i=0;i<node.childNodes.length;++i){
retStr+=arguments.callee(node.childNodes[i]);
}
}
return retStr;
};
Use jquery. In the head of your html doc, put this line:
<script type="text/javascript" src="http://code.jquery.com/jquery-1.7.2.min.js"></script>
Now use a jQuery ajax call to the local XML file.
//pulls in the xml
$.ajax({
type: "GET",
url: "MapPoints.xml",
dataType: "xml",
success: function(xml) {
$(xml).find('MapPoint').each(function(){
var lat = $.trim(this.LocationLat);
var lng = $.trim(this.LocationLng);
//use the same method to extract your other data
var mappoint = new google.maps.LatLng(lng,lat);
//now create the marker and set it to your map
var marker = new google.maps.Marker({
position:mappoint,
map:map,
title:'Your Marker Title',
icon:null
});
});
}
});
How to use own map database to display map on a website and use that map to find route and do other stuff ?
You should try the Google Maps API. http://code.google.com/apis/maps/index.html
You can store locations or routes in your database and use the Maps API to display them. Not sure if this is what you're looking for, but I've found their API really easy to use.
That is an absolutely massive task, I'm not sure I understand your question correctly... You've tagged this with Javascript, Web-development and map - so presumably you want to know how to implement a front-end that renders a map to a web page, and then performs custom pathfinding and other logic. Surely I'm misunderstanding you! :D
The O'rielly RESTful Web Services book uses a map service as its operative example throughout the book, so you may find it useful, at least for the design of your service front end. It doesn't delve into the implementation very deeply, particularly the actual mechanics of map image generation, as it is primarily concerned with the design of the service interface from an HTTP perspective. It also doesn't treat very much with the client-side logic that would be involved in dragging, zooming and the like.
You have two options in order to calculate routes depending on your database.
If your database has clean and accurate address names then you can easily use the google maps API that can be found here: https://developers.google.com/maps/documentation/directions/.
Bare in mind that you can only execute 2500 requests per day with the free version.
On the other hand if you have a network defined on your db (have the roads in a nodes and arcs manner) then you can implement Dijsktra's algorithm.
Have a look here: http://www.vogella.com/articles/JavaAlgorithmsDijkstra/article.html
Because of the fact that the network should be loaded from the database in order to calculate the best route I suggest the singleton pattern.
An OpenSource way to do this, which I would recommend in most cases, is using GeoServer and OpenLayers.
GeoServer can read gegraphic data from all the major databases and be used as host for the widely used standard GeographicgWebServices WMS and WFS.
OpenLayers is a JavaScript API to show your map on the webpage.
I recently implemented something like this. I realize it is an old question but Google has the javascript api v3 out for Google Maps and it works great.
https://developers.google.com/maps/articles/phpsqlajax_v3
This page helped me implement the entire system. Works great. You can also use php to update and edit the entries on the map.
You need xml pages and others but here is the map html page just to give you an idea of the javascript it entails.
<!DOCTYPE html >
<head>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
<meta http-equiv="content-type" content="text/html; charset=UTF-8"/>
<title>PHP/MySQL & Google Maps Example</title>
<script type="text/javascript" src="http://maps.googleapis.com/maps/api/js?sensor=false"></script>
<script type="text/javascript">
//<![CDATA[
var customIcons = {
restaurant: {
icon: 'http://labs.google.com/ridefinder/images/mm_20_blue.png',
shadow: 'http://labs.google.com/ridefinder/images/mm_20_shadow.png'
},
bar: {
icon: 'http://labs.google.com/ridefinder/images/mm_20_red.png',
shadow: 'http://labs.google.com/ridefinder/images/mm_20_shadow.png'
}
};
function load() {
var map = new google.maps.Map(document.getElementById("map"), {
center: new google.maps.LatLng(47.6145, -122.3418),
zoom: 13,
mapTypeId: 'roadmap'
});
var infoWindow = new google.maps.InfoWindow;
// Change this depending on the name of your PHP file
downloadUrl("phpsqlajax_genxml.php", function(data) {
var xml = data.responseXML;
var markers = xml.documentElement.getElementsByTagName("marker");
for (var i = 0; i < markers.length; i++) {
var name = markers[i].getAttribute("name");
var address = markers[i].getAttribute("address");
var type = markers[i].getAttribute("type");
var point = new google.maps.LatLng(
parseFloat(markers[i].getAttribute("lat")),
parseFloat(markers[i].getAttribute("lng")));
var html = "<b>" + name + "</b> <br/>" + address;
var icon = customIcons[type] || {};
var marker = new google.maps.Marker({
map: map,
position: point,
icon: icon.icon,
shadow: icon.shadow
});
bindInfoWindow(marker, map, infoWindow, html);
}
});
}
function bindInfoWindow(marker, map, infoWindow, html) {
google.maps.event.addListener(marker, 'click', function() {
infoWindow.setContent(html);
infoWindow.open(map, marker);
});
}
function downloadUrl(url, callback) {
var request = window.ActiveXObject ?
new ActiveXObject('Microsoft.XMLHTTP') :
new XMLHttpRequest;
request.onreadystatechange = function() {
if (request.readyState == 4) {
request.onreadystatechange = doNothing;
callback(request, request.status);
}
};
request.open('GET', url, true);
request.send(null);
}
function doNothing() {}
//]]>
</script>
</head>
<body onload="load()">
<div id="map" style="width: 500px; height: 300px"></div>
</body>
</html>