What is the proper way of visualizing data? - javascript

I am trying to plot chart using canvas.js!
As I want the data dynamically from my API, I created an array and is then passing it into the json object.
so I did the following:
<!DOCTYPE HTML>
<html>
<head>
<script>
var xhr = new XMLHttpRequest(),
method = "GET",
url = "url";
xhr.open(method, url, true);
var data_array = [];
xhr.send();
window.onload = function () {
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && xhr.status === 200) {
var api_data = xhr.responseText;
var api_json = JSON.parse(api_data);
var data = api_json["data"];
for(var i=0; i<data.length; i++) {
dp_data = data[i];
dp_median = dp_data["dp_median_price"];
dp_date = dp_data["date"];
var datearray = dp_date.split("-");
var newdate = datearray[0] + ', ' + datearray[1] + ', ' + datearray[2];
data_array.push({x:newdate, y:Number(dp_median)});
}
var chart = new CanvasJS.Chart("chartContainer", {
title: {
text: "title"
},
axisX: {
valueFormatString: "YYYY MM DD"
},
axisY2: {
title: "Median Price",
prefix: "₹",
suffix: ""
},
toolTip: {
shared: true
},
legend: {
cursor: "pointer",
verticalAlign: "top",
horizontalAlign: "center",
dockInsidePlotArea: true,
itemclick: toogleDataSeries
},
data:[
{
type:"line",
axisYType: "secondary",
name: "name1",
showInLegend: true,
markerSize: 1,
yValueFormatString: "₹#,###",
dataPoints: [
{ x: new Date(2015, 08, 01), y: 648 },
{ x: new Date(2015, 09, 01), y: 649 },
{ x: new Date(2015, 10, 01), y: 649 },
{ x: new Date(2017, 03, 01), y: 400 },
{ x: new Date(2017, 04, 01), y: 749 },
{ x: new Date(2017, 05, 01), y: 740 }]
},
{
type:"line",
axisYType: "secondary",
name: "name2",
showInLegend: true,
markerSize: 1,
yValueFormatString: "₹#,###",
dataPoints: data_array
}
]
});
chart.render();
function toogleDataSeries(e){
if (typeof(e.dataSeries.visible) === "undefined" || e.dataSeries.visible) {
e.dataSeries.visible = false;
} else{
e.dataSeries.visible = true;
}
chart.render();
}
}
}
};
</script>
</head>
<body>
<div id="chartContainer" style="height: 300px; width: 100%;"></div>
<script src="https://canvasjs.com/assets/script/canvasjs.min.js"></script>
</body>
</html>
Here, I cant read the data_array. How do I pass it in the chart data?
Above way is not working!
But when I pass data in a static way it works!
My array is in exact format as shown example of static information!
output of console.log(data_array) =
0:
x: "2019, 08, 29"
y: 1935
__proto__: Object

The problem is in how you try to track your ajax request.
The onredystatechange event fires multiple times during the executon of the xhr request.
0 - UNSENT Client has been created. open() not called yet.
1 - OPENED open() has been called.
2 - HEADERS_RECEIVED send() has been called, and headers and status are available.
3 - LOADING Downloading responseText holds partial data.
4 - DONE The operation is complete.
It is only when the state is 4 that you should start processing your data.
xhr.onreadystatechange = function () {
if (xhr.readyState ==0 4 and xhr.status === 200) {
//Process your data

Related

Plotline (vertical line) in highcharts scatter chart

https://jsfiddle.net/7zL0v5oq/
I would like to have a plotline at today's date. The list can get quite long and in that case it helps with having an oversight. I fear it doesn't work because it is a scatter chart but I don't know what the problem is. I've searched all over the place but everything leads to plotlines, which clearly doesn't work. I would also be thankful if anyone knew, whether there was an easy way to filter my data the way I have it (standard highcharts filtering is deactivated but doesn't really help because of the static y values, so I get a huge, white space in the middle unless I filter at the edges. Thank you in advance for your help.
data = [{
"id": 1,
"release": "Software1",
"routine_failure_analysis_ended_on": null,
"sw_maintenance_releases_ended_on": "2014-04-01",
"sale_ended_on": "2013-04-01",
"security_vul_support_ended_on": "2015-04-01",
"service_contract_renewal_ended_on": null,
"svc_attach_ended_on": null,
"support_ended_on": "2018-03-31",
"updated_dates_on": "2012-10-03",
"created_at": "2018-05-04T18:53:21.301+02:00",
"updated_at": "2018-05-16T08:36:24.940+02:00"
},
{
"id": 2,
"release": "Software2",
"routine_failure_analysis_ended_on": null,
"sw_maintenance_releases_ended_on": "2019-07-24",
"sale_ended_on": "2017-07-31",
"security_vul_support_ended_on": "2020-07-24",
"service_contract_renewal_ended_on": null,
"svc_attach_ended_on": null,
"support_ended_on": "2022-07-31",
"updated_dates_on": "2015-08-14",
"created_at": "2018-05-05T04:00:44.170+02:00",
"updated_at": "2018-05-16T08:36:29.325+02:00"
},
{
"id": 3,
"release": "Software3",
"routine_failure_analysis_ended_on": null,
"sw_maintenance_releases_ended_on": "2018-03-01",
"sale_ended_on": "2017-03-01",
"security_vul_support_ended_on": "2018-12-01",
"service_contract_renewal_ended_on": null,
"svc_attach_ended_on": null,
"support_ended_on": "2022-02-28",
"updated_dates_on": "2016-09-02",
"created_at": "2018-05-05T04:00:44.401+02:00",
"updated_at": "2018-05-16T08:36:31.643+02:00"
}
];
const colors = ["#516", "#1781e3", "#25b252", "#20c997", "#ffc107", "#ff8b2e", "#dd1122"];
//Change to store y value paired to release/pid
var change = {};
//Which y values need to be displayed
var ticks = [0];
//Description of events
var sale = "Sale";
var support = "Support";
var svc = " SVC attach";
var sw = "Software maintenance";
var routine = "Routine failure analysis";
var service = "Service contract renewal";
var security = "Security vulnerability support";
//Data array for series
var high = [];
data.sort(function(a, b) {
return Date.parse(a.support_ended_on) < Date.parse(b.support_ended_on) ? 1 : -1
})
for (var i = 0; i < data.length; i++) {
var arr = [{
x: Date.parse(data[i].sale_ended_on),
y: (i + 1) * 20,
color: colors[0],
myValue: sale
},
{
x: Date.parse(data[i].sw_maintenance_releases_ended_on),
y: (i + 1) * 20,
color: colors[1],
myValue: sw
},
{
x: Date.parse(data[i].security_vul_support_ended_on),
y: (i + 1) * 20,
color: colors[2],
myValue: security
},
{
x: Date.parse(data[i].svc_attach_ended_on),
y: (i + 1) * 20,
color: colors[3],
myValue: svc
},
{
x: Date.parse(data[i].routine_failure_analysis_ended_on),
y: (i + 1) * 20,
color: colors[4],
myValue: routine
},
{
x: Date.parse(data[i].service_contract_renewal_ended_on),
y: (i + 1) * 20,
color: colors[5],
myValue: service
},
{
x: Date.parse(data[i].support_ended_on),
y: (i + 1) * 20,
color: colors[6],
myValue: support
}
];
var key, value;
line = [{
x: Date.parse(data[i].sale_ended_on),
y: (i + 1) * 20
}, {
x: Date.parse(data[i].support_ended_on),
y: (i + 1) * 20
}]
//Adding to change list, so we can add release/pid as label to y axis
key = (i + 1) * 20;
ticks.push(key);
if (data[i].pid) {
value = data[i].pid;
} else {
value = data[i].release;
}
change[key] = value;
//Expanding high (which is used for the highcharts series) with arr (all points for one pid)
if (data[i].pid) {
high.push({
label: data[i].pid,
name: data[i].pid,
type: 'scatter',
data: arr
}, {
type: 'line',
data: line,
linkedTo: ":previous"
});
} else {
high.push({
label: data[i].release,
name: data[i].release,
type: 'scatter',
data: arr,
showInLegend: false
}, {
type: 'line',
data: line,
linkedTo: ":previous"
});
}
}
Highcharts.chart("container", {
chart: {
height: data.length * 75
},
credits: {
enabled: false
},
yAxis: {
title: {
text: null
},
tickPositions: ticks,
visible: true,
labels: {
formatter: function() {
var value = change[this.value];
return value !== 'undefined' ? value : this.value;
}
}
},
xAxis: {
plotlines: [{
color: "#dd1122",
width: 2,
value: +new Date()
}],
type: 'datetime',
},
plotOptions: {
scatter: {
marker: {
symbol: 'circle',
radius: 7,
lineWidth: 2
}
},
line: {
enableMouseTracking: false,
marker: {
enabled: false
},
color: '#bbb',
lineWidth: 3
}
},
tooltip: {
formatter: function() {
var str = '<b>' + this.series.name + '</b><br/>'
if (this.point.myValue) {
str += this.point.myValue;
} else {
str += "Corrupted data!";
}
if (this.point.x < Date.parse(new Date))
return str += " ended on:<br/>" + Highcharts.dateFormat('%e %b %Y', new Date(this.x));
else
return str += " will end on:<br/>" + Highcharts.dateFormat('%e %b %Y', new Date(this.x));
},
shared: false
},
series: high
})
You have a typo, use plotLines instead of plotlines:
xAxis: {
plotLines: [{
...
}],
...
}
Live demo: https://jsfiddle.net/BlackLabel/p3u8ejtb/
API Reference: https://api.highcharts.com/highcharts/xAxis.plotLines

How to add Data Points to be dynamic chart in canvasJS without knowing how many datas we need?

I want to make array that in some way will hold all the objects without hard coding how many objects I got, that I want to get their data, ill make it clear with the code: `
const localSavedCoins = getParsedToggledCurrencies(); // Brings JSON.parse array from localstorage which stores the name of the symbols.
const firstData = []; // dataPoints
const secondData = []; // dataPoints
const thirdData = []; // dataPoints
const fourthData = []; // dataPoints
const fivthData = []; // dataPoints
let addTextIfMissingDetails = [];
const updateInterval = 2000;
const dataLength = 20; // number of dataPoints visible at any point
let addedSubtitles = false;
localSavedCoins.forEach(coin => {
const updateChart = function () {
const date = new Date();
let currentYear = date.getFullYear();
let currentMonth = date.getMonth();
let currentDay = date.getDate();
let currentHour = date.getHours();
let currentMinutes = date.getMinutes();
let currentSeconds = date.getSeconds();
$.ajax({
url: `https://min-api.cryptocompare.com/data/pricemulti?fsyms=${coin}&tsyms=USD`,
success: information => {
const chart = new CanvasJS.Chart("contentDiv", {
exportEnabled: true,
zoomEnabled: true,
zoomType: "xy",
toolTip: {
shared: true,
},
title: {
text: "Coin Price Graph In USD"
},
subtitles: addTextIfMissingDetails
,
axisX: {
valueFormatString: "HH:mm:ss",
title: "Time"
},
axisY: {
includeZero: false,
title: "Price in USD",
titleFontColor: "#4F81BC",
lineColor: "#4F81BC",
labelFontColor: "#4F81BC",
tickColor: "#4F81BC"
},
data: [
{
type: "spline",
name: localSavedCoins[0],
showInLegend: true,
dataPoints: firstData
},
{
type: "spline",
name: localSavedCoins[1],
showInLegend: true,
dataPoints: secondData
},
{
type: "spline",
name: localSavedCoins[2],
showInLegend: true,
dataPoints: thirdData
},
{
type: "spline",
name: localSavedCoins[3],
showInLegend: true,
dataPoints: fourthData
},
{
type: "spline",
name: localSavedCoins[4],
showInLegend: true,
dataPoints: fivthData
},
]
})
if (information[Object.keys(information)[0]].USD === undefined && !addedSubtitles) {
addTextIfMissingDetails.push({
text: "Note: There are coins that are missing information"
})
addedSubtitles = true;
}
if (coin === localSavedCoins[0]) {
firstData.push({
x: new Date(currentYear, currentMonth, currentDay, currentHour, currentMinutes, currentSeconds),
y: information[Object.keys(information)[0]].USD
});
}
if (coin === localSavedCoins[1]) {
secondData.push({
x: new Date(currentYear, currentMonth, currentDay, currentHour, currentMinutes, currentSeconds),
y: information[Object.keys(information)[0]].USD
});
}
if (coin === localSavedCoins[2]) {
thirdData.push({
x: new Date(currentYear, currentMonth, currentDay, currentHour, currentMinutes, currentSeconds),
y: information[Object.keys(information)[0]].USD
});
}
if (coin === localSavedCoins[3]) {
fourthData.push({
x: new Date(currentYear, currentMonth, currentDay, currentHour, currentMinutes, currentSeconds),
y: information[Object.keys(information)[0]].USD
});
}
if (coin === localSavedCoins[4]) {
fivthData.push({
x: new Date(currentYear, currentMonth, currentDay, currentHour, currentMinutes, currentSeconds),
y: information[Object.keys(information)[0]].USD
});
}
chart.render();
},
error: () => {
alert("Error getting graph.");
}
})
}
updateChart(dataLength);
const intervalAjaxCalls = setInterval(function () { updateChart() }, updateInterval);`
Here I hard coded how many objects I got (5) but what if I want to make it that the client will save 100 objects and show them on a chart, it's not realistic to hardcode 100 objects like that,I couldn't find any other way to store in 1 single data array all the objects so it will be without code copying.
Thanks in advance, ill provide more details, explanation as needed.

Live Update Callback -> afterTitle with Array via JSON file

I'm working on a chart, I'm live updating the Chart every 5 seconds that the data comes in. I could manage to get the info from the database and update it really easy, but I just came across a problem with involves setting a path to a part of the chart, in the case: options->tootltips->callbacks->afterTitle and inside of it create an array and pass the array from the JSON to an array inside the callback.
What I would need to do, In a really brief way is, since I already made a function to update the info from my Data and Labels, somehow I will need to make inside this function, a path to the afterTitle, than I will be able send the fifth array, in with stores the data. As you can see in my function, I could manage to do it for the data and label.
I can't have another function that updates, so basically I can't have 2 loadData(), because it makes the Chart blink every time it updates, and that's not what I'm aiming for (The chart can't blink).
Inside this patch, I made an example that didn't work, with is the //:
$.getJSON('loadchart.php', function(response) {
myLineChart.data.datasets[0].data = response[0];
myLineChart.data.datasets[1].data = response[1];
myLineChart.data.datasets[2].data = response[2];
myLineChart.data.datasets[3].data = response[3];
myLineChart.data.labels = response[4];
//The response array that I need is response[5];
//myLineChart.options.tooltips.callbacks[1] = return response[tooltipItem[0]['index']];
myLineChart.update();
});
All my Chart so you can see the path:
<script>
function loadData() {
$.getJSON('loadchart.php', function(response) {
myLineChart.data.datasets[0].data = response[0];
myLineChart.data.datasets[1].data = response[1];
myLineChart.data.datasets[2].data = response[2];
myLineChart.data.datasets[3].data = response[3];
myLineChart.data.labels = response[4];
myLineChart.update();
});
}
loadData();
setInterval(loadData, 5000);
var lbl = [];
var ctx1 = document.getElementById('mychart1').getContext('2d');
var myLineChart = new Chart(ctx1, {
type: 'line',
data: {
labels: lbl,
datasets: [
{
label: "Corrente 1",
data: [],
borderWidht: 6,
borderColor: 'red',
backgroundColor: 'transparent'
},
{
label: "Corrente 2",
data: [],
borderWidht: 6,
borderColor: 'blue',
backgroundColor: 'transparent'
},
{
label: "Corrente 3",
data: [],
borderWidht: 6,
borderColor: 'green',
backgroundColor: 'transparent'
},
{
label: "Corrente Total",
data: [],
borderWidht: 6,
borderColor: 'black',
backgroundColor: 'transparent'
},
]
},
options: {
animation:{
update: 0
},
scales: {
yAxes: [{
ticks: {
beginAtZero: true
}
}],
xAxes: [{
gridLines: {
display: false
}
}]
},
title: {
display: true,
fontSize: 20,
text: "Gráfico das Correntes"
},
labels: {
fontStyle: "bold",
},
layout: {
padding: {
left: 0,
right: 0,
top: 0,
bottom: 0
}
},
tooltips: {
enabled: true,
mode: 'single',
responsive: true,
backgroundColor: 'black',
titleFontFamily: "'Arial'",
titleFontSize: 14,
titleFontStyle: 'bold',
titleAlign: 'center',
titleSpacing: 4,
titleMarginBottom: 10,
bodyFontFamily: "'Mukta'",
bodyFontSize: 14,
borderWidth: 2,
borderColor: 'grey',
callbacks:{
title: function(tooltipItem, data) {
return data.labels[tooltipItem[0].index];
},
afterTitle: function(tooltipItem, data) {
var tempo = [];
return tempo[tooltipItem[0]['index']];
},
label: function(tooltipItem, data) {
var label = data.datasets[tooltipItem.datasetIndex].label || '';
if (label) {
label += ': ';
}
label += (tooltipItem.yLabel)+"A";
return label;
}
}
},
aspectRatio: 1,
maintainAspectRatio: false
}
});
</script>
The part I need is this one:
afterTitle: function(tooltipItem, data) {
var tempo = [];
return tempo[tooltipItem[0]['index']];
This will display a clock but you can also set it to 5000 seconds and call your chart update. Which i would suggest to put in some kind of AJAX to let it work asynchonous.
<!DOCTYPE html>
<html>
<head>
<script>
function startTime() {
var today = new Date();
var h = today.getHours();
var m = today.getMinutes();
var s = today.getSeconds();
m = checkTime(m);
s = checkTime(s);
document.getElementById('txt').innerHTML =
h + ":" + m + ":" + s;
var t = setTimeout(startTime, 500); //<---- !!!
}
function checkTime(i) {
if (i < 10) {i = "0" + i}; // add zero in front of numbers < 10
return i;
}
</script>
</head>
<body onload="startTime()">
<div id="txt"></div>
</body>
</html>
As you mention in afterTitle function you want to create an array and pass the array from the JSON to an array inside the callback, and the missing part is you are creating an array tempo and treating it like an object tempo[tooltipItem[0]['index']];, but what you need to do is push this object tooltipItem[0]['index'] to tempo array.
Please replace afterTitle function with the below code
afterTitle: function(tooltipItem, data) {
var tempo = [];
return tempo.push(tooltipItem[0]['index']);

showing Y axis in a chart using CanvasJS

I made a chart that shows machines and the times that was taken for them to be fixed (machines X, time Y)
the data is loaded dynamically via mysql like the following
<?php
include_once(“connexion.php”);
ini_set(‘max_execution_time’,300);
//ini_set(‘error_reporting’, E_ALL);
$sq = “select machine,date_tech,time(time_fin – time_deb) as diff from action_archiv_tech WHERE (date_tech BETWEEN ‘2018-09-10’ AND ‘2018-10-06’)”;
$r = mysql_query($sq) or (die(mysql_error()));
while($tab = mysql_fetch_assoc($r)) {
$machine = $tab[‘machine’];
$diff = $tab[‘diff’];
// $data[] = [“label”=>$machine, “y”=>$diff];
$data[] = array(
‘label’ => $tab[‘machine’],
‘y’ => $tab[‘diff’]
);
}
?>
<!DOCTYPE HTML>
<html>
<head>
<meta charset=”UTF-8”>
<script>
window.onload = function () {
var chart = new CanvasJS.Chart(“chartContainer”, {
theme:”light2″,
animationEnabled: true,
title:{
text: “PM”
},
axisY :{
includeZero: false,
title: “Heures”,
suffix: “H”
},
toolTip: {
shared: “true”
},
legend:{
cursor:”pointer”,
itemclick : toggleDataSeries
},
data: [
{
type: “spline”,
showInLegend: true,
yValueFormatString: “##.00H”,
name: “Curative”,
dataPoints: <?php echo json_encode($data); ?>
}
]
});
chart.render();
function toggleDataSeries(e) {
if (typeof(e.dataSeries.visible) === “undefined” || e.dataSeries.visible ){
e.dataSeries.visible = false;
} else {
e.dataSeries.visible = true;
}
chart.render();
}
}
</script>
</head>
<body>
<div id=”chartContainer” style=”height: 370px; max-width: 1920px; margin: 0px auto;”></div>
<script src=”../../canvasjs.min.js”></script>
</body>
</html>
However the results are not like the expected
results : https://i.stack.imgur.com/zyIZM.png
Could you please help me figure out how to solve this problem :)
It seems like you are passing date-time in y-values, whereas CanvasJS supports only numeric in axisY. Please refer documentation for more info. However you can workaround this by passing -values as timestamp and format the value in axis-labels and toolTip as shown in below example, here is the JSFiddle for the same.
var chart = new CanvasJS.Chart("chartContainer", {
title: {
text: "Machine Operating Time"
},
axisY: {
minimum: (new Date(2016, 0, 25, 17, 30)).getTime(),
interval: (12 * 60 * 60 * 1000),
labelFormatter: function(e){
return CanvasJS.formatDate(e.value, "DD-MMM h:mm TT");
}
},
toolTip:{
contentFormatter: function ( e ) {
return "<strong>Machine " + e.entries[0].dataPoint.label + "</strong></br> Start Time: " + CanvasJS.formatDate(e.entries[0].dataPoint.y[0], "DD-MMM h:mm TT") + "</br> Stop Time: " + CanvasJS.formatDate(e.entries[0].dataPoint.y[1], "DD-MMM h:mm TT");
}},
data: [{
type: "rangeColumn",
dataPoints: [
{ label: "A", y: [(new Date(2016, 0, 25, 18, 30)).getTime(), (new Date(2016, 0, 26, 11, 00)).getTime()] }, //.getTime() returns timestamp => y-value is numeric
{ label: "B", y: [(new Date(2016, 0, 26, 12, 00)).getTime(), (new Date(2016, 0, 27, 14, 00)).getTime()] },
{ label: "C", y: [(new Date(2016, 0, 27, 3, 30)).getTime(), (new Date(2016, 0, 27, 14, 00)).getTime()] },
{ label: "D", y: [(new Date(2016, 0, 27, 12, 00)).getTime(), (new Date(2016, 0, 28, 14, 00)).getTime()] }
]
}]
});
chart.render();
<script src="http://canvasjs.com/assets/script/canvasjs.min.js"></script>
<div id="chartContainer" style="height: 260px; width: 100%;"></div>

How to reload data in Google Charts Calendar while keeping selected cell?

I use jQuery and I use the following JS function to load and reload / redraw the Google Chart Calendar.
It works, however, it also removes the border from the selected item. I want to reload the calendar data, while keeping the currently selected item selected.
Any ideas?
function refreshCalendar( rows)
{
//if( calendar != 0 )
{
calendar = new google.visualization.Calendar(document.getElementById('calendar_basic'))
google.visualization.events.addListener(calendar, 'select', calendarSelectHandler);
calendarData = new google.visualization.DataTable();
calendarData.addColumn({ type: 'date', id: 'Date' });
calendarData.addColumn({ type: 'number', id: 'Logs' });
calendarData.addRows( rows );
calendarOptions = {
title: "Logs",
height: 175,
colorAxis: {minValue: 0, colors: ['#FFFFFF', '#FF0000']},
calendar: {
focusedCellColor: {
background: '#00FF00',
stroke: '#004400',
strokeOpacity: 1,
strokeWidth: 2,
},
cellColor: {
stroke: '#76a7fa',
strokeOpacity: 0.5,
strokeWidth: 1,
}
}
};
calendar.draw(calendarData, calendarOptions);
}
}
Normally, you would use chart.getSelection and chart.setSelection.
Get selection on 'select' event
Set selection on 'ready' event
getSelection works fine, but setSelection doesn't work with the Calendar chart.
No error is thrown, but nothing is selected.
I tried versions '41' thru 'current'...
To demonstrate, the following example uses both a Calendar chart and a Column chart.
Make a selection on both charts, then click "Redraw Chart".
The selection for the Column chart remains but not on the Calendar.
google.charts.load('current', {
callback: drawChart,
packages: ['calendar', 'corechart']
});
function drawChart() {
var selectionCal;
var selectionCol;
var calendar = new google.visualization.Calendar(document.getElementById('calendar'))
google.visualization.events.addListener(calendar, 'select', function () {
selectionCal = calendar.getSelection();
});
google.visualization.events.addListener(calendar, 'ready', function () {
if (selectionCal) {
calendar.setSelection(selectionCal);
}
});
var column = new google.visualization.ColumnChart(document.getElementById('column'))
google.visualization.events.addListener(column, 'select', function () {
selectionCol = column.getSelection();
});
google.visualization.events.addListener(column, 'ready', function () {
if (selectionCol) {
column.setSelection(selectionCol);
}
});
document.getElementById('test_button').addEventListener('click', function () {
calendar.draw(calendarData, calendarOptions);
column.draw(calendarData, {});
}, false);
var calendarData = new google.visualization.DataTable();
calendarData.addColumn({ type: 'date', id: 'Date' });
calendarData.addColumn({ type: 'number', id: 'Logs' });
calendarData.addRows([
[ new Date(2012, 3, 13), 37032 ],
[ new Date(2012, 3, 14), 38024 ],
[ new Date(2012, 3, 15), 38024 ],
[ new Date(2012, 3, 16), 38108 ],
[ new Date(2012, 3, 17), 38229 ],
]);
var calendarOptions = {
title: "Logs",
height: 175,
colorAxis: {minValue: 0, colors: ['#FFFFFF', '#FF0000']},
calendar: {
focusedCellColor: {
background: '#00FF00',
stroke: '#004400',
strokeOpacity: 1,
strokeWidth: 2,
},
cellColor: {
stroke: '#76a7fa',
strokeOpacity: 0.5,
strokeWidth: 1,
}
}
};
calendar.draw(calendarData, calendarOptions);
column.draw(calendarData, {});
}
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="calendar"></div>
<div id="column"></div>
<input type="button" id="test_button" value="Redraw Chart" />
I can also confirm that the setSelection() method doesn't change anything on the UI for the calendar chart.
So I looked up what happens after selecting a day in the chart with the mouse. Then I implemented a simple DOM manipulation logic which does the same. You can use that logic as a replacement of the setSelection() use case. (It is just a quick prototype, but I hope it helps you, too).
For a litte demo I adjusted #WhiteHat snippet / the selected day survives now the refresh action (doesn't work with charts which needs to display more than one year!):
google.charts.load('current', {
callback: drawChart,
packages: ['calendar', 'corechart']
});
function drawChart() {
var selectionCal;
var selectionDate;
var selectionCol;
var calendar = new google.visualization.Calendar(document.getElementById('calendar'))
google.visualization.events.addListener(calendar, 'select', function () {
selectionCal = calendar.getSelection();
selectionDate = new Date(selectionCal[0].date);
});
google.visualization.events.addListener(calendar, 'ready', function () {
if (selectionDate) {
// google calendar setSelection BUG :/
// https://stackoverflow.com/a/36093217/810944
// do it manually
var doy = selectionDate.getDOY();
markDayInChart(doy);
}
});
var column = new google.visualization.ColumnChart(document.getElementById('column'))
google.visualization.events.addListener(column, 'select', function () {
selectionCol = column.getSelection();
});
google.visualization.events.addListener(column, 'ready', function () {
if (selectionCol) {
column.setSelection(selectionCol);
}
});
document.getElementById('test_button').addEventListener('click', function () {
calendar.draw(calendarData, calendarOptions);
column.draw(calendarData, {});
}, false);
var calendarData = new google.visualization.DataTable();
calendarData.addColumn({ type: 'date', id: 'Date' });
calendarData.addColumn({ type: 'number', id: 'Logs' });
calendarData.addRows([
[ new Date(2012, 3, 13), 37032 ],
[ new Date(2012, 3, 14), 38024 ],
[ new Date(2012, 3, 15), 38024 ],
[ new Date(2012, 3, 16), 38108 ],
[ new Date(2012, 3, 17), 38229 ],
]);
var calendarOptions = {
title: "Logs",
height: 175,
colorAxis: {minValue: 0, colors: ['#FFFFFF', '#FF0000']},
calendar: {
focusedCellColor: {
background: '#00FF00',
stroke: '#004400',
strokeOpacity: 1,
strokeWidth: 2,
},
cellColor: {
stroke: '#76a7fa',
strokeOpacity: 0.5,
strokeWidth: 1,
}
}
};
calendar.draw(calendarData, calendarOptions);
column.draw(calendarData, {});
}
function markDayInChart(dayOfYear) {
// clones the logic for clicking / selecting a day via mouse
// keep in mind to clean up the adjusted and added `rect`-elements if you do not use full page reloads!
// doesn't work with charts which needs to display more than one year!
var days_all_svg_group = $('#calendar svg').children('g')[1];
var days_marked_svg_group = $('#calendar svg').children('g')[4];
var day_svg_rect = $('rect:nth-of-type('+dayOfYear+')',$(days_all_svg_group));
// hide the original rect
$(day_svg_rect).css('display: none;');
// add a cloned rect with a different stroke
var day_marked_svg_rect = $(day_svg_rect).clone();
$(day_marked_svg_rect).attr({stroke: '#000000', 'stroke-width': 2});
$(day_marked_svg_rect).attr('stroke-opacity', null);
$(days_marked_svg_group).append(day_marked_svg_rect);
}
// https://stackoverflow.com/a/26426761/810944
Date.prototype.isLeapYear = function() {
var year = this.getFullYear();
if((year & 3) != 0) return false;
return ((year % 100) != 0 || (year % 400) == 0);
};
// Get Day of Year
Date.prototype.getDOY = function() {
var dayCount = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334];
var mn = this.getMonth();
var dn = this.getDate();
var dayOfYear = dayCount[mn] + dn;
if(mn > 1 && this.isLeapYear()) dayOfYear++;
return dayOfYear;
};
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="calendar"></div>
<div id="column"></div>
<input type="button" id="test_button" value="Redraw Chart" />

Categories

Resources