I have a question regarding piecharts on Chart.js.
What would be the best way to remove a slice when clicking on it?
I'm aware the method getSegmentsAtEvent() can be used to read the slice properties.
It's possible to find out which slicing I'm clicking looping through the slices object until a match is found.
Is there a simpler way to achieve it?
tks
This can be achieved using the functions: getSegmentsAtEvent(event) and removeData( index ) Chart.js API
With getSegmentsAtEvent you can recover the segment that has been clicked.
The next step, is to find the index of the slice in the chart. To do the search, you can iterate through all the current segments of the chart and call removeData when it's found. (I think there is no way to directly know the index)
var segments = myChart.segments;
for (var index = 0; index < segments.length; index++) {
if (activeLabel == segments[index].label) {
myChart.removeData(index);
}
}
Full demo:
<html>
<head>
<script type="text/javascript" src="http://code.jquery.com/jquery-2.0.2.js"></script>
<script type="text/javascript" src="Chart.js"></script>
<script type="text/javascript">
var data = [
{
value: 300,
color:"#F7464A",
highlight: "#FF5A5E",
label: "Red"
},
{
value: 50,
color: "#46BFBD",
highlight: "#5AD3D1",
label: "Green"
},
{
value: 100,
color: "#FDB45C",
highlight: "#FFC870",
label: "Yellow"
}
];
$(document).ready(
function () {
var ctx = document.getElementById("myChart").getContext("2d");
var myChart = new Chart(ctx).Pie(data);
$("#myChart").click(
function(evt){
var activePoints = myChart.getSegmentsAtEvent(evt);
var activeLabel = activePoints[0].label;
var segments = myChart.segments;
for (var index = 0; index < segments.length; index++) {
if (activeLabel == segments[index].label) {
myChart.removeData(index);
}
}
}
);
}
);
</script>
</head>
<body>
<canvas id="myChart" width="400" height="400"></canvas>
</body>
</html>
Get the onclick property in options of chart.
This onclick event will trigger even when you click outside of pie (anywhere in canvas), so you have to filter it out by using myChart.getElementsAtEvent(event);
Get data of chart and then remove an item using checks(In the following snippet you can only remove china or any country with value less than 50).
Update the chart by using .update() method
Following is the required working snippet
var chart_click_event = function(event) {
debugger;
let activePoints = myChart.getElementsAtEvent(event);
//If you click on empty area this if check will not pass.
if (activePoints[0]) {
let chartData = activePoints[0]['_chart'].config.data;
let idx = activePoints[0]['_index'];
let label = chartData.labels[idx];
let value = chartData.datasets[0].data[idx];
if (label == 'China' || value < 50) {
chartData.labels.splice(idx, 1);
chartData.datasets[0].data.splice(idx, 1);
myChart.update();
}
}
}
var data = [{
data: [50, 55, 60, 33],
backgroundColor: [
"#4b77a9",
"#5f255f",
"#d21243",
"#B27200"
],
borderColor: "#fff"
}];
var options = {
tooltips: {
enabled: true
},
plugins: {
datalabels: {
color: '#fff',
}
},
onClick: chart_click_event
};
var ctx = document.getElementById("pie-chart").getContext('2d');
var myChart = new Chart(ctx, {
type: 'pie',
data: {
labels: ['Pakistan', 'China', 'US', 'Canada'],
datasets: data
},
options: options
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.2/Chart.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-datalabels#0.7.0"></script>
<canvas id="pie-chart"></canvas>
Related
I have written the following code:
<!DOCTYPE html>
<html lang = "en">
<head>
<meta charset = "UTF-8">
<meta name = viewport" content ="width=device-width, intial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content = "ie=edge">
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.2/Chart.min.js"></script>
<link rel ="stylesheet" href = "https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css">
<title>My Chart.js</title>
</head>
<body>
<div class = "container">
<canvas id="myChart"></canvas>
</div>
<script>
var c = [];
var randomNumber = Math.random()*190;
function getRandomDataPoint(x){
if (x == "x"){
var _return
return Math.random()*20;
}
else if (x == "y"){
return Math.random()*10 + randomNumber;
}
else{
}
}
var xPoints = [];
var yPoints = [];
var storage = [];
for(var i=0;i<100;i++)
{
xPoints[i] = Math.random()*20;
yPoints[i] = Math.random()*10 + randomNumber;
x = xPoints[i];
y = yPoints[i];
var json = {x: x, y: y};
storage.push(json);
}
var concatenatedArray = xPoints.concat(yPoints);
let myChart = document.getElementById('myChart');//.getContext('2d');
Chart.defaults.global.defaultColor = '#000000';
let massPopChart = new Chart(myChart, {
type: 'scatter',
data: {
datasets: [{label: 'Data Set', data: [storage]}],
},
options: {
scales: {
yAxes: [{
ticks: {
max: 200,
min: 0,
beginAtZero:true
},
}]
}
}
});
</script>
</body>
</html>
What I would like for this code to do is take 100 random data points and plot them using the for-loop depicted in the code. The issue is the current set of code does create the axis however no data appears to be plotted.
Thank you for any help.
Best Regards
The problem is in how you pass your data values to Chart.js on this line:
datasets: [{label: 'Data Set', data: [storage]}],
Specifically, data is supposed to be an array of objects. Because you have added the square brackets ([]) you are passing an 'array of array of objects'.
The problem can be fixed simply by removing the brackets:
data: storage
I used this ,to multiply doughnut chart according as array(arr) has,but it can't change to object,(data has string type).So chart doesn't appear here..,how fix it
var arr=['HTML','CSS','JS'],i,data;
data ='[';
for(i=0;i<arr.length;i++){
if(i==arr.length-1){
data+='{value:"300",color:"#fff",highlight:"#aaa",label:arr[i]}';
}
else{
data+='{value:"300",color:"#fff",highlight:"#aaa",label:arr[i]},';
}
}
data += ']';
var dat = data;
window.onload = function () {
var ctx = document.getElementById("chart-area").getContext("2d");
window.myBar = new Chart(ctx).Doughnut(dat,{
responsive: true,
});
};
//want like this
dat =[{value:"300",color:"#fff",highlight:"#aaa",label:"HTML"},
{value:"200",color:"#fff",highlight:"#aaa",label:"CSS"}];
You are creating your array as a String.
You need to create an array of objects [{},{},{}].
The method used to INSERT a new object in an array is PUSH().
Check the fiddle. Now it´s working OK (move the mouse on the screen to see the chart is there (you will only see it when mouse is over it):
window.onload = function() {
var arr = ['HTML', 'CSS', 'JS'],
i, data;
data = [];
for (i = 0; i < arr.length; i++) {
if (i == arr.length - 1) {
data.push({
value: "300",
color: "#fff",
highlight: "#aaa",
label: arr[i]
});
} else {
data.push({
value: "300",
color: "#fff",
highlight: "#aaa",
label: arr[i]
});
}
}
var dat = data;
var ctx = document.getElementById("chart-area").getContext("2d");
window.myBar = new Chart(ctx).Doughnut(dat, {
responsive: true,
});
};
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://rawgit.com/nnnick/Chart.js/master/Chart.js"></script>
<canvas id="chart-area"></canvas>
I am working with jquery HighCharts. I want to create a common function to develop multiple charts of same type.
To achieve this goad I created a function as follow -
function generateGraph(data) {
var dates = new Array();
var startDate = "";
for (var i = 0; i < data.length; i++) {
dates[i] = data[i].date;
}
var productInsight = _comm.getProductInsightArray();
var productInsight_Array = new Array();
$.each(productInsight, function(key, value) {
productInsight_Array.push(key);
});
if(dates.length > 0) {
startDate = dates[0].split("/");
}
intervals = 24 *3600 * 1000; //one day
var title = $("#DateSearch_analytics_Similar_Stores1").val();
var color = ['#000000', '#FFFFFF', '#000080', '#0000FF', '#808080'];
var containers =['container1', 'container2','container3','container4', 'container5', 'container6', 'container7', 'container8', 'container9'];
for(var j=0; j<containers.length; j++)
{
var chart = new Highcharts.Chart({
chart: {
zoomType: 'x',
renderTo: containers[j],
type: 'line',
},
title: {
text: title
},
subtitle: {
text: document.ontouchstart === undefined ?
'Click and drag in the plot area to zoom in' :
'Pinch the chart to zoom in'
},
xAxis: {
type: 'datetime',
tickInterval: intervals,
},
series: []
});
for(var i=0; i < productInsight_Array.length; i++) {
var fillData = new Array();
var counter = 0;
var productValue = document.getElementById('product-nm').value;
$.each(dates, function() {
fillData[counter] = _comm.randomNumberFromRange(_randomNumberStartRange, _randomNumberEndRange);
counter++;
});
chart.addSeries({
name: productInsight_Array[i],
type: 'line',
color: color[i],
pointStart: Date.UTC(startDate[2], startDate[0] - 1, startDate[1]),
pointInterval: intervals,
data: fillData,
});
}
$("text:contains('Highcharts.com')").css("display", "none");
}
}
Its working fine and developing charts on window load and button click. I am saving these graph in 9 container but this script is not loading graph in 3rd container and when I remove 3rd container than its not loading in fourth and so on. But it works fine when I call this function on button click in place of document load.
I am little surprised why its happing, As a common function creting all graphs.
I need your help! :(
Thanks
The problem is when load the function your markup doesnt exists. For this reason when you click the button works ok. When the button is visible, all markup is already loaded.
Review your load order.
Also aside comment: put this in your chart declaration:
credits: {
enabled: false
}
To not show the credits message: "Highcharts.com".
An example
I'm trying to replicate the following code from a working example:
series: {0: {targetAxisIndex:0},
1: {targetAxisIndex:0},
2: {targetAxisIndex:1},
This is for setting which y-axis is used to plot different columns from a dataTable on a Google chart.
However I have a variable number of columns (based on user input), therefore am collecting an array of the required axis (the axisAssignment Array in the below example).
My code is below:
var series = {};
for (i=0;i<axisAssignment.length;i++)
{
series[i] = {targetAxisIndex: axisAssignment[i]};
}
return series;
However, all of my data is only being written to the left axis, despite the debugger suggesting that the object is correct. My option code is below:
var options =
{
hAxis: {title: xTitle},
vAxes: {0: {title: y1Type},
1: {title: y2Type}
},
series: calculateSeries(),
pointSize: 1,
legend: {position: 'top', textStyle: {fontSize: 10}}
};
Any assistance would be greatly apreciated.
Thanks
Tom
edit: whole file for reference (it's a work in progress so a bit of a mess I'm afraid)
google.load("visualization", "1", {packages:["corechart"]});
google.setOnLoadCallback(drawChart());
function drawChart()
{
var title = "Node: "+currentNode;
var xTitle = "Date";
var yTitle = titles[currentVariable];
if (totalData !== null)
{
var tempData = newData();
var tempData2 = totalData;
dataArray[dataCount] = tempData;
var joinMark = countArray(dataCount);
totalData = google.visualization.data.join(tempData2,tempData,'full',[[0,0]],joinMark,[1]);
dataCount = dataCount+1;
}
else
{
totalData = newData();
dataArray[dataCount] = totalData;
dataCount = 1;
}
var options =
{
hAxis: {title: xTitle},
vAxes: {0: {title: y1Type},
1: {title: y2Type}
},
series: calculateSeries(),
pointSize: 0.5,
legend: {position: 'top', textStyle: {fontSize: 10}}
};
var chart = new google.visualization.ScatterChart(document.getElementById('graph'));
console.log(calculateSeries());
chart.draw(totalData, options);
function countArray(count)
{
var arrayCount= new Array();
if (count===1)
{
arrayCount[0] = count;
}
else
{
for (var i=0;i<count;i++)
{
var temp = i+1;
arrayCount[i] = temp;
}
}
return arrayCount;
}
function calculateSeries()
{
var series = {};
for (i=0;i<axisAssignment.length;i++)
{
series[i] = {targetAxisIndex: axisAssignment[i]};
}
return series;
}
function newData()
{
var dataType = dataIn[0];
dataIn.shift();
var axis = dataSelect(dataType);
axisAssignment.push(axis);
var data = new google.visualization.DataTable();
data.addColumn('date', 'Date');
data.addColumn('number', "Node: "+currentNode+": "+titles[currentVariable]);
var num = (dataIn.length);
data.addRows(num/2);
var i = 0;
var j = 0;
while (i<num)
{
var d = (dataIn[i]);
if (i%2===0)
{
d = new Date(d);
data.setCell(j,0,d);
i++;
}
else
{
data.setCell(j,1,parseFloat(d));
i++;
j++;
}
}
return data;
}
function dataSelect(type)
{
var axisNumber;
if (y1Type === null || y1Type === type)
{
y1Type = type;
axisNumber = 0;
}
else if (y2Type === null || y2Type === type)
{
y2Type = type;
axisNumber = 1;
}
else
{
alert("You already have 2 axes assigned.\n\nPlease clear the graph \nor select more objects of \ntype"+y1Type+" or \ntype "+y2Type+" to continue.");
axisNumber = null;
}
return axisNumber;
}
}
Ok, it seems that it's an issue with my choice of ScatterChart,
var options =
{
hAxis: {title: xTitle},
series: calculateSeries(),
vAxes: {0: {title: y1Type },
1: {title: y2Type}
},
pointSize: 0.5,
legend: {position: 'top', textStyle: {fontSize: 10}}
};
var chart = new google.visualization.LineChart(document.getElementById('graph'));
chart.draw(totalData, options);
I've changed it to LineChart and it's working fine, by keeping the pointSize option, the appearance is almost completely unchanged. Thanks for your help juvian.
I wish to be able to determine the minimum and maximum for each series in the below (series being pH, ORP, Tank, Heater and Room). Tank, Heater and Room should all be written to the same min and max variable as they display on the same scale (ie. Show me the min or max of any of the 3 sets of data – being Min of 22.20 & Max being 24.33 from the sample data below)
The raw data being imported is in the following format (there are far more columns)
For a complete sample see http://macca.myreef.info/24hr_final.csv
Sample:
pnt_1 1375935000.00 1375935300.00 1375935600.00 1375935900.00
pH 8.34 8.35 8.36 8.36
ORP 415.24 415.44 415.05 414.74
Tank 24.27 24.26 24.20 24.22
Heater 24.33 24.30 24.30 24.30
Room 22.20 22.32 22.44 22.52
Where pnt_1 is rubbish, column 1 is the "header", row 1 is epoch and the remaining data is the value (at that epoch time).
Hope I haven't lost you as yet.
Using the code below I have managed to get Highcharts to display almost as I want it – see http://macca.myreef.info/test1.html
I want to be able to
Declare the min and max of each row (treating the tank, Heater and Room row as 1) as a variable.
Use the min and max variables to set the axis
Eg. If minph = 8.34 and maxph = 8.36 I might declare
var minphscale = minph*0.9
var maxphscale = maxph*1.1
The reason for wanting to do this as variables is I am also working of presenting the most recent data as a Highchart of type gauge where I will use the variables to set the “bands” of color to indicate the amount of swing any given series has had as well as the actual series value as being the most recent sample. The variables minph and maxph would determine the band (Geez – I hope that makes sense.)
Current code is
<html>
<head>
<meta http-equiv = "Content-Type" content = "text/html; charset = utf-8">
<meta http-equiv = "refresh" content = "180">
<meta http-equiv = "cache-control" content = "no-cache">
<title>Daily Data</title>
<!-- 1. Add these JavaScript inclusions in the head of your page -->
<script src = "http://code.jquery.com/jquery-1.9.1.js"></script>
<script type = "text/javascript"
src = "http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js">
</script>
<script type="text/javascript" src="/js/highcharts.js"></script>
<!-- 2. Add the JavaScript to initialize the chart on document ready -->
<script type="text/javascript">
var minph = 13;
$(document).ready(function() {
var options = {
credits: {
enabled: false
},
plotOptions: {
line: {
marker: {
enabled: false
}
}
},
chart: {
renderTo: 'container',
type: 'line',
marginRight: 130,
marginBottom: 25,
zoomType: 'x',
spacingRight: 2
},
title: {
text: '24hr history',
x: -20 //center
},
subtitle: {
text: 'Temp',
x: -20
},
xAxis: {
tickInterval:60,
categories: []
},
yAxis: [
{ //Primary [0]
title: {
text: 'orp'
},
id: 'ORP',
opposite: true,
min: 350,
max: 450
},
{ //Secondary [1]
title: {
text: 'pH'
},
id: 'pH',
min: 8,
max: 9
},
{ //Tertiary [2]
title: {
text: 'Temp'
},
id: 'Temp',
min: 20,
max: 30,
opposite: false
}],
tooltip: {
crosshairs: true,
shared: true
},
legend: {
layout: 'vertical',
align: 'right',
verticalAlign: 'top',
x: -10,
borderWidth: 1
},
series: []
};
$.get('24hr_final.csv', function(data) {
// Split the lines
var lines = data.split('\n');
$.each(lines, function(lineNo, line) {
var items = line.split(',');
// Below is an attempt to change UNIX EPOCH to Java EPOCH
// and load into series1 as a date
if (lineNo === 0) {
$.each(items, function(itemNo, item) {
if (itemNo > 0) {
var javaepoch = (item) / 0.001;
var date = new Date(javaepoch);
options.xAxis.categories.push(date);
}
});
} else {
var series = {
data: []
};
$.each(items, function(itemNo, item) {
if (itemNo === 0) {
// Set the Axis for each data type
series.name = item;
if (item == 'pH') {
series.yAxis = item;
}
if (item == 'ORP' ) {
series.yAxis = item;
}
if (item == 'Tank' ) {
series.yAxis = 'Temp';
}
if (item == 'Heater' ) {
series.yAxis = 'Temp';
}
if (item == 'Room' ) {
series.yAxis = 'Temp';
}
// Finished mods for axis
} else {
var minph = 5;
series.data.push(parseFloat(item));
}
});
options.series.push(series);
}
});
var chart = new Highcharts.Chart(options);
});
});
</script>
</head>
<body>
<div id = "container" style = "width: 100%; height: 400px; margin: 0 auto">
</div>
<script>
document.write ("Min pH is " + minph + ". <BR>")
</script>
Test 1
</body>
</html>
Well, I think you can do this in that way:
else {
var minph = 5,
val = parseFloat(item);
series.data.push(val);
// get min and max
series.minVal = series.minVal < val ? series.minVal : val;
series.maxVal = series.maxVal > val ? series.maxVal : val;
}
Then before creating chart set for connected yAxis minVal and maxVal as min and max. If you want to have three rows connected to one yAxis, compare that rows minVal and maxVal and choose min and max value of them.