DOJO onclick on a pie chart slice for drill down - ajax

I tried to find several places how this work but could not.
The requirement is to drill down by clicking on the slice of the pie to next level. I can get the onclick even but not sure how to get the value from the chart. Everywhere it is pointing to http://www.sitepen.com/blog/2008/05/27/dojo-charting-event-support-has-landed/ but nowhere any live demo is given. Till now i have managed to get the onclick.
chart.addSeries("Monthly Sales - 2010", chartData);
var h = chart.connectToPlot("default", function(o){
if(o.type == "onclick"){
alert("clicked!");
}
});

var store = new dojo.store.Memory({data: [
{ id: '2', value: 10, usedForDrillDown:'x' },
{ id: '3', value: 5, usedForDrillDown: 'y' },
{ id: '4', value: 8, usedForDrillDown:'z' }
]});
// adapter needed, because the chart uses the dojo.data API
var storeAdapter = new dojo.data.ObjectStore({
objectStore: store
});
var ds = new dojox.charting.DataSeries(
storeAdapter/*, { query: { needed if the store contains more than data points } }*/);
var chart = new dojox.charting.Chart("chart");
chart.addPlot("default", { type: "Pie" });
chart.addSeries("default", ds);
chart.connectToPlot("default", function(evt) {
if(evt.type == "onclick"){
var itm = evt.run.source.items[evt.index];
console.dir(itm);
}
});
chart.render();

Related

C3.js combination chart with time series - tooltip not functional

I've been trying for 3 days to get this chart to display the way I want it to. Everything was working 100% until I realized the grouped bar chart numbers were off.
Example: When the bottom bar value equals 10 and the top bar value equals 20, the top of the grouped bar read 30. This is the default behavior, but not how I want to represent my data. I want the top of the grouped bar to read whatever the highest number is, which lead me to this fiddle representing the data exactly how I wanted to.
After refactoring my logic, this is what I have so far. As you can see the timeseries line is broken up and the tooltip is not rendering the group of data being hovered over.
My questions:
1) How to get the tooltip to render all three data points (qty, price, searches)
2) How to solidify the timeseries line so it's not disconnected
Any help would be greatly appreciated so I can move on from this 3 day headache!
Below is most of my code - excluding the JSON array for brevity, which is obtainable at my jsfiddle link above. Thank you in advance for your time.
var chart = c3.generate({
bindto: '#chart',
data: {
x: 'x-axis',
type: 'bar',
json: json,
xFormat: '%Y-%m-%d',
keys: {
x: 'x-axis',
y: 'searches',
value: ['qty', 'searches', 'price']
},
types: {
searches: 'line'
},
groups: [
['qty', 'price']
],
axes: {
qty: 'y',
searches: 'y2'
},
names: {
qty: 'Quantity',
searches: 'Searches',
price: 'Price ($)'
},
colors: {
price: 'rgb(153, 153, 153)',
qty: 'rgb(217, 217, 217)',
searches: 'rgb(255, 127, 14)'
}
},
bar: {
width: {
ratio: 0.60
}
},
axis: {
x: {
type: 'timeseries',
label: { text: 'Timeline', position: 'outer-right' },
tick: {
format: '%Y-%m-%d'
}
},
y: {
type: 'bar',
label: {
text: 'Quantity / Price',
position: 'outer-middle'
}
},
y2: {
show: true,
label: {
text: 'Searches',
position: 'outer-middle'
}
}
},
tooltip: {
grouped: true,
contents: function(d, defaultTitleFormat, defaultValueFormat, color) {
var data = this.api.data.shown().map(function(series) {
var matchArr = series.values.filter(function(datum) {
return datum.value != undefined && datum.x === d[0].x;
});
if (matchArr.length > 0) {
matchArr[0].name = series.id;
return matchArr[0];
}
});
return this.getTooltipContent(data, defaultTitleFormat, defaultValueFormat, color);
}
}
});
1) If I got it right, you want tooltip to show all values, even if some of them are null.
Null values are hidden by default. You can replace them with zero (if it is suitable for your task) and thus make them visible.
Also, it seems to me that there is a shorter way to get grouped values:
var data = chart.internal.api.data().map(function(item) {
var row = item.values[d[0].index]; // get data for selected index
if (row.value === null) row.value = 0; // make null visible
return row;
});
2) I think you are talking about line.connectNull option:
line: {
connectNull: true
}
UPDATE
Looks like having duplicate keys breaks work of api.data() method.
You need to change json structure to make keys unique:
Before:
var json = [
{"x-axis":"2017-07-17","qty":100},
{"x-axis":"2017-07-17","price":111},
{"x-axis":"2017-07-17","searches":1},
{"x-axis":"2017-07-18","qty":200},
{"x-axis":"2017-07-18","price":222},
{"x-axis":"2017-07-18","searches":2}
];
After:
var json = [
{"x-axis":"2017-07-17","qty":100,"price":111,"searches":1},
{"x-axis":"2017-07-18","qty":200,"price":222,"searches":2}
];
See fiddle.

How to integrate KendoUI chart with SignalR

i want to create a real time chart, using Kendo ui chart and signalr. I see this example, but has no code. So i try alone.
A little demonstration of my code:
At first I created a kendo chart
function queueActivityChart() {
$("#queueActivityChart").kendoChart({
legend: {
visible: true
},
seriesDefaults: {
labels: {
visible: true,
format: "{0}",
background: "transparent"
}
},
series: [{
type: "line",
field: "Incoming",
categoryField: "DateTime",
}],
valueAxis: {
labels: {
format: "{0}"
},
line: {
visible: false
}
},
categoryAxis: {
labels:
{
rotation: -90,
dateFormats:
{
seconds: "ss",
minutes: "HH:mm:ss",
hours: "HH:mm",
days: "dd/MM",
months: "MMM 'yy",
years: "yyyy"
}
}, type: "Date", field: "DateTime", baseUnit: "seconds"
}
});
var chart = $("#queueActivityChart").data("kendoChart");
chart.options.transitions = false;
}
$(document).ready(queueActivityChart);
$(document).bind("kendo:skinChange", queueActivityChart);
Then I have this part of code, that get from server data
$scope.signalRData = [];
$scope.signalR.on('receiveCounters', function (data) {
$scope.queueData = data;
for (var i = 0; i < data.length; i++) {
$scope.signalRData.push(data[i]);
}
while ($scope.signalRData.length > 12) {
$scope.signalRData.splice(0, 1);
}
$("#queueActivityChart").data("kendoChart").setDataSource(
new kendo.data.DataSource({
group: {
field: "Name"
},
data: $scope.signalRData
}));
});
This works! And I get a picture of the latest updated items.
But the problem is that this chart is like to put one picture in front of other. I mean that this is the first time that load Data Source; that creates a chart of my data, the second time my data has changed, some values are still in my array some others has move out, the third too.
It seems like it puts a picture of my current data in front of the
previous data. It's not smoothie and cannot use chart's legend
property because I initialize my Data Source everytime.
Can someone help me how can create a smoothie kendo chart with real time data like the kendo official example? Also can somehow to add scroller to bottom?
I looked at the code for the benchmark and I think you may be missing in your chart which is renderAs: "canvas"
Also, in the example, the data is kept locally (saved) and then moved so it creates that "smooth" effect you may be talking about.
Here is the code that you can be of interest:
function step() {
addPoint();
$("#chart").data("kendoChart").refresh();
frames++;
if (playing) {
kendo.animationFrame(step);
}
}
function addPoint() {
var stockData,
change,
lastValue;
// Shift existing categories to the left and add the next date at the end
lastDate = new Date(lastDate.getTime() + TICKS_PER_DAY);
categoryList.push((lastDate.getMonth() + 1) + "/" + (lastDate.getDay() + 1));
if (categoryList.length > POINTS) {
categoryList.shift();
}
for (var i = 0; i < stocks.length; i++) {
stockData = stocks[i];
change = (Math.random() > 0.5 ? 1 : - 1) * Math.random() * 10;
lastValue = stockData[stockData.length - 1] || Math.random() * 10;
// Add a new pseudo-random data point
stockData.push(Math.min((i + 1) * 20, Math.max((i + 1) * 10, lastValue + change)));
// Shift the data points of each series to the left
if (stockData.length > POINTS) {
stockData.shift();
}
}
}
Check out the source code of your example for the full source code and use the dojo to test our their code and play around with it easily

How to filter/sort OpenUI5 Grid by column, which is nested in the json?

I'm now testing the capabilities of this grid and I'm having a look at this example at the moment.
Last week, I tried some basic loading of data, returned from the controller of the MVC app that I'm working on. It returns json, which I then give to the grid to be displayed.
The data, that I want to show, is stored in multiple tables. For now, I load data from only two of them for simplicity, because I'm only testing the capabilities of the grid - will it suit our needs.
The data, which arrives at the grid (in js), looks something like this:
{
Cars: [
{
car_Number: '123',
car_Color: 'red',
car_Owner: Owner: {
owner_ID: '234',
owner_Name: 'John'
},
car_DateBought: '/Date(1450648800000)/'
},
{
car_Number: '456',
car_Color: 'yellow',
car_Owner: Owner: {
owner_ID: '345',
owner_Name: 'Peter'
},
car_DateBought: '/Date(1450648800000)/'
},
{
car_Number: '789',
car_Color: 'green',
car_Owner: Owner: {
owner_ID: '567',
owner_Name: 'Michael'
},
car_DateBought: '/Date(1450648800000)/'
}
]
}
Here is some sample code of what I have done so far:
$.ajax({
type: 'post',
url: BASE_HREF + 'OpenUI5/GetAllCars',
success: function (result) {
var dataForGrid = result['rows'];
debugger;
var oModel = new sap.ui.model.json.JSONModel();
oModel.setData(dataForGrid);
var oTable = new sap.ui.table.Table({
selectionMode: sap.ui.table.SelectionMode.Multi,
selectionBehavior: sap.ui.table.SelectionBehavior.Row,
visibleRowCountMode: sap.ui.table.VisibleRowCountMode.Auto,
minAutoRowCount: 10,
//visibleRowCount: 10,
showNoData: false
});
// define the Table columns and the binding values
oTable.addColumn(new sap.ui.table.Column({
label: new sap.ui.commons.Label({
text: "ID of car"
}),
template: new sap.ui.commons.TextView({ text: "{car_Number}" }),
sortProperty: "car_Number", // https://sapui5.netweaver.ondemand.com/sdk/test-resources/sap/ui/table/demokit/Table.html#__2
filterProperty: "car_Number"
}));
oTable.addColumn(new sap.ui.table.Column({
label: new sap.ui.commons.Label({ text: "Color of car" }),
template: new sap.ui.commons.TextView({ text: "{car_Color}" }),
sortProperty: "car_Color",
filterProperty: "car_Color"
}));
oTable.addColumn(new sap.ui.table.Column({
label: new sap.ui.commons.Label({ text: "Car Owner ID" }),
template: new sap.ui.commons.TextView({
// does not work like this -> text: "{Owner.owner_ID}"
text: {
path: 'Owner',
formatter: function (owner) {
return owner !== null ? owner['owner_ID'] : '';
}
}
}),
sortProperty: "Owner.owner_ID", // these two don't work
filterProperty: "Owner.owner_ID"
}));
oTable.addColumn(new sap.ui.table.Column({
label: new sap.ui.commons.Label({ text: "Car Owner Name" }),
template: new sap.ui.commons.TextView({
// does not work like this -> text: "{Owner.owner_Name}"
text: {
path: 'Owner',
formatter: function (owner) {
return owner !== null ? owner['Name'] : '';
}
}
}),
sortProperty: "Owner.owner_Name", // these two don't work
filterProperty: "Owner.owner_Name"
}));
var dateType = new sap.ui.model.type.Date({ // http://stackoverflow.com/questions/22765286/how-to-use-a-table-column-filter-with-formatted-columns
pattern: "dd-MM-yyyy"
});
oTable.addColumn(new sap.ui.table.Column({
label: new sap.ui.commons.Label({ text: "Date bought" }),
template: new sap.ui.commons.TextView({
text: {
path: 'car_DateBought',
formatter: dateFormatterBG
}
}),
sortProperty: "car_DateBought",
filterProperty: "car_DateBought",
filterType: dateType
}));
oTable.setModel(oModel);
oTable.bindRows("/");
oTable.placeAt("testTable", "only");
},
error: function (xhr, status, errorThrown) {
console.log("XHR:");
console.log(xhr);
console.log("Status:");
console.log(status);
console.log("ErrorThrown:");
console.log(errorThrown);
}
});
My problems:
I cannot sort or filter the list of cars by owner_ID or owner_Name. How should I do the filtering and sorting? Should it be done with the help of a formatter function in some way, or...?
I can sort by car_DateBought, but I cannot filter the cars by this field. First, I tried setting filterType: dateType, then I tried setting it to filterType: dateFormatterBG(it turns out, that dateType does exactly the same thing as my own dateFormatterBG does, btw).
function dateFormatterBG(cellvalue, options, rowObject) {
var formatedDate = '';
if ((cellvalue != undefined)) {
var date = new Date(parseInt(cellvalue.substr(6)));
var month = '' + (date.getMonth() + 1);
var day = '' + date.getDate();
var year = date.getFullYear();
if (month.length < 2) {
month = '0' + month;
}
if (day.length < 2) {
day = '0' + day;
}
formatedDate = [day, month, year].join('-');
}
return formatedDate;
}
Anyway, as I said, I tried both, but it doesn't work. When I click on the header of a column like in the example in the first link, I don't get any sort of a datepicker. How can I tell OpenUI5, that this column needs to be filtered by date and it should provide the user with a datepicker, when he/she clicks on the 'Filter' input field at the bottom of the dropdown menu? When I try to write the date in the filter field like '07-11-2016' (the way it is formatted), I get an empty table/grid. If I try to enter the huge number from field car_DateBought in the json object, all available rows in the table stay the same and when I reclick on the header, the filter field at the bottom of the dropdown menu appears with error-state.
Thank you in advance for your help and pieces of advice!
Edit:
This is just sample, dummy data. I try to load the real data and I see, that in the table I've got a couple of rows with date, which is today (07-11-2016, or 11/7/2016 if you prefer). That's why getting an empty table after trying to filter means it's not working correctly.
Sorting: in a sample I am looking at the following appears in the controller:
onInit : function () {
this._IDSorter = new sap.ui.model.Sorter("my_id", false);
},
....
Then in the view there is a button defined in the header column as
<Column>
<Label text="Project"/>
<Button icon="sap-icon://sort" press="onSortID" />
</Column>
And back in the controller there is a further function:
onSortID: function(){
this._IDSorter.bDescending = !this._IDSorter.bDescending;
this.byId("table").getBinding("items").sort(this._IDSorter);
},
I read this collectively as defining a sorter in the onInit(), then toggle/reversing it in the click event of the sort button in the column header via the onSortId() function. The OpenUI5 API doc re sorters indicates there are more parameters in the sorter constructor for initial sort direction and sorting function.
Following this pattern, for your needs to sort on the owner_ID or owner_Name, I assume you could set up a sorter as
this._OwnerIDSorter = new sap.ui.model.Sorter("car_Owner/owner_ID", false);
this._OwnerNameSorter = new sap.ui.model.Sorter("car_Owner/owner_Name", false);

KendoUI Multiselect Remove Multiple

I am using Kendo UI Multiselect:
http://demos.kendoui.com/web/multiselect/events.html
I have this Data:
var data =
[
{ text: "Shirt-Black", value: "1" },
{ text: "Shirt-Brown", value: "2" },
{ text: "Shirt-Blue", value: "3" },
{ text: "Cap-Green", value: "4" },
{ text: "Cap-Red", value: "5" },
{ text: "Cap-White", value: "6" },
{ text: "Jacket-Denim", value: "7" }
];
Now I want that if I select "Shirt-Brown" then rest entries for shirt i.e. "Shirt-Black" and "Shirt-Blue" should not appear in the list which means that the user should not be able to choose the Shirt of two colors.
Similarly, If a "Cap" of any color has been chosen then user should not be able to choose the "Cap" of any other color.
Is there any way to achieve this?
This is not build-in functionality. You can't even use dataSource filter() method because it will remove selected items from list as well.
However, this code will do what you're asking:
$("#select").kendoMultiSelect({
...
change: function(e) {
var dataItems = e.sender.dataItems();
var categories = [];
for(var i = 0; i < dataItems.length; i++){
var category = dataItems[i].text.substring(0, dataItems[i].text.indexOf('-'));
categories.push(category);
}
e.sender.ul.find('li').each(function(index, value){
var $li = $(value);
var hidden = false;
for(var i = 0; i < categories.length; i++){
var category = categories[i];
if ($li.text().match("^" + category)){
$li.css('display', 'none');
hidden = true;
}
}
if(!hidden){
$li.css('display', 'list-item');
}
});
}
});
Working KendoUi Dojo: http://dojo.telerik.com/AGisi

Kendo grid resizable column width

The grid columns may be resizable. I want to store user-adjusted columns width and restore them when the next session starts.
The best way to store columns width I've found is the following:
var element = $('#grid').kendoGrid({
...
resizable: true,
columnResize: function(e) {
var state = {};
this.columns.every(function(c,i) {
state[c.field] = c.width;
return true;
});
var state_txt = JSON.stringify(state);
localStorage['profile_userprofile_grid_column_width'] = state_txt;
}
}
Now I want to restore column width saved in the previous user session. I can read columns width from the storage:
var state = JSON.parse(localStorage['profile_userprofile_grid_column_width']);
Does somebody know some elegant way to apply these values back to the grid if it is already created at this time? The resize handle does it internally, so it is possible, but the code doing it in the grid source is ugly.
You can trigger the columnResize event post initilisation as shown below
function grid_columnResize(e) {
// Put your code in here
console.log(e.column.field, e.newWidth, e.oldWidth);
}
$("#grid").kendoGrid({
columns: [
{ field: "name" },
{ field: "age" }
],
dataSource: [
{ name: "Jane Doe", age: 30 },
{ name: "John Doe", age: 33 }
],
resizable: true
});
var grid = $("#grid").data("kendoGrid");
grid.bind("columnResize", grid_columnResize);
Documentation
This is an old question, but here is what we have. Function handles column widths and groups.
var _updateResultsGridColumns = function(columns, groups) {
var kendoGrid = $resultsGrid.data("kendoGrid");
if (kendoGrid) {
kendoGrid.setOptions({
columns: columns,
});
var dataSource = kendoGrid.dataSource;
dataSource.group(groups);
kendoGrid.setDataSource(dataSource);
}
}

Resources