I want to use anchorBgColor attribute for Real-time Line chart.
Real-time Line chart.
function updateData() {
var t = new Date(),
date =
t.getHours() + ":" + t.getMinutes() + ":" + t.getSeconds(),
val = Math.floor(Math.random() * (7800 - 7200 + 1)) + 7200,
strData = "&label=" + date + "&value=" + val;
// Feed it to chart.
chartRef.feedData(strData);
}
Could you recommend how to change anchorBgColor for this chart?
If you are wanting to have all the points the same color all you have to do is include the anchorBgColor property in the chart object
{
...
dataSource: {
chart: {
...
anchorBgColor: "#26aa5a"
}
}
}
If you want points to change colors as you add them you have manipulate the chart data object and use setJSONData rather than using the feedData method.
<div id="chart-container">FusionCharts will render here</div>
FusionCharts.ready(function() {
var chartObj = new FusionCharts({
type: 'line',
renderAt: 'chart-container',
id: 'myChart',
width: '500',
height: '300',
dataFormat: 'json',
dataSource: {
"chart": {
"theme": "fusion",
"anchorRadius": "6",
"theme": "fusion"
},
"data": []
}
});
chartObj.render();
function pushNewPoint() {
var t = new Date(),
date =
t.getHours() + ":" + t.getMinutes() + ":" + t.getSeconds(),
val = Math.floor(Math.random() * (7800 - 7200 + 1)) + 7200,
randomColor = Math.floor(Math.random()*16777215).toString(16)
newEntry = {
label: date,
value: val,
anchorBgColor: "#" + randomColor
}
chartData = chartObj.getChartData('json')
chartData.data.push(newEntry)
chartObj.setJSONData(chartData)
}
var counter = 0;
var i = setInterval(function(){
pushNewPoint()
counter++;
if(counter === 10) {
clearInterval(i);
}
}, 1000);
});
Example can be seen here
Related
I have some information inside the doughnut chart and want to prevent tooltip blinks when this info is accessed with the mouse.
Check out the attached screenshot below:
I am trying to implement the following solution:
Not show the label tooltip if the label hover is less than 1 second.
If the label hover is more than 1 second (i.e. the cursor is stuck on the label for some time) then I need to show the tooltip.
Check out the following JSFiddle
var chart_data = [6,5,4,3,2,1]
function chart() {
var options = {
type: 'doughnut',
data: {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: [{
label: '# of Votes',
data: chart_data,
backgroundColor: [ "Red", "Blue", "Yellow", "Green", "Purple", "Orange" ],
borderWidth: 1,
}
]
},
options: {
cutoutPercentage : 65,
responsive: false,
tooltips: {
callbacks: { label: label_tooltip }
},
}
}
var ctx = document.getElementById('chart-container').getContext('2d')
new Chart(ctx, options)
}
function label_tooltip(item, data) {
var index = item.index
var name = data.labels[index]
var value = data.datasets[0].data[index]
var tooltip = ' ' + name + ' - ' + value
return tooltip
}
chart()
document.getElementById('chart-info').innerHTML = chart_data.reduce((a, b) => a + b, 0) + '<br>TOTAL'
For a custom tooltip you will need to put enabled: false in your tooltips option. I made a quick example that showcases what you want. It shows the custom tooltip after 1 sec by delaying the making of the table. If you go off the element it will remove it imideatly.
Example: https://jsfiddle.net/Leelenaleee/ks3wgvLp/12/
code:
var tttimer;
Chart.defaults.global.tooltips.custom = function(tooltip) {
// Tooltip Element
var tooltipEl = document.getElementById('chartjs-tooltip');
// Hide if no tooltip
if (tooltip.opacity === 0) {
tooltipEl.style.opacity = 0;
return;
}
clearTimeout(tttimer);
tttimer = setTimeout(() => {
// Set caret Position
tooltipEl.classList.remove('above', 'below', 'no-transform');
if (tooltip.yAlign) {
tooltipEl.classList.add(tooltip.yAlign);
} else {
tooltipEl.classList.add('no-transform');
}
function getBody(bodyItem) {
return bodyItem.lines;
}
// Set Text
if (tooltip.body) {
var titleLines = tooltip.title || [];
var bodyLines = tooltip.body.map(getBody);
var innerHtml = '<thead>';
titleLines.forEach(function(title) {
innerHtml += '<tr><th>' + title + '</th></tr>';
});
innerHtml += '</thead><tbody>';
bodyLines.forEach(function(body, i) {
var colors = tooltip.labelColors[i];
var style = 'background:' + colors.backgroundColor;
style += '; border-color:' + colors.borderColor;
style += '; border-width: 2px';
var span = '<span class="chartjs-tooltip-key" style="' + style + '"></span>';
innerHtml += '<tr><td>' + span + body + '</td></tr>';
});
innerHtml += '</tbody>';
var tableRoot = tooltipEl.querySelector('table');
tableRoot.innerHTML = innerHtml;
}
var positionY = this._chart.canvas.offsetTop;
var positionX = this._chart.canvas.offsetLeft;
// Display, position, and set styles for font
tooltipEl.style.opacity = 1;
tooltipEl.style.left = positionX + tooltip.caretX + 'px';
tooltipEl.style.top = positionY + tooltip.caretY + 'px';
tooltipEl.style.fontFamily = tooltip._bodyFontFamily;
tooltipEl.style.fontSize = tooltip.bodyFontSize;
tooltipEl.style.fontStyle = tooltip._bodyFontStyle;
tooltipEl.style.padding = tooltip.yPadding + 'px ' + tooltip.xPadding + 'px';
}, 1000)
};
Credits for clearing timer first to make it work go to one of the mainainers of Chart.js
Hello, I have a timeline made with google charts, what I want to do is update it every so often, for example every 5 seconds, I get the data from a json, I tried it this way but it didn't work for me:
setTimeout(function () {
drawChart();
}, 5000);
Is there any way to do it?
google.load("visualization", "1", {packages: ["timeline"]});
google.setOnLoadCallback(drawChart);
// google.charts.setOnLoadCallback(drawChart);
function drawChart() {
$(".timeline").each(function () {
var obje = {{ devicejson|safe }};
var elem = $(this),
id = elem.attr('id');
var container = document.getElementById(id);
var chart = new google.visualization.Timeline(container);
var dataTable = new google.visualization.DataTable();
dataTable.addColumn({type: 'string', id: 'Role'});
dataTable.addColumn({type: 'string', id: 'Name'});
dataTable.addColumn({type: 'date', id: 'Start'});
dataTable.addColumn({type: 'date', id: 'End'});
dataTable.addColumn({type: 'string', id: 'TimeEst'});
dataTable.addColumn({type: 'string', role: 'style'});
for (n = 0; n < obje.length; ++n) {
if (obje[n].device_id == id) {
dataTable.addRows([
['Department', obje[n].digitaloutput_user_description, new Date('"' + obje[n].startdatetime + '"'), new Date('"' + obje[n].enddatetime + '"'), obje[n].lighstate_user_description, obje[n].color],
]);
}
}
for (n = 0; n < obje.length; ++n) {
if (obje[n].device_id == id) {
console.log(obje[n].color)
}
}
var options = {
chartArea: {
height: '90%',
width: '100%',
top: 36,
right: 12,
bottom: 2,
left: 12
},
height: 100,
tooltip: {isHtml: true},
timeline: {
showRowLabels: false,
},
avoidOverlappingGridLines: false,
{#hAxis: {format: 'dd-MMM-yyyy HH:mm:ss'}#}
};
var formatTime = new google.visualization.DateFormat({
pattern: 'yyyy-MM-dd HH:mm:ss a'
});
var view = new google.visualization.DataView(dataTable);
view.setColumns([0, 1, {
role: 'tooltip',
type: 'string',
calc: function (dt, row) {
// build tooltip
var dateBegin = dt.getValue(row, 2);
var dateEnd = dt.getValue(row, 3);
var oneHour = (60 * 1000);
var duration = (dateEnd.getTime() - dateBegin.getTime()) / oneHour;
var tooltip = '<div><div class="ggl-tooltip"><span>';
tooltip += dt.getValue(row, 0) + ':</span> ' + dt.getValue(row, 1) + '</div>';
tooltip += '<div class="ggl-tooltip"><div>' + formatTime.formatValue(dateBegin) + ' - ';
tooltip += formatTime.formatValue(dateEnd) + '</div>';
tooltip += '<div><span>Duration: </span>' + duration.toFixed(0) + ' minutes</div>';
tooltip += '<div><span>Estate: </span>' + dt.getValue(row, 5) + '</div></div>';
return tooltip;
},
p: {html: true}
}, 2, 3]);
google.visualization.events.addListener(chart, 'ready', function () {
var labels = container.getElementsByTagName('text');
Array.prototype.forEach.call(labels, function (label) {
label.setAttribute('font-weight', 'normal');
});
});
chart.draw(view.toDataTable(), options);
})
setTimeout(function () {
drawChart();
}, 5000);
}
for starters, the old version of google charts should no longer be used.
replace the old library...
<script src="https://www.google.com/jsapi"></script>
with the new library...
<script src="https://www.gstatic.com/charts/loader.js"></script>
this will only change the load statement.
which can be found in the following snippet...
next, it appears you are loading the data from the server, here...
var obje = {{ devicejson|safe }};
JavaScript runs on the client.
so no matter how many times drawChart is called,
it will always use the same data received from the server on the first page load.
instead, try this...
create two pages, one that returns the data, and the other that draws the chart.
then you can use AJAX to get the data and draw the chart as many times as needed.
create a new page, and all you really need in the new page is the following line of code.
{{ devicejson|safe }}
aside from any header information, and existing code you're using to get the data to the current page.
but you don't want to assign it to a variable in the new page.
just write the data to the page using the above statement.
then you can use AJAX to get the data and draw the chart.
function getData() {
$.ajax({
url: 'get_data.url', // <-- use url to new page here
dataType: 'JSON'
}).done(function (data) {
drawChart(data);
});
}
then, wait for the chart's ready event, before calling setTimeout.
because we don't know how long it will take to get the data and draw the chart.
so let's wait for the first chart to finish, before trying again.
see following snippet...
google.charts.load('current', {
packages:['timeline']
}).then(getData); // <-- load google charts, then get the data
function getData() {
$.ajax({
url: 'get_data.url', // <-- use url to new page here
dataType: 'JSON'
}).done(function (data) {
drawChart(data); // <-- draw chart with data from new page
});
}
function drawChart(obje) {
$(".timeline").each(function () {
var elem = $(this),
id = elem.attr('id');
var container = document.getElementById(id);
var chart = new google.visualization.Timeline(container);
var dataTable = new google.visualization.DataTable();
dataTable.addColumn({type: 'string', id: 'Role'});
dataTable.addColumn({type: 'string', id: 'Name'});
dataTable.addColumn({type: 'date', id: 'Start'});
dataTable.addColumn({type: 'date', id: 'End'});
dataTable.addColumn({type: 'string', id: 'TimeEst'});
dataTable.addColumn({type: 'string', role: 'style'});
for (n = 0; n < obje.length; ++n) {
if (obje[n].device_id == id) {
dataTable.addRows([
['Department', obje[n].digitaloutput_user_description, new Date('"' + obje[n].startdatetime + '"'), new Date('"' + obje[n].enddatetime + '"'), obje[n].lighstate_user_description, obje[n].color],
]);
}
}
for (n = 0; n < obje.length; ++n) {
if (obje[n].device_id == id) {
console.log(obje[n].color)
}
}
var options = {
chartArea: {
height: '90%',
width: '100%',
top: 36,
right: 12,
bottom: 2,
left: 12
},
height: 100,
tooltip: {isHtml: true},
timeline: {
showRowLabels: false,
},
avoidOverlappingGridLines: false,
{#hAxis: {format: 'dd-MMM-yyyy HH:mm:ss'}#}
};
var formatTime = new google.visualization.DateFormat({
pattern: 'yyyy-MM-dd HH:mm:ss a'
});
var view = new google.visualization.DataView(dataTable);
view.setColumns([0, 1, {
role: 'tooltip',
type: 'string',
calc: function (dt, row) {
// build tooltip
var dateBegin = dt.getValue(row, 2);
var dateEnd = dt.getValue(row, 3);
var oneHour = (60 * 1000);
var duration = (dateEnd.getTime() - dateBegin.getTime()) / oneHour;
var tooltip = '<div><div class="ggl-tooltip"><span>';
tooltip += dt.getValue(row, 0) + ':</span> ' + dt.getValue(row, 1) + '</div>';
tooltip += '<div class="ggl-tooltip"><div>' + formatTime.formatValue(dateBegin) + ' - ';
tooltip += formatTime.formatValue(dateEnd) + '</div>';
tooltip += '<div><span>Duration: </span>' + duration.toFixed(0) + ' minutes</div>';
tooltip += '<div><span>Estate: </span>' + dt.getValue(row, 5) + '</div></div>';
return tooltip;
},
p: {html: true}
}, 2, 3]);
google.visualization.events.addListener(chart, 'ready', function () {
var labels = container.getElementsByTagName('text');
Array.prototype.forEach.call(labels, function (label) {
label.setAttribute('font-weight', 'normal');
});
setTimeout(getData, 5000); // <-- get data and draw again in 5 seconds
});
chart.draw(view.toDataTable(), options);
});
}
I'm trying to add gauges dynamically and actually it works but not with the expected behavior, the graphics are shown but the value is 0 even when the graph shows that is not 0, my gauges will be show in a onclick event the divs and the gauges are created in a ajax request.
function getLocationsGauge(row, countryId) {
var chartsDataTemp;
var requestData = {
countryId: $("#hCountryName" + countryId).val()
};
$("div").removeClass("blurELearning");
$("#gg" + countryId).addClass("blurELearning");
$.ajax({
type: 'GET',
dataType: 'json',
contentType: 'application/json',
url: '../XXX/GetLocations',
async: false,
data: requestData,
success: function (chartsdata) {
chartsDataTemp = chartsdata;
$(".location").remove();
$("#divLocations").remove();
var count = chartsdata.length / 6;
$('#countryGraphs section:eq(' + (row) + ')').after('<div id="divLocations" class="card card-info"><div class="card-header"><strong class="header-block">' + $("#hCountryName" + countryId).val() + '</strong></div></div>');
for (var i = 0; i <= count; i++) {
$('#divLocations').append('<section id="location' + i + '" class="section location"><div id="rowLocation' + i + '" class="row"></div></section>');
for (var j = i * 6; j < (i + 1) * 6; j++) {
$('#rowLocation' + i).append('<div class="col-md-2"><div id= "ggLocation' + (j + 1) + '" ></div ></div >');
}
}
for (var i = 0; i < chartsdata.length; i++) {
var limit = Number(chartsdata[i].total) * 0.8;
var total = Number(chartsdata[i].total);
var approved = Number(chartsdata[i].approved);
var name = chartsdata[i].location;
var percentage = approved * 100 / total;
percentage = parseFloat(Math.round(percentage * 100) / 100).toFixed(2)
var x = "ggLocation" + (i + 1);
objectsLocation[i] = new JustGage({
id: x,
value: approved,
min: 0,
max: total,
gaugeWidthScale: 1,
counter: true,
hideInnerShadow: true,
title: name + ' ' + percentage + '%',
label: "approved",
levelColors: ["#a9d70b", "#ffd6b6", "#fe9e50"],
levelColorsGradient: true,
pointer: true,
pointerOptions: {
toplength: 1,
bottomlength: -40,
bottomwidth: 6,
color: '#8e8e93'
}
});
}
},
complete: function () {
},
error: function () {
alert("Error loading data for location! Please try again.");
}
});}
After a lot of effort I decide to modify the html code directly with javascript.
After creating the object (JustGage) in the for I accessed the span object which contains the text and modified the value
var list = document.getElementById(x);
var list2 = list.childNodes[0];
list2.childNodes[6].childNodes[0].innerHTML = approved;
I'm trying to edit the tooltip in a c3 line-chart. Specifically, I need to access the current x-value within the chart.tooltip.format.value function. However, the function is not passed the x-value explicitly.
var chart = c3.generate({
tooltip: {
format: {
value: function (value, ratio, id, index) {
return value;
}
}
},
data: {
x: 'YEAR',
xFormat: '%Y',
url: myURL',
},
axis: {
x: {
type: 'timeseries',
tick: {
format: '%Y'
}
},
},
});
You can use the tooltip's contents property to create a custom tooltip, and in there you can access the X value via: d[0].x.
Edit: use d[0].x.getFullYear() to retrieve only the year part of the date (it's a time series so C3 internally stores the supplied year as a javascript date object)
Here's code I've taken from this discussion https://github.com/c3js/c3/issues/444, and modified:
function tooltip_contents(d, defaultTitleFormat, defaultValueFormat, color) {
var $$ = this, config = $$.config, CLASS = $$.CLASS,
titleFormat = config.tooltip_format_title || defaultTitleFormat,
nameFormat = config.tooltip_format_name || function (name) { return name; },
valueFormat = config.tooltip_format_value || defaultValueFormat,
text, i, title, value, name, bgcolor;
// You can access all of data like this:
//console.log($$.data.targets);
for (i = 0; i < d.length; i++) {
if (! (d[i] && (d[i].value || d[i].value === 0))) { continue; }
// to exclude
//if (d[i].name === 'data2') { continue; }
if (! text) {
title = 'MY TOOLTIP # ' + d[0].x.getFullYear(); // SHOW X-VALUE, year only (given it is a time series)
text = "<table class='" + CLASS.tooltip + "'>" + (title || title === 0 ? "<tr><th colspan='2'>" + title + "</th></tr>" : "");
}
name = nameFormat(d[i].name);
value = valueFormat(d[i].value, d[i].ratio, d[i].id, d[i].index);
bgcolor = $$.levelColor ? $$.levelColor(d[i].value) : color(d[i].id);
text += "<tr class='" + CLASS.tooltipName + "-" + d[i].id + "'>";
text += "<td class='name'><span style='background-color:" + bgcolor + "'></span>" + name + "</td>";
text += "<td class='value'>" + value + "</td>";
text += "</tr>";
}
return text + "</table>";
}
var chart = c3.generate({
data: {
x: 'year',
xFormat: '%Y',
columns: [
['year', '1970', '1975', '1980', '1985', '1990'],
['data1', 100, 200, 150, 300, 200],
['data2', 400, 500, 250, 700, 300],
]
},
axis: {
x: {
type: 'timeseries',
tick: {
format: '%Y'
}
},
},
tooltip: {
contents: tooltip_contents
}
});
My fiddle, showing the current x-value: http://jsfiddle.net/w7h385h3/5/
I've combined a jquery datepicker widget with jqplot, and am using the values of the datepicker to recreate the plot when something changes.
However, during large date ranges, the labels on the x-axis run together to look very ugly.
Here's it regularly:
Here's it with a large range:
My question is -- is it possible to change the rendering of the axis, so if there is a large range that not every single date shows? Maybe 2 or 3, but always including the beginning date and end date.
Here's my code -- please let me know if you can help!
$(document).ready(function(){
var ajaxDataRenderer = function(url, plot, options) {
var ret = null;
$.ajax({
async: false,
url: url,
type: "GET",
dataType:"json",
data: {metricName: ""},
success: function(data) {
ret = data;
},
error:function (xhr, ajaxOptions, thrownError){
alert(xhr.responseText);
}
});
return ret;
};
//var jsonurl = "reports/reportData.json";
var jsonurl = "tenant/metrics/get.json";
var currentTime = new Date()
var month = currentTime.getMonth() + 1;
var day = currentTime.getDate();
var year = currentTime.getFullYear();
var today = month + "-" + day + "-" + year;
var currentDatePlus = new Date(new Date().getTime() + 24 * 60 * 60 * 1000);
var dayPlus = currentDatePlus.getDate()
var monthPlus = currentDatePlus.getMonth() + 1
var yearPlus = currentDatePlus.getFullYear()
var tomorrow = monthPlus + "/" + dayPlus + "/" + yearPlus;
function getLastWeek(){
var today = new Date();
var lastWeek = new Date(today.getFullYear(), today.getMonth(), today.getDate() - 7);
return lastWeek ;
}
var lastWeek = getLastWeek();
var lastWeekMonth = lastWeek.getMonth() + 1;
var lastWeekDay = lastWeek.getDate();
var lastWeekYear = lastWeek.getFullYear();
var lastWeekDisplay = lastWeekMonth + "/" + lastWeekDay + "/" + lastWeekYear;
var datepickerBegin = $("#datepicker_start").val();
var datepickerEnd = $("#datepicker_to").val();
$('#applyBtn').click( function() {
// Check to make sure the datepicker isn't empty
if ($("#datepicker_start").val() !== "" && $("#datepicker_to").val() !== "") {
var datepickerBegin = $("#datepicker_start").val();
var datepickerEnd = $("#datepicker_to").val();
//Recreate the plot
var plot2 = $.jqplot('chart2', jsonurl,{
title: "",
dataRenderer: ajaxDataRenderer,
dataRendererOptions: {unusedOptionalUrl: jsonurl},
axes: {
xaxis: {
//'numberTicks' : 7,
min: datepickerBegin,
max: datepickerEnd,
renderer:$.jqplot.DateAxisRenderer,
rendererOptions:{tickRenderer:$.jqplot.CanvasAxisTickRenderer},
tickInterval: '1 day',
tickOptions:{formatString:'%#m/%#d/%Y'
}
//rendererOptions: {sdaTickInterval: [1, 'month']}
},
yaxis: {
label: "MB",
tickOptions:{formatString:'%d '},
// Comment the next line out to allow negative values (and therefore rounded ones)
min: 0
}
},
highlighter: {
show: true,
sizeAdjust: 7.5
}
});
//redraw the plot now.
//plot2.reInitialize({});
plot2.replot({});
}
})
// The default plot
var plot2 = $.jqplot('chart2', jsonurl,{
title: "",
dataRenderer: ajaxDataRenderer,
dataRendererOptions: {unusedOptionalUrl: jsonurl},
axes: {
xaxis: {
//'numberTicks' : 7,
min: lastWeekDisplay,
max: tomorrow,
renderer:$.jqplot.DateAxisRenderer,
rendererOptions:{tickRenderer:$.jqplot.CanvasAxisTickRenderer},
tickInterval: '1 day',
tickOptions:{formatString:'%#m/%#d/%Y'
}
//rendererOptions: {sdaTickInterval: [1, 'month']}
},
yaxis: {
label: "MB",
tickOptions:{formatString:'%d '},
// Comment the next line out to allow negative values (and therefore rounded ones)
min: 0
}
},
highlighter: {
show: true,
sizeAdjust: 7.5
}
});
});
Okay - I've got a better grasp on this issue.
I've limited the tick number using the 'numberTicks' property, so it has a certain number if the date range is over a specificed value.
The only issue left is that, with numberTicks, the intersections aren't always correct (meaning that on the x-axis 10/05/12, the value isn't always placed there when numberTicks is limited.