Drive Time and Distance from Leaflet Routing Machine - maps

I’m building embedded content for a CRM using JQuery Datatables, Leaflet with OSM tiles, and Leaflet Routing Machine. Markers on the map and the rows of the table are based on the SAME JSON data, and I’m building interactions (using SHARED JavaScript functions) between the two libraries. For example, when a Datatable row is clicked, the row is highlighted, a popup is opened over the corresponding map marker, and a route is calculated using LRM which places the route line on the map. Conversely, when a map marker is clicked, all the same events happen because I'm calling the SAME function.
By default, the Itinerary LRM creates is hidden on the map, but I would like to parse out the Drive Time and Distance, and insert them in the popup opened by the shared function. I have spent four days pouring over the API documentation and searching the internet looking for clear instructions or code samples on how to access these values from the Itinerary object, but with no success. I have inspected every object I can figure out how to log to the console, but the data I need is in properties that come up ‘undefined’ when I try to access them.
Please, from start to finish, how do I access the Itinerary Summary?
When I init the map, I also init the Routing Control with null waypoints:
ctrl = L.Routing.control({
waypoints: null,
units: 'imperial',
show: false,
createMarker: function() { return null; }
}).addTo(map);
When a marker/row is clicked, I call this function:
function clickEffects(id, latlon) {
// set waypoints for routing control
ctrl.setWaypoints([ ctr, latlon])
// scroll the table to the row for the clicked marker
table.$('tr.selected').removeClass('selected');
var idx = table.row("#" + id).index()
table.row(idx).show().draw(false);
table.row(idx).nodes().to$().addClass('selected');
// create and open a popup
var popup = L.popup()
.setLatLng(latlon)
.setContent("Dan was here!!!")
.openOn(map);
}

Figured it out:
Declared popup in global scope
Bound default "Loading..." content when creating marker
In shared function, set div's with target id's in new popup content
(in addition to freshly retrieved ajax content.
In "routesfound" event listener, used JQuery to insert formatted
drive time and distance on target divs.
Works like a charm. Just need to expand on ajax data now...

Related

Binding CSV Data to SVG Drawing with AngularJS

I have started a scaled down, proof-of-concept floor plan application for my employer that is using an SVG floor plan drawing generated by Adobe Illustrator CC, HTML, CSS and AngularJS.
The idea is to have a floor plan that contains static cubicle/office numbers and to marry that floor plan with a CSV file with personnel data that updates periodically and make the information available on our intranet.
Although I am new at AngularJS/SVG, I was following an example for a map of the US and have made some pretty good progress so far, however am now at a point where I need to map the CSV data (personnel) to the SVG (cubicles) and am not sure how to proceed.
From the example in the link above, the author appears to have injected an "sg-click" directive into the SVG DOM with Angular.$compile that fires a JS Alert() of the ID of the SVG DOM when clicked:
link: function (scope, element, attrs) {
scope.elementId = element.attr("id");
scope.regionClick = function () {
alert(scope.elementId);
};
element.attr("ng-click", "regionClick()");
element.removeAttr("region");
$compile(element)(scope);
}
I am wondering if the same thing is possible with the CSV data, IE:
Outer loop over the SVG (Cubicle ID)
Inner loop over the CSV (Personnel/Cubicle ID) data
If Cubicle ID matches Personnel ID, inject the CSV data into that SVG node.
Since I am having some difficulty including the functional code here due to tag and external file restrictions, I have created a Plunk, where you can view everything in context along with external files that is operational in its current state.
Thanks.
After talking with a colleague, he suggested that I:
Convert the CSV list into an array.
Load the array into some kind of container.
When a user clicks on a cubicle.
Iterate through the array and see if there's a match based on the cubicle ID.
Since this my first attempt at Angular, my implementation may well be incorrect, but I've created a new plunk to reflect the latest code changes.
...code in plunker.
Thanks.
Plunk

How can I reinitialize ngMaps when changing routes in Angular, using ui-router?

I'm using ngMap and here's my relevant code:
<div map-lazy-load="https://maps.google.com/maps/api/js" map-lazy-load-params="{{googleMapsUrl}}" ng-style="{'height': feedActualHeight + 'px'}">
<ng-map id="iPadFeedMap" zoom="14" center="Times Square, New York, NY">
</ng-map>
</div>
This works great and loads the map perfectly. But when I navigate away and then come back to the page, the map is grayed out:
Is there a way to re-initialize the map when this page loads?
I experienced the exact same issue regardless of how center was being set (it failed both with lat/lng and a physical address), but the accepted answer wasn't quite working for me.
My solution was to use NgMap's lazy-init property to re-initialize the map each time I returned to it.
<ng-map id="dashboard-map"
center="Boston, MA"
lazy-init="true"
zoom="9"
map-type-id="TERRAIN">
</ng-map>
In my ctrl I used the following code to 1) find the uninitialized map in the DOM and 2) initialize it
// dashboardCtrl.js
NgMap.getMap({ id: "dashboard-map" }).
then(function(map) {
NgMap.initMap(map.id);
});
This way every time I hit my dashboard, the ctrl would run and re-init the map. It now shows properly every time.
This was a helpful thread to read through: https://github.com/allenhwkim/angularjs-google-maps/issues/387
It seems it only occurs in case when value for center attribute is provided as address value (e.g. Times Square, New York, NY). In that case the way the map center is determined consist of the following steps:
since ng-map leverages Google Maps Geocoding API, the corresponding method is invoked to resolve actual location (lat,lng)
Map object center property is getting updated
Since this issue never occurred for me when center attribute is provided as location value (e.g. [40.759011, -73.98447220000003]) i propose to change the way how map is initialized:
remove setting of center attribute center="Times Square, New
York,NY"
instead set map center as demonstrated below:
Example: set map center by address
NgMap.getMap("iPadFeedMap").then(function (map) {
NgMap.getGeoLocation($scope.address)
.then(function (latlng) {
map.setCenter(latlng);
});
});
$scope.address = "Times Square, New York, NY";
Demo

Angularjs - Charts.js: Same chart element doesn't redraw on other view

I am new to angularjs, trying to create my first directive. I am creating a directive to load Charts.js2.0(beta) into my application.
I have 2 views managed by angular-route, both html view has ng-included a html page that contains only charts-element.
The problem is the first page properly draws the chart, when i go to other view the charts div is loaded but charts is not re-drawn. And now if i go back to first view its blank.
Link to Plunker
What i am doing wrong? Is there any issue with my directive?
Thanks in advance.
There appears to be an issue with the Charts library modifying the existing object on the root scope, and thereby ignoring it forever afterward. I can't really trace down what is doing it, but here's a fix for you: http://plnkr.co/edit/jDQFV62FSeXAQJ6o7jE8
Here is what you had
scope.$watch('config', function(newVal) {
if(angular.isDefined(newVal)) {
if(charts) {
charts.destroy();
}
var ctx = element[0].getContext("2d");
charts = new Chart(ctx, scope.config);
//scope.$emit('create', charts);
}
});
Above, you can see that you're passing scope.config directly into the charts method. That appears to be modifying the data somehow, and since that's passed by reference, you're actually modifying $rootScope.sales.charts. If you copy that object and use it locally like below, you don't have that problem.
Here's how I fixed it.
scope.$watch('config', function(newVal) {
var config = angular.copy(scope.config);
if(angular.isDefined(newVal)) {
if(charts) {
charts.destroy();
}
var ctx = element[0].getContext("2d");
charts = new Chart(ctx, config);
//scope.$emit('create', charts);
}
});
You can see that instead of passing that object directly in, we use angular to make a copy (angular.copy()), and that's the object we pass in.
I think it has relation with the id of the canvas where you are drawing. I've had this problem too amd it was because i was using the same id for the canvas of two graphs in different views. Be sure that those ids are different and that the javasrcipt of each graph is in the controller of each view or in each view itself.
Taking a look at your pluker I see that you are using the same html for the graph and I guess that when angular moves from one of your views to the other thinks that the graph is already drawn. Differentiating two graphs will solve the problem. I don't know of there is any other approach that allows using the same html for the canvas of the graph.
Hope it helps you solve it

Where to put a function to create a pdf

I have an application which deals with projects evolving according to a process defined by a series of status transitions. I have a button to set a project to the next status. The button calls a function in the ProjectsController. This function calls another function in the Project model, where I search for the correct transition, depending on the current status, the user_group and some other parameter, and set the new status. After everything successfully accomplished, I return to the original page with 'return $this->redirect($this->referer());' from the controller.
Some of the transitions have side effects. One is to create a PDF, save it on the server and add a new entry to the 'documents' table referenced to the current project.
Problem: where should I put the function to create the PDF? I would like to put it to the Model. But I need some View Files to first render a html page and then convert it to the PDF. I could put it to the Controller. But then I have a controller function which should not be called directly an doesn't render a view.
The functions all work, but where to put them? Is there another possibility? Would it be possible to use a component?
Implement it as PdfView that will render any (pdf) view for you as Pdf. There is already a plugin that does this, search for CakePdf on Github.
A component is clearly the wrong place. A Pdf is output, so it's a kind of view. Model gets you the data, controller sets it, view renders it.

Capture page number in Ext.PagingToolbar

I'm working on a ExtJS.Grid that uses a Ext.data.Store with jsonp proxy and Ext.PagingToolbar to control paging. It's all working fine.
But some users are complaining that they further browse pages, leave the grid, and when they come back they are back to page 1. They want "the grid to remember" the page they were and starts on it.
I use a Ext.onReady(function(){},false); to define all components and another Ext.onReady(function(){}); to create the grid with a store.loadPage(1); to make the first load after everything is done.
If I could listen to some event from the Ext.PagingToolbar, when a new load happens, and capture the page it was used, I could pehaps store it in some cookie or something, and retrieve it to load that page again.
I looked on http://docs.sencha.com/extjs/4.1.3/#!/api/Ext.toolbar.Paging and found no event that could be used. Anybody has any idea of where I could do it?
You can track the change event of the Ext.toolbar.Paging and remember the currentPage in a cookie.
pagingtoolbar.on('change', function(pb, pageData) {
Ext.util.Cookies.set('lastGridPage', pageData.currentPage, new Date('1/1/2016'));
});
And setup your grid to load that page on afterrender
grid.on('afterrender', function() {
var pageNumber = Ext.util.Cookies.get('lastGridPage') || 1;
grid.store.loadPage(pageNumber);
})

Resources