Leaflet Routing API: retrieve the legs data - leaflet

I use the Leaflet Routing API, connected to Mapbox, to display a route with several waypoints.
Now, I have to retrieve the distance and the time between these waypoints for some calculations...
I see that the api.mapbox.com/directions API (called via Leaflet) receives as result an array of legs between my waypoints, and all data I need (legs'' distance and duration):
routes: [,…]
0: {legs: [{summary: "A 35, D 415", weight: 4813.6, duration: 4594.8,…},…], weight_name: "routability",…}
distance: 447598.9
duration: 22889.300000000003
legs: [{summary: "A 35, D 415", weight: 4813.6, duration: 4594.8,…},…]
0: {summary: "A 35, D 415", weight: 4813.6, duration: 4594.8,…}
distance: 101906.2
duration: 4594.8
steps: [{intersections: [{out: 0, entry: [true], bearings: [301], location: [7.761832, 48.592052]},…],…},…]
summary: "A 35, D 415"
1: {summary: "D 18bis, D 1bis", weight: 2070.1, duration: 1890.6,…}
distance: 28743.3
duration: 1890.6
steps: [{intersections: [{out: 0, entry: [true], bearings: [310], location: [7.538932, 47.928985]}],…},…]
summary: "D 18bis, D 1bis"
weight: 2070.1
2: {summary: "D 83, N 66", weight: 5097, duration: 4510.1,…}
...
I catch this result with a "routesfound" event, but I don't retrieve the legs from the result set:
{route: {…}, alternatives: Array(0), type: "routeselected", target: e, sourceTarget: e}
alternatives: []
route:
coordinates: (8188) [M, M, M, M, M, M, M, M, …]
inputWaypoints: (6) [e, e, e, e, e, e]
instructions: (104) [{…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, …]
name: "A 35, D 415, D 18bis, D 1bis, D 83, N 66, Rue du Ballon d'Alsace, D 465, La Comtoise, L'Alsacienne"
properties: {isSimplified: true}
routesIndex: 0
summary:
totalDistance: 447598.9
totalTime: 22889.300000000003
__proto__: Object
waypointIndices: (6) [0, 1611, 2100, 3485, 5808, 8187]
waypoints: (6) [e, e, e, e, e, e]
__proto__: Object
sourceTarget: e {options: {…}, _router: e, _plan: e, _requestCount: 1, _formatter: e, …}
target: e {options: {…}, _router: e, _plan: e, _requestCount: 1, _formatter: e, …}
type: "routeselected"
Is there a way to access the native result via Leaflet, or am I forced to do a duplicate call to the Mapbox API to bypass Leaflet ?

I have the same problem and I tried to get the response of the router. After digging into the code I found the _pendingRequest that hold the router XML HTTP request
ACTIVE_DAY_ROUTE = L.Routing.control({
show: false,
waypoints: routeWaypoints,
router: ROUTER,
routeWhileDragging: false,
draggableWaypoints: false,
lineOptions: {
styles: [{
color: ROUTE_COLOR,
opacity: ROUTE_OPACITY,
weight: 4
}]
},
createMarker: function() {
return null;
}
});
console.log(ACTIVE_DAY_ROUTE._pendingRequest.response);
I succeed to get it on console.log but can't get the response attribute (perhaps because it is pending or finished when I try to get the value)
UPDATE:
I hacked the _convertRoute method to include legs in it
var result = {
name: '',
coordinates: [],
instructions: [],
legs: '', // HACK HERE
summary: {
totalDistance: responseRoute.distance,
totalTime: responseRoute.duration
}
},
result.legs = responseRoute.legs; // HACK HERE - Affect leg

Related

flutter/dart value from Map

I want to get a single value from a nested map.
In this case, the value of the postal_code: 52034
Map:
{plus_code: {compound_code: QW8C+JTA ExampleTown, ExampleCountry, global_code: 8FFGDSC+JTA},
results: [
{address_components: [{long_name: 31, short_name: 31, types: [street_number]},
{long_name: ExampleRoute, short_name: ExampleRoute, types: [route]},
{long_name: ExampleTown, short_name: ExampleTown, types: [locality, political]},
{long_name: ExampleCountry, short_name: DE, types: [country, political]},
{long_name: 52034, short_name: 52034, types: [postal_code]}
],
formatted_address: ExampleRoute 31, 52034 ExampleTown, ExampleCountry, geometry: {location: {lat: 12.345678, lng: 12.345678}, locati
maybe something like:
print(data["results"][0]["address_components"]...???..);
for (var i = 0; i < data["results"][0]["address_components"].length; i++) {
if(data["results"][0]["address_components"][i]["types"].toString() == "[postal_code]"){
print(data["results"][0]["address_components"][i]["long_name"].toString(););
}
}

SVG Path length in Leaflet Routing Machine

I am using Leaflet Routing Machine to create map route.
My requirement is, if there are multiple locations like A, B, C, D, E. I am getting the length of svg path from A to E. But i need length form A to B, B to C, C to D, D to E. Please help someone.
click to see image
Red color line is svg path. So, when i click on any marker then i need length from basel to that marker. i mean, i need to get length from basel to neuchatel or basel to bern or neuchatel to bern, etc.
var routeControl = L.Routing.control({
waypoints: waypoints,
reverseWaypoints: false,
lineOptions: {
styles: [{color: 'red', opacity: 1, weight: 3}]
},
geocoder: L.Control.Geocoder.nominatim({
serviceUrl: 'http://localhost:8084/'
}),
createMarker: function(i, wp, nWps) {
console.log(wp)
let custom_icon = L.divIcon({
iconSize: [100, 20],
popupAnchor: [-30, -18],
shadowUrl: '',
html: '<div class="notification '+wp.name+'" data-pathid="'+(i+1)+'" style="color: #000;background-color: transparent;"><img src="img/blue.png"><span class="city-name">' + latlng[i].name + '</span></div>'
})
marker = L.marker(
[wp.latLng.lat, wp.latLng.lng],
{
icon: custom_icon
})
.bindPopup(latlng[i].name)
.openPopup()
.addTo(map);
// marker.on('click', onMarkerClick);
}
}).addTo(map);

Can Protractor ignores the timeouts of 3rd party plugin in angular?

I'm using amchart to show my data analytics in the Angular app. If I run an E2E test on that page that contains the amchart plugin, it's not able to finish (script timeout) cause it using real-time updates for charts (dynamic)...
This command 'getAllAngularTestabilities()' in console shows that has been pendingMacrotasks on page, so if the Protractor not working here, it's totally okay.
[Testability]
0: Testability
taskTrackingZone: TaskTrackingZoneSpec {name: "TaskTrackingZone", microTasks: Array(0), macroTasks: Array(3), eventTasks: Array(474), properties: {…}}
_callbacks: []
_didWork: true
_isZoneStable: true
_ngZone: NgZone
hasPendingMacrotasks: true
hasPendingMicrotasks: false
isStable: true
lastRequestAnimationFrameId: -1
nativeRequestAnimationFrame: ƒ requestAnimationFrame()
onError: EventEmitter_ {_isScalar: false, observers: Array(1), closed: false, isStopped: false, hasError: false, …}
onMicrotaskEmpty: EventEmitter_ {_isScalar: false, observers: Array(1), closed: false, isStopped: false, hasError: false, …}
onStable: EventEmitter_ {_isScalar: false, observers: Array(2), closed: false, isStopped: false, hasError: false, …}
onUnstable: EventEmitter_ {_isScalar: false, observers: Array(1), closed: false, isStopped: false, hasError: false, …}
shouldCoalesceEventChangeDetection: false
I have 3 charts on that page, so I checked what NgZone says: Coming to a request in every second, and I can't turn off them. I'm trying to find the solution in amchart's documentation but I haven't found anything yet...
ZONE pending tasks=
(3) [ZoneTask, ZoneTask, ZoneTask]
0: ZoneTask
callback: ƒ ()
cancelFn: undefined
creationLocation: Error: Task 'macroTask' from 'setTimeout'. at TaskTrackingZoneSpec.push.FGvd.TaskTrackingZoneSpec.onScheduleTask (http://localhost:4200/vendor.js:54102:40) at ZoneDelegate.scheduleTask (http://localhost:4200/polyfills.js:9471:55) at Object.onScheduleTask (http://localhost:4200/polyfills.js:9365:69) at ZoneDelegate.scheduleTask (http://localhost:4200/polyfills.js:9471:55) at Zone.scheduleTask (http://localhost:4200/polyfills.js:9303:47) at Zone.scheduleMacroTask (http://localhost:4200/polyfills.js:9326:29) at scheduleMacroTaskWithCurrentZone (http://localhost:4200/polyfills.js:10227:29) at http://localhost:4200/polyfills.js:11679:34 at proto.<computed> (http://localhost:4200/polyfills.js:10542:52) at loop_1 (http://localhost:4200/vendor.js:23731:42)
data: {isPeriodic: false, delay: 1000, args: Arguments(2), handleId: 1516}
invoke: ƒ ()
runCount: 0
scheduleFn: ƒ scheduleTask(task)
source: "setTimeout"
type: "macroTask"
_state: "notScheduled"
_zone: Zone {_parent: Zone, _name: "angular", _properties: {…}, _zoneDelegate: ZoneDelegate}
_zoneDelegates: null
state: (...)
zone: (...)
__proto__: Object
1: ZoneTask {_zone: Zone, runCount: 0, _zoneDelegates: null, _state: "notScheduled", type: "macroTask", …}
2: ZoneTask {_zone: Zone, runCount: 0, _zoneDelegates: null, _state: "notScheduled", type: "macroTask", …}
length: 3
__proto__: Array(0)
UPDATE!
I can avoid this problem with a tiny workaround.
Need to create a function that using runOutsideAngular(), and if I create the chart inside the callback, no will be running macrotasks!
constructor(#Inject(PLATFORM_ID) private platformId, private zone: NgZone) {
}
// Run the function only in the browser
browserOnly(f: () => void): void {
if (isPlatformBrowser(this.platformId)) {
this.zone.runOutsideAngular(() => {
f();
});
}
}
ngOnInit(): void {
this.browserOnly(() => {
this.chart = am4core.create('line-chart-placeholder', am4charts.XYChart);
});
}
yes, you can ignore it. You need to disable main protractor's feature that waits for page to be ready, like this
await browser.waitForAngularEnabled(false)
for more info, read here

Replace a showR2 with a custom text in a Google Chart?

I am playing around with Google Chart to look a certain way. In this situation I have a combo chart a line and column chart.
I have stumble upon a view "layout" problems
How do replace the show2r legend with just some custom text? At
the moment says: y = 2.032E-4 * x - 8.203 r^2 = 7.005E-3 and I want
to replace it with "Trendline (Lineair)
2/ Also the legend gets a
1/2 and Arrows left and right. I like the legend to always be
visible?
3/ The x axis doesn't display all dates, how can I set that
as a default?
4/ How do I add vertical line in say month June??
Regards
to change the trendline label in the legend, use option --> labelInLegend
there are no standard options to change the value in the tooltip,
but it can be changed manually using event --> onmouseover
when the legend's position is top,
you can use option --> legend.maxLines
to increase the number of lines available and prevent the arrows...
to ensure all dates are shown on the x-axis,
allow enough room by using option --> chartArea.bottom
see following working snippet for examples of each...
google.charts.load('current', {
packages: ['corechart']
}).then(function () {
var data = google.visualization.arrayToDataTable([
['x', 'y0', 'y1'],
[new Date(2017, 11, 28), 175, 10],
[new Date(2017, 11, 29), 159, 20],
[new Date(2017, 11, 30), 126, 35],
[new Date(2017, 11, 31), 129, 40],
[new Date(2018, 0, 1), 108, 60],
[new Date(2018, 0, 2), 92, 70]
]);
var options = {
chartArea: {
bottom: 72
},
hAxis: {
slantedText: true
},
height: 400,
legend: {
maxLines: 2,
position: 'top'
},
tooltip: {
isHtml: true
},
trendlines: {
0: {
labelInLegend: '0-Linear Trend',
showR2: true,
type: 'linear',
visibleInLegend: true
},
1: {
labelInLegend: '1-Linear Trend',
showR2: true,
type: 'linear',
visibleInLegend: true
}
},
width: 400
};
var container = document.getElementById('chart_div');
var chart = new google.visualization.ColumnChart(container);
google.visualization.events.addListener(chart, 'onmouseover', function (props) {
var tooltipLabels = container.getElementsByTagName('span');
for (var i = 0; i < tooltipLabels.length; i++) {
if (tooltipLabels[i].innerHTML.indexOf('y =') > -1) {
tooltipLabels[i].innerHTML = 'CUSTOM TEXT:';
}
}
});
chart.draw(data, options);
});
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="chart_div"></div>

Highcharts custom error handler

We are using highcharts to plot multiple charts on a single HTML page.
However one/some of the chart throw highchart error and we like to capture those error and show different error to user.
For this highcharts do provide custom error handler. But this custom error handler does not provide information about specific chart throwing that error.
Here that JS Fiddle provided by highcharts, which works fine for a chart :
Highcharts.error = function (code, true) {
// See
https://github.com/highcharts/highcharts/blob/master/errors/errors.xml
// for error id's
Highcharts.charts[0].renderer
.text('Chart error ' + code)
.attr({
fill: 'red',
zIndex: 20
})
.add()
.align({
align: 'center',
verticalAlign: 'middle'
}, null, 'plotBox');
};
http://jsfiddle.net/gh/get/library/pure/highslide-software/highcharts.com/tree/master/samples/highcharts/chart/highcharts-error/
Any idea how can I use this custom error handler per chart?
I'm using new Highcharts.Charts(options) to create new chart, but don't see way to specify error handler per chart.
Additional info: Charts are refreshed/appended using data through APIs. User that configures chart also configures refresh interval and query to use for chart.
Error handling in HighCharts does not make much sense. It would make more sense to pass the chart instance to Highcharts.error (like Kamil Kulig wrote) or to have an error event in chart.events. Anyways
here is a solution I came up with:
Create an array of errors:
var chartErrors = [];
Create an error handler which will push errors into the chartErrors. Error objects I'm making look like this: {"chartIndex": <chart index>, "errorCode": <error code>}. All charts are added to the Highcharts.charts array when they are created so we can use Highcharts.charts.length - 1 for the chartIndex.
Highcharts.error = function (code) {
// See https://github.com/highcharts/highcharts/blob/master/errors/errors.xml
// for error id's
chartErrors.push({"chartIndex": Highcharts.charts.length - 1, "errorCode":code});
};
After initiating all charts we will have an array of errors. We can call forEach on this array and handle errors the way we want.
chartErrors.forEach(function(c) {
Highcharts.charts[c.chartIndex].renderer
.text('Chart error ' + c.errorCode)
.attr({
fill: 'red',
zIndex: 20
})
.add()
.align({
align: 'center',
verticalAlign: 'middle'
}, null, 'plotBox');
});
Working example:
Note: I've wrapped the code in a self invoking function to prevent leaking variables to global scope.
(function() {
var chartErrors = [];
Highcharts.error = function (code) {
// See https://github.com/highcharts/highcharts/blob/master/errors/errors.xml
// for error id's
chartErrors.push({"chartIndex": Highcharts.charts.length - 1, "errorCode":code});
};
Highcharts.chart('container1', {
title: {
text: 'Demo of Highcharts error handling'
},
xAxis: {
categories: ['Jan', 'Feb', 'Mar', 'Apr', 'May']
},
yAxis: {
type: 'logarithmic',
min: 0
},
series: [{
data: [1, 3, 2],
type: 'column'
}]
});
Highcharts.chart('container2', {
title: {
text: 'Solar Employment Growth by Sector, 2010-2016'
},
subtitle: {
text: 'Source: thesolarfoundation.com'
},
yAxis: {
title: {
text: 'Number of Employees'
}
},
legend: {
layout: 'vertical',
align: 'right',
verticalAlign: 'middle'
},
plotOptions: {
series: {
label: {
connectorAllowed: false
},
pointStart: 2010
}
},
series: [{
name: 'Installation',
data: [43934, 52503, 57177, 69658, 97031, 119931, 137133, 154175]
}, {
name: 'Manufacturing',
data: [24916, 24064, 29742, 29851, 32490, 30282, 38121, 40434]
}, {
name: 'Sales & Distribution',
data: [11744, 17722, 16005, 19771, 20185, 24377, 32147, 39387]
}, {
name: 'Project Development',
data: [null, null, 7988, 12169, 15112, 22452, 34400, 34227]
}, {
name: 'Other',
data: [12908, 5948, 8105, 11248, 8989, 11816, 18274, 18111]
}],
responsive: {
rules: [{
condition: {
maxWidth: 500
},
chartOptions: {
legend: {
layout: 'horizontal',
align: 'center',
verticalAlign: 'bottom'
}
}
}]
}
});
Highcharts.chart('container3', {
title: {
text: 'Demo of Highcharts error handling'
},
xAxis: {
categories: ['Jan', 'Feb', 'Mar', 'Apr', 'May']
},
yAxis: {
type: 'logarithmic',
min: 0
},
series: [{
data: [1, 3, 2],
type: 'column'
}]
});
chartErrors.forEach(function(e) {
Highcharts.charts[e.chartIndex].renderer
.text('Chart error ' + e.errorCode)
.attr({
fill: 'red',
zIndex: 20
})
.add()
.align({
align: 'center',
verticalAlign: 'middle'
}, null, 'plotBox');
});
})();
<script src="https://code.highcharts.com/highcharts.js"></script>
<div id="container1" style="height: 400px"></div>
<div id="container2" style="height: 400px"></div>
<div id="container3" style="height: 400px"></div>
Highcharts error function is not adjusted to have a chart context as an argument, because it can be executed in different contexts too.
For example: error number 16 occurs when Highcharts/Highstock is loaded second time in the same page. It has nothing to do with the chart, because it depends on script importing only.
The workaround I found requires some searching and and a little bit of coding.
Refer to this live demo: http://jsfiddle.net/kkulig/a8nun9aL/
I found the place in the code responsible for throwing the error 10 (the one you used in your example). I overwrote this function (see this doc page for more information about overwriting in Highcharts: https://www.highcharts.com/docs/extending-highcharts/extending-highcharts) and added a chart variable (from Highcharts.Axis.prototype.setTickInterval scope) as the third argument:
if (
axis.positiveValuesOnly &&
!secondPass &&
Math.min(axis.min, pick(axis.dataMin, axis.min)) <= 0
) { // #978
H.error(10, 1, chart); // Can't plot negative values on log axis // MODIFIED LINE
}
It should be done for all errors you want to custom handle.
Now it can be used in custom Highcharts.error function:
Highcharts.error = function(code, stop, chart) {
// See https://github.com/highcharts/highcharts/blob/master/errors/errors.xml
// for error id's
Highcharts.charts[0].renderer
.text('Chart error ' + code + " on chart titled: " + chart.title.textStr)
(...)
You can add your own property in chart constructor options and find it in chart.options object.