Customizing Chart.js troubleshoot - javascript

Have some trouble with Chart.js
1) is it possible to move bottom labels on top of the chart?
2) is it possible to hide left labels with first grey line?
3) is it possible to set up permanent tooltips(to show temperature) on every point instead of hover tooltips?
Here is my chart http://jsfiddle.net/JohnnyJuarez/ojc09hv4/:
<canvas id="weeksChart" width="651" height="335"></canvas>
var dayTemperatureArray = [-5, 14, 15, 15, 17, 18, 19, 21, 22, 25, 24, 20, 19, 16];
var nightTemperatureArray = [-10, 4, 5, 6, 8, 11, 12, 15, 17, 15, 13, 12, 11, 9];
var dataWeeks = {
labels: ["16.02", "17.02", "18.02", "19.02", "20.02", "21.02", "22.02", "23.02", "24.02", "25.02", "26.02", "27.02", "28.02", "01.03"],
datasets: [
{
label: "Days temperature chart",
fillColor: "transparent",
strokeColor: "rgba(244, 6, 6, 1)",
data: dayTemperatureArray
},
{
label: "Nights temperature chart",
strokeColor: "#3f6bf5",
data: nightTemperatureArray
}
]
};
var ctx = document.getElementById("weeksChart").getContext("2d");
window.weeksChart = new Chart(ctx).Line(dataWeeks, {
responsive: true,
pointDot: true,
datasetStrokeWidth: 0.5,
scaleSteps: 2,
scaleLabel: "<%=value + '°'%>",
tooltipTemplate: "<%= value %>",
showTooltips: true
});
Thanx a lot in advance!
p.s. please avoid jquery, if it's possible :-)

Let's start with the easiest one first
2) is it possible to hide left labels with first grey line?
I assume you meant the y axis labels. You can set the scaleShowLabels option to false in the chart options to hide the y axis labels
window.weeksChart = new Chart(ctx).Line(dataWeeks, {
scaleShowLabels: false,
...
1) is it possible to move bottom labels on top of the chart?
I assume you mean the x axis labels. Chart.js doesn't have a direct option to do this. However you can hide the actual x axis labels and draw the x axis labels at the top of the chart by yourself.
Again, Chart.js doesn't have an option to hide x axis labels, but luckily there is an option to control the scale font color. Just set it to transparent and your original x axis labels are now hidden!
window.weeksChart = new Chart(ctx).Line(dataWeeks, {
scaleFontColor: "transparent",
...
Now the drawing of the x axis labels at the top of the chart. To save us the trouble of extending the chart, we can add a post animation event handler and do this in that, like so
window.weeksChart = new Chart(ctx).Line(dataWeeks, {
onAnimationComplete: function () {
animationComplete.apply(this)
}
...
with
var animationComplete = function () {
var self = this;
Chart.helpers.each(self.datasets[0].points, function (point, index) {
self.chart.ctx.font = Chart.helpers.fontString(self.fontSize, self.fontStyle, self.fontFamily)
self.chart.ctx.textAlign = 'center';
self.chart.ctx.textBaseline = "middle";
self.chart.ctx.fillStyle = "#666";
self.chart.ctx.fillText(point.label, point.x, self.scale.startPoint);
});
};
We just loop through all points in one of the dataset and add the labels (scale.startPoint is the top edge of the chart area)
Note - why do we set the font, alignment, etc. every iteration? That's for when we add the tooltips.
3) is it possible to set up permanent tooltips(to show temperature) on every point instead of hover tooltips?
The first step would be to actually show the tooltips. This is fairly simple, though a bit tedious. We loop through all the x axis point, build the label (by going through each dataset) and then construct a tooltip (fortunately, we can use Chart.MultiTooltip function for this.
We add it into the same loop we used to construct the new x axis labels. Since we need to color our tooltips, we need to get and store the set of colors in an array (which we pass on to the MultiTooltip function - we need to do this only once, so we take it out of the loop.
The modified animationComplete function is now this
var animationComplete = function () {
var self = this;
var tooltipColors = []
Chart.helpers.each(self.datasets, function (dataset) {
tooltipColors.push({
fill: dataset.strokeColor,
stroke: dataset.strokeColor
})
});
Chart.helpers.each(self.datasets[0].points, function (point, index) {
var labels = []
var total = 0;
Chart.helpers.each(self.datasets, function (dataset) {
labels.push(dataset.points[index].value)
total += Number(dataset.points[index].y);
});
new Chart.MultiTooltip({
x: point.x,
y: total / 2,
xPadding: self.options.tooltipXPadding,
yPadding: self.options.tooltipYPadding,
xOffset: self.options.tooltipXOffset,
fillColor: self.options.tooltipFillColor,
textColor: self.options.tooltipFontColor,
fontFamily: self.options.tooltipFontFamily,
fontStyle: self.options.tooltipFontStyle,
fontSize: self.options.tooltipFontSize,
titleTextColor: self.options.tooltipTitleFontColor,
titleFontFamily: self.options.tooltipTitleFontFamily,
titleFontStyle: self.options.tooltipTitleFontStyle,
titleFontSize: self.options.tooltipTitleFontSize,
cornerRadius: self.options.tooltipCornerRadius,
labels: labels,
legendColors: tooltipColors,
legendColorBackground: self.options.multiTooltipKeyBackground,
title: point.label,
chart: self.chart,
ctx: self.chart.ctx,
custom: self.options.customTooltips
}).draw()
self.chart.ctx.font = Chart.helpers.fontString(self.fontSize, self.fontStyle, self.fontFamily)
self.chart.ctx.textAlign = 'center';
self.chart.ctx.textBaseline = "middle";
self.chart.ctx.fillStyle = "#666";
self.chart.ctx.fillText(point.label, point.x, self.scale.startPoint);
});
};
It looks complex, but all we are doing is passing a options that we copy from the chart instance options to the MultiTooltip function.
The tooltips all show up when the animation is complete. HOWEVER, once you move your mouse over the chart they all up and disappear! That's because the chart instance listens for multiple events to decide whether to start checking if tooltips should be shown - one of these is mousemove (and that causes it to redraw the chart, wiping out all our hard drawn tooltips and, if we are lucky, it draws a tooltip based on the point our mouse is hovering over)
This is a configurable option. So, all we have to do is remove all such events.
window.weeksChart = new Chart(ctx).Line(dataWeeks, {
tooltipEvents: []
...
Working fiddle - http://jsfiddle.net/fuodxsfv/
Unless your chart is wide enough, you will have tooltips (mostly the middle 2 ones) overlap (of course you could incorporate logic into the above loop to handle that), but anyhoo, those were actually meant to be tooltips!

Related

c3js bar chart, align data to x tick start position (not centered)

If you take a normal bar chart from c3js, the bars will be centered at the x-tick position. I have a chart which goes hourly, so any timespan between 00-24 (usually like 8-16). If I have a line-chart or scatter plot it will align it self exactly on the x-tick nicely, but not as a step-chart or a bar chart.
var chart = c3.generate({
data: {
x: 'x',
columns: [
['x', 8, 9, 10, 11, 12, 13, 14, 15, 16],
['data1', 1, 1, 0, 1, 0, 0, 1, 1, 1],
],
type: "bar"
},
axis: {
x: {
type: "category",
categories: [],
}
}
});
See this fiddle: https://jsfiddle.net/jvcarphe/1/
I've been trying with all sorts of culling / tick values / time series etc. but I can't for the love of god figure out how to do it. If the type in the fiddle is changed to "line" it does exactly what I want, beside it's not a bar.
I've had to do this before and there doesn't seem to be a simple setting that does it, but a bit of d3 manipulation works. I came to the conclusion it's easier to move the ticks than the bars:
If you know the width of your bar, you can set a css rule to offset the ticks, just change the -10px to whatever is necessary -->
.c3-axis-x .tick line, .c3-axis-x .tick text {
transform: translate(-10px,0);
}
(can't just apply the rule to .tick as c3 overrides its transform style)
If you don't know the width then you need to find it out by querying one of the bars and applying the same style rule dynamically in c3's onrendered callback:
onrendered: function () {
var thisChart = d3.select(this.config.bindto);
var barWidth = thisChart.select(".c3-bar-0").node().getBoundingClientRect().width / 2;
thisChart.selectAll(".c3-axis-x .tick line,.c3-axis-x .tick text").style("transform", "translate(-"+barWidth+"px,0)");
}
Fiddle edited as newer version of c3 didn't work in the fiddle:
https://jsfiddle.net/15w50f06/4/

How to change the bar chart orientation in Google Charts

I need to draw two bar charts facing each other in one page. (The chart on the left faces right, and the one on the right faces left).
But with Google Charts, I only managed to make both charts face right.
Is it possible to implement? What should I do?
using a 100% stacked chart, you can get the bars to align to the right
then color the first series transparent,
and manipulate the data to reveal the proper length
then when the chart's 'ready' event fires,
you can move around the chart elements,
such as the y-axis, and the order of the x-axis labels
first, you need to allow enough room on the left,
for the original y-axis labels to print
otherwise they will be cutoff, i.e.
Canis Major Dwarf vs. Canis Maj...
then need to leave enough room on the right,
by limiting the chartArea, otherwise cutoff and simply not visible, i.e.
Canis Major Dwarf vs. Canis M
might be easier, providing your own labels
this should give you something to tweak on...
google.charts.load('current', {'packages':['corechart']});
google.charts.setOnLoadCallback(drawStuff);
function drawStuff() {
var data = new google.visualization.arrayToDataTable([
['Galaxy', 'Distance', 'Brightness'],
['Canis Major Dwarf', 10, 20],
['Sagittarius Dwarf', 20, 40],
['Ursa Major II Dwarf', 40, 50],
['Lg. Magellanic Cloud', 60, 80],
['Bootes I', 80, 120]
]);
var options = {
isStacked: 'percent',
colors: ['transparent', 'magenta'],
legend: {
position: 'bottom'
},
chartArea: {
left: 200,
width: 400
},
width: 800
};
var container = document.getElementById('dual_x_div');
var chart = new google.visualization.BarChart(container);
google.visualization.events.addListener(chart, 'ready', function () {
var labels = container.getElementsByTagName('text');
var hAxisLabels = [];
Array.prototype.forEach.call(labels, function (text, index) {
switch (text.getAttribute('text-anchor')) {
// move y axis labels
case 'end':
text.setAttribute('x', parseFloat(text.getAttribute('x')) + 540);
break;
// save x axis labels
case 'middle':
// save x position here
// otherwise, x position will change
// before you know where the next should have been
hAxisLabels.push({
text: text,
x: parseFloat(text.getAttribute('x'))
});
break;
}
});
// swap label positions
hAxisLabels.forEach(function (label, index) {
label.text.setAttribute('x', hAxisLabels[hAxisLabels.length - index - 1].x);
});
});
chart.draw(data, options);
};
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="dual_x_div"></div>

chart.js LIne Graphs: Fill area above line as opposed to below and to the right

I have a chart.js which displays two different lines, on which will always be positive and one which will always be negative.
I want to visualize the area between both lines and a value of 0 on the y axis and therefore want to fill in below the the positive line and above the negative line both ending at 0. Chart.js however always fills in the line to the bottom right of a given line as far as I cant tell.
Correct Behaviour: (from chartist.js)
Incorrect Behavior (from chart.js)
Does anyone know if it is possible to achieve something similar to the look of the first graph with chart.js?
edits:
I am using chart.js through it's ember plugin
{{ember-chart type='Line' data=dataPanelService.chartData width=500 height=600}}
so I am only passing in chartData. It should be using the default options.
The chart data in the dataPanelService:
chartData: {
labels: ["9 /15 /15", "9 /28 /15", "10 /5 /15", "10 /13 /15", "10 /19 /15", "10 /30 /15", "11 /15 /15"],
datasets: {
{
fillColor: "#FF1717",
pointColor: "#da3e2f",
data: [200000, 180000, 150000, 110000, 60000, 0, 0]
},
{
fillColor: "#4575b5",
pointColor: "#1C57A8",
data: [-300000, -300000, -300000, -150000, -150000, -20000, 0]
},
}
}
Filling / Coloring the Area between Lines
Just extend the chart to write your own fill logic.
Note that the animation is a bit weird because of the filling logic. It would be easier to turn off the animation to fix this, or you could try a variation of https://stackoverflow.com/a/33932975/360067 to animate from the 0 line.
Preview
Script
Chart.types.Line.extend({
name: "LineAlt",
draw: function () {
Chart.types.Line.prototype.draw.apply(this, arguments);
var ctx = this.chart.ctx;
var scale = this.scale;
ctx.save();
ctx.fillStyle = this.datasets[0].fillColor;
ctx.beginPath();
ctx.moveTo(scale.calculateX(0), scale.calculateY(0))
this.datasets[0].points.forEach(function (point) {
ctx.lineTo(point.x, point.y);
})
ctx.closePath();
ctx.fill();
ctx.fillStyle = this.datasets[1].fillColor;
ctx.beginPath();
ctx.moveTo(scale.calculateX(0), scale.calculateY(0))
this.datasets[1].points.forEach(function (point) {
ctx.lineTo(point.x, point.y);
})
ctx.closePath();
ctx.fill();
ctx.restore();
}
});
...
var myNewChart = new Chart(ctx).LineAlt(chartData, {
bezierCurve: false,
datasetFill: false
});
Fiddle - https://jsfiddle.net/fhxv0vL7/
This is available with a plugin using the latest (not in beta) version of charts
https://www.chartjs.org/docs/master/charts/area/#example-with-multiple-colors

Finding the Y axis value for a plot line in HIghCharts.js

I am trying to size a background image on a HighCharts line chart dynamically depending on the position of the top plot line. The image I am trying to size is the bell curve in the image below.
I can't set the height of the image as a static value because the size of the screen can change and the top plot line also changes over time.
At the moment I am setting the position of the plot lines with external functions like this:
plotLines: [
value: upperControl3()}, {
color: '#ccc',
zIndex: 3,
width: 1,
label: {
text: '-2s',
x: 520,
y: 3
}
The closest thing to the y value of the top plot line I have been able to find is a dataMax value but this stays the same on every chart load.
I have been trying to overlay and size the image with a function at the end of the chart like this:
function(chart) {
console.log(chart.yAxis[0].plotLinesAndBands[7].axis.plotLinesAndBands[0].axis);
var h = chart.yAxis[0].plotLinesAndBands[7].axis.plotLinesAndBands[0].axis.dataMax;
var y = chart.yAxis[0].axisTitle.y + extra;
// X, Y, Width, Height
chart.renderer.image('images/bell.jpg', 60, y, 200, h).add();
}
Is the any way to find the coordinates of a plot line in highcharts?
You can use plotLinesAndBands object, where plotlines are kept. In the options you have value, whcih can be translated into pixels value by toPixels function.
var $button = $('#button'),
$report = $('#report'),
chart = $('#container').highcharts();
$button.click(function () {
chart.xAxis[0].addPlotLine({
value: 5.5,
color: 'red',
width: 2,
id: 'plot-line-1'
});
var plotline = chart.xAxis[0].plotLinesAndBands[0];
$report.html('Value: ' + plotline.options.value + ' Pixels: ' + chart.xAxis[0].toPixels(plotline.options.value));
});
http://jsfiddle.net/HhP39/1/
If you know which plot line (by index) it is, you can do this:
chart.yAxis[0].plotLinesAndBands[0].options.value
Of course, you need to make sure your data is actually normally distributed, or else that normal curve means nothing :)
And zero-bounded data is not usually normally distributed.

How to add jqplot pie chart labels with lines?

I have a pie chart and I can add labels for it normal way.But I want to add labels with line as following.
I took this image from web as a example. here is my code ,
drawPieCharts = function(dev,title,data){
$('#'+dev).empty();
var plot = $.jqplot(dev, [data], {
title: {
text: title,
fontWeight: 'bold',
fontSize : '16',
show: true
},
grid: {
drawBorder: false,
drawGridlines: false,
background: '#ffffff',
shadow:false,
//diameter : 30
},
axesDefaults: {
},
highlighter: {
show: true,
formatString:'%s , P%',
tooltipLocation:'n',
useAxesFormatters:false
},
seriesDefaults:{
renderer:$.jqplot.PieRenderer,
rendererOptions: {
showDataLabels: true,
dataLabelThreshold: 0,
dataLabelPositionFactor: 1.05,
dataLabels : mapSeperater(data)[0],
padding: 2
}
},
});
}
And also I have another problem I want to bold the title of the chart and in this way it doesn't work. Is there a way to do that?
Thank you.
i'm looking for the same, not successful yet.
but for the title maybe you can try to style the div with the class "jqplot-title", that's where the title is rendered.
in jquery would be something like that:
$(".jqplot-title").wrap("<b></b>")
EDIT:
sorry i had no time to jsfiddle it, but you can try it and get the idea. looks a little awful but you can make it better.
what i did was putting labels of the slices outside the pie and draw some lines from the center to these labels.
..i came with something like this:
series: [{
renderer: $.jqplot.PieRenderer,
rendererOptions: {
diameter: 140,
showDataLabels: true,
dataLabelThreshold: 0, //minimum area to show a label, (i want all the labels)
dataLabelPositionFactor: 2.3, //in function of the radius, how far show the label
dataLabels: 'label',
dataLabelFormatString: '%s',
//(just more options, etc, etc)
plot = $.jqplot("myDivHere", [data], options).replot(); // <-- that's for me
// ******************************
// HERE COMES THE MAGIC:
//
var w = $("#myDivHere .jqplot-series-shadowCanvas").width();
var h = $("#myDivHere .jqplot-series-shadowCanvas").height();
x1 = (w/2);
y1 = (h/2);
var canvas = $("#myDivHere .jqplot-series-shadowCanvas")[0];
var context = canvas.getContext('2d');
$(".jqplot-pie-series.jqplot-data-label").each(
function(){
var l = $(this).position().left;
var t = $(this).position().top;
console.log("x1, y1 are: ["+x1+", "+y1+"]\n l, t are ["+l+", "+t+"]");
context.beginPath();
context.moveTo(x1, y1);
context.lineTo(l, t);
context.stroke();
});
I have no more time to work on this this week, so you could use it as awful it is and make it better. or wait for a better solution to show up.
Greetings!!
Ahh, and if you can make it better, please share it with me.

Categories