Unable to get series vale for chart-click in angular stacked bar graph - angularjs

<canvas class="chart chart-bar" chart-data="data" chart-labels="labels"
chart-options="options" chart-series="series" chart-click="onclick"></canvas>
'use strict';
var app = angular.module('examples', ['chart.js', 'ui.bootstrap']);
app.controller('StackedBarCtrl', ['$scope', function ($scope) {
$scope.labels = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'];
$scope.type = 'StackedBar';
$scope.series = ['2015', '2016'];
$scope.options = {
scales: {
xAxes: [{
stacked: true,
}],
yAxes: [{
stacked: true
}]
}
};
$scope.onclick = function(points,evt)
{
console.log("evt "+points[0]["_modal"]["datasetLabel"]);
}
$scope.data = [
[65, 59, 90, 81, 56, 55, 40],
[28, 48, 40, 19, 96, 27, 100]
];
}]);
If i click on bar 28 i am not getting the value 2016, because points array in onclick function return 2 objects on for each stack and i am unable to figure out how to get value 2016 as there is no flag to indicate which bar was clicked upon

The second argument passed to your onclick callback contains array of active elements and each item in it contains _datasetIndex and _index
array[1]
[Element]
_datasetIndex:0
_index: 0
Using these values you can obtain the value you need
$scope.onclick = function(event, elems)
{
var datasetIndex = elems[0]._datasetIndex;
console.log("evt " + $scope.series[datasetIndex]);
}
Please, refer to chartjs docs and this issue related to your problem
UPDATE
Looks like it is a little tricky with stacked bar charts. The solution is to find the closest clicked bar using Chart.helpers
$scope.$on('chart-create', function(event, instance){
// used to obtain chart instance
$scope.chart = instance.chart;
});
$scope.onclick = function(elements,e)
{
// helper function that translates an event to a position in canvas coordinates
var pos = Chart.helpers.getRelativePosition(e, $scope.chart);
// inRange is the function on the chart element that is used for hit testing
var intersect = elements.find(function(element) {
return element.inRange(pos.x, pos.y);
});
if(intersect){
alert('You clicked ' + $scope.labels[intersect._index] + ' ' + $scope.series[intersect._datasetIndex]);
}
}
Here is the working plunkr

Related

do not show 0 value on google line chart

var data = google.visualization.arrayToDataTable([
['Year', 'Massachusetts', 'National'],
['2010', 88, 76],
['2011', 0, 82],
['2012', 96, 86],
['2013', 100, 91],
['2014', 0, 94],
['2015', -1, 98],
['2016', 100, 99],
['2017', 124, 100],
['2018', 125, 102]
]);
This is the data I am using to create a line chart, I do not want to show 0's and negative values on the chart. I just want to skip these values.
my current chart looks like this
Expected chart is like this
we can use a data view with calculated columns,
to replace values less than or equal to zero with null
var view = new google.visualization.DataView(data);
var viewColumns = [0];
for (var i = 1; i < data.getNumberOfColumns(); i++) {
addViewColumn(i);
}
view.setColumns(viewColumns);
function addViewColumn(columnIndex) {
viewColumns.push({
calc: function (dt, row) {
var valNew = null;
var valOrig = dt.getValue(row, columnIndex);
if (valOrig > 0) {
valNew = valOrig;
}
return valNew;
},
label: data.getColumnLabel(columnIndex),
type: data.getColumnType(columnIndex)
});
}
then use the following configuration option, which skips null values
interpolateNulls: true
see following working snippet...
google.charts.load('current', {
packages: ['corechart']
}).then(function () {
var data = google.visualization.arrayToDataTable([
['Year', 'Massachusetts', 'National'],
['2010', 88, 76],
['2011', 0, 82],
['2012', 96, 86],
['2013', 100, 91],
['2014', 0, 94],
['2015', -1, 98],
['2016', 100, 99],
['2017', 124, 100],
['2018', 125, 102]
]);
var view = new google.visualization.DataView(data);
var viewColumns = [0];
for (var i = 1; i < data.getNumberOfColumns(); i++) {
addViewColumn(i);
}
view.setColumns(viewColumns);
function addViewColumn(columnIndex) {
viewColumns.push({
calc: function (dt, row) {
var valNew = null;
var valOrig = dt.getValue(row, columnIndex);
if (valOrig > 0) {
valNew = valOrig;
}
return valNew;
},
label: data.getColumnLabel(columnIndex),
type: data.getColumnType(columnIndex)
});
}
var options = {
title: 'Average Home Insurance Premium',
interpolateNulls: true
};
var chart = new google.visualization.LineChart(document.getElementById('chart'));
chart.draw(view, options);
});
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="chart"></div>

iterating through an array of objects in an object while also grabbing an outer value

I've been stuck on something simple for a little bit. I have the following response JSON:
{
"terminalName": "Montreal",
"shipThruLocationCodes":[
{
"shipThruLocationId": 112,
"shipThruLocationCode": "B84"
}
]
}
I have a select where I need to display terminalName (shipThruLocationCode) for each item in the shipThruLocationCodes array, there will only be one terminalName. The data is stored in an array in the controller called $scope.shipThrus. This is what I tried in my ng-repeat but it did not work:
data-ng-options="shipThru.terminalName for shipThru in shipThrus, item.shipThruLocationCode for item in shipThru.shipThruLocationCodes"
I think my idea is correct, but the comma (since I'm trying to display two values) is throwing an error.
So to summarize, the select should show the following for each item
"terminal Name" (shipThruLocationCode)
There will be only one terminal name and can be multiple location codes in the shipThrulocationCodes array.
Use a function to generate the options. Here's a Plunker to show you an example:
https://plnkr.co/edit/hxlowXWCS6BWh6gGfMMl?p=preview
HTML:
<select ng-model="main.selectedOption" ng-options="option.name for option in main.options"></select>
JS:
var app = angular.module('angularApp', []);
app.controller('MainCtrl', function($scope, $http) {
var vm = this;
vm.terminals = [
{
"terminalName": "Montreal",
"shipThruLocationCodes":[
{
"shipThruLocationId": 112,
"shipThruLocationCode": "B84"
}
]
},
{
"terminalName": "Somewhere else",
"shipThruLocationCodes":[
{
"shipThruLocationId": 113,
"shipThruLocationCode": "B9999"
}
]
}
];
vm.options = [];
generateOptions();
function generateOptions() {
for(var i = 0; i < vm.terminals.length; i++) {
var selectOption = {
name: vm.terminals[i].terminalName + " (" + vm.terminals[i].shipThruLocationCodes[0].shipThruLocationCode + ")"
};
vm.options.push(selectOption);
}
}
});
Check Plunker http://plnkr.co/edit/Vs2mC9zt3HmO9KGMzV6D?p=preview
If you have the list as:
$scope.shipThrus = [{
terminalName: "Montreal",
shipThruLocationCodes: [{
shipThruLocationId: 112,
shipThruLocationCode: "B84"
}, {
shipThruLocationId: 112,
shipThruLocationCode: "B89"
}]
}];
Just create this function:
function getLocationCodes(shipThru) {
return shipThru.shipThruLocationCodes.map(function(locationCode) {
return locationCode.shipThruLocationCode;
}).join(', ');
};
Which will parse the locationCodes to B84, B89.
Then parse the shipThrus:
$scope.shipThrus.forEach(function(shipThru) {
shipThru.label = shipThru.terminalName + ' (' + getLocationCodes(shipThru) + ')';
});
Now you can create the select element with the ng-options attribute as:
ng-options="shipThru.shipThruLocationCodes as shipThru.label for shipThru in shipThrus"

angular-google-maps not showing infowindow on mouseover event

I am using angularjs-google-map http://angular-ui.github.io/angular-google-maps/#!/api
I can add multiple markers with showing infoWindow by cliking on a marker, but now I need to show the marker infoWindow when the mouse enters the area of the marker icon and hide it when the mouse leaves the area of the marker icon instead of using the click event.
You can look on this example on Jsfiddle https://jsfiddle.net/meher12/bgb36q7b/ to get idea about my purpose !
My HTML code:
<ui-gmap-google-map center="map.center" zoom="map.zoom" dragging="map.dragging" bounds="map.bounds"
events="map.events" options="map.options" pan="true" control="map.control">
<ui-gmap-markers models="map.randomMarkers" coords="'self'" icon="'icon'"
doCluster="map.doClusterRandomMarkers" clusterOptions="map.clusterOptions" modelsbyref="true"
events="map.markersEvents" options="'options'"
>
<ui-gmap-windows show="'showWindow'" ng-cloak>
<div>
<p>This is an info window</p>
</div>
</ui-gmap-windows>
</ui-gmap-markers>
</ui-gmap-google-map>
</div>
My JS code:
myApp.controller('MainController', function ($scope,uiGmapGoogleMapApi) {
$scope.numOfMarkers = 25;
uiGmapGoogleMapApi.then(function(maps) { $scope.googleVersion = maps.version; });
$scope.map = {
center: {
latitude: 45,
longitude: -73
},
zoom: 10,
options: {
streetViewControl: false,
panControl: false,
maxZoom: 20,
minZoom: 3
},
dragging: false,
bounds: {},
randomMarkers: [],
doClusterRandomMarkers: true,
currentClusterType: 'standard',
clusterOptions: {
title: 'Hi I am a Cluster!', gridSize: 60, ignoreHidden: true, minimumClusterSize: 2
}
};
$scope.map.markersEvents = {
mouseover: function (marker, eventName, model, args) {
model.options.labelContent = "Position - lat: " + model.latitude + " lon: " + model.longitude;
marker.showWindow = true;
$scope.$apply();
},
mouseout: function (marker, eventName, model, args) {
model.options.labelContent = " ";
marker.showWindow = false;
$scope.$apply();
}
};
var genRandomMarkers = function (numberOfMarkers, scope) {
var markers = [];
for (var i = 0; i < numberOfMarkers; i++) {
markers.push(createRandomMarker(i, scope.map.bounds))
}
scope.map.randomMarkers = markers;
};
var createRandomMarker = function (i, bounds, idKey) {
var lat_min = bounds.southwest.latitude,
lat_range = bounds.northeast.latitude - lat_min,
lng_min = bounds.southwest.longitude,
lng_range = bounds.northeast.longitude - lng_min;
if (idKey == null)
idKey = "id";
var latitude = lat_min + (Math.random() * lat_range);
var longitude = lng_min + (Math.random() * lng_range);
var ret = {
latitude: latitude,
longitude: longitude,
title: 'm' + i,
showWindow: false,
options: {
labelContent: ' ',
labelAnchor: "22 0",
labelClass: "marker-labels",
draggable: true
}
};
ret[idKey] = i;
return ret;
};
$scope.genRandomMarkers = function (numberOfMarkers) {
genRandomMarkers(numberOfMarkers, $scope);
};
$scope.removeMarkers = function () {
$scope.map.randomMarkers = [];
};
});
Like you see on my JS code I have created markerEvents and I can get the marker label changed on mouse events but still not showing the infoWindow attached to each marker on the map when the mouse Event is fired, despite its value is changing and take the correct value.
Someone Have an idea to resolve this issue ?
Feel free to put your changes to my Jsfiddle code :)
You must set model.showWindow instead of marker.showWindow
You can set model.show = true instead of model.showWindow, in html remove show =showWindow.

Struggling with Kendo Grid datasource and Angular.js

I tried to make a simple example of adding a new item to a kendo grid data source but I can't seem to get it to work. The item is added to the array but the grid never updates. Is this supposed to be automatic or do I have to make a call to trigger the update?
HTML:
<kendo-grid source="people" drop="selectedPeople" groupable="true" sortable="true" columns="columns" pageable="true"></kendo-grid>
<input type="text" ng-model="nameInput">
<input type="number" ng-model="ageInput">
<button ng-click="onAdd()" type="button">Add</button>
JS:
var myApp = angular.module('myApp', []).controller('Tester', ['$scope', Tester]);
myApp.directive('kendoGrid', function() {
return {
restrict: 'E',
replace: true,
scope:{source:'=source',columns:'=columns',drop:'=drop'},
template: '<div id="kendogrid"></div>',
link: function(scope,element,attrs) {
element.kendoGrid({
dataSource: scope.source,
groupable: attrs.groupable,
sortable: attrs.sortable,
pageable: {
refresh: true,
pageSizes: true
},
columns: scope.columns
});
}
};
});
function Tester($scope) {
$scope.columns = [ {
field: "name",
width: 90,
title: "First Name"
} , {
field: "age",
width: 90,
title: "Last Name"
} , {
field: "id",
hidden: true
}
];
var man1 = new Man('name1', 25, 1);
var man2 = new Man('name2', 28, 2);
var man3 = new Man('name3', 21, 3);
var man4 = new Man('name4', 29, 4);
var man5 = new Man('name5', 22, 5);
var lastId = 5;
$scope.onAdd = function(){
if($scope.nameInput !== "" && $scope.ageInput !== "")
{
lastId++;
var myman = new Man(lastId, $scope.nameInput,$scope.ageInput);
$scope.people.push(myman);
alert("Added!");
}
}
$scope.people = [man1, man2, man3];
$scope.selectedPeople = [man4, man5];
}
function Man(name, age, id) {
this.id = id;
this.name = name;
this.age = age;
}
The fiddle:
http://jsfiddle.net/yuqorcvL/5/
Any help would be appreciated.
Use kendo observable array and it will do the magic !!.
Instead of
$scope.people = [man1, man2, man3];
Use this :
$scope.people = new kendo.data.ObservableArray([man1, man2, man3]);
updated ur fiddle : JSfiddle

Webbrowser control in winform showning html with parameters (Google Maps)

I have a winform client, that contains a webbrowser control inside it. Working with C# in visual studio, and running a MSSQL for persistance.
My goal is:
Take the data stored in my MSSQL (handle via DBML/DataContext), and show a marker on a google map (Javascript v3) for each address I got in the database.
Right now I have an HTML file in my app solution, with the JS code for showing a Google map like this (lets call it mymap.html):
var map;
var _geoLocationsArr = [
["Tranehavevej 10, 2450", "Fiberby"],
["Tranehavevej 8, 2450", "Fiberby"],
["Tranehavevej 6, 2450", "Fiberby"],
["Tranehavevej 4, 2450", "Fiberby"],
["Johan Kellers Vej 27, 2450", "Service"],
["Johan Kellers Vej 25, 2450", "Service"],
["Johan Kellers Vej 23, 2450", "Service"],
["Johan Kellers Vej 21, 2450", "Service"],
["Johan Kellers Vej 24, 2450", "Potentiel"]
];
var customIcons = {
Fiberby: {
icon: 'http://labs.google.com/ridefinder/images/mm_20_red.png',
shadow: 'http://labs.google.com/ridefinder/images/mm_20_shadow.png',
title: 'Fiberby'
},
Service: {
icon: 'http://labs.google.com/ridefinder/images/mm_20_yellow.png',
shadow: 'http://labs.google.com/ridefinder/images/mm_20_shadow.png',
title: 'Service'
},
Unknown: {
icon: 'http://labs.google.com/ridefinder/images/mm_20_gray.png',
shadow: 'http://labs.google.com/ridefinder/images/mm_20_shadow.png',
title: 'Ukendt'
}
};
var geocoder;
function initialize(lat, lng) {
geocoder = new google.maps.Geocoder();
var myLatlng = new google.maps.LatLng(lat, lng);
var mapOptions = {
zoom: 14,
center: myLatlng,
mapTypeId: google.maps.MapTypeId.ROADMAP
}
map = new google.maps.Map(document.getElementById("map_canvas"), mapOptions);
//geocodeMe();
}
function toggle() {
initialize(55.66718, 12.5411);
for (var i = 0; i < _locations.length; i++) {
var item = _locations[i];
var latlng = new google.maps.LatLng(item[0], item[1]);
var icon = customIcons[_locations[i][1]] || {};
var marker = new google.maps.Marker({
position: latlng,
map: map,
icon: icon.icon,
shadow: icon.shadow,
title: "Hello World! " + i
});
}
}
function toggleGeocodes() {
initialize(55.66718, 12.5411);
for (var i = 0; i < _geoLocationsArr.length; i++) {
geocodeMe(_geoLocationsArr[i][0], _geoLocationsArr[i][1]);
}
}
function geocodeMe(address, type) {
geocoder.geocode({
'address': address
},
function(result, status){
if(status == google.maps.GeocoderStatus.OK){
map.setCenter(result[0].geometry.location);
var icon = customIcons[type] || customIcons['Unknown'];
var marker = new google.maps.Marker({
map: map,
icon: icon.icon,
shadow: icon.shadow,
position: result[0].geometry.location,
title: icon.title
});
} else{
alert('Geocode was not successful for the following reason: ' + status);
}
});
}
</script>
</head>
<body onload="initialize(55.665919, 12.55482)">
<div id="map_canvas" style="width: 100%; height: 100%"></div>
</body>
When I hit the "Geo toggle" button in my winforms, it shows the markers on the map for each geocoded address in _geoLocationsArr. And everything is working perfect.
But! Now, I want to replace the _geoLocationsArr with data generated from my winform, where my winform creates the marker data (xml, or string array, it doesn't really matter what format for me, what matters is that it can send data from the winform to the JS in the HTML page).
So, how can I create data within my WinForm, and when clicking the button calling the JS html page with the data the form has created as a parameter?
So when calling function toogleGeocodes() it will have the data as a parameter like function toggleGeocodes(_myGeoLocationsArr[]) where _myGeoLocationsArr[] is something that the winform has created and sended as parameter when calling the function.

Resources