I have a vertical bar chart which is displaying exactly as I want it when the number of bars is up to 50 or so. However, I also need to display up to 365 bars, one for each day of the year. It displays the bars with the code I was using but there were artefacts due to using a barPercentage less than 1.0 and a border.
backgroundColor: 'rgba(54, 162, 235, 0.6)',
borderColor: 'rgba(54, 162, 235, 1.0)',
borderWidth: 2,
categoryPercentage: 1.0,
barPercentage: 0.8
So when the number of bars is over 100, I change these values as follows and do a chart update:
backgroundColor: 'rgba(54, 162, 235, 1.0)', // No transparency in the bar colour
borderColor: 'rgba(54, 162, 235, 1.0)',
borderWidth: 0,
categoryPercentage: 1.0,
barPercentage: 1.0
However, there is still a faint visible vertical line between the bars where I would expect nothing. I'm on Mac OSX with Safari and I also see the problem on iPad and iPhone.
Any idea what I'm doing wrong??
(click on the 'SWITCH' button to swap between 50 and 120 bars)
https://jsfiddle.net/8xdLb9qe/
I've searched and found this comment:
Be sure you don't have the Dataset barThickness value set, or it will
override the barPercentage setting. Philip F
I change the chart settings as follows:
myChart = new Chart(document.getElementById('thisChart'), {
type: 'bar',
data: {
labels: myScales,
datasets: [{
backgroundColor: 'rgba(54, 162, 235, 0.6)',
borderColor: 'rgba(54, 162, 235, 1.0)',
data: myValues,
barThickness: 16 //
}]
},
options: option
});
Here is the working jsfiddle.
Full code:
var thisChart = null;
var myScales = [];
var myValues = [];
var numBars = 50;
var option = {
responsive: true,
maintainAspectRatio: false,
interaction: {
intersect: false,
mode: 'nearest'
},
scales: {
x: {
display: true,
grid: {
drawOnChartArea: false,
drawTicks: false
}
},
y: {
max: 100,
grace: '5%',
grid: {
drawTicks: false
},
display: true
}
},
plugins: {
legend: {
display: false
},
tooltip: {
enabled: false
},
hover: {
mode: null
}
}
};
myChart = new Chart(document.getElementById('thisChart'), {
type: 'bar',
data: {
labels: myScales,
datasets: [{
backgroundColor: 'rgba(54, 162, 235, 0.6)',
borderColor: 'rgba(54, 162, 235, 1.0)',
//borderWidth: 2,
data: myValues,
barThickness: 16,
//categoryPercentage: 1.0,
//barPercentage: 0.1
}]
},
options: option
});
for (var i = 1; i != numBars; i++) {
myScales[i] = i;
myValues[i] = Math.floor(Math.random() * (100 - 50 + 1) + 50);
}
displayGraph();
function displayGraph() {
// Remove the old data
myChart.data.labels.pop();
myChart.data.datasets.forEach((dataset) => {
dataset.data.pop();
});
myChart.update();
// Add in the new data
myChart.data.labels = myScales;
myChart.data.datasets.forEach((dataset, i) => {
dataset.data = myValues;
});
if (myValues.length > 100) {
myChart.data.datasets.forEach((dataset, i) => {
dataset.barPercentage = 1.0; // Remove gap between bars
dataset.borderWidth = 0; // Remove bar border
dataset.backgroundColor = 'rgba(54, 162, 235, 1.0)'; // Remove transparency
});
} else {
myChart.data.datasets.forEach((dataset, i) => {
dataset.barPercentage = 0.8; // Default width of gap between bars
dataset.borderWidth = 2; // Default bar border
dataset.backgroundColor = 'rgba(54, 162, 235, 0.6)'; // Default bar background colour
dataset.borderColor = 'rgba(54, 162, 235, 1.0)'; // Default bar border colour
});
}
myChart.update();
}
function switchBars() {
if (numBars == 50) { // Toggle number of bars
numBars = 120;
} else {
numBars = 50;
}
myScales.length = numBars;
myValues.length = numBars;
for (var i = 1; i != numBars; i++) {
myScales[i] = i;
myValues[i] = Math.floor(Math.random() * (100 - 50 + 1) + 50);
}
displayGraph();
}
.chart-container {
width: 100vw;
height: 60vh;
margin-top: 4em;
position: relative;
}
canvas {
display: block;
margin-left: 2em;
margin-right: 2em;
}
.styleSelectorButton {
width: 100vw;
height: 5em;
margin-top: 1em;
display: flex;
justify-content: center;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.2.0/chart.min.js"></script>
<div class="chart-container">
<canvas id="thisChart"></canvas>
</div>
<div id="selectorButton" class="styleSelectorButton">
<input type="button" onclick="switchBars()" class="button" value="SWITCH">
</div>
Related
I have a question about filtering/subsetting my dataset. Im creating a custom legend function by leveraging isDatasetVisible and setDatasetVisibility but I was wondering if its possible for my function to also subset the x-axis?
Here's the function now, but it works just like the default legend behavior
function updateLegend(click, output) {
const element = click.target.parentNode;
element.classList.toggle('fade');
output.update();
}
function generateLegend(output, container) {
if (document.querySelectorAll('.customLegend').length === 0) {
const chartBox = document.querySelector(container);
const div = document.createElement('DIV');
div.setAttribute('class', 'customLegend');
const ul = document.createElement('UL');
output.legend.legendItems.forEach((dataset, index) => {
const text = dataset.text;
const stroke = dataset.strokeStyle;
const fill = dataset.fillStyle;
const fontColor = '#666';
const dat = dataset.data;
const li = document.createElement('LI');
const spanBox = document.createElement('SPAN');
spanBox.style.borderColor = stroke;
if (fill == 'rgba(0,0,0,0.1)') {
spanBox.setAttribute('class', 'legend-annotation');
} else {
spanBox.setAttribute('class', 'legend-content');
spanBox.style.backgroundColor = fill;
}
const p = document.createElement('P');
const textNode = document.createTextNode(text);
li.onclick = (click) => {
const isHidden = !output.isDatasetVisible(index);
output.setDatasetVisibility(index, isHidden);
updateLegend(click, output);
};
ul.appendChild(li);
li.appendChild(spanBox);
li.appendChild(p);
p.appendChild(textNode);
});
chartBox.prepend(div);
div.appendChild(ul);
}
}
const customLegend = {
id: 'customLegend',
afterDraw(chart, args, options) {
generateLegend(chart, '.chart-container');
},
};
I created an example below where on click of Dataset 2 I not only want the bars to be removed as they are now but for [A, B, C] to take up the entire x-axis space since [D,E,F] no longer have visible data..... would this require creating my own data subset and triggering a redraw? Any advice would be super helpful!!
var data = {
datasets: [{
label: "Dataset #1",
backgroundColor: 'red',
data: [
{x: "A", y: 65},
{x: "B", y: 59},
{x: "C", y: 20}
],
}, {
label: "Dataset #2",
backgroundColor: 'blue',
data: [
{x: "D", y: 12},
{x: "E", y: 11},
{x: "F", y: 10}
],
}]
};
var option = {
plugins: {
legend: {
display: false,
}
}
};
function updateLegend(click, output) {
const element = click.target.parentNode;
element.classList.toggle('fade');
output.update();
}
function generateLegend(output, container) {
if (document.querySelectorAll('.customLegend').length === 0) {
const chartBox = document.querySelector(container);
const div = document.createElement('DIV');
div.setAttribute('class', 'customLegend');
const ul = document.createElement('UL');
output.legend.legendItems.forEach((dataset, index) => {
const text = dataset.text;
const stroke = dataset.strokeStyle;
const fill = dataset.fillStyle;
const fontColor = '#666';
const dat = dataset.data;
const li = document.createElement('LI');
const spanBox = document.createElement('SPAN');
spanBox.style.borderColor = stroke;
if (fill == 'rgba(0,0,0,0.1)') {
spanBox.setAttribute('class', 'legend-annotation');
} else {
spanBox.setAttribute('class', 'legend-content');
spanBox.style.backgroundColor = fill;
}
const p = document.createElement('P');
const textNode = document.createTextNode(text);
li.onclick = (click) => {
const isHidden = !output.isDatasetVisible(index);
output.setDatasetVisibility(index, isHidden);
updateLegend(click, output);
};
ul.appendChild(li);
li.appendChild(spanBox);
li.appendChild(p);
p.appendChild(textNode);
});
chartBox.prepend(div);
div.appendChild(ul);
}
}
const customLegend = {
id: 'customLegend',
afterDraw(chart, args, options) {
generateLegend(chart, '.chart-container');
},
};
new Chart('chart_0', {
// this is the string the constructor was registered at, ie Chart.controllers.MyType
type: 'bar',
data: data,
options: option,
plugins: [customLegend],
});
.chart-container {
position: relative;
max-width: 800px;
margin: auto;
}
.chartBox {
width: 80%;
}
.customLegend ul {
display: flex;
flex-direction: row;
margin: 0 auto;
list-style: none;
justify-content: center;
}
.customLegend ul li {
margin: 15px;
display: flex;
align-items: center;
cursor: pointer;
flex-direction: row;
line-height: 22px;
}
.customLegend p {
font-family: 'Helvetica';
font-size: 12px;
color: #666;
}
.customLegend ul li.fade p {
color: rgba(102, 102, 102, 0.5);
}
li.fade span {
opacity: 0.3;
}
.customLegend ul li span {
display: inline-block;
margin-right: 15px;
}
.legend-content {
height: 10px;
width: 10px;
}
.legend-annotation {
border-top-style: dotted;
height: 0px;
width: 20px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.9.1/chart.min.js"></script>
<div class="chart-container">
<canvas id="chart_0"></canvas>
</div>
I answered this by storing the individual data sets outside of the config, and switching what the config is pointing at based on the button clicks.
I used d3s rollup function to group my data, then leveraged the fade class to see what datasets should and should not be seen!
original_data = [
{x: "A", y: 65, mygroup: "Group 1"},
{x: "B", y: 59, mygroup: "Group 1"},
{x: "C", y: 20, mygroup: 'Group 1'},
{x: "D", y: 12, mygroup: 'Group 2'},
{x: "E", y: 11, mygroup: 'Group 2'},
{x: "F", y: 10, mygroup: 'Group 2'},
{x: "G", y: 12, mygroup: 'Group 3'},
{x: "H", y: 11, mygroup: 'Group 3'},
{x: "I", y: 10, mygroup: 'Group 3'}
]
original_data2 = [
{x: "A", y: 65},
{x: "B", y: 59,},
{x: "C", y: 20,},
{x: "D", y: 12,},
{x: "E", y: 11},
{x: "F", y: 10}
]
config = {colors: ['red', 'blue', 'green']}
let chartified = d3.rollups(
original_data,
(group) => {
return {
label: group[0].mygroup,
data: group,
};
},
(d) => d.mygroup
).map((group, i) => {
const dataset = group[1];
dataset.backgroundColor = config.colors[i];
return dataset;
});
console.log(chartified)
// 1. break out your data by dataset
/*
let data2 = [
{
label: "Dataset #2",
backgroundColor: 'blue',
data: [
{x: "D", y: 12},
{x: "E", y: 11},
{x: "F", y: 10}
],
}
]
let data1 = [{
label: "Dataset #1",
backgroundColor: 'red',
data: [
{x: "A", y: 65},
{x: "B", y: 59},
{x: "C", y: 20}
],
}]
let all_data = [ ...data1, ...data2 ]
console.log(all_data)*
let named_data = [
{name: "Dataset #1", data: data1},
{name: "Dataset #2", data: data2}
]
*/
var option = {
plugins: {
legend: {
display: false,
}
}
};
function updateLegend(click, output) {
const element = click.target.parentNode;
element.classList.toggle('fade');
output.update();
}
function generateLegend(output, container) {
if (document.querySelectorAll('.customLegend').length === 0) {
const chartBox = document.querySelector(container);
const div = document.createElement('DIV');
div.setAttribute('class', 'customLegend');
const ul = document.createElement('UL');
output.legend.legendItems.forEach((dataset, index) => {
const text = dataset.text;
const stroke = dataset.strokeStyle;
const fill = dataset.fillStyle;
const fontColor = '#666';
const dat = dataset.data;
const li = document.createElement('LI');
const spanBox = document.createElement('SPAN');
spanBox.style.borderColor = stroke;
if (fill == 'rgba(0,0,0,0.1)') {
spanBox.setAttribute('class', 'legend-annotation');
} else {
spanBox.setAttribute('class', 'legend-content');
spanBox.style.backgroundColor = fill;
}
const p = document.createElement('P');
const textNode = document.createTextNode(text);
li.onclick = (event) => {
var target = event.target || event.srcElement;
target.parentElement.classList.toggle('fade');
// get all elements that are currently faded
let to_omit = target.parentElement
.parentElement
.querySelectorAll(".fade")
let omitted_data = [...to_omit].map(x => x.querySelector('p').innerHTML)
if (to_omit.length === 0) {
output.data.datasets = chartified
} else if (to_omit.length === chartified.length) {
output.data.datasets = []
} else {
output.data.datasets = chartified.filter(x => !omitted_data.includes(x.label))
}
output.update()
};
ul.appendChild(li);
li.appendChild(spanBox);
li.appendChild(p);
p.appendChild(textNode);
});
chartBox.prepend(div);
div.appendChild(ul);
}
}
const customLegend = {
id: 'customLegend',
afterDraw(chart, args, options) {
generateLegend(chart, '.chart-container');
},
};
new Chart('chart_0', {
// this is the string the constructor was registered at, ie Chart.controllers.MyType
type: 'bar',
data: {datasets: chartified },
options: option,
plugins: [customLegend],
});
/*
data: [
{},
{},
{},
]
*/
.chart-container {
position: relative;
max-width: 800px;
margin: auto;
}
.chartBox {
width: 80%;
}
.customLegend ul {
display: flex;
flex-direction: row;
margin: 0 auto;
list-style: none;
justify-content: center;
}
.customLegend ul li {
margin: 15px;
display: flex;
align-items: center;
cursor: pointer;
flex-direction: row;
line-height: 22px;
}
.customLegend p {
font-family: 'Helvetica';
font-size: 12px;
color: #666;
}
.customLegend ul li.fade p {
color: rgba(102, 102, 102, 0.5);
}
li.fade span {
opacity: 0.3;
}
.customLegend ul li span {
display: inline-block;
margin-right: 15px;
}
.legend-content {
height: 10px;
width: 10px;
}
.legend-annotation {
border-top-style: dotted;
height: 0px;
width: 20px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/7.6.1/d3.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.9.1/chart.min.js"></script>
<div class="chart-container">
<canvas id="chart_0"></canvas>
</div>
I have a line chart in chart.js. Now I would like to have a tooltip, when I hover over the line not just when i hover over a point.
The tooltip should then be displayed at the position of the mouse.
Is this somehow possible?
I have tried all interaction.mode options, but non of them have this behavior.
Thank You
You can use the croshair plugin for this if you are still using v2 of the lib: https://chartjs-plugin-crosshair.netlify.app/
Live example:
var ctx = document.getElementById("myChart");
function generateDataset(shift, label, color) {
function getRandomInt(min, max) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min + 1)) + min;
}
let data = [];
let index = 0;
while (index < 5) {
data.push({
x: index,
y: getRandomInt(10, 40)
});
index++;
}
var dataset = {
backgroundColor: color,
borderColor: color,
showLine: true,
fill: false,
pointRadius: 2,
label: label,
data: data,
lineTension: 0,
interpolate: true,
xAxisID: 'x-axis-0'
};
return dataset;
}
var myChart = new Chart(ctx, {
type: 'line',
data: {
labels: ['A', 'B', 'C', 'D', 'E'],
datasets: [
generateDataset(0, "A", "red"),
generateDataset(1, "B", "green")
]
},
options: {
scales: {
xAxes: [{
display: true,
type: 'linear',
position: 'bottom',
id: 'x-axis-0',
ticks: {
source: 'labels'
}
}]
},
tooltips: {
mode: "interpolate",
intersect: false,
callbacks: {
title: function(a, d) {
// return a[0].xLabel.toFixed(2);
return a[0].xLabel;
},
label: function(i, d) {
return (
d.datasets[i.datasetIndex].label + ": " + i.yLabel.toFixed(2)
);
}
}
},
plugins: {
crosshair: {
line: {
// Add alpha chanel so line becomes transparant so you dont see it
color: '#ffffff00',
},
sync: {
enabled: false
}
}
}
}
});
.myChartDiv {
max-width: 600px;
max-height: 400px;
}
<html>
<body>
<div class="myChartDiv">
<canvas id="myChart" width="600" height="400"></canvas>
</div>
<script src="https://npmcdn.com/chart.js#2.9.4/dist/Chart.bundle.min.js"></script>
<script src="https://unpkg.com/chartjs-plugin-crosshair#1.1.6/dist/chartjs-plugin-crosshair.js"></script>
</body>
</html>
If you are using V3 of the lib you will need to use a custom own plugin
Example:
// Options for the indicators
const indicatorOptions = {
radius: 4, borderWidth: 1, borderColor: 'red', backgroundColor: 'transparent'
};
// Override getLabelAndValue to return the interpolated value
const getLabelAndValue = Chart.controllers.line.prototype.getLabelAndValue;
Chart.controllers.line.prototype.getLabelAndValue = function(index) {
if (index === -1) {
const meta = this.getMeta();
const pt = meta._pt;
const vScale = meta.vScale;
return {
label: 'interpolated',
value: vScale.getValueForPixel(pt.y)
};
}
return getLabelAndValue.call(this, index);
}
// The interaction mode
Chart.Interaction.modes.interpolate = function (chart, e, option) {
const x = e.x;
const items = [];
const metas = chart.getSortedVisibleDatasetMetas();
for (let i = 0; i < metas.length; i++) {
const meta = metas[i];
const pt = meta.dataset.interpolate({ x }, "x");
if (pt) {
const element = new Chart.elements.PointElement({...pt, options: {...indicatorOptions}});
meta._pt = element;
items.push({element, index: -1, datasetIndex: meta.index });
} else {
meta._pt = null;
}
}
return items;
};
// Plugin to draw the indicators
Chart.register({
id: 'indicators',
afterDraw(chart) {
const metas = chart.getSortedVisibleDatasetMetas();
for (let i = 0; i < metas.length; i++) {
const meta = metas[i];
if (meta._pt) {
meta._pt.draw(chart.ctx);
}
}
},
afterEvent(chart, args) {
if (args.event.type === 'mouseout') {
const metas = chart.getSortedVisibleDatasetMetas();
for (let i = 0; i < metas.length; i++) {
metas[i]._pt = null;
}
args.changed = true;
}
}
})
var ctx = document.getElementById("myChart").getContext("2d");
var chart = new Chart(ctx, {
type: "line",
data: {
labels: ["January", "February", "March", "April", "May", "June", "July"],
datasets: [
{
fill: true,
label: "My First dataset",
backgroundColor: "rgba(132, 0, 0, 1)",
borderColor: "rgb(255, 99, 132)",
data: [0, 10, 5, 2, 20, 30, 45]
},
{
data: [30, 40, 50],
label: 'My Second Dataset',
fill: true,
backgroundColor: "lightgreen",
borderColor: "green"
}
]
},
options: {
interaction: {
mode: "interpolate",
intersect: false,
axis: "x"
},
plugins: {
tooltip: {
position: 'nearest',
displayColors: false,
}
}
},
});
.myChartDiv {
max-width: 600px;
max-height: 400px;
}
<h1>Interpolating line values</h1>
<div class="myChartDiv">
<canvas id="myChart" width="600" height="400"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.3.2/chart.js"></script>
</div>
I am trying to replicate the NSE Stock exchange comparison graph as displayed here.
I am using Chartjs 2.0. I have 2 line graphs in the chart.
On hovering on the data points I want to show the tooltip's ylabel in a div which is outside the canvas, (like the changing values are displayed in the top right corner in the chart above)
I found GRUNT's code helpful
Moving vertical line when hovering over the chart using chart.js
You can use Label Callback
document.getElementById('y-label').textContent = tooltipItem.yLabel;
Chart.defaults.LineWithLine = Chart.defaults.line;
Chart.controllers.LineWithLine = Chart.controllers.line.extend({
draw: function(ease) {
Chart.controllers.line.prototype.draw.call(this, ease);
if (this.chart.tooltip._active && this.chart.tooltip._active.length) {
var activePoint = this.chart.tooltip._active[0],
ctx = this.chart.ctx,
x = activePoint.tooltipPosition().x,
topY = this.chart.scales['y-axis-0'].top,
bottomY = this.chart.scales['y-axis-0'].bottom;
// draw line
ctx.save();
ctx.beginPath();
ctx.moveTo(x, topY);
ctx.lineTo(x, bottomY);
ctx.lineWidth = 2;
ctx.strokeStyle = '#07C';
ctx.stroke();
ctx.restore();
}
}
});
var chart = new Chart(ctx, {
type: 'LineWithLine',
data: {
labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul'],
datasets: [{
label: 'Statistics',
data: [3, 1, 2, 5, 4, 7, 6],
backgroundColor: 'rgba(0, 119, 204, 0.8)',
borderColor: 'rgba(0, 119, 204, 0.3)',
fill: false
}]
},
options: {
responsive: false,
tooltips: {
intersect: false,
callbacks: {
label: function(tooltipItem, data) {
var label = data.datasets[tooltipItem.datasetIndex].label || '';
if (label) {
label += ': ';
}
label += Math.round(tooltipItem.yLabel * 100) / 100;
document.getElementById('y-label').textContent = tooltipItem.yLabel;
return label;
}
}
},
scales: {
yAxes: [{
ticks: {
beginAtZero: true
}
}]
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.6.0/Chart.min.js"></script>
<h4 id="y-label"> </h4>
<canvas id="ctx" height="200"></canvas>
I am working ChartJS component using angular2. I would like to know whether there is any way to render as this image or not.
Basically, The Bar Chart rendered on the grid. When I click on the column bar, for example, June the horizontal line should be displayed with the up arrow at the exact month under the column bar. Do you have any suggestions? Thanks in advance.
You can capture the onclick event of the canvas and check which bar has been clicked with the getElementAtEvent method of chartjs. getElementAtEvent gives you all the relevant information you need (chart-width, x-coordinate of the bar, label etc.) to draw a custom line below the chart.
canvas.onclick = function (evt) {
var activePoints = myBarChart.getElementAtEvent(evt);
if (activePoints[0]) {
//draw your custom line
}
};
The snippet below has two canvas. One for chart.js to draw the actual chart and the second below to draw a line with the text of the clicked label.
var canvas = document.getElementById('myChart');
var data = {
labels: ["January", "February", "March", "April", "May", "June", "July"],
datasets: [{
label: "My First dataset",
backgroundColor: "rgba(255,99,132,0.2)",
borderColor: "rgba(255,99,132,1)",
borderWidth: 2,
hoverBackgroundColor: "rgba(255,99,132,0.4)",
hoverBorderColor: "rgba(255,99,132,1)",
data: [65, 59, 20, 81, 56, 55, 40],
}]
};
var option = {
scales: {
yAxes: [{
stacked: true,
gridLines: {
display: true,
color: "rgba(255,99,132,0.2)"
}
}],
xAxes: [{
gridLines: {
display: false
}
}]
}
};
var myBarChart = Chart.Bar(canvas, {
data: data,
options: option
});
canvas.onclick = function (evt) {
var activePoints = myBarChart.getElementAtEvent(evt);
if (activePoints[0]) {
var chart = activePoints[0]._chart;
var canvasX = document.getElementById('xAxis2');
// set the width of the second canvas to the chart width
canvasX.width = chart.width;
var canvas2D = canvasX.getContext('2d');
// draw the line
canvas2D.moveTo(0, 20);
canvas2D.lineTo(activePoints[0]._view.x - 10, 20);
canvas2D.lineTo(activePoints[0]._view.x, 0);
canvas2D.lineTo(activePoints[0]._view.x + 10, 20);
canvas2D.lineTo(canvasX.width, 20);
canvas2D.stroke();
// add the label text
canvas2D.font = '12px serif';
canvas2D.fillText('for ' + activePoints[0]._view.label, canvasX.width - 100, 15);
}
};
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.1/Chart.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.1/Chart.bundle.min.js"></script>
<canvas id="myChart" width="400" height="250"></canvas>
<canvas id="xAxis2" height="20"></canvas>
My chart is working fine as expected except that the hAxis labels have very little or no padding in between the chart itself and the legend. Is there a way to increase it?
options:
var options = {
colors:['rgb(32, 170, 188)', 'rgb(32, 188, 77)'],
lineWidth:4,
areaOpacity: 0.15,
width:$(window).width() * 0.5,
height:$(window).width() * 0.25,
animation: {
"startup": true,
duration: 1200,
easing: 'out',
},
fontName: 'Open Sans',
legend: {
position:'bottom',
},
chartArea:{
width:'90%',
height:'80%',
}
};
only option I can think of, would be to modify the labels once the chart is 'ready',
or on 'animationfinish'
in this example, the y position is increased by 4
looks kind of jumpy with the animation,
there may be other options, if you know svg
google.charts.load('current', {
'callback': function () {
var data = google.visualization.arrayToDataTable([
['Year', 'Sales', 'Expenses'],
['2013', 1000, 400],
['2014', 1170, 460],
['2015', 660, 1120],
['2016', 1030, 540]
]);
var options = {
colors:['rgb(32, 170, 188)', 'rgb(32, 188, 77)'],
lineWidth:4,
animation: {
startup: true,
duration: 1200,
easing: 'out',
},
areaOpacity: 0.15,
fontName: 'Open Sans',
legend: {
position:'bottom',
},
chartArea:{
}
};
var container = document.getElementById('chart_div');
var chart = new google.visualization.AreaChart(container);
google.visualization.events.addListener(chart, 'animationfinish', moveLabels);
google.visualization.events.addListener(chart, 'ready', moveLabels);
function moveLabels() {
Array.prototype.forEach.call(container.getElementsByTagName('text'), function (label) {
if (label.getAttribute('text-anchor') === 'middle') {
label.setAttribute('y', parseFloat(label.getAttribute('y')) + 4);
}
});
}
chart.draw(data, options);
},
'packages':['corechart']
});
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="chart_div"></div>