knockoutjs highcharts parse arrays of data to chart - javascript

I am using a combination of highcharts and knockoutjs to feed data into my chart.
I have 4 massive arrays of data that need to be fed into my highchart upon a click event. I showed the data arrays empty here due to their huge size. Currently it returns an error like: Uncaught TypeError: Cannot read property 'metric' of undefined
My question is how do I access the areas.metric.data and parse it into my chart?
here is my (non) working fiddle:
http://jsfiddle.net/whiteb0x/BG8Qe/18/
function MetricsViewModel(areas) {
var self = this;
self.areas = [ // data structure
{
name: 'Game',
metrics: [{name : 'metric1', id : 'usdeur', data : []}, {name : 'metric2', id : 'msft', data : []}]
},
{
name: 'Player',
metrics: [{name : 'metric1', id : 'msft', data : []}, {name : 'metric2', id : 'msft', data : []}]
},
{
name: 'Social',
metrics: [{name : 'metric1', id : 'googl', data : [] }, {name : 'metric2', id : 'msft', data : []}]
}
];
series: [{ // default series
id: 'adbe',
data: ADBE
}]
}, function(chart){
var data = areas.metric.data; // corresponds to my object above ^^^
self.updateChart = function(metric) {
var id = this.id,
series = chart.get(id);
if(!series){
chart.addSeries({
id: id,
data: data
});
} else {
series.remove();
}
console.log(metric);
}
});

I'm not sure I understand you correctly, but according your code, this function declared in the ViewModel scope:
function(chart){
so you can access access both areas array and you observable metrics array like this:
var data = self.areas[0].metrics;
or observable metrics array like
self.metrics()
in any case, at the line where you have troubles, you are in ViewModel scope and can access whatever you want in it by this or self

Related

Recreate array on basis of object's child

Some time ago I asked a question about how to filter array based on its key today this function but i am working a new implementation that I'm doing.
create array on basis of object's child
But I'm doing a refactoring of how I treat the field value because before I just need the first object and its value [0].value now I need to expand this logic to work with array I'll leave some examples below.
My Code I'm currently using
https://codesandbox.io/s/lodash-tester-forked-fcdmy1?file=/index.js
Original, unfiltered data from API:
[
{
"_id" : ObjectId("62548802054c225fe560f41a"),
"test" : [
"taetea",
"atty",
],
"Peso" : [
{
"_id" : "624f2ab363dd92f2101de167",
"value" : "255"
}
],
}
]
Expected result for table data:
[
{
"_id" : "62548802054c225fe560f41a",
"test1":"taetea",
"test2":"atty",
"Peso":"255"
},
{
...
},
]
Anyone who can help I'm grateful I will repay with rep+ and my eternal thanks xD
As i understand,you want to use title property from the table Columns & search it in the API data.If the title property represents an array of strings,then add all the strings otherwise add the value property.
const apiData = [
{
"_id" : "62548802054c225fe560f41a",
"test" : [
"taetea",
"atty",
],
"Peso" : [
{
"_id" : "624f2ab363dd92f2101de167",
"value" : "255"
}
],
}
];
const tableData = [
{
title: "Peso",
dataIndex: "peso",
key: "peso",
},
{
title: "test",
children: [
{
title: "ex: ${title} field ${title.length}",
dataIndex: "ex: ${title} + ${title.length}",
key: "ex: ${title} + ${title.length}",
},
{
title: "ex: ${title} field ${title.length}",
dataIndex: "ex: ${title} + ${title.length}",
key: "ex: ${title} + ${title.length}",
},
],
},
];
const tableKeys = tableData.map(t => t.title)
const output = []
apiData.forEach(obj => {
const data = []
Object.keys(obj).filter(key => tableKeys.includes(key)).forEach(key =>{
if(typeof obj[key][0]=== 'string'){
data.push(...obj[key].map((val,index) => ({[`${key}${index+1}`]:val})))
}else{
data.push({[key]: obj[key][0].value})
}
})
// Add the id of the the api data & spread the objects collected
output.push({'_id':obj._id,
...data.reduce((map,elem)=>({...map,...elem}),
{})})
})
console.log('output',output)

Filtering column's collection

In my Webix datatable one column fetches the data from the DataColletion. The problem is in the column's filtering: seems like it works with the original data (that contains the ID) and ignores the value of the data collection. How can I change this behavior and filter datatable by the collection's value?
Data:
var mycollection = new webix.DataCollection({
data:[{
id: '12',
value: 'CollItem 1'
}]
});
var mydata = [{
id: 1,
name: 'Item 1',
troublesomeColumn: '12' // id of the CollItem 1
}];
Config:
columns:[{
id: 'troublesomeColumn',
collection: mycollection,
header:{
content:"textFilter"
}
}],
data:mydata
Code snippet. Thanks in advance.
Filters work with the dataset, not with the templates or values from the linked collections. Therefore, you need to create a custom filtering rule as described in the Webix Docs, i.e. define the needed pattern in the compareproperty of the filter:
{
content:"textFilter",
compare:function(value, filter, obj){
var colValue = mycollection.getItem(value).value;
toFilter = colValue.toString().toLowerCase();
filter = filter.toString().toLowerCase();
return toFilter.indexOf(filter) !== -1;
}
}
Updated snippet

Webix DataTable - expand object properties

If I have a list of (JavaScript) objects in the following form:
var results = [
{'name': 'mary', 'availability' : { 'monday': 'True', 'tuesday': 'False' ... } },
{'name': 'john', 'availability' : { 'monday': 'False', 'tuesday': 'False' ... } },
{'name': 'pete', 'availability' : { 'monday': 'True', 'tuesday': 'True' ... } }
]
how do I display this data in a Webix DataTable, having each of the days in availability as a column?
My configuration object for the DataTable looks like this:
var dtable = webix.ui({
....
view:"datatable",
id: "nameTable",
columns:[
{ id: "name", header:"Name"},
{ id: "availability.monday", header:'Mon'},
{ id: "availability.tuesday", header:'Tue'},
...
],
data:results,
...
});
I have also tried: id: "availability['mon']" which doesn't work or report any error. If I just do : id:"availability", in the browser I see that it shows [object Object] for each row.
I've also tried the autoconfig option but that doesn't render anything (no errors).
I have tried to find examples in the documentation but haven't found any so far. I'm sure this must be possible without having to restructure my incoming data!
There is no native support for complex properties in the Webix DataTable. You can use "template" property of column object to show any property of data object as value of a column, though.
columns:[
{ id: "col1", template:"#availability.monday#"},

How to pass json data to highcharts series?

I have following json array which is generated at runtime.
Hence the number of name/data pairs varies.
`var sales = { "SalesData" : [
{ "name" : "AllProducts|Canada", "data" :[44936.0,50752.0] },
{ "name" : "AllProducts|Mexico", "data" : [200679.0,226838.0] },
{ "name" : "AllProducts|USA", "data" : [288993.0,289126.0] }
]} `
I want to pass this data to series in highcharts.
This is how I am doing it currently.
series: [
{name:sales.SalesData[0].name,data:sales.SalesData[0].data},
{name:sales.SalesData[1].name,data:sales.SalesData[1].data},
{name:sales.SalesData[2].name,data:sales.SalesData[2].data}
]
But if the number of elements in array are changed then this won't work.
How do I solve this problem ? Demo code will help me.
I have refereed following questions but I was not able to solve the problem.
Dynamically adding to Highcharts
Highcharts series data array
I solved the problem
Changed json array as follows:
var sales = [
{ "name" : "AllProducts123|Canada", "data" :[44936.0,50752.0] },
{ "name" : "AllProducts|Mexico", "data" : [200679.0,226838.0] },
{ "name" : "AllProducts|USA", "data" : [288993.0,289126.0] }
]
Now pass it directly to series in highcharts.
series:sales
Done !!!!!
Instead of constructing the series array manually you could loop through the sales variable data and construct the array. So what ever the number of elements in the sales.SalesData array, all items will be there in the series array
var series = [],
salesData= sales.SalesData;
for (var i=0 i< salesData.length; i++) {
series.push({"name" : key, "data" : sales[key]})
}
This constructed series array is part of the object which you must pass as argument to highcharts method.
var chartdata = {
chart: {type: 'column'},
title: {text: 'Sales Data'},
xAxis: {
categories: ['Category 1','Category 2']
},
yAxis: {
min: 0,
title: {text: 'Sales'}
},
series : []
}
chartdata.series = series;
$('#chart').highcharts(chartdata);
where #chart is the container where you want to display the chart.
you can also refer to the fiddles which are available in their demo pages for each type of chart to know more on how to display a particular type of chart.

Referencing a javascript object literal array

How would you reference the models (Accord, CRV, Prius, etc) in this structure?
Is this a bad structure to be able to extract the makes...then use a make to get the models...then use the model to get the options?
var cars = [
{
"makes" : "Honda",
"models" : [
{'Accord' : ["2dr","4dr"]} ,
{'CRV' : ["2dr","Hatchback"]} ,
{'Pilot' : ["base","superDuper"] }
]
},
{
"makes" : "Toyota",
"models" : [
{'Prius' : ["green","reallyGreen"]} ,
{'Camry' : ["sporty","square"]} ,
{'Corolla' : ["cheap","superFly"] }
]
}
];
Thanks
The structure:
var cars = [
{ name: 'Honda', models: [
{ name: 'Accord', features: ['2dr', '4dr'] },
{ name: 'CRV', features: ['2dr', 'Hatchback'] },
{ name: 'Pilot', features: ['base', 'superDuper'] }
]},
{ name: 'Toyota', models: [
{ name: 'Prius', features: ['green', 'superGreen'] },
{ name: 'Camry', features: ['sporty', 'square'] },
{ name: 'Corolla', features: ['cheap', 'superFly'] }
]}
];
I wrote about the traversal and everything else here.
cars[0].models.Accord
cars[0].models.CRV
cars[0].models.Pilot (See olliej's answer)
Though, it may be easier to use the following access concept:
cars.Honda.Accord
cars.Toyota.Prius
...using...
var cars = {
Honda : {
Accord : ["2dr", "4dr"],
CRV : ["2dr", "Hatchback"],
Pilot : ["base", "superDuper"]
},
Toyota : {
Prius : ["green", "reallyGreen"],
Camry : ["sporty", "square"],
Corolla : ["cheap", "superFly"]
}
};
Jonathan's is correct, but he missed the additional level of Array's at the model level, so it should be
cars[0].models[0].Accord
cars[0].models[1].CRV
etc
I suspect you would find it easier to use a structure along the lines of:
var cars = [
{makes : "Honda",
models : {
Accord : ["2dr","4dr"],
CRV : ["2dr","Hatchback"],
Pilot: ["base","superDuper"]
}
},
{makes :"Toyota",
models : {
Prius : ["green","reallyGreen"],
Camry : ["sporty","square"],
Corolla : ["cheap","superFly"]
}
}];
In which the models array is replaced by an object (or associative array if you like)
[edit (olliej): tidying up code in second example]
You can traverse models with this code:
for (var i = 0, carslen = cars.length; i < carslen; i++) {
for (var j = 0, modelslen = cars[i].models.length; j < modelslen; j++) {
// do something with cars[i].models[j]
}
}
but I agree with Olliej about changing the structure of your JSON to his format.
If I were you, I wouldn't lump all your data into one big multidimensional array/object literal mess like that. I'd encapsulate each object and use methods to access the data. It'll mess with your brain a lot less.

Categories

Resources