I am working on a project with Vue and Leaflet that for now just shows a map and I want that when you give the start and end coordinates it colours the route from between those points (or many points and a route than goes through all of them). Unfortunately, I found that the plugin for Leaflet that uses OSRM for automating routing "will not work unless you configure a routing backend yourself". Is there an alternative to that? Any other open-source plugin for Vue Leaflet (or alternatively for OpenLayers(VueLayers) that can auto-track existing routes? Thank you in advance.
You could interface Openlayers directly with a service such as OpenRouteService https://openrouteservice.org/dev/#/api-docs/v2/directions/{profile}/json/post This code assumes a map routesMap with a vector layer orsRoute, and array routeComplete of coordinate pairs in view projection for start, optional waypoint, and end, and API key orsKey
var viewProj = routesMap.getView().getProjection();
var startA = ol.proj.transform(routeComplete[0], viewProj, 'EPSG:4326');
var viaA = routeComplete[1] ? ol.proj.transform(routeComplete[1], viewProj, 'EPSG:4326') : null;
var endA = ol.proj.transform(routeComplete[2], viewProj, 'EPSG:4326');
var startN = startA.toString();
var viaN = viaA ? viaA.toString() : null;
var endN = endA.toString();
var url = 'https://api.openrouteservice.org/v2/directions/driving-car/json';
var params = '{"coordinates":[[' + startN + '],[' + (viaN ? viaN + '],[' : '') + endN + ']]}';
var orsXhr = new XMLHttpRequest();
orsXhr.onreadystatechange = function() {
if (orsXhr.readyState == 4) {
if (orsXhr.status == 200) {
var route = JSON.parse(orsXhr.responseText).routes[0];
var linestring = route.geometry;
var distance = route.summary.distance;
var duration = route.summary.duration;
orsRoute.getSource().addFeature(
new ol.Feature({
geometry: new ol.format.Polyline().readGeometry(linestring).transform('EPSG:4326', viewProj),
name: 'Openrouteservice',
distance: distance,
duration: duration
})
);
orsRoute.getSource().setAttributions('© Powered by openrouteservice');
}
}
}
orsXhr.onerror = function(e) { console.log('error'); }
orsXhr.ontimeout = function(e) { console.log('timeout'); }
orsXhr.open('POST', url, true);
orsXhr.timeout = 3000;
orsXhr.setRequestHeader('Content-type', 'application/json');
orsXhr.setRequestHeader('Authorization', orsKey);
orsXhr.send(params);
Related
I have a bootstrap tabs that is working well.
I have an area map that is working well if it is not inserted into a tab.
I use the Responsive Image Maps jQuery Plugin from Matt Stow, also works fine.
The symptom:
Then I put the area map into one of the tabs, a not active by default.
Then I click on the tab to make it shown. So the img is well shown.
But the area map does not working. I can't see the clickable rect.
But if I manually resize my navigator, then the area map works.
The page: https://boutique.bilp.fr/71-les-pieds-de-poteaux.html
Select tab "Guide de choix", the white rectangles should be clickable. THey are not until I manually resize the window.
The cause:
The responsible is the Responsive Image Maps jQuery Plugin. In its code, it makes a call to the jquery .width() method to obtain the width of the img where the map should works. And because the parent (tab) is hidden, the returned width is wrong. And it uses it to resize the map... with bad values. The map is then so small that it seems to not work.
Thanks for your help.
One solution is to modify the Responsive Image Maps jQuery Plugin by making ancestors visible before calling width().
Original code:
/*
* rwdImageMaps jQuery plugin v1.6
*
* Allows image maps to be used in a responsive design by recalculating the area coordinates to match the actual image size on load and window.resize
*
* Copyright (c) 2016 Matt Stow
* https://github.com/stowball/jQuery-rwdImageMaps
* http://mattstow.com
* Licensed under the MIT license
*/
;(function($) {
$.fn.rwdImageMaps = function() {
var $img = this;
var rwdImageMap = function() {
$img.each(function() {
if (typeof($(this).attr('usemap')) == 'undefined')
return;
var that = this,
$that = $(that);
// Since WebKit doesn't know the height until after the image has loaded, perform everything in an onload copy
$('<img />').on('load', function() {
var attrW = 'width',
attrH = 'height',
w = $that.attr(attrW),
h = $that.attr(attrH);
if (!w || !h) {
var temp = new Image();
temp.src = $that.attr('src');
if (!w)
w = temp.width;
if (!h)
h = temp.height;
}
var wPercent = $that.width()/100,
hPercent = $that.height()/100,
map = $that.attr('usemap').replace('#', ''),
c = 'coords';
$('map[name="' + map + '"]').find('area').each(function() {
var $this = $(this);
if (!$this.data(c))
$this.data(c, $this.attr(c));
var coords = $this.data(c).split(','),
coordsPercent = new Array(coords.length);
for (var i = 0; i < coordsPercent.length; ++i) {
if (i % 2 === 0)
coordsPercent[i] = parseInt(((coords[i]/w)*100)*wPercent);
else
coordsPercent[i] = parseInt(((coords[i]/h)*100)*hPercent);
}
$this.attr(c, coordsPercent.toString());
});
}).attr('src', $that.attr('src'));
});
};
$(window).resize(rwdImageMap).trigger('resize');
return this;
};
})(jQuery);
The modified code:
/*
* rwdImageMaps jQuery plugin v1.6
*
* Allows image maps to be used in a responsive design by recalculating the area coordinates to match the actual image size on load and window.resize
*
* Copyright (c) 2016 Matt Stow
* https://github.com/stowball/jQuery-rwdImageMaps
* http://mattstow.com
* Licensed under the MIT license
*/
;(function($) {
$.fn.rwdImageMaps = function() {
var $img = this;
var rwdImageMap = function() {
$img.each(function() {
if (typeof($(this).attr('usemap')) == 'undefined')
return;
var that = this,
$that = $(that);
// Since WebKit doesn't know the height until after the image has loaded, perform everything in an onload copy
$('<img />').on('load', function() {
// Modif BC : make ancestors visible so .width() can return the right value
//************************************************
var hidden_ancestors = [];
$that.parents().each(function() {
if ($(this).css('display') == 'none')
{
$(this).show();
hidden_ancestors.push($(this));
};
});
// END Modif BC
var attrW = 'width',
attrH = 'height',
w = $that.attr(attrW),
h = $that.attr(attrH);
if (!w || !h) {
var temp = new Image();
temp.src = $that.attr('src');
if (!w)
w = temp.width;
if (!h)
h = temp.height;
}
var wPercent = $that.width()/100,
hPercent = $that.height()/100,
map = $that.attr('usemap').replace('#', ''),
c = 'coords';
$('map[name="' + map + '"]').find('area').each(function() {
var $this = $(this);
if (!$this.data(c))
$this.data(c, $this.attr(c));
var coords = $this.data(c).split(','),
coordsPercent = new Array(coords.length);
for (var i = 0; i < coordsPercent.length; ++i) {
if (i % 2 === 0)
coordsPercent[i] = parseInt(((coords[i]/w)*100)*wPercent);
else
coordsPercent[i] = parseInt(((coords[i]/h)*100)*hPercent);
}
$this.attr(c, coordsPercent.toString());
});
// Modif BC : Restore invisibility on ancestors
//*********************************************
jQuery.each(hidden_ancestors, function(index, value)
{
$(value).css({display: ''});
});
// END Modif BC
}).attr('src', $that.attr('src'));
});
};
$(window).resize(rwdImageMap).trigger('resize');
return this;
};
})(jQuery);
I will propose this improvment to Matt Stow, the author
We are trying to find suggestions, or implementation options on how to hide a marker once a new point on the map has been clicked.
In our application, once the user clicks on a particular pin on the map, we display a new pin (in a different lat/long location) that is associated with the click event. I.e. a point should be in oklahoma, but the map is displaying texas, so once the marker texas is clicked, a new marker in oklahoma is shown. Our issue is that whenever a user selects a new point, we are not able to "hide" the marker for the previous selection, which then clutters our screen.
Any suggestions on how we could handle this issue?
Code is below:
require(["esri/map", "esri/geometry/Point", "esri/symbols/SimpleMarkerSymbol", "esri/graphic", "dojo/_base/array", "dojo/dom-style", "dojox/widget/ColorPicker", "esri/InfoTemplate", "esri/Color", "dojo/dom", "dojo/domReady!", "esri/geometry/Polyline", "esri/geometry/geodesicUtils", "esri/units","esri/symbols/SimpleLineSymbol"],
function( Map, Point,SimpleMarkerSymbol, Graphic, arrayUtils, domStyle, ColorPicker, InfoTemplate, Color, dom, Polyline, geodesicUtils, Units,SimpleLineSymbol) {
map = new Map("mapDiv", {
center : [-98.35, 35.50],
zoom : 5,
basemap : "topo"
//basemap types: "streets", "satellite", "hybrid", "topo", "gray", "oceans", "osm", "national-geographic"
} );
map.on("load", pinMap);
var arr = [];
var initColor, iconPath;
function pinMap( ) {
map.graphics.clear();
iconPath = "M16,3.5c-4.142,0-7.5,3.358-7.5,7.5c0,4.143,7.5,18.121,7.5,18.121S23.5,15.143,23.5,11C23.5,6.858,20.143,3.5,16,3.5z M16,14.584c-1.979,0-3.584-1.604-3.584-3.584S14.021,7.416,16,7.416S19.584,9.021,19.584,11S17.979,14.584,16,14.584z";
var infoContent = "<b>Id</b>: ${Id} ";
var infoTemplate = new InfoTemplate(" Details",infoContent);
$.post( '{{ path( 'points' ) }}', {}, function( r ) {
arrayUtils.forEach( r.points, function( point ) {
if (point.test==1) {
initColor = "#CF3A3A";
}
else {
initColor = "#FF9900";
}
arr.push(point.id,point.pinLon1,point.pinLat1,point.pinLon2,point.pinLat2);
var attributes = {"Site URL":point.url,"Activity Id":point.id,"Updated By":point.updated,"Customer":point.customer};
var graphic = new Graphic(new Point(point.pinLon1,point.pinLat1),createSymbol(iconPath,initColor),attributes,infoTemplate);
map.graphics.add( graphic );
map.graphics.on("click",function(evt){
var Content = evt.graphic.getContent();
var storeId = getStoreId(Content);
sitePins(storeId);
});
} );
}, 'json' );
}
function getStoreId( content ){
var init = content.split(":");
var fin= init[2].split("<");
return fin[0].trim();
}
function sitePins( siteId ) {
iconPathSite = "M15.834,29.084 15.834,16.166 2.917,16.166 29.083,2.917z";
initColorSite = "#005CE6";
var infoContent = "<b>Distance</b>: ${Distance} Miles";
var infoTemplate = new InfoTemplate(" Distance to Location",infoContent);
var indexValue=0;
for (var index = 0; index < arr.length; index++){
if (arr[index]==storeId){
indexValue =index;
}
}
pinLon1 = arr[indexValue+1];
pinLat1 = arr[indexValue+2];
pinLon2 = arr[indexValue+3];
pinLat2 = arr[indexValue+4];
var line = {"paths":[[[pinLon1, pinLat1], [pinLon2, pinLat2]]]};
line = new esri.geometry.Polyline(line);
var lengths = Number(esri.geometry.geodesicLengths([line], esri.Units.MILES)).toFixed(2);
var attributes = {"Distance":lengths};
var graphicSite = new Graphic(new Point (pinLon1,pinLat1), createSymbol(iconPathSite, initColorSite),attributes,infoTemplate);
var pathLine = new esri.Graphic(line, new esri.symbol.SimpleLineSymbol());
map.graphics.add( pathLine );
map.graphics.add( graphicSite );
}
function createSymbol( path, color ) {
var markerSymbol = new esri.symbol.SimpleMarkerSymbol( );
markerSymbol.setPath(path);
markerSymbol.setSize(18);
markerSymbol.setColor(new dojo.Color(color));
markerSymbol.setOutline(null);
return markerSymbol;
}
} );
</script>
As far as I get the code, it shows the distance between the marker and the point then clicked.You are creating point and polyline on each click event on map. Following can help:
1) Please provide id say 'abc' to polyline, graphic site.
2) Then on every click event remove the graphic and polyline with id 'abc'.
dojo.forEach(this.map.graphics.graphics, function(g) {
if( g && g.id === "abc" ) {
//remove graphic with specific id
this.map.graphics.remove(g);
}
}, this);
3) Then you can create the new polyline and point as you are already doing it.
Ti.GeoLocation.forwardGeocoder() is not converting Non US address to lat and long values.
sample code below.
Ti.GeoLocation.forwardGeocoder('Hyderabad, India', function(e){
var lat = e.latitude;
var long = e.longitude;
});
with this code we are getting lat and long values are undefined.
The proper way to get US addresses, and everywhere else in the world (that Google can find) and display the Long/Lat on a titanium Map.
The code below uses the string variable: myAddress
var myAddress = address + ','+ city + ',' + postal + ',' + country //'Vieux Port, Montreal, Quebec, H2X3R4, Canada'
var xhrGeocode = Ti.Network.createHTTPClient();
xhrGeocode.setTimeout(120000);
xhrGeocode.onerror = function (e) {
alert('Google couldn\'t find the address... check your address');
};
xhrGeocode.onload = function (e) {
var response = JSON.parse(this.responseText);
if (response.status == 'OK' && response.results != undefined && response.results.length > 0) {
longitude = response.results[0].geometry.location.lng;
latitude = response.results[0].geometry.location.lat;
}
};
var urlMapRequest = "http://maps.google.com/maps/api/geocode/json?address=" + myAddress.replace(/ /g, '+');
urlMapRequest += "&sensor=" + (Ti.Geolocation.locationServicesEnabled == true);
xhrGeocode.open("GET", urlMapRequest);
xhrGeocode.setRequestHeader('Content-Type', 'application/json; charset=utf-8');
xhrGeocode.send();
var addrReq = Titanium.Network.createHTTPClient();
var addrUrl = "http://maps.googleapis.com/maps/api/geocode/json?sensor=true&address="+ query;
addrReq.open("GET",addrUrl);
addrReq.send(null);
addrReq.onload = function()
{
var response = JSON.parse(this.responseText);
if(response.status == "OK"){
LT.Customlat=response.results[0].geometry.location.lat;
LT.Customlon=response.results[0].geometry.location.lng;
}
you will need to roll your own solution using google REST APIs, the underlying Titanium API does not support non-us addresses
I am having some problems using the gem gmaps4rails. I am using a mix of javascript and gmaps4rails. Here is a sample of my code:
function handle_locations(position) {
alert("Length = " + Gmaps.map.markers.length);
var yourStartLatLng = new google.maps.LatLng(position.coords.latitude, position.coords.longitude);
var marker = new google.maps.Marker({position: yourStartLatLng});
alert("Ola 2");
if(document.getElementById("map") != null)
alert("diff");
Gmaps.map.markers[0] = marker;
alert("Ola 333");
//var map = $document.filter('#map');
//var map = document.getElementById("map");
//Gmaps.map.add_marker(marker);
}
navigator.geolocation.getCurrentPosition(handle_locations);
The handle_locations function works fine and i can get my location. The problem is to add a marker to the map created using gmaps. how can i add my geolocaton marker to the map in this function?
I had similar problem and this worked for me.
lat = position.coords.latitude;
lng = position.coords.longitude;
Gmaps.map.callback = function() {
Gmaps.map.createMarker({
Lat: lat,
Lng: lng,
rich_marker: null,
marker_picture: ""
});
}
Make sure you use position.coords.latitude/longitude only after the navigator.geolocation.getCurrentPosition(function(position) {
request has succeeded (propably you are doing so), because getting the location from user is asyncronous and will take some time.
You can check that you have the right lat and lng with
alert(lat+" "+lng);
To start off with, I would like to say that I have been looking on the internet for a really long time and have been unable to find the answer, hence my question here.
My latest school project is to create an admin page for adding articles to a database, the articles are connected to a point on a google map. The requirement for adding the point on the map is that the user is able to click the map once and the marker is produced, if the map is clicked a second time the first marker is moved to the second location. (this is what I am struggling with.)
The problem is, as the code is now, I get the error that markersArray is undefined. If I place the var markersArray = new Array; underneath the eventListener then I get an error that there is something wrong the main.js (googles file) and markersArray[0] is undefined in the second if.
By the way, I have to use google maps API v2, even though it is old.
<script type="text/javascript">
//<![CDATA[
var map;
var markers = new Array;
function load() {
if (GBrowserIsCompatible()) {
this.counter = 0;
this.map = new GMap2(document.getElementById("map"));
this.map.addControl(new GSmallMapControl());
this.map.addControl(new GMapTypeControl());
this.map.setCenter(new GLatLng(57.668911, 15.203247), 7);
GDownloadUrl("genxml.php", function(data) {
var xml = GXml.parse(data);
var Articles = xml.documentElement.getElementsByTagName("article");
for (var i = 0; i < Articles.length; i++) {
var id = Articles[i].getAttribute("id");
var title = Articles[i].getAttribute("title");
var text = Articles[i].getAttribute("text");
var searchWord = Articles[i].getAttribute("searchWord");
var point = new GLatLng(parseFloat(Articles[i].getAttribute("lat")),
parseFloat(Articles[i].getAttribute("lng")));
var article = createMarker(point, id, title, text);
this.map.addOverlay(article);
}
});
}
var myEventListener = GEvent.bind(this.map,"click", this, function(overlay, latlng) {
if (this.counter == 0) {
if (latlng) {
var marker = new GMarker(latlng);
latlng1 = latlng;
this.map.addOverlay(marker);
this.counter++;
markers.push(marker); //This is where I get the error that markersArray is undefined.
}
}
else if (this.counter == 1) {
if (latlng){
alert (markers[0]);
this.map.removeOverlay(markers[0]);
var markers = [];
this.map.addOverlay(marker);
this.counter++;
}
}
});
}
function createMarker(point, id, title, text) {
var article = new GMarker(point);
var html = "<b>" + title + "</b> <br/>"
GEvent.addListener(article, 'click', function() {
window.location = "article.php?id=" + id;
});
return article;
}
I solved the problem. I'm not exactly sure why it worked but this is what it looks like now:
var markersArray = [];
function load() {
if (GBrowserIsCompatible()) {
this.counter = 0;
this.map = new GMap2(document.getElementById("map"));
this.map.addControl(new GSmallMapControl());
this.map.addControl(new GMapTypeControl());
this.map.setCenter(new GLatLng(57.668911, 15.203247), 7);
GDownloadUrl("genxml.php", function(data) {
var xml = GXml.parse(data);
var Articles = xml.documentElement.getElementsByTagName("article");
for (var i = 0; i < Articles.length; i++) {
var id = Articles[i].getAttribute("id");
var title = Articles[i].getAttribute("title");
var text = Articles[i].getAttribute("text");
var searchWord = Articles[i].getAttribute("searchWord");
var type = Articles[i].getAttribute("type");
var point = new GLatLng(parseFloat(Articles[i].getAttribute("lat")),
parseFloat(Articles[i].getAttribute("lng")));
var article = createMarker(point, id, title, text);
this.map.addOverlay(article);
}
});
}
var myEventListener = GEvent.bind(this.map,"click", this, function(overlay, latlng) {
var marker = new GMarker(latlng);
if (this.counter == 0) {
if (latlng) {
latlng1 = latlng;
this.map.addOverlay(marker);
markersArray.push(marker);
this.counter++;
}
}
else if (this.counter == 1) {
if (latlng){
this.map.removeOverlay(markersArray[0]);
this.map.addOverlay(marker);
this.counter++;
}
}
});
}
function createMarker(point, id, title, text) {
var article = new GMarker(point);
var html = "<b>" + title + "</b> <br/>"
GEvent.addListener(article, 'click', function() {
window.location = "article.php?id=" + id;
});
return article;
}