Chart.js – how to remove data entries from the tooltip? - javascript

I have a simpel doughnut chart, made with the following code:
var ctx = document.getElementById('myChart');
var myChart = new Chart(ctx, {
type: 'doughnut',
data: {
labels: ["Buchen (65%)", "Eschen (11%)", "Ahorn (8%)", "Eichen, Linden und weitere Laubhölzer (11%)", "Nadelholz (5%)"],
datasets: [
{
backgroundColor: ["#2F4F4F", "#008080","#2E8B57","#3CB371","#3AC9A3"],
data: [65,11,8,11,5]
}
]
},
options: {
responsive: true,
maintainAspectRatio: false,
tooltips: {
enabled: false
},
plugins: {
legend: {
onClick: (e) => e.stopPropagation(),
display: true,
position: 'right',
}
}
}
});
which turns into:
How to remove the '65' at the very end of the tooltip which pops up while hovering?
I came to understand that callbacks make it possible to customize the tooltip, however not yet managed this edit via the documentation.

I think this is the way you want to see the hover over tooltips:
var ctx = document.getElementById('myChart');
var myChart = new Chart(ctx, {
type: 'doughnut',
data: {
labels: ["Buchen (65%)", "Eschen (11%)", "Ahorn (8%)", "Eichen, Linden und weitere Laubhölzer (11%)", "Nadelholz (5%)"],
datasets: [{
backgroundColor: ["#2F4F4F", "#008080", "#2E8B57", "#3CB371", "#3AC9A3"],
data: [65, 11, 8, 11, 5]
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
onClick: (e) => e.stopPropagation(),
display: true,
position: 'right',
},
tooltip: {
callbacks: {
label: function(context) {
return context.label;
}
}
}
}
}
});

After testing this might be the solution and also soft coded the labels. As your labels were hard coded and if the values would change it should match up automatically.
Added a video as well breaking it down: https://youtu.be/b6oVAcQijIw
// Created an array to soft code your values in the labels.
const datavalue = [65,11,8,11,5];
const datalabels = ['Buchen', 'Eschen', 'Ahorn', 'Eichen, Linden und weitere Laubhölzer', 'Nadelholz'];
var ctx = document.getElementById('myChart');
var myChart = new Chart(ctx, {
type: 'doughnut',
data: {
labels: [datalabels[0], datalabels[1] + ' (' + datavalue[1] +'%)', datalabels[2] + ' (' + datavalue[2] +'%)', datalabels[3] + ' (' + datavalue[3] +'%)', datalabels[4] + ' (' + datavalue[4] +'%)'],
datasets: [
{
backgroundColor: ["#2F4F4F", "#008080","#2E8B57","#3CB371","#3AC9A3"],
data: datavalue
}
]
},
options: {
responsive: true,
maintainAspectRatio: false,
tooltips: {
enabled: false
},
plugins: {
legend: {
onClick: (e) => e.stopPropagation(),
display: true,
position: 'right',
},
// For the tooltipItem is the trigger of the hover effect.
tooltip: {
callbacks: {
label: function(tooltipItem){
let label = myChart.data.labels[tooltipItem.dataIndex];
let value = myChart.data.datasets[tooltipItem.datasetIndex].data[tooltipItem.dataIndex];
return label;
}
}
}
}
}
});

Just read the description and I noticed you are gonna change tooltips.
Okay, I am gonna write how I solve that problem.
tooltips: {
titleFontSize: 15,
titleMarginBottom: 10,
bodyFontSize: 15,
bodySpacing: 5,
xPadding: 15,
yPadding: 10,
enabled: false,
callbacks: {
label: function (context, data) {
return parseFloat(context.value).toFixed(1);
},
title: function (context) {
return mediaList.length;
},
},
custom: function (tooltipModel) {
let tooltipEl = document.getElementById("chartjs-tooltip");
// Create element on first render
if (!tooltipEl) {
tooltipEl = document.createElement("div");
tooltipEl.id = "chartjs-tooltip";
tooltipEl.innerHTML = "<table></table>";
document.body.appendChild(tooltipEl);
}
tooltipEl.classList.add("tooltip-wrapper");
// Hide if no tooltip
if (tooltipModel.opacity === 0) {
tooltipEl.style.opacity = 0;
return;
}
// Set caret Position
tooltipEl.classList.remove("above", "below", "no-transform");
if (tooltipModel.yAlign) {
tooltipEl.classList.add(tooltipModel.yAlign);
} else {
tooltipEl.classList.add("no-transform");
}
function getBody(bodyItem) {
return bodyItem.lines;
}
// Set Text
if (tooltipModel.body) {
let titleLines = tooltipModel.title || [];
let bodyLines = tooltipModel.body.map(getBody);
let innerHtml = "<thead>";
titleLines.forEach(function (title) {
innerHtml +=
"<tr><th style='text-align: left'>" + title + "</th></tr>";
});
innerHtml += "</thead><tbody>";
bodyLines.forEach(function (body, i) {
const colors = tooltipModel.labelColors[i];
let style = "background:" + colors.backgroundColor;
style += "; border-color:" + colors.borderColor;
style += "; border-width: 2px";
style += "; width: 15px";
style += "; height: 15px";
style += "; display: inline-block";
style += "; margin: 0px 5px";
style += "; border-radius: 50%";
let span = '<span style="' + style + '"></span>';
innerHtml +=
"<tr><td style='display: flex;align-items: center'>" +
parseFloat(body[0].split(":")[1]).toFixed(1) +
"%" +
span +
body[0].split(":")[0] +
"</td></tr>";
});
innerHtml += "</tbody>";
var tableRoot = tooltipEl.querySelector("table");
tableRoot.innerHTML = innerHtml;
}
// `this` will be the overall tooltip
const position = this._chart.canvas.getBoundingClientRect();
// Display, position, and set styles for font
tooltipEl.style.backgroundColor = "rgb(45 54 89 / 75%)";
tooltipEl.style.color = "white";
tooltipEl.style.borderRadius = "6px";
tooltipEl.style.opacity = 1;
tooltipEl.style.position = "absolute";
tooltipEl.style.width = "max-content";
tooltipEl.style.transform = "translate(-106%, -50%)";
tooltipEl.style.left =
position.left + window.pageXOffset + tooltipModel.caretX + "px";
tooltipEl.style.top =
position.top + window.pageYOffset + tooltipModel.caretY + "px";
tooltipEl.style.fontFamily = tooltipModel._bodyFontFamily;
tooltipEl.style.fontSize = tooltipModel.bodyFontSize + "px";
tooltipEl.style.fontStyle = tooltipModel._bodyFontStyle;
tooltipEl.style.padding =
tooltipModel.yPadding + "px " + tooltipModel.xPadding + "px";
tooltipEl.style.pointerEvents = "none";
},
},
As you can see here, you should create a custom tooltip in the tooltip option.

Under Tooltip Callbacks there is a reference to modifying the tooltip label: https://www.chartjs.org/docs/3.0.2/configuration/tooltip.html#label-callback
I think you need to add something like this:
options: {
plugins: {
tooltip: {
callbacks: {
label: function(context) {
var newLabel = context.label || '';
var lastIndexOfSpace = newLabel.lastIndexOf(' ');
if (lastIndexOfSpace > 0) {
newLabel = newLabel.substring(0, lastIndexOfSpace);
}
return newLabel;
}
}
}
}
}

Related

Render images as labels on Y axis

I'm using chart.js to graph my data.
I'm wondering if I can show the flag image/icon PNG for the labels.
function drawChart(obj, columnName, type = 'bar', selectedVal){
var ajax = $.ajax({url: '/query/' + obj + '/'+ columnName + '/' + selectedVal });
ajax.done(function (response) {
console.log('Response from API >>',response);
$('.lds-ripple').fadeOut();
var selector = `chart-${columnName}`;
var chartHtml = `<div class="col-sm-6"><canvas class="chart" id="${selector}" height="200"></canvas></div>`;
$('.charts').append(chartHtml);
keys = [];
values = [];
var length = 0
$.each(response, function(key,val) {
//console.log(key+val);
length++;
if(length<15){
keys.push(key);
values.push(val);
}
});
var showLegend = false;
if(type == 'doughnut' || type == 'radar' || type == 'polarArea' || type == 'pie'){
showLegend = true;
}
let chart = document.getElementById(selector).getContext('2d');
let xAxisTitle = columnName;
var sumOfAllValues = values.reduce((a, b) => a + b, 0);
Chart.defaults.global.defaultFontColor = "#fff";
var ticksDisplay = true;
if(columnName == 'country'){
ticksDisplay = false;
}
const images = ['https://i.stack.imgur.com/2RAv2.png', 'https://i.stack.imgur.com/Tq5DA.png', 'https://i.stack.imgur.com/3KRtW.png', 'https://i.stack.imgur.com/iLyVi.png'];
new Chart(chart, {
type: type, // bar, horizontalBar, pie, line, doughnut, radar, polarArea
plugins: [{
afterDraw: chart => {
var ctx = chart.chart.ctx;
var xAxis = chart.scales['x-axis-0'];
var yAxis = chart.scales['y-axis-0'];
xAxis.ticks.forEach((value, index) => {
var x = xAxis.getPixelForTick(index);
var y = yAxis.getPixelForTick(index);
var image = new Image();
image.src = images[index],
ctx.drawImage(image, x - 12, yAxis.bottom + 10);
// ctx.drawImage(image, x + 12, yAxis.left - 10);
});
}
}],
data:{
labels: keys,
datasets:[{
label:'Count',
data:values,
borderWidth:2,
hoverBorderWidth:2,
hoverBorderColor:'#fff',
color:'#fff',
backgroundColor: neonBgColors,
borderColor: neonBgBorders,
defaultFontColor: 'white'
}
]
},
options:{
title:{
display:true,
fontSize: 20,
text: columnName + '(' + sumOfAllValues + ')'
},
legend:{
display:showLegend,
position:'right',
labels:{
fontColor:'#000'
}
},
scales: {
xAxes: [{
ticks: {
precision:0,
beginAtZero: true
},
scaleLabel: {
display: true,
labelString: xAxisTitle + ' (' + sumOfAllValues + ')'
}
}],
yAxes: [{
ticks: {
precision:0,
beginAtZero: true,
display: ticksDisplay,
},
scaleLabel: {
display: true,
// labelString: 'Visitor Count'
}
}]
},
layout: {
padding: {
bottom: 30
}
},
}
});
});
}
I kept getting
I adapted the code of this answer and came up with the following solution for your case.
const labels = ['Red Vans', 'Blue Vans', 'Green Vans', 'Gray Vans'];
const images = ['https://i.stack.imgur.com/2RAv2.png', 'https://i.stack.imgur.com/Tq5DA.png', 'https://i.stack.imgur.com/3KRtW.png', 'https://i.stack.imgur.com/iLyVi.png']
.map(png => {
const image = new Image();
image.src = png;
return image;
});
const values = [48, 56, 33, 44];
new Chart(document.getElementById("myChart"), {
type: "horizontalBar",
plugins: [{
afterDraw: chart => {
var ctx = chart.chart.ctx;
var xAxis = chart.scales['x-axis-0'];
var yAxis = chart.scales['y-axis-0'];
yAxis.ticks.forEach((value, index) => {
var y = yAxis.getPixelForTick(index);
ctx.drawImage(images[index], xAxis.left - 40, y - 10);
});
}
}],
data: {
labels: labels,
datasets: [{
label: 'My Dataset',
data: values,
backgroundColor: ['red', 'blue', 'green', 'lightgray']
}]
},
options: {
responsive: true,
layout: {
padding: {
left: 50
}
},
legend: {
display: false
},
scales: {
yAxes: [{
ticks: {
display: false
}
}],
xAxes: [{
ticks: {
beginAtZero: true
}
}],
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js"></script>
<canvas id="myChart" height="90"></canvas>

Chart js legend are being cut off if the bar height is equal to port height - chart js

I am using chart js to display barchart as :
$(function(){
let aid;
let $radio_input;
let none_obs;
let display = true;
let $js_dom_array = ["76.44", "120.00"];
let $js_am_label_arr = ["None $0", "Terrace - Large $2000"];
if($js_am_label_arr.length > 20){
display = false;
}
let $js_backgroundColor = ["rgba(26,179,148,0.5)", "rgba(26,179,148,0.5)"];
// let $div = document.getElementById("barChart");
// $div.height="140";
let ctx2 = document.getElementById("barChart").getContext("2d");
let chart = new Chart(ctx2, {
type: 'bar',
data: {
labels: $js_am_label_arr,
datasets: [{
label: 'DOM',
data: $js_dom_array,
backgroundColor: $js_backgroundColor,
barPercentage: 0.4,
maxBarThickness: 50,
// maxBarLength: 5,
}]
},
options: {
legend: {
display: false
},
responsive: true,
maintainAspectRatio: false,
legendCallback: function(chart) {
var text = [];
for (var i=0; i<chart.data.datasets.length; i++) {
text.push(chart.data.labels[i]);
}
return text.join("");
},
tooltips: {
mode: 'index',
callbacks: {
// Use the footer callback to display the sum of the items showing in the tooltip
title: function(tooltipItem, data) {
let title_str = data['labels'][tooltipItem[0]['index']];
// let lastIndex = title_str.lastIndexOf(" ");
// return title_str.substring(0, lastIndex);
return title_str;
},
label: function(tooltipItem, data) {
return 'Avg. DOM: '+data['datasets'][0]['data'][tooltipItem['index']];
},
},
},
scales: {
xAxes: [{
stacked: false,
beginAtZero: true,
// scaleLabel: {
// labelString: 'Month'
// },
ticks: {
display: display,
min: 0,
autoSkip: false,
maxRotation: 60,
callback: function(label, index, labels) {
// let lastIndex = label.lastIndexOf(" ");
// let avg_amount = label.split(" ").pop();
// let am_name = label.substring(0, lastIndex);
// let truncated_am_name = am_name.length > 30 ? (am_name.substring(0, 30)+'...') : am_name;
// return truncated_am_name+' '+avg_amount;
return label;
}
}
}]
},
layout: {
margin: {
top: 5
}
},
},
plugins:[{
afterDatasetsDraw: function(chart,options) {
// var chartInstance = chart,
let ctx = chart.ctx;
ctx.font = Chart.defaults.global.defaultFontStyle;
ctx.fillStyle = Chart.defaults.global.textColor;
ctx.textAlign = "center";
ctx.textBaseline = "bottom";
chart.data.datasets.forEach(function (dataset, i) {
var meta = chart.controller.getDatasetMeta(i);
meta.data.forEach(function (bar, index) {
ctx.fillText(Math.round(dataset.data[index]), bar._model.x, bar._model.y); //bar._model.y - 5
});
})
}
}]
});
document.getElementById('barChart').innerHTML = chart.generateLegend();
})
<script src="https://code.jquery.com/jquery-3.5.1.min.js" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js#2.9.3"></script>
<div style="height:400px;">
<canvas id="barChart" xheight="140px"></canvas>
</div>
If you need jsfiddle
Here, the value of second barchart is 120 and it is being cut off. I could pull text little down as: ctx.fillText(Math.round(dataset.data[index]), bar._model.x, bar._model.y + 5); But I don't wat the value to be overlapped with the bar. I have also tried with following options
layout: {
margin: {
top: 5
}
},
and
axisY:{
viewportMaximum: 130
},
But, none of these seems to work. Is there any way to increase the height or viewport of the chart js? It would be helpful if you could provide the js fiddle as well.
Instead of layout.margin.top, you need to define layout.padding.top as follows:
layout: {
padding: {
top: 20
}
},

In Graph2d sometimes points are not connected

I'm using vis.js v. 4.12.0. I've noticed that sometimes using Graph2d some points are not connected.
.
I think this behaviour depends on points distance; does someone knows how to force points connection?
#selten98: Sure, here my code:
for (var i in plot) {
groups.add({
content: labelArray[i],
id: plot[i],
options: {
shaded: {
orientation: "bottom"
}
}
});
for (var j in GD) {
if (GD[j].hasOwnProperty(plot[i])) {
items.push({
group: plot[i],
label: {
className: "visibility-hidden label-group-" + labelArray[i],
content: GD[j][plot[i]].toFixed(1),
xOffset: -10 / 3 * GD[j][plot[i]].toFixed(1).length,
yOffset: 20
},
x: new Date(GD[j].timestamp),
y: Number(String(GD[j][plot[i]]).replace(",", "."))
});
}
}
}
for (var i = 0; i < items.length; i++) {
if (i == 0) {
groups.add({
content: groupId,
id: groupId,
style: "stroke:" + arr_color[properties],
options: {
shaded: {
orientation: "bottom",
style: "fill:" + arr_color[properties]
},
drawPoints: {
styles: "stroke:" + arr_color[properties] + ";fill:" + arr_color[properties]
}
}
});
items[i].group = groupId;
scope.labels[properties].max = Number(items[i].y).toFixed(1);
scope.labels[properties].min = Number(items[i].y).toFixed(1);
} else {
if (items[i].label.className == items[i - 1].label.className) {
if (items[i].x.getTime() - items[i - 1].x.getTime() > Number(type[1]) * 60 * 1000) {
groupId++;
groups.add({
content: groupId,
id: groupId,
style: "stroke:" + arr_color[properties],
options: {
shaded: {
orientation: "bottom",
style: "fill:" + arr_color[properties]
},
drawPoints: {
styles: "stroke:" + arr_color[properties] + ";fill:" + arr_color[properties]
}
}
});
}
items[i].group = groupId;
scope.labels[properties].max = Math.max(scope.labels[properties].max, Number(items[i].y)).toFixed(1);
scope.labels[properties].min = Math.min(scope.labels[properties].min, Number(items[i].y)).toFixed(1);
} else {
groupId++;
properties++;
groups.add({
content: groupId,
id: groupId,
style: "stroke:" + arr_color[properties],
options: {
shaded: {
orientation: "bottom",
style: "fill:" + arr_color[properties]
},
drawPoints: {
styles: "stroke:" + arr_color[properties] + ";fill:" + arr_color[properties]
}
}
});
items[i].group = groupId;
scope.labels[properties].max = Number(items[i].y).toFixed(1);
scope.labels[properties].min = Number(items[i].y).toFixed(1);
}
}
}
var container = document.getElementById("graph");
container.innerHTML = "";
var dataset = new vis.DataSet(items);
var options = {
dataAxis: {
left: {
format: function (value) {
return Number(value).toFixed(1);
}
}
},
drawPoints: {
style: "circle"
},
orientation: "top",
showCurrentTime: true,
end: new Date(end),
max: new Date(end),
min: new Date(start),
start: new Date(start)
};
startTime = options.start.getTime();
endTime = options.end.getTime();
var graph2d = new vis.Graph2d(container, dataset, groups, options);

Chart.js 2.0 doughnut tooltip percentages

I have worked with chart.js 1.0 and had my doughnut chart tooltips displaying percentages based on data divided by dataset, but I'm unable to replicate this with chart 2.0.
I have searched high and low and have not found a working solution. I know that it will go under options but everything I've tried has made the pie dysfunctional at best.
<html>
<head>
<title>Doughnut Chart</title>
<script src="../dist/Chart.bundle.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<style>
canvas {
-moz-user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
}
</style>
</head>
<body>
<div id="canvas-holder" style="width:75%">
<canvas id="chart-area" />
</div>
<script>
var randomScalingFactor = function() {
return Math.round(Math.random() * 100);
};
var randomColorFactor = function() {
return Math.round(Math.random() * 255);
};
var randomColor = function(opacity) {
return 'rgba(' + randomColorFactor() + ',' + randomColorFactor() + ',' + randomColorFactor() + ',' + (opacity || '.3') + ')';
};
var config = {
type: 'doughnut',
data: {
datasets: [{
data: [
486.5,
501.5,
139.3,
162,
263.7,
],
backgroundColor: [
"#F7464A",
"#46BFBD",
"#FDB45C",
"#949FB1",
"#4D5360",
],
label: 'Expenditures'
}],
labels: [
"Hospitals: $486.5 billion",
"Physicians & Professional Services: $501.5 billion",
"Long Term Care: $139.3 billion",
"Prescription Drugs: $162 billion",
"Other Expenditures: $263.7 billion"
]
},
options: {
responsive: true,
legend: {
position: 'bottom',
},
title: {
display: false,
text: 'Chart.js Doughnut Chart'
},
animation: {
animateScale: true,
animateRotate: true
}
}
};
window.onload = function() {
var ctx = document.getElementById("chart-area").getContext("2d");
window.myDoughnut = new Chart(ctx, config);{
}
};
</script>
</body>
</html>
Update: The below answer shows a percentage based on total data but #William Surya Permana has an excellent answer that updates based on the shown data https://stackoverflow.com/a/49717859/2737978
In options you can pass in a tooltips object (more can be read at the chartjs docs)
A field of tooltips, to get the result you want, is a callbacks object with a label field. label will be a function that takes in the tooltip item which you have hovered over and the data which makes up your graph. Just return a string, that you want to go in the tooltip, from this function.
Here is an example of what this can look like
tooltips: {
callbacks: {
label: function(tooltipItem, data) {
//get the concerned dataset
var dataset = data.datasets[tooltipItem.datasetIndex];
//calculate the total of this data set
var total = dataset.data.reduce(function(previousValue, currentValue, currentIndex, array) {
return previousValue + currentValue;
});
//get the current items value
var currentValue = dataset.data[tooltipItem.index];
//calculate the precentage based on the total and current item, also this does a rough rounding to give a whole number
var percentage = Math.floor(((currentValue/total) * 100)+0.5);
return percentage + "%";
}
}
}
and a full example with the data you provided
fiddle
var randomScalingFactor = function() {
return Math.round(Math.random() * 100);
};
var randomColorFactor = function() {
return Math.round(Math.random() * 255);
};
var randomColor = function(opacity) {
return 'rgba(' + randomColorFactor() + ',' + randomColorFactor() + ',' + randomColorFactor() + ',' + (opacity || '.3') + ')';
};
var config = {
type: 'doughnut',
data: {
datasets: [{
data: [
486.5,
501.5,
139.3,
162,
263.7,
],
backgroundColor: [
"#F7464A",
"#46BFBD",
"#FDB45C",
"#949FB1",
"#4D5360",
],
label: 'Expenditures'
}],
labels: [
"Hospitals: $486.5 billion",
"Physicians & Professional Services: $501.5 billion",
"Long Term Care: $139.3 billion",
"Prescription Drugs: $162 billion",
"Other Expenditures: $263.7 billion"
]
},
options: {
responsive: true,
legend: {
position: 'bottom',
},
title: {
display: false,
text: 'Chart.js Doughnut Chart'
},
animation: {
animateScale: true,
animateRotate: true
},
tooltips: {
callbacks: {
label: function(tooltipItem, data) {
var dataset = data.datasets[tooltipItem.datasetIndex];
var total = dataset.data.reduce(function(previousValue, currentValue, currentIndex, array) {
return previousValue + currentValue;
});
var currentValue = dataset.data[tooltipItem.index];
var percentage = Math.floor(((currentValue/total) * 100)+0.5);
return percentage + "%";
}
}
}
}
};
var ctx = document.getElementById("chart-area").getContext("2d");
window.myDoughnut = new Chart(ctx, config); {
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.1.3/Chart.bundle.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="canvas-holder" style="width:75%">
<canvas id="chart-area" />
</div>
For those who want to display dynamic percentages based on what currently displayed on the chart (not based on total data), you can try this code:
tooltips: {
callbacks: {
label: function(tooltipItem, data) {
var dataset = data.datasets[tooltipItem.datasetIndex];
var meta = dataset._meta[Object.keys(dataset._meta)[0]];
var total = meta.total;
var currentValue = dataset.data[tooltipItem.index];
var percentage = parseFloat((currentValue/total*100).toFixed(1));
return currentValue + ' (' + percentage + '%)';
},
title: function(tooltipItem, data) {
return data.labels[tooltipItem[0].index];
}
}
},
In 3.5 it will be:
options: {
plugins: {
tooltip: {
callbacks: {
label: function(context){
var data = context.dataset.data,
label = context.label,
currentValue = context.raw,
total = 0;
for( var i = 0; i < data.length; i++ ){
total += data[i];
}
var percentage = parseFloat((currentValue/total*100).toFixed(1));
return label + ": " +currentValue + ' (' + percentage + '%)';
}
}
}
}
}
but better, dynamic version:
options: {
plugins: {
tooltip: {
callbacks: {
label: function(context){
var label = context.label,
currentValue = context.raw,
total = context.chart._metasets[context.datasetIndex].total;
var percentage = parseFloat((currentValue/total*100).toFixed(1));
return label + ": " +currentValue + ' (' + percentage + '%)';
}
}
}
}
}
I came across this question because I needed to show percentage on stacked bar charts. The percentage I needed was per stacked columns. I accomplished this by modifying Willian Surya's answer like this:
tooltips: {
callbacks: {
label: function(tooltipItem, data) {
var index = tooltipItem.index;
var currentValue = data.datasets[tooltipItem.datasetIndex].data[index];
var total = 0;
data.datasets.forEach(function(el){
total = total + el.data[index];
});
var percentage = parseFloat((currentValue/total*100).toFixed(1));
return currentValue + ' (' + percentage + '%)';
},
title: function(tooltipItem, data) {
return data.datasets[tooltipItem[0].datasetIndex].label;
}
}
}
This is the final result:
The usage has changed in 3.x and higher versions, so I will attach a method for this.
const data: ChartData = {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: [
{
data: excerciseData,
backgroundColor: [
"rgba(255, 99, 132, 0.5)",
"rgba(54, 162, 235, 0.5)",
"rgba(255, 206, 86, 0.5)",
"rgba(75, 192, 192, 0.5)",
"rgba(153, 102, 255, 0.5)",
"rgba(255, 159, 64, 0.5)"
]
}
]
};
...
callbacks: {
label: tooltipItem => {
let total = 0;
data.datasets[0].data.forEach(num => {
total += num as number;
});
const currentValue = data.datasets[0].data[tooltipItem.dataIndex] as number;
const percentage = ((currentValue * 100) / total).toFixed(1) + "%";
return `${currentValue}(${percentage})`;
},
title: tooltipItems => {
return tooltipItems[0].label;
}
}
Simply use this:
const options = {
responsive: true,
plugins: {
tooltip: {
callbacks: {
label: (Item) => '%' + (Item.formattedValue) + ' | ' + Item.label
}
}
},
};

highcharts / highstock doesn't show markers after 500 pts

It seems that over 500 points causes our highstocks markers not to show at all - you can see
http://www.ethnographicedge.com/topic/senkaku-trial-400/ (400 pts) vs http://www.ethnographicedge.com/topic/senkaku-trial-600-s1/ (600pts). The data that's not showing is the "event" represented by the green sphere.
I've looked into editing the turboThreshold, but no luck..
Here's a simplified jsfiddle, and my full code below:
jsfiddle.net/marquex/etdL7/1
when you change the var points = 200; to 400, the red dot doesn't display. Is there a way to force certain mandatory points to show, regardless of the data size?
graphdata = <?php echo topic_data(get_the_ID()); ?>;
extradata = <?php echo extra_data(get_the_ID()); ?>;
eventdata = <?php global $events; echo json_encode($events) ?>;
eventdata.sort(function(a,b){
return a.date - b.date;
});
;(function($){
var parseData,
container = $('#graphcontainer'),
last = false,
m_names = new Array("January", "February", "March",
"April", "May", "June", "July", "August", "September",
"October", "November", "December");
;
if(! container.length)
return;
getEventPoint = function(e,idx){
var color = 'gray';
if(e.forecast == 'fore_successful_down')
color = 'red';
else if(e.forecast == 'fore_successful_up')
color = 'green';
return {
x: parseInt(e.stringdate),
y: parseInt(e.value),
marker: {
enabled: true,
radius:8,
fillColor: color,
lineWidth:3,
lineColor: 'white',
states: {
hover: {
enabled: true,
radius:8,
fillColor: 'white',
lineWidth:3,
lineColor: color
}
}
},
name: idx
}
}
dateDay = function(day){
if( day % 10 == 1)
return day + 'st';
if( day % 10 == 2)
return day + 'nd';
if( day % 10 == 3)
return day + 'rd';
return day + 'th';
}
formatDate = function(timestamp){
var date = new Date(timestamp);
return m_names[date.getMonth()] + ' ' + date.getDay() + ', ' + date.getFullYear();
}
tooltipFormatter = function(data){
var point = data.points[0],
name = point.point.name,
output = '<div class="tooltip-date">' + formatDate(data.x) + '</div><div class="tooltip-value"><span class="tooltip-unit"><?php the_field("value_text") ?>:</span> ' + data.y + '</div>';
if(typeof name !== "undefined"){
var e = eventdata[name];
return '<div class="tooltip-date">' + formatDate(data.x) + '</div>' +
'<div class="tooltip-title">' + e.number + '</div>' +
'<div class="tooltip-trend tooltip-' + e.trend + '"></div> <!-- I will resize the image > background-size: -->' +
'<div class="tooltip-cycle">' + e.cycle + '</div>';
}
if(data.points[1])
output += '<div class="tooltip-secondary><div class="tooltip-value"><span class="tooltip-unit"><?php the_field("extra_value_text") ?>:</span> ' + data.points[1].y + '</div>'
return output;
}
parseData = function(data, eventsData){
var parsedData = [],
eventIdx = 0,
events = eventsData ? eventsData.slice(0) : [],
e = events[0]
;
if(e)
e.stringdate = (new Date(e.date.substring(0,4) + '/' + e.date.substring(4,6) + '/' + e.date.substring(6,8))).getTime();
for (var i = 0; i < data.length; i++) {
var item = data[i],
timestamp = false;
if(item.date && item.date.match(/^\d{4}\/\d{2}\/\d{2}$/) && item.value && parseFloat(item.value) == item.value){
timestamp = (new Date(item.date)).getTime();
if(e && timestamp > e.stringdate > last) {
parsedData.push(getEventPoint(e, eventIdx));
parsedData.push([timestamp, parseFloat(item.value)]);
e = events[++eventIdx];
if(e)
e.stringdate = (new Date(e.date.substring(0,4) + '/' + e.date.substring(4,6) + '/' + e.date.substring(6,8))).getTime();
}
else if(e && timestamp == e.stringdate) {
parsedData.push(getEventPoint(e, eventIdx));
e = events[++eventIdx];
if(e)
e.stringdate = (new Date(e.date.substring(0,4) + '/' + e.date.substring(4,6) + '/' + e.date.substring(6,8))).getTime();
}
else
parsedData.push([timestamp, parseFloat(item.value)]);
}
};
while(e){
parsedData.push(getEventPoint(e, eventIdx));
e = events[++eventIdx];
if(e)
e.stringdate = (new Date(e.date.substring(0,4) + '/' + e.date.substring(4,6) + '/' + e.date.substring(6,8))).getTime();
}
return parsedData;
};
var series = [{
name: 'Topic Data',
data: parseData(graphdata, eventdata),
color: '#666'
}];
if(extradata && extradata.length){
series.push({
name: 'Extra Data',
data: parseData(extradata),
yAxis: 1,
color: '#fbb800'
});
}
var yAxis = [{
title: {
text: '<?php the_field("value_text") ?>',
style: { color: '#BBBBBB', fontSize: '1.2em' },
margin: 12,
},
labels: {
enabled: false,
formatter: function() {
return this.value
}
},
height: 300,
lineColor: '#FFFFFF'
}];
if(extradata && extradata.length){
yAxis[0].lineWidth = 2;
yAxis.push({
title: {
text: '<?php the_field("extra_value_text") ?>'
},
height: 200,
top:350,
offset:0,
lineWidth:2,
lineColor: '#FFFFFF'
});
}
container.highcharts('StockChart', {
chart: {
type: 'spline',
events: {
load: function(e){
$('#tapapubli')
.detach()
.addClass('tapapubli')
.appendTo('#graphcontainer');
}
}
},
rangeSelector: {
enabled: false,
buttons:[
{
type: '<?php echo $initial_zoom["type"] ?>',
count: <?php echo $initial_zoom["count"] ?>,
text: 'Initial'
},
{
type: 'All',
text: 'Reset'
}
],
},
scrollbar: {
enabled: false,
},
navigator: {
maskFill: 'rgba(170, 170, 170, 0.75)',
series: {
color: '#FFD600',
lineColor: '#AE8800'
}
},
xAxis: {
labels: {
enabled: false
},
lineColor: '#FFF', /* BITBUCKET */
tickColor: '#666666',
tickLength: 0,
tickWidth: 1,
tickPosition: 'outside',
type: 'datetime',
dateTimeLabelFormats: { // don't display the dummy year
day: '%e of %b',
}
},
yAxis: yAxis,
plotOptions: {
lineColor: 'green',
spline: {
lineWidth: 3,
states: {
hover: {
lineWidth: 3
}
},
marker: {
enabled: false
},
pointInterval: 36000000000,
point: {
events: {
click: function(){
//console.log(this);
if(this.name)
window.location.href = '#event-' + eventdata[this.name].number;
}
}
}
}
},
series: series,
tooltip: {
formatter: function(){
return tooltipFormatter(this);
},
useHTML: true,
borderColor: '#333',
shadow: false,
borderRadius: 0
}
});
if(!window.chart)
window.chart = container.highcharts();
})(jQuery);
var getPointRecursive = function(date, list){
if(list.length < 5){
var found = false;
for (var i = 0; i < list.length; i++) {
var point = list[i];
};
}
}
var getSeriesPoint = function(date){
}
As #Sebastian Bochan said, you just need to set plotOptions.series.dataGrouping.enabled = false explicitly. Then the problem will disappear.

Categories

Resources