How to use c3.js No data option - d3.js

I am trying to use no data option from c3.js but somehow it does not work for me.
My js fiddle:
http://jsfiddle.net/ymqef2ut/7/
I am trying to use the empty option according to c3 documentation:
empty: { label: { text: "No Data Available" } }

There are two issues in your fiddle:
Problem1:
data: {
columns: [
['electricity plants', elec_plants],
['CHP plants', chp_planrs],
['Unallocated autoproducers / Other energy industry own use', auto_pro],
['Other', other_elec],
],
type : 'pie'
},
empty: { label: { text: "No Data Available" } },//this is wrong should be a part of data
The empty should be a part of the data json like below
data: {
columns: [
['electricity plants', elec_plants],
['CHP plants', chp_planrs],
['Unallocated autoproducers / Other energy industry own use', auto_pro],
['Other', other_elec],
],
type : 'pie',
empty: { label: { text: "No Data Available" } },//this is correct
},
Problem 2:
When data is not present the column array should be an empty array
var col5 = [];//set empty array
if (resi || com || agri || other_sec){
col5 = [['Residential', resi],
['Commercial and public services', com],
['Agriculture/forestry', agri],
['Other', other_sec]]
}
//if all are 0 then col = []
var chart = c3.generate({
bindto: "#chart_5",
data: {
columns: col5,
type: 'pie',
empty: {
label: {
text: "No Data Available"
}
}
},
Working code here
Testcase: Check for Iraq
Hope this helps!

Related

Select a specific row in a table with single select

I want to implement a method that cancels moving to the next row if data has changed.
My thought was to use the on-current-change event as this provides me with the oldCurrentRow.
What event should I emit with what parameters to achieve staying on the last highlighted row.
You can find a fiddle here https://jsfiddle.net/arjanno/pdazb5kf/28/
Key is what happens here
onCancel: function () {
//Move back to oldCurrentRow
this.$Message.info(`Clicked cancel`);
}
As long as you don't set data dirty you should be able to click on any row.
When you click Dirty it should show a modal asking you if you want to lose your changes.
On cancel I want to stay on the row I was before clicking on another row.
I don't think we can know the index of the row by the data the on-current-change callback gives us. This can/should be changed since its useful, fell free to open a issue for it.
In any case what you can do is to compare the last selected row with the current data set and use the _highlight key to tell i-table which row to highlight.
Example: https://jsfiddle.net/pdazb5kf/40/
The code would be:
function rowToString(row) {
const data = ['name', 'age', 'address'].map(key => row[key]);
return JSON.stringify(data);
}
export default {
data() {
return {
columns3: [{
type: 'index',
width: 60,
align: 'center'
},
{
title: 'Name',
key: 'name'
},
{
title: 'Age',
key: 'age'
},
{
title: 'Address',
key: 'address'
}
],
dirty: false,
modal1: false,
data1: [{
name: 'John Brown',
age: 18,
address: 'New York No. 1 Lake Park',
date: '2016-10-03'
},
{
name: 'Jim Green',
age: 24,
address: 'London No. 1 Lake Park',
date: '2016-10-01'
},
{
name: 'Joe Black',
age: 30,
address: 'Sydney No. 1 Lake Park',
date: '2016-10-02',
},
{
name: 'Jon Snow',
age: 26,
address: 'Ottawa No. 2 Lake Park',
date: '2016-10-04'
}
]
}
},
methods: {
onCurrentChange: function(currentRow, oldCurrentRow) {
this.lastIndex = rowToString(oldCurrentRow);
if (this.dirty) {
this.modal1 = true;
}
},
onCancel: function() {
//Move back to oldCurrentRow
this.$Message.info(`Clicked cancel`);
this.data1 = this.data1.map((row, i) => {
return {
...row,
_highlight: rowToString(row) === this.lastIndex
}
});
}
}
}

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.

KendoGrid - After applying custom filter and then navigating to next or any other page, the filter values are not getting passed to controller

Used Kendo Version: 2015.2.624
I have implemented kendogrid server side paging with additional parameters. Below is how my controller looks like:
public ActionResult GetData([DataSourceRequest] DataSourceRequest request, DateTime startDate, DateTime endDate, int state = -1, string poolName = null, string submitter = null)
{
poolName = string.IsNullOrEmpty(poolName) ? null : poolName;
submitter = string.IsNullOrEmpty(submitter) ? null : submitter;
var summarylist = new List<Summary>();
var total = 0;
using (var db = new SummaryEntities())
{
var jobs = db.SummaryTable.Where(k => k.created >= startDate && k.created <= endDate)
.Where(k => state != -1 ? k.state == state : k.state > state)
.Where(k => poolName != null ? k.pool_name == poolName : k.pool_name != null)
.Where(k => submitter != null ? k.submitter == submitter : k.submitter != null);
jobs = jobs.OrderByDescending(job => job.id);
total = jobs.Count();
// Apply paging...
if (request.Page > 0)
{
jobs = jobs.Skip((request.Page - 1) * request.PageSize);
}
jobs = jobs.Take(request.PageSize);
foreach (var job in jobs)
{
summarylist.Add(new Summary(job));
}
}
var result = new DataSourceResult()
{
Data = summarylist,
Total = total
};
return Json(result, JsonRequestBehavior.AllowGet);
}
additional parameters are the current values which the user has set over the widget datepicker, input box etc.
Below is how my datasource looks like in grid:
<script type="text/javascript">
j$ = jQuery.noConflict();
j$(document).ready(function () {
j$("#grid").kendoGrid({
dataSource: {
transport: {
read: {
url: "/Home/GetData/",
dataType: "json",
data: {
startDate: j$("#startdate").val(),
endDate: j$("#enddate").val()
}
}
},
pageSize: 30,
serverPaging: true,
schema: {
data: 'Data',
total: 'Total'
}
},
height: j$(window).height() - 85,
groupable: true,
sortable: true,
filterable: false,
columnMenu: true,
pageable: true,
columns: [
{ field: "JobId", title: "Job Id", template: '#:JobId#', type: "number" },
{ field: "Name", title: "Job Name", hidden: true },
{ field: "PoolName", title: "Pool Name" },
{ title: "Date Time", columns: [{ field: "Start", title: "Start" },
{ field: "End", title: "End" }
],
headerAttributes: {
"class": "table-header-cell",
style: "text-align: center"
}
},
{ field: "State", title: "State" },
{
title: "Result", columns: [{ field: "ResultPassed", title: "P" },
{ field: "ResultFailed", title: "F" }
],
headerAttributes: {
"class": "table-header-cell",
style: "text-align: center"
}
},
{ field: "Submitter", title: "Submitter" }
]
});
});
</script>
It works pretty good until I observed this issue:
Change the filter values i.e submitter, date range etc and
controller gets all this information in additional parameters where
I am taking action accordingly and it works just fine.
Now suppose the result returned from step 1 has multiple pages and
when you click next page, or last page or any other page number, the
controller gets invoked which is expected but the additional
parameters being set in step 1 is not getting passed again instead
the default values are there which is ruining everything.
Correction:
Additional parameters are getting lost at client side only.
Now please tell me what am I missing here?
Expected Result: In step 2 additional parameters should not get lost and it should be same as step 1.
Any help is appreciated.
EDITED:
Complete controller and grid code.
Thanks,
Vineet
I got the solution from telerik support team:
Reply:
The described undesired behavior can be caused by the fact that the additional parameters:
data: {
startDate: j$("#startdate").val(),
endDate: j$("#enddate").val()
}
... are set to objects, instead of a functions. If they are set as functions, the values of the corresponding inputs will be evaluated every time read() is called, and the current values will be passed (like shown in the second example in the API reference):
http://docs.telerik.com/kendo-ui/api/javascript/data/datasource#configuration-transport.read.data

Kendo UI grid number column with template won't filter

I created a Kendo UI grid with two columns.
One is just a number called num0.
the other is is called num1 and it's data is created from num0 through a
template.
The filter on num0 works find.
The filter on num1 shows up and you can use it but
no matches are found. ie: filter on num1 and select "Is equal" and enter "2",
then click "Filter"
and grid is emptied when it should have shown the 1st record.
Also, I made the num0 column editable and the num1 column not editable.
I would like num1 column to change if num0 is edited.
I think it has something to do with the "template" that I am using
to fill num1 column.
What do I need to do to fix this so the filter works?
Thanks
http://jsfiddle.net/elbarto99/acyxekgx/
$(document).ready(function()
{
// Define the datasource for the grid.
var dsNums = new kendo.data.DataSource({
// NOTE: I don't want a num1: data field set to static values.
// I would like one that is set from "num0 + 1" and when num0 data is edited
// num1 would be updated to "num0 + 1"
data: [
{ num0: 1 },
{ num0: 2 },
{ num0: 3 },
{ num0: 4 },
],
schema:
{
model:
{
id: "myGridID",
fields:
{
num0: { type: "number" },
num1: { type: "number", editable: false },
}
}
}
});
// Create the grid.
var _grid = $("#grid").kendoGrid({
dataSource: dsNums,
filterable: { extra: false },
editable: true,
columns: [
{ field: "num0" , title: "Num 0" , width: "90px", },
// Add 1 to num0 and display in num1 column
// Note: A filter shows up and is for numbers but doesn't work
// I think it doesn't work because I am using a template.
//
// What do I need to do to make the filter for column num1 work like it does for num0?
{ field: "num1" , title: "Num 1 - Filter shows up but doesn't find matchs. :-(" , width: "90px", template: "#= num0 + 1 #", },
],
}).data("kendoGrid");
});
num1 value is not part of the data so filter will not filter by it. Filters work at datasource level and not presentation.
What you might do is computing that same value on schema.parse function. Something like:
parse: function(d) {
$.each(d, function(idx, elem) {
elem.num1 = elem.num0 + 1;
});
return d;
}
Your JSFiddle modified here: http://jsfiddle.net/OnaBai/acyxekgx/2/
Thanks OnaBai:
I modified your jfiddle
and add some editable settings so num0 column is editable and num1 column is not editable.
Is there a way to make num1's data and presentation get updated to num0 + 1 if num0 is edited?
ie: num0 changed to 11, num1's data gets changed to num0+1 or 12,
and filter on num1 to find 12 will list row 1.
Also, make the presentation of num1 set to 12 so the user can see the change.
http://jsfiddle.net/elbarto99/acyxekgx/
// Define the datasource for the grid.
var dsNums = new kendo.data.DataSource({
// NOTE: I don't want a num1: data field set to static values.
// I would like one that is set from "num0 + 1" and when num0 data is edited
// num1 would be updated to "num0 + 1"
data: [
{ num0: 1 },
{ num0: 2 },
{ num0: 3 },
{ num0: 4 }
],
schema:
{
model:
{
id: "myGridID",
fields:
{
num0: { type: "number" },
num1: { type: "number", editable: false }
}
},
// This changes the data for num1 at load time but
// if the data in num0 is edited this doesn't change data for num1
// at edit time.
parse: function(d) {
$.each(d, function(idx, elem) {
elem.num1 = elem.num0 + 1;
});
return d;
}
}
});
// Create the grid.
var _grid = $("#grid").kendoGrid({
dataSource: dsNums,
filterable: { extra: false },
editable: true,
columns: [
{ field: "num0", title: "Num 0", width: "90px" },
{ field: "num1", title: "Num 1", width: "90px" }
]
}).data("kendoGrid");

How to access column name dynamically in Kendo Grid template

I need to access the column name dynamically in Kendo Grid template.
Code:
$("#grid").kendoGrid({
dataSource: [
{ Quantity: 2 , Amount: 650},
{ Quantity: 0, Amount: 0 },
{ Quantity: 1, Amount: 500 },
{ Quantity: 4, Amount: 1047 }
],
sortable: true,
columns: [
{
field: "Quantity",
template: function (dataItem) {
if (dataItem.Quantity == '0') {
return "--";
} else {
return dataItem.Quantity;
}
}
},
{
field: "Amount",
template: function (dataItem) {
if (dataItem.Amount == '0') {
return "--";
} else {
return dataItem.Amount;
}
}
}
]
});
Here inside the "columns -> template", I need to access the column thru variable instead of hardcoding it. How can I do that? Because in real life I will be having dynamic columns populated into dataSource and I will construct the columns array inside the for loop. Please help.
Please access this JSBIN: http://jsbin.com/egoneWe/1/edit
From what I understand, you build the columns array using something like:
var Definition = [
{ field: "Quantity" },
{ field: "Amount" }
];
var columns = [];
$.each(Definition, function (idx, item) {
columns.push({
field : item.field,
template: function (dataItem) {
...;
}
})
});
$("#grid").kendoGrid({
dataSource: data,
sortable : true,
columns : columns
});
Right? And the problem is that you want to use the same template function for several (all) columns instead of having to rewrite many.
If so, what you can do is:
var Definition = [
{ field: "Quantity" },
{ field: "Amount" }
];
var columns = [];
$.each(Definition, function (idx, item) {
columns.push({
field : item.field,
template: function (dataItem) {
return commonTemplateFunction(dataItem, item.field);
}
})
});
What I use in the columns array (columns definition for the Grid) is a function that receives two arguments: the dataItem for the row and the field's name being edited.
Then, I define the template function as:
function commonTemplateFunction(dataItem, field) {
if (dataItem[field] == '0') {
return "--";
} else {
return dataItem[field];
}
}
And your modified code is here : http://jsbin.com/egoneWe/3/edit
So, despite I cannot guess the column name, I can do the trick using the columns initiator.

Resources