Chartist JS, line graph going under X axis - javascript

Currently I'm using the Chartist JS jQuery plugin and I'm having this issue where one of the function is going below x axis even though it doesn't have any negative points.
Is there anyway to avoid this issue, please check the image to further understanding.
The code
var options = {
low: 0,
fullWidth: true,
height: '225px',
chartPadding: {
left: 0,
right: 40,
},
showArea: true,
onlyInteger:true,
bezierCurve:false
};
$.ajax({
url: $('.ct-log-lead').data('url'),
method: 'GET',
data: {customerId:$('.ct-log-lead').data('id'),phoneNumber: $('.ct-log-lead').data('phone')},
success: function (d) {
data = {
labels: d[0],
datasets: d[1]
};
// var leadsLastSevenDays = 0;
// data.datasets[0].forEach(function (value) {
// leadsLastSevenDays += value;
// })
// $('.call-seven').html(d[2]);
var a = new Chartist.Line('.ct-log-lead', {
labels: data.labels,
series: [
{
name: 'Form Leads',
data: data.datasets[0]
},
{
name: 'Call Logs',
data: data.datasets[1]
}
],
}, options);
}
});
THanks

I faced the same problem just add this in your options variable and for more information By default Chartist uses a cardinal spline algorithm to smooth the lines.You can customize it eaisly.
lineSmooth: Chartist.Interpolation.simple({
divisor: 2
}),
see the both of fiddles
http://jsfiddle.net/Van_Jarvis/3uL7zu4o/113/
http://jsfiddle.net/3uL7zu4o/114/

In options you can pass bezierCurve so that you will not get smooth curves,
var options = {
bezierCurve:false
}
var myLineChart = new Chart(ctx).Line(data, options);

The standard line interpolation / smoothing can cause unwanted artifacts. Use the simple interpolation as an alternative:
http://gionkunz.github.io/chartist-js/examples.html#example-line-simple-smoothing

Related

ChartJS: Percentage labels

First of all, I would like to say that I'm a student learning programming for around a month, so expect to see many mistakes.
I'm working on a website where I use a chart from the ChartJs library. I have one outer circle that shows the hours worked on the company and the hours left to reach the monthly goal. The inner circle shows the days of the month and the days left of the month. Here is the code:
const data = {
labels: ['Summe', 'Noch um Ziel zu erreichen', 'Tage', 'Verbleibende Tage im Monat'],
datasets: [
{
backgroundColor: ['#5ce1e6', '#2acaea'],
data: [studenGesamt, (800 - studenGesamt)]
},
{
backgroundColor: ['#cd1076', '#8b0a50'],
data: [dayD, (23 - dayD)]
},
]
};
// Configuration of the pie chart
let outterChart = new Chart(chart, {
type: 'pie',
data: data,
options: {
responsive: true,
plugins: {
legend: {
labels: {
render: 'percentage',
fontColor: ['green', 'white'],
precision: 2,
generateLabels: function(chart) {
// Get the default label list
const original = Chart.overrides.pie.plugins.legend.labels.generateLabels;
const labelsOriginal = original.call(this, chart);
// Build an array of colors used in the datasets of the chart
var datasetColors = chart.data.datasets.map(function(e) {
return e.backgroundColor;
});
datasetColors = datasetColors.flat();
// Modify the color and hide state of each label
labelsOriginal.forEach(label => {
// Change the color to match the dataset
label.fillStyle = datasetColors[label.index];
});
return labelsOriginal;
}
},
onClick: function(mouseEvent, legendItem, legend) {
// toggle the visibility of the dataset from what it currently is
legend.chart.getDatasetMeta(
legendItem.datasetIndex
).hidden = legend.chart.isDatasetVisible(legendItem.datasetIndex);
legend.chart.update();
}
},
tooltip: {
callbacks: {
label: function(context) {
const labelIndex = (context.datasetIndex * 2) + context.dataIndex;
return context.chart.data.labels[labelIndex] + ': ' + context.formattedValue;
}
}
},
}
},
});
I want to show the percentage of each section of the pie chart on the pie chart. For that I found the plugin "chartjs-plugin-labels", and I added the following link on the script tag so I can use it on my website:
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.5.1/chart.min.js"></script>
<script src="script.js"></script>
<script src="https://cdn.jsdelivr.net/gh/emn178/chartjs-plugin-labels/src/chartjs-plugin-labels.js"></script>
On my code, I added the following code (I didn't add the closing brackets here as they are further down in the code and I just wanted to show this small specific part of the code):
plugins: {
legend: {
labels: {
render: 'percentage',
fontColor: ['green', 'white'],
precision: 2,
However, this code is not working and no percentages are showing up on the chart. I assume I have done something wrong, maybe on the CDN link or on the code itself, but I can't figure out. If someone could help me, I would really appreciate it! Here is a picture of the chart so you can get an idea of what I exactly want:
The plugin you are trying to use is outdated and doesnt work with chart.js version 3, you can use datalabels plugin.
When using the datalabels plugin you need to use the formatter function to change the values to percentages and you will need to register the plugin:
Chart.register(ChartDataLabels);
const data = {
labels: ['Summe', 'Noch um Ziel zu erreichen', 'Tage', 'Verbleibende Tage im Monat'],
datasets: [{
backgroundColor: ['#5ce1e6', '#2acaea'],
data: [200, (800 - 200)]
},
{
backgroundColor: ['#cd1076', '#8b0a50'],
data: [4, (23 - 4)]
},
]
};
var ctx = document.getElementById('chartJSContainer').getContext('2d');
// Configuration of the pie chart
let outterChart = new Chart(ctx, {
type: 'pie',
data: data,
options: {
responsive: true,
plugins: {
datalabels: {
color: 'white',
formatter: (val, ctx) => {
const totalDatasetSum = ctx.chart.data.datasets[ctx.datasetIndex].data.reduce((a, b) => (a + b), 0);
const percentage = val * 100 / totalDatasetSum;
const roundedPercentage = Math.round(percentage * 100) / 100
return `${roundedPercentage}%`
}
},
legend: {
labels: {
generateLabels: function(chart) {
// Get the default label list
const original = Chart.overrides.pie.plugins.legend.labels.generateLabels;
const labelsOriginal = original.call(this, chart);
// Build an array of colors used in the datasets of the chart
var datasetColors = chart.data.datasets.map(function(e) {
return e.backgroundColor;
});
datasetColors = datasetColors.flat();
// Modify the color and hide state of each label
labelsOriginal.forEach(label => {
// Change the color to match the dataset
label.fillStyle = datasetColors[label.index];
});
return labelsOriginal;
}
},
onClick: function(mouseEvent, legendItem, legend) {
// toggle the visibility of the dataset from what it currently is
legend.chart.getDatasetMeta(
legendItem.datasetIndex
).hidden = legend.chart.isDatasetVisible(legendItem.datasetIndex);
legend.chart.update();
}
},
tooltip: {
callbacks: {
label: function(context) {
const labelIndex = (context.datasetIndex * 2) + context.dataIndex;
return context.chart.data.labels[labelIndex] + ': ' + context.formattedValue;
}
}
},
}
},
});
<body>
<canvas id="chartJSContainer" width="600" height="400"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.5.1/chart.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/chartjs-plugin-datalabels/2.0.0/chartjs-plugin-datalabels.js"></script>
</body>

Chart.js - Mouseover causes graphs to flicker and resize

To start, I have made a short video to show exactly what I'm running into.
To summarize the video: while using Chart.js (2.6.0), I can create my charts without issue; but when I mouse-over the bars/points, the chart will resize its elements and flicker. The weird thing is that it's totally inconsistent. Sometimes when I refresh, it doesn't have this behaviour at all; but if I hover over something and it starts doing it, it won't stop until I refresh again or close out of the tab (it is inconsistent with this, also). I don't change anything in the code when this occurs, it does this all on its own.
In an attempt to fix it, I've referenced many other threads here on SO, as well as the Chart.js documentation. Among my solutions: I have made a point to add in a specified Height/Width to the Divs & Canvas creating the graphs; Set the Animation duration to 0, the Hover Animation duration to 0, and the Responsive Animation duration to 0; I've ensured that Responsive is set to true, and have kept Maintain Aspect Ratio as true, changed the tooltip mode... I've tried all of these, among other little things that seem to have little-to-no effect.
I'm stumped!
Here is one of my charts' code (without how I'm grabbing the JSON data etc, just the Chart):
new Chart($("#runwayChart"), {
type: "horizontalBar",
data: {
labels: runwayLabels,
datasets: [{
label: "Months Left", fill: true,
backgroundColor: "#3333ff",
borderColor: "#3333ff",
data: score
}, {
label: "Expenses",
fill: true,
backgroundColor: "#aa2222",
borderColor: "#aa2222",
data: expenses
}, {
label: "Revenue",
fill: true,
backgroundColor: "#2222aa",
borderColor: "#2222aa",
data: revenues
}]
},
options: {
tooltips: {
mode: 'index'
},
responsive: true,
maintainAspectRatio: true,
animation: {
duration: 0,
},
hover: {
animationDuration: 0,
},
responsiveAnimationDuration: 0
}
});
I'd appreciate any help you all may have!
Thanks =)
I see that it has been a while since somebody wrote an answer to this post. I solved my flickering issue by applying two things.
First one
When I declare the chart I use:
var ctx = document.getElementById('chart').getContext('2d');
window.chart = new Chart(ctx, {}) ...
rather than var chart = new Chart(ctx, {})..
In this way, we make sure that the chart has been appended to the window. object.
Secondly
Before drawing the new diagram (For example for data update) we need to make sure that the previous canvas has been destroyed. And we can check that with the code below:
if(window.chart && window.chart !== null){
window.chart.destroy();
}
It was actually a really simple, and odd solution.
When the data point was near the top of the chart, the chart would try to resize depending on the div. As the chart lived in a larger canvas, putting inside its own div solved this issue.
<div>
<canvas id="chart"></canvas>
</div>
Formatting it like this was the solution =)
Try This :
var myLineChart = null;
function createChart() {
var ctx1 = document.getElementById("barcanvas").getContext("2d");
myLineChart = new Chart(ctx1, {
type: 'horizontalBar',
data: {
labels: runwayLabels
, datasets: [{
label: "Months Left"
, fill: true
, backgroundColor : "#3333ff"
, borderColor: "#3333ff"
, data: score
}, {
label: "Expenses"
, fill: true
, backgroundColor : "#aa2222"
, borderColor: "#aa2222"
, data: expenses
}, {
label: "Revenue"
, fill: true
, backgroundColor : "#2222aa"
, borderColor: "#2222aa"
, data: revenues
}]
}
options:
{
scales: {
xAxes: [{
ticks: {
callback: function (tick) {
var characterLimit = 20;
if (tick.length >= characterLimit) {
return tick.slice(0, tick.length).substring(0, characterLimit - 1).trim() + '...';
}
return tick;
}
}
}]
},
tooltips: {
callbacks: {
// We'll edit the `title` string
title: function (tooltipItem) {
// `tooltipItem` is an object containing properties such as
// the dataset and the index of the current item
// Here, `this` is the char instance
// The following returns the full string
return this._data.labels[tooltipItem[0].index];
}
}
},
title:
{
display: true,
text: "Your Chart Title"
},
responsive: true,
maintainAspectRatio: true
}
});
}
I had the same issue with my angular application(angular v6 and chartjs 2.9.4).
After adding delay and destroying the chart instance before redrawing the chart resolved my issue.
public redraw() {
setTimeout(() => {
if (this.chart && this.chart != null) {
this.chart.destroy()
}
this.chart = new Chart(this.chartId, this.chartConfig);
}, 500);
}

Flotr2 different colors for two sets of data

I've merged positive and negative data to one data set called yAxis (multiple columns for both positive and negative). Here's the code:
//...
var yAxis = [wololoTotalValues];
var xAxis = wololoTotalKeys;
window.onload = function () {
Flotr.draw(document.getElementById("chart"), yAxis, {
title: "wololo",
bars: {
show: true,
barWidth: 0.8
},
yaxis: {
min: 0,
max: wololoMaxValue + 10,
tickDecimals: 0
},
xaxis: {
ticks: xAxis
}
});
};
//...
<div id='chart' style="width:1200px;height:500px;"></div>
I would like 'bad' and 'ble' to be red. I found some manuals how to handle this problem with flot, but not flotr(flotr2).
Is there any way to make it somehow like below? Or maybe I must split the data like here?
colors: (yAxis[0-lastGood] : "#0000FF"), (yAxis[lastGood+1-lastBad] : "#FF0000")
Okay, found the solution, splitting the data into two arrays helped. Code is below:
var gud = [];
for(i=0; i<wololoLengthGood; i++){
gud.push([i, wololoValuesGood[i]]);
}
var bad = [];
for(i=wololoLengthGood; i<wololoLengthGood+wololoLengthBad; i++){
bad.push([i, wololoValuesBad[i-wololoLengthGood]]);
}
window.onload = function () {
Flotr.draw(document.getElementById("chart"),
[{ // replacement of 'yAxis' from here
data: gud,
color: "#0000FF"
},{
data: bad,
color: "#FF0000"
}], // till here.
//...

Show only the MIN/MAX value on Y-AXIS with C3JS

I would like to have the y-axis only with the min/max values of my data.
I tried to use the d3 directive but without results.
I had a look at google but I didn't find an answer to achieve this behaviour.
Below the code:
$.getJSON('assets/json/chartc3.json', function(data)
{
scene=data;
var chart = c3.generate({
bindto: '#chartc3',
data:
{
json: scene,
keys:
{
x: 'round',
value: ['Marketable', 'Total Requested Capacity', 'Your Bid'],
},
types: {
Marketable: 'area'
},
colors: {
Marketable: '#A09FA2',
'Total Requested Capacity': '#272E80',
'Your Bid': '#8EBF60'
}
},
axis:
{
x: {
tick:
{
culling:
{
max: 10
}
},
type: 'category'
},
y:
{
min: 0,
padding : {
bottom : 0
},
tick:
{
values: [[0], [***d3.max(scene)]***],
format: function (d) { return d3.format(',f')(d) +' kWh/h' }
//or format: function (d) { return '$' + d; }
}
}
}.........
How could I achieve the result described above ? d3.max(scene) returns NaN.
Well the problem is scene is not an array its a json object.
var k = d3.max([1,5,2])
k will be 5
so you will need to pass an array of elements which constitute your y ordinals.
you need to use
d3.max(arr, function(d){return numberic value});
or
var arr = scene.map(function(d){return ...the number value..})
y:{
min:d3.min(arr),
max:d3.max(arr)
},
the function depends on the array element of your data.
I used a little function to calculate the max by myself.
var maxs=0;
for (var j=0; j<scene.length; j++) {
var maxtemp=Math.max(scene[j].Marketable, scene[j]['Your Bid'], scene[j]['Total Requested Capacity']);
maxs=Math.max(maxs, maxtemp);
}

Draw a Chart.js with ajax data and responsive. A few problems and questions

I am using Chart.js (http://www.chartjs.org/docs/) for charting.
I need to get the data from an Ajax request and the chart to be responsive.
In my HTML code I added a canvas as follows:
<div>
<canvas id="userscreated" class="plot" data-url="/stats/userscreated"></canvas>
</div>
And in my javascript (JQuery) code I have:
var data2;
$.ajax({
url: $('#userscreated').data('url'),
async: true,
dataType: 'json',
type: "get",
}).done(function (data) {
data2 = data;
// Draw chart
var context = $('#userscreated').get(0).getContext("2d");
var wrapper = $('#userscreated').parent();
var width = $('#userscreated').attr('width', $(wrapper).width());
new Chart(context).Line(
{
labels: data.Dates,
datasets: [
{ fillColor: #404040, data: data.Users }
]
},
{ animation: false }
);
});
// Redraw the chart with the same data
$(window).resize(function () {
var context = $('#userscreated').get(0).getContext("2d");
var wrapper = $('#userscreated').parent();
var width = $('#userscreated').attr('width', $(wrapper).width());
new Chart(context).Line(
{
labels: data2.Dates,
datasets: [
{ fillColor: #404040, data: data2.Users }
]
},
{ animation: false }
);
});
PROBLEMS
The chart is not being resized on window resize.
Is there better code to do this? I think I am repeating to much code.
In Google the drawing is fast. In firefox sometimes it hangs for a while.
Is anything wrong with my code?
Should the request be async or not?
You can make async AJAX calls no problem. It's just important that you setup the chart only after the success callback fires. Otherwise, you'll get issues with your canvas context not being defined. The first call to respondCanvas does the initial setup while the subsequent calls do the resizing.
Here is what works for me:
var max = 0;
var steps = 10;
var chartData = {};
function respondCanvas() {
var c = $('#summary');
var ctx = c.get(0).getContext("2d");
var container = c.parent();
var $container = $(container);
c.attr('width', $container.width()); //max width
c.attr('height', $container.height()); //max height
//Call a function to redraw other content (texts, images etc)
var chart = new Chart(ctx).Line(chartData, {
scaleOverride: true,
scaleSteps: steps,
scaleStepWidth: Math.ceil(max / steps),
scaleStartValue: 0
});
}
var GetChartData = function () {
$.ajax({
url: serviceUri,
method: 'GET',
dataType: 'json',
success: function (d) {
chartData = {
labels: d.AxisLabels,
datasets: [
{
fillColor: "rgba(220,220,220,0.5)",
strokeColor: "rgba(220,220,220,1)",
pointColor: "rgba(220,220,220,1)",
pointStrokeColor: "#fff",
data: d.DataSets[0]
}
]
};
max = Math.max.apply(Math, d.DataSets[0]);
steps = 10;
respondCanvas();
}
});
};
$(document).ready(function() {
$(window).resize(respondCanvas);
GetChartData();
});
If you want to insert a small delay between calls, you can use a timeout:
$(document).ready(function() {
$(window).resize(setTimeout(respondCanvas, 500));
GetChartData();
});
The delay will make your resizing more responsive in case you have a large dataset on your graph.
you can set that in chart.js
new Chart(context, {
type:"line",
labels: data.Dates,
datasets: [
{ fillColor: #404040, data: data.Users }
]
options: { responsive: false }
});
For those reading this in 2021:
Update for chart.js v3.x.x
Following updated answer for v3.x.x (which is not backwards compatible with v2.x.x)
First, answers to the 4 initial questions:
The chart is not being resized on window resize.
Is there better code to do this? I think I am repeating to much code.
In Google the drawing is fast. In firefox sometimes it hangs for a while. Is anything wrong with my code?
Should the request be async or not?
With current version, it should resize automatically, try it yourself running the snippet below and resizing the browser window.
The trick was to assign your chart to a variable const myLineChart = and then call simply myLineChart.update() when needed. Be aware to assign programmatically the labels and datasets again before calling myLineChart.update(), otherwise data changes would not reflect in chart.
Should be fine now in firefox according to my testings.
Oh yes, absolutely async (either ajax or http-request with callback or promises).
// once the success function of your $.ajax request fires,
// put following code within your success-function
// for now, let's assume sample data
let data2 = {
"Dates" : [
"2021-08-02",
"2021-08-03",
"2021-08-04",
"2021-08-05",
"2021-08-06"
],
"Users": [
6,
4,
3,
8,
2
]
};
// Draw chart
const ctx = document.querySelector('canvas').getContext('2d');
const myLineChart = new Chart(ctx, {
type: 'line',
data: {
labels: data2.Dates,
datasets: [{
label: 'Users created',
data: data2.Users,
borderColor: 'green',
backgroundColor: '#404040',
fill: true,
animations: false // <-- now plural, instead of "animation" before
}]
}
});
// Redraw the chart with an added record
function updateData(event) {
event.target.disabled = true;
data2 = {
"Dates" : [
"2021-08-02",
"2021-08-03",
"2021-08-04",
"2021-08-05",
"2021-08-06",
"2021-08-07"
],
"Users": [
6,
4,
3,
8,
2,
12
]
};
// assign programmatically the datasets again, otherwise data changes won't show
myLineChart.data.labels = data2.Dates;
myLineChart.data.datasets[0].data = data2.Users;
myLineChart.update();
};
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<!-- gets you the latest version of Chart.js, now at v3.5.0 -->
<button onclick="updateData(event)">add Data</button>
<canvas width="320" height="240"></canvas>
Indeed
Yes, I'll give you an example.
I dont see anything that might cause an issue. Except that window.resize might be firing rendering a new chart far more often then you want.
No. (I don't really know why, this is more coincidence.)
The code:
window.getVisitCounts = ($canvas) ->
url = Routes.visits_between_project_path($canvas.data('project-id'), {
format: "json",
start: $canvas.data('start'),
end: $canvas.data('end')
})
visits = []
days = []
$.ajax
url: url,
async: false,
dataType: "json",
type: "GET",
success: (data) - >
for point in data.chart.data
visits.push(point.visits)
days.push(point.date)
{
days: days,
visits: visits
}
window.createChartData = (raw) - > {
labels: raw.days,
datasets: [{
fillColor: "rgba(151,187,205,0.5)",
strokeColor: "rgba(151,187,205,1)",
pointColor: "rgba(151,187,205,1)",
pointStrokeColor: "#fff",
data: raw.visits,
}]
}
window.setupCanvas = ($canvas, data) - >
newWidth = $canvas.parent().width()
$canvas.prop
width: newWidth
height: 400
options = {
scaleOverride: true,
scaleSteps: 10,
scaleStepWidth: Math.ceil(Math.max.apply(Math, data.datasets[0].data) / 10),
scaleStartValue: 0
}
ctx = $canvas.get(0).getContext("2d")
new Chart(ctx).Line(data, options)
$ - > #canvas = $("#analytics-canvas")
if# canvas.length != 0# visits = window.createChartData(window.getVisitCounts(#canvas))
window.setupCanvas(#canvas, #visits)
$(window).on('resizeEnd', - >
setupCanvas(document.canvas, document.visits)
)
$(window).resize - >
if (#resizeTO)
clearTimeout(#resizeTO)
#resizeTO = setTimeout(- >
$(this).trigger "resizeEnd"
500
)

Categories

Resources