ChartJS - legends and tooltips options - javascript

This is the first time I'm using ChartJS v2.
I creating a simple line chart with several datasets.
I have 3 problems:
1 - It has the correct data shown, but I have a problem with the legends, as they appear left aligned with the color box out of the canvas, and one per line like in the image bellow (https://i.stack.imgur.com/c9qBe.png).
I want the legends like float: left; in css.
2 - Other problem is the tooltips, they're very big.. like shown in the image bellow. (https://i.stack.imgur.com/txXCF.png)
I tried to find the options to achieve this but it hard for me to make it work.
3 - I want the interval in the y-axis to be 1 not 0.1.
Bellow is the JS code used to create the chart:
var scripts = $(".sending-data");
var datasets = [];
var days = [];
var counter = 0;
scripts.each(function (index, script){
var json = JSON.parse(script.innerHTML);
var data = [];
for (var i = 0; i<json.DATA.length; i++) {
data.push(json.DATA[i][2]);
if (counter === 0)
days.push(json.DATA[i][1].substr(8, 2));
}
var r = Math.floor((Math.random() * 255) + 1);
var g = Math.floor((Math.random() * 255) + 1);
var b = Math.floor((Math.random() * 255) + 1);
var rgbStr = r+ ", " +g + ", " + b;
console.log(rgbStr);
datasets.push({
label: "## " + $(script).attr("data-send-id"),
backgroundColor: 'rgba('+rgbStr+', 0.2)',
borderColor: 'rgba('+rgbStr+', 1)',
borderWidth: 2,
lineTension: 0.1,
data: data,
fill: false
});
counter++;
});
var config ={
type: 'line',
data: {
labels: days,
datasets: datasets
},
options: {
title: {
display: true,
text: 'Custom Chart Title'
},
responsive : true,
legend: {
fullWidth: false,
boxWidth: 50,
padding: 40,
position: "top",
display: true
},
scales: {
yAxes: [{
ticks: {
beginAtZero:true,
stepSize: 1
}
}]
}
}
};
var ctx = document.querySelector("##canvas-chart").getContext("2d");
console.log(document.querySelector("##canvas-chart"));
var myLine = new Chart(ctx, config);
Dont mind the '##' selector, I'm using CFusion.
Any help from you guys?
--DISCLAIMER--
I managed to set the stepSize: 1 so the interval is 1. But still have the problem (1) and (2)
Thanks in advance!
Happy Programming!

So the problem is this - I'm dumb..
hahaha
The dataset labels had a lot of whitespace... so I just replaced all " " by "" and it showed correctly..
Thanks to all of you.
Cheers and happy programming!

Related

Can i use crosshairs with OHLC/candlestick charts using ChartJS

I have installed the crosshair plugin and am using chartJS 3.0 to take advantage of the candlestick charts but the crosshair does not appear. are these things compatible together? my data appear no problem but the crosshair never appears. how do i use these two things together? are there any working examples?
the tags i am using
<script src="https://cdn.jsdelivr.net/npm/luxon#1.24.1"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js#3.0.0-beta.9/dist/chart.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-luxon#0.2.1"></script>
<script src="https://dd7tel2830j4w.cloudfront.net/f1614793727236x392906938665549250/chartjs-chart-financial.js"></script>
<script scr="https://cdn.jsdelivr.net/npm/chartjs-plugin-crosshair"></script>
and the chart code which also works
var divID = "chartContainer" + properties.chartid
var chartID = "myChart" + properties.chartid
instance.canvas.append('<div id="' + divID + '"></div>')
document.getElementById(divID).innerHTML = ' ';
document.getElementById(divID).innerHTML = '<canvas id=' + chartID + ' width="' + properties.bubble.width() + '" height="' + properties.bubble.height() + '"></canvas>';
var ctx = document.getElementById(chartID).getContext('2d');
var chart = new Chart(ctx, {
type: 'candlestick',
data: {
datasets: [{
label: 'CHRT - Chart.js Corporation',
data: getData()
}]
},
options: {
scales: {
y: {
min: 0,
max: 500
}
},
tooltips: {
mode: "interpolate",
intersect: false
},
plugins: {
crosshair: {
line: {
color: '#F66', // crosshair line color
width: 3, // crosshair line width
dashPattern: [5, 5] // crosshair line dash pattern
},
sync: {
enabled: true, // enable trace line syncing with other charts
group: 1, // chart group
suppressTooltips: false // suppress tooltips when showing a synced tracer
},
zoom: {
enabled: true, // enable zooming
zoomboxBackgroundColor: 'rgba(66,133,244,0.2)', // background color of zoom box
zoomboxBorderColor: '#48F', // border color of zoom box
zoomButtonText: 'Reset Zoom', // reset zoom button text
zoomButtonClass: 'reset-zoom', // reset zoom button class
},
callbacks: {
beforeZoom: function(start, end) { // called before zoom, return false to prevent zoom
return true;
},
afterZoom: function(start, end) { // called after zoom
}
}
}
}
}
});
function getData() {
var dates = properties.time.get(0, properties.time.length())
var opens = properties.open.get(0, properties.open.length())
var highs = properties.high.get(0, properties.high.length())
var lows = properties.low.get(0, properties.low.length())
var closes = properties.close.get(0, properties.close.length())
let data = []
for (i = 0; i < dates.length; i++) {
data.push({
t: dates[i].valueOf(),
o: opens[i],
h: highs[i],
l: lows[i],
c: closes[i]
})
}
console.log(data)
return data
}
chart.update()
The crosair plugin is not yet compatible with the new beta of version 3. They have a pr to be up to date with beta 11 but after that there have been breaking changes again. So you will have to update the plugin yourself or wait till it has been updated to support v3

How can I add a label above just the last bar in a Chart.JS bar chart?

I am creating a bar chart like so:
var ctxForecastChart = $("#forecastLineChart").get(0).getContext("2d");
var forecastChartData = {
labels: [
"Total Sales"
],
datasets: [
{
label: "8/28/2016 - 9/3/2016",
backgroundColor: "rgba(255,0,0,0.75)",
hoverBackgroundColor: "rgba(255,0,0,1)",
data: [240]
},
{
label: "9/25/2016 - 10/2/2016",
backgroundColor: "rgba(255,153,0,0.75)",
hoverBackgroundColor: "rgba(255,153,0,1)",
data: [272]
},
{
label: "9/18/2016 - 9/24/2016",
backgroundColor: "rgba(255,255,0,0.75)",
hoverBackgroundColor: "rgba(255,255,0,1)",
data: [250]
},
{
label: "9/4/2016 - 9/10/2016",
backgroundColor: "rgba(0,255,0,0.75)",
hoverBackgroundColor: "rgba(0,255,0,1)",
data: [232]
},
{
label: "9/11/2016 - 9/17/2016",
backgroundColor: "rgba(0,0,255,0.75)",
hoverBackgroundColor: "rgba(0,0,255,1)",
data: [244]
}]
};
var forecastOptions = {
tooltips: {
enabled: true
}
};
var forecastBarChart = new Chart(ctxForecastChart,
{
type: 'bar',
data: forecastChartData,
options: forecastOptions
});
This looks like so:
What I want to do is to add a label above the last bar (the blue one) with a percentage difference between the previous/4th one and that one. In this case, the value should be "+5.2%" so that it looks like this:
I reckon this will require the registring of an afterDraw() event, but the nitty-gritty of how it should look is beyond me.
UPDATE
If I add this to the proposed code:
if (chartInstance.id !== 2) return; // affect this one only
In context:
afterDraw: function (chartInstance) {
if (chartInstance.id !== 2) return; // affect this one only
// We get the canvas context
var ctx = chartInstance.chart.ctx;
...the results are a little better than without it (which mangles my first (pie) chart and completely obliterates the next two (including the one being discussed here):
As you can see, the pie chart is still hosed, and the values in the two bar charts are shrunken down as if a cannibalistic tribe has perpetrated its inicuous tricks on them. And, there is no value added atop the final bar.
First, you were right thinking about using the afterDraw event with a plugin and I understand it can be quite a mess to find what we really want in all the data and options.
Yet, follows a plugin that will help you do what you are looking for :
var myPlugin = {
afterDraw: function(chartInstance) {
// We get the canvas context
var ctx = chartInstance.chart.ctx;
// And set all the properties we need
ctx.font = Chart.helpers.fontString(14, 'bold', Chart.defaults.global.defaultFontFamily);
ctx.textAlign = 'center';
ctx.textBaseline = 'bottom';
ctx.fillStyle = '#666';
// We get the number of datasets we have in your chart
var numOfDatasets = chartInstance.config.data.datasets.length;
// For every dataset in our chart ...
chartInstance.data.datasets.forEach(function(dataset) {
// If it is not the last dataset, we return now (no action at all)
if (dataset._meta[0].controller.index != numOfDatasets - 1) return;
// For every data in the dataset ...
for (var i = 0; i < dataset.data.length; i++) {
// We get the previous dataset (to compare later)
var previousDataset = chartInstance.config.data.datasets[dataset._meta[0].controller.index - 1];
// And get the model of the current value
var model = dataset._meta[Object.keys(dataset._meta)[0]].data[i]._model;
// We calculate the percentage difference with the previous
var value = ((dataset.data[i] - previousDataset.data[i]) / previousDataset.data[i]) * 100;
// And write it with a "%" symbol
// The ternary adds a "+" symbol if it is a positive value
ctx.fillText((value > 0 ? "+" : "") + value.toFixed(1) + "%", model.x, model.y);
}
});
}
};
Chart.pluginService.register(myPlugin);
You can see this code working on this jsFiddle and here is its result :

How to add links to chart.js (Doughnut Charts)?

I would like to add links to doughnut charts to be able to send the user for a page with the records filtered by the clicked option.
For example here, if the user click on "Green", I want to send the user to a page that will show all "Green" records.
I didn't find a easy way to do that, and tried something like this that isn't working yet:
(I added a attribute "filter" with the "id" that I need to filter it)
var data = [
{
value: 300,
color:"#F7464A",
highlight: "#FF5A5E",
label: "Red",
filter: 1
},
{
value: 50,
color: "#46BFBD",
highlight: "#5AD3D1",
label: "Green",
filter: 2
},
{
value: 100,
color: "#FDB45C",
highlight: "#FFC870",
label: "Yellow",
filter: 3
}
]
$(document).ready(
function () {
$("#chart").click(
function(evt){
var activePoints = chart.getSegmentsAtEvent(evt);
var url = "http://example.com/?grid[f][collor][]=" + activePoints[0].filter
alert(url);
}
);
}
);
I'm not being able to get the attribute "filter" using "activePoints[0].filter"
Thank you.
Adding custom properties in JSON is a feature that may be on the roadmap for v2 (https://github.com/nnnick/Chart.js/issues/1185). As it currently stands, you can add properties in javascript doing something like this:
var segments = chart.segments;
for (var i = 0; i < segments.length; i++) {
segments[i].filter = i+1;
}
Here's a jsfiddle with the filter/id property loading in the url (http://jsfiddle.net/tcy74pcc/1/):
If you want to do this with a chart based on points rather than segments, here's a post with a similar solution for lines:
Displaying custom dataset properties in tooltip in chart.js
Hope that helps. Best of luck!
getSegmentsAtEvent is now deprecated. Use getElementsAtEvent instead.
Here's the complete function with added bonus of having dynamic colors for each segment.
var piChart = function (ctx, labelName, labels, values, filters) {
var colors = dynamicColors(values.length)
var data = {
labels: labels,
datasets: [
{
label: labelName,
backgroundColor: colors.backColors,
hoverBackgroundColor: colors.highColors,
borderColor: colors.borders,
hoverBorderColor: colors.borders,
borderWidth: 1,
data: values
}
]
};
var pieChart = new Chart(ctx, {
type: "pie",
data: data
});
if (filters != null) {
ctx.click(
function (evt) {
var activePoints = pieChart.getElementAtEvent(evt);
if (activePoints.length > 0) {
var index = activePoints[0]["_index"];
location.href = filters[index];
}
});
}
}
var dynamicColors = function (count) {
var backColors = [];
var highColors = [];
var borders = [];
for (var i = 0; i < count; i++) {
var r = Math.floor(Math.random() * 255);
var g = Math.floor(Math.random() * 255);
var b = Math.floor(Math.random() * 255);
var backColor = "rgba(" + r + "," + g + "," + b + ", 0.4)";
var highColor = "rgba(" + r + "," + g + "," + b + ", 0.8)";
var border = "rgba(" + r + "," + g + "," + b + ", 1)";
backColors.push(backColor);
highColors.push(highColor);
borders.push(border);
}

How I can have different values and different labels at graphael?

I am using a linechart at graphael. My datapoints are dates,which are not recognisable by the graphael. So I have represented every date, using 1,2,3 ....
The fact is that I need to display dates at my chart, as the x axis labels. How I can do that? I tried the label property, but it does not working.
My code is shown below:
var lines = r.linechart(30, 30, 600, 440,[[1,2,3,4,5]],[[100,150,130,85,100]], {axisxstep : 20,nostroke: false, axis: "0 0 1 1", symbol: "circle", smooth: true }).hoverColumn(function () {
this.tags = r.set();
for (var i = 0, ii = this.y.length; i < ii; i++) {
this.tags.push(r.tag(this.x, this.y[i], this.values[i], 160, 10).insertBefore(this).attr([{ fill: "#fff" }, { fill: this.symbols[i].attr("fill") }]));
}
}, function () {
this.tags && this.tags.remove();
});
Take a look at this fiddle. You have to change the attribute of each label (date for us) inside chartobject:
var lineChart = r.linechart(0, 0, 200, 250, xValues, yValues1, {
smooth: true,
colors: ['#F00', '#0F0', '#FF0'],
symbol: 'circle',
axis: '0 0 1 1'
});
for (var i = 0; i < lineChart.axis[0].text.items.length; i++) {
var label = lineChart.axis[0].text.items[i];
var originalDate = new Date(parseInt(label.attr('text'), 10));
var newText = originalDate.getDate() + "/" + (originalDate.getMonth() + 1) + "/" + (originalDate.getFullYear());
label.rotate(60);
label.attr({
'text': newText
});
}
Also, the data for graphael can only be numerical type to plot the graph, we have to create a Date object for each label in x like this:
var xValues = [
new Date("01/05/2014"),
new Date("01/06/2014"),
new Date("01/07/2014"),
new Date("01/08/2014"),
new Date("01/09/2014"),
new Date("01/10/2014"),
new Date("01/11/2014"),
new Date("01/12/2014"),
new Date("01/13/2014")
];

Flot Stacked Bar Chart and displaying bar values on mouse over

I'm trying to understand the tooltip functionality of Flot but not really getting my head around it!
I am trying to achieve a tooltip that displays the label and value of each section of a stacked bar chart
Would someone be able to point my towards an example of this or provide code for doing so?
The following code works for my Flot stacked bar chart, based on the Flot example that shows data point hover. The trick is that the 'item' values in the stacked chart are cumulative, so the 'y' value displayed in the tool tip has to first subtract the datapoint for the bars underneath.
var previousPoint = null;
$("#chart").bind("plothover", function (event, pos, item) {
if (item) {
if (previousPoint != item.datapoint) {
previousPoint = item.datapoint;
$("#tooltip").remove();
var x = item.datapoint[0],
y = item.datapoint[1] - item.datapoint[2];
showTooltip(item.pageX, item.pageY, y + " " + item.series.label);
}
}
else {
$("#tooltip").remove();
previousPoint = null;
}
});
I did not find this in the Flot documentation, but the item.datapoint array seemed to contain what I needed in practice.
The code above caused redraw-issues for me.
Here is an improved code:
var previousPoint = [0,0,0];
$("#regionsChart").bind("plothover", function (event, pos, item) {
if (item) {
if (previousPoint[0] != item.datapoint[0]
|| previousPoint[1] != item.datapoint[1]
|| previousPoint[2] != item.datapoint[2]
) {
previousPoint = item.datapoint;
$("#tooltip").remove();
var x = item.datapoint[0],
y = item.datapoint[1] - item.datapoint[2];
showTooltip(item.pageX, item.pageY, item.series.label + " " + y.toFixed(0) );
}
}
else {
$("#tooltip").remove();
previousPoint = [0,0,0];
}
});
This is the same as Thomas above, except that I shifted the tooltip up to prevent it blocking the hover action.
var previousPoint = [0,0,0];
$("#regionsChart").bind("plothover", function (event, pos, item) {
if (item) {
if (previousPoint[0] != item.datapoint[0]
|| previousPoint[1] != item.datapoint[1]
|| previousPoint[2] != item.datapoint[2]
) {
previousPoint = item.datapoint;
$("#tooltip").remove();
var x = item.datapoint[0],
y = item.datapoint[1] - item.datapoint[2];
showTooltip(item.pageX, item.pageY - 35, item.series.label + " " + y.toFixed(0) );
}
}
else {
$("#tooltip").remove();
previousPoint = [0,0,0];
}
});
The solution is using tooltipOpts -> content method with a callback function to properly return dynamic data to the label.
I figured out that passing a 4th argument to the callback function of the "tooltipOpts" actually gives you the whole data object from which the chart/graph is constructed from.
From here, you can easily extract the X axis labels, using the second argument of this same function as the index of the label to extract.
EXAMPLE:
Data object I'm passing to the plot function:
[
{ data: [[1,137],[2,194],[3,376],[4,145],[5,145],[6,145],[7,146]] }
],
{
bars: { show: true, fill: true, barWidth: 0.3, lineWidth: 1, fillColor: { colors: [{ opacity: 0.8 }, { opacity: 1}] }, align: 'center' },
colors: ['#fcc100'],
series: { shadowSize: 3 },
xaxis: {
show: true,
font: { color: '#ccc' },
position: 'bottom',
ticks: [[1,'Thursday'],[2,'Friday'],[3,'Saturday'],[4,'Sunday'],[5,'Monday'],[6,'Tuesday'],[7,'Wednesday']]
},
yaxis:{ show: true, font: { color: '#ccc' }},
grid: { hoverable: true, clickable: true, borderWidth: 0, color: 'rgba(120,120,120,0.5)' },
tooltip: true,
tooltipOpts: {
content: function(data, x, y, dataObject) {
var XdataIndex = dataObject.dataIndex;
var XdataLabel = dataObject.series.xaxis.ticks[XdataIndex].label;
return y + ' stories created about your page on ' + XdataLabel
},
defaultTheme: false,
shifts: { x: 0, y: -40 }
}
}
Bar chart rendered from the above data object:
As you can see on the image preview, the logic used to render the label's content dynamically form the actual data is this:
tooltipOpts: {
content: function(data, x, y, dataObject) {
var XdataIndex = dataObject.dataIndex;
var XdataLabel = dataObject.series.xaxis.ticks[XdataIndex].label;
return y + ' stories created about your page on ' + XdataLabel;
},
defaultTheme: false,
shifts: { x: 0, y: -40 }
}

Categories

Resources