Reputation: 313
I have three select menus: modality, bodyPart and equipmentModel and what I want to do is: when the user select a modality, it shows only the data of that modality, secondly appears the bodyParts available for that modality and finally the equipmentModels available for the bodyPart and modality selected. When the user selects this 3 menus the data is filtered in a chart (highchart).
My data format:
[
{
"x":1437001200000,
"y":7,"bodyPart":null,
"equipmentModel":"asfasf"
}
]
I have this js code to do this (example for CT data):
var type1 = $("#s2 option:selected").text();
var type2 = $("#s3 option:selected").text();
$.each(chart.series[2].data, function(i, p) {
if (p.bodyPart != type1 && p.equipmentModel != type2) {
chart.series[2].data[i].remove();
}
});
Although I'm getting this error:
Uncaught TypeError: Cannot read property 'bodyPart' of undefined
And it only filters the data according to the middle menu. I suspect that it is because when a point is removed the length of the serie changes and it starts to count from index 0.
How can I fix this?
Thanks in advance.
Upvotes: 1
Views: 13358
Reputation: 5222
I think that you can make your chart in two ways. First of all you can add all your series to your chart and use series.hide() and series.show() for hiding and showing your filtered data. http://api.highcharts.com/highcharts#Series.hide http://api.highcharts.com/highcharts#Series.show
$(function() {
var mod, bodyP;
$('#container').highcharts({
plotOptions: {
series: {
showInLegend: false
}
},
series: [{
name: 'CT ARM',
mod: 'CT',
data: [7.0, 6.9, 9.5],
bodyPart: 'arm'
}, {
name: 'MRI BRAIN',
mod: 'MRI',
data: [-0.2, 0.8, 5.7],
bodyPart: 'brain'
}, {
name: 'MRI WRIST',
mod: 'MRI',
data: [-0.9, 0.6, 3.5],
bodyPart: 'wrist'
}, {
name: 'PET THYROID',
mod: 'PET',
data: [3.9, 4.2, 5.7],
bodyPart: 'thyroid'
}, {
name: 'PET BRAIN',
mod: 'PET',
data: [1.9, 6.2, 2.7],
bodyPart: 'brain'
}, {
name: 'PET HEART',
mod: 'PET',
data: [7.9, 1.2, 7],
bodyPart: 'heart'
}]
}, function(chart) {
$('.mod').change(function() {
mod = this.value;
if (mod) {
Highcharts.each(chart.series, function(ob, j) {
if (ob.userOptions.mod == mod && (bodyP ? ob.userOptions.bodyPart == bodyP : true)) {
ob.show()
} else {
ob.hide()
}
});
}
});
$('.body').change(function() {
bodyP = this.value;
if (bodyP) {
Highcharts.each(chart.series, function(ob, j) {
if (ob.userOptions.bodyPart == bodyP && (mod ? ob.userOptions.mod == mod : true)) {
ob.show()
} else {
ob.hide()
}
});
}
})
});
});
You can use for it your load callback function (when your chart will be loaded). Then you will not have any problems with changing index of series when remove one of your series.
As you can see I am checking values inside my forms after every change.
Here you can see an example how it work: http://jsfiddle.net/2q1376Le/2/
If you want, you can as well remove and add series that will meet your requirements but I think it will be a little bit more complicated problem and it all depends on your number of data.
Here you can see this second method for making your chart:
$(function() {
var mod, bodyP, exist,
series = [{
name: 'CT ARM',
mod: 'CT',
data: [7.0, 6.9, 9.5],
bodyPart: 'arm'
}, {
name: 'MRI BRAIN',
mod: 'MRI',
data: [-0.2, 0.8, 5.7],
bodyPart: 'brain'
}, {
name: 'MRI WRIST',
mod: 'MRI',
data: [-0.9, 0.6, 3.5],
bodyPart: 'wrist'
}, {
name: 'PET THYROID',
mod: 'PET',
data: [3.9, 4.2, 5.7],
bodyPart: 'thyroid'
}, {
name: 'PET BRAIN',
mod: 'PET',
data: [1.9, 6.2, 2.7],
bodyPart: 'brain'
}, {
name: 'PET HEART',
mod: 'PET',
data: [7.9, 1.2, 7],
bodyPart: 'heart'
}];
$('#container').highcharts({
series: []
}, function(chart) {
$('.mod').change(function() {
mod = this.value;
if (mod) {
for (var i = chart.series.length - 1; i >= 0; i--) {
if (!(chart.series[i].userOptions.mod == mod && (bodyP ? chart.series[i].userOptions.bodyPart == bodyP : true))) {
chart.series[i].remove();
}
};
Highcharts.each(series, function(p, i) {
Highcharts.each(chart.series, function(ob, j) {
if (ob.name == p.name) {
exist = true;
}
})
if (!exist && p.mod == mod && (bodyP ? p.bodyPart == bodyP : true)) {
chart.addSeries(p);
}
exist = false;
})
}
});
$('.body').change(function() {
bodyP = this.value;
if (bodyP) {
for (var i = chart.series.length - 1; i >= 0; i--) {
if (!(chart.series[i].userOptions.bodyPart == bodyP && (mod ? chart.series[i].userOptions.mod == mod : true))) {
chart.series[i].remove();
}
};
Highcharts.each(series, function(p, i) {
Highcharts.each(chart.series, function(ob, j) {
if (ob.name == p.name) {
exist = true
}
});
if (!exist && p.bodyPart == bodyP && (mod ? p.mod == mod : true)) {
chart.addSeries(p);
}
exist = false;
})
}
});
});
});
As you can see I am not adding all my data to chart. I am adding only this data that is choosen inside forms. The problem is that I have to loop not only over my chart series (to check if it should be removed or not) but also over all not added series (to check if I should add it).
Here you can see an example how this code works: http://jsfiddle.net/2q1376Le/4/
Kind regards
Update: If you want to have just three series and information inside your data, you can do it as well, changing my code a little bit.
The mod section will be almost the same, because mod is connected directly with series.
Your bodyPart parameter is specific for every point so you need to iterate over all your series and over all of this series points for checking if this parameter is correct:
$('.body').change(function() {
bodyP = this.value, dataPoints;
for (var i = chart.series.length - 1; i >= 0; i--) {
chart.series[i].remove();
};
Highcharts.each(series, function(p, i) {
if (mod ? p.mod == mod : true) {
dataPoints = [];
Highcharts.each(p.data, function(ob, j) {
if (ob.bodyPart == bodyP) {
dataPoints.push(ob);
}
});
if (mod ? p.mod == mod : true) {
chart.addSeries({
name: p.name,
mod: p.mod,
data: dataPoints
})
}
}
});
});
Here you can see an example how it work: http://jsfiddle.net/2q1376Le/9/
Upvotes: 5