I implemented a chart with legend based on Echarts libary. What i want to develop now is tooltip for each data on chart legend. Data are prepared as array of object and each name have corresponding description which i want to show on tooltip. In other word, i want tooltip from picture below to be shown after mouse hover on legend names.
<div class="card grid-stack-item-content cd-example" id="dashboard-header">
<div class="card-header container-fluid">
<div class="row dashboard-row">
<div class="col-3 dashboard-icon-div text-center">
<h1 class="dashboard-h1"><i class="fa fa-tags dashboard-logo"></i></h1>
</div>
<div class="col-5">
<h4 class="card-title dashboard-card-title">{{trans('app.icd10_codes')}}</h4>
<h6 class="card-subtitle text-muted">
#if (count($binnedIcds['targetIcds']['codes']) > 0)
<span class="info-box-number">
{{count($binnedIcds['targetIcds']['codes'])}}
{{trans('app.skin_disease_groups')}}
</span>
#endif
</h6>
</div>
</div>
</div>
<div class="card-body">
<div class="row">
<div class="col-lg-12 col-md-12 col-sm-12">
<div id="pie-chart" style="width:100%; min-height: 480px;"></div>
</div>
</div>
</div>
</div>
NewIcdTile.js
class NewIcdChart
{
constructor(ctx, targetsLabels, othersLabel, undefLabel, targetsTooltips, othersTooltip,
undefTooltip, nTargets, nOthers, nTotal)
{
this.othersColor = '#888888';
this.undefColor = '#cccccc';
var labels = {
targetsLabels,
othersLabel,
undefLabel
};
var tooltips = {
targetsTooltips,
othersTooltip,
undefTooltip,
};
var nTargetImages = nTargets.reduce((a,b) => a + b, 0);
var nUndef = nTotal - nTargetImages - nOthers;
var counts = {
nTargets,
nOthers,
nTotal,
nUndef,
};
this.chart;
this.hasOthers = false;
this.hasUndef = false;
this.drawChart(ctx, labels, tooltips, counts);
}
drawChart(ctx, labels, tooltips, counts){
var otherValue=counts.nOthers;
var otherLabel=labels.othersLabel;
var otherTooltip=tooltips.othersTooltip;
var undefinedValue=counts.nUndef;
var undefinedLabel=labels.undefLabel;
var undefinedTooltip=tooltips.undefTooltip;
var targetValues=counts.nTargets;
var targetLabels=labels.targetsLabels;
var targetTooltip=tooltips.targetsTooltips;
var finalChartValue=[];
for(var i=0; i<targetValues.length; i++){
for(var i=0; i<targetLabels.length; i++){
for(var i=0; i<targetTooltip.length; i++){
var obj = {"value": targetValues[i], "name": targetLabels[i], "tooltip": targetTooltip[i]};
finalChartValue.push(obj);
}
}
}
var otherObject={
value: otherValue,
name : otherLabel,
tooltip : otherTooltip
};
var undefinedObject={
value: undefinedValue,
name : undefinedLabel,
tooltip : undefinedTooltip
};
finalChartValue.unshift(otherObject, undefinedObject);
console.log("finalChartValue", finalChartValue);
var finalChartLables=[];
finalChartValue.forEach(function(res) {
finalChartLables.push(res.name);
});
// specify chart configuration item and data
var option = {
tooltip: {
trigger: 'item',
formatter: "{a} <br/>{b} : {c}",
},
legend: {
x : 'center',
y : 'bottom',
padding: 1,
formatter: function(name) {
var data = this.getSeries()[0].data;
var totalValue = data.reduce((acc, item) => {
acc += item.value;
return acc;
}, 0)
var targetValue;
var targetTooltip;
data.map(item => {
if (item.name == name) {
targetValue = item.value;
targetTooltip= item.tooltip;
}
})
var p = (targetValue / totalValue * 100).toFixed(2);
console.log("name", name);
return name + ' ' + p + '%';
},
data:finalChartLables
},
toolbox: {
show: true,
feature: {
dataView: { show: true, readOnly: false },
magicType: {
show: true,
type: ['pie']
},
restore: { show: true },
saveAsImage: { show: true }
}
},
color: ["#f62d51", "#dddddd", "#ffbc34", "#7460ee", "#009efb", "#2f3d4a", "#90a4ae", "#55ce63"],
calculable: true,
series: [{
name: 'ICD',
type: 'pie',
radius: [20, 180],
center : ['50%', '50%'],
roseType: 'radius',
itemStyle: {
normal: {
label: {
show: false,
formatter: "{b} : \n ({c})",
fontWeight: 100
},
labelLine: {
show: false,
formatter: "{b} : \n ({c})",
fontWeight: 100
}
},
emphasis: {
label: {
show: true,
formatter: "{b} : \n ({c})",
fontWeight: 100
},
labelLine: {
show: true,
formatter: "{b} : \n ({c})",
fontWeight: 100
}
}
},
data: finalChartValue
},
]
};
// use configuration item and data specified to show chart
ctx.setOption(option, true), $(function() {
function resize() {
setTimeout(function() {
ctx.resize()
}, 100)
}
$(window).on("resize", resize), $(".sidebartoggler").on("click", resize)
});
console.log("ctx", ctx);
}
}
you can add a tooltip option, and add a formatter function intolegend option, that will show a tooltip on top of the legend when mouse hover. for example:
var chart1 = echarts.init(document.getElementById("chart1"));
var option = {
tooltip: {
show: true,
formatter: "{a} <br/>{b} : {c} ({d}%)"
},
series: [
{
name: "WHATEVER",
type: "pie",
data: [
{ name: "A", value: 100 },
{ name: "B", value: 150 }
]
}
],
legend: {
data: ["A", "B"],
tooltip: {
show: true,
formatter: function (params) {
var total = 0,
cur_item = null;
var _selected = chart1.getOption().legend[0].selected;
if (_selected[params.name] === false) return; // no tooltip if legend unchecked.
for (var i = 0; i < option.series[0].data.length; i++) {
var item = option.series[0].data[i];
if (_selected[item.name] !== false) total += item.value; // get total amount checked only
if (item.name == params.name) cur_item = item;
}
if (!cur_item) return;
var format = "{a} <br/>{b} : {c} ({d}%)";
format = format.replace("{a}", option.series[0].name);
format = format.replace("{b}", cur_item.name);
format = format.replace("{c}", cur_item.value);
format = format.replace(
"{d}",
((cur_item.value / total) * 100).toFixed(2)
);
return format;
}
}
}
};
chart1.setOption(option);
Codepen
Related
this is my donut chart (ApexCharts):
var options = {
series: [umsatzSum, ausgabenSum, auslagenSum],
chart: {
type: 'donut',
height: 320,
fontFamily: chartFontStyle
},
labels: ["Umsatz", "Ausgaben", "Auslagen"],
colors:['#7ebd0b', '#661818', "#333"],
track: {
background: "#cccccc"
},
dataLabels: {
enabled: false
},
stroke: {
colors:['#7ebd0b', '#661818', "#333"],
},
plotOptions: {
pie: {
donut: {
labels: {
show: true,
value: {
formatter: function (val,chart) {
let valPercent = val/chart.config.series.reduce((a, b) => a + b, 0)*100;
return Math.round(valPercent) + "%"
}
}
}
}
}
}
var chart = new ApexCharts(document.querySelector("#myChart"), options);
chart.render();
Result:
And If I mouse over a series element, it will show this:
And If I click on the series element, the percent value in the middle stays
How can I realize, that the percent value will be show at the beginning (after the chart was created), without hover or click an element first?
https://apexcharts.com/docs/options/plotoptions/pie/#total total will be shown when no series is selected or hovered over.
labels: {
show: true,
value: {
formatter: function (val,chart) {...}
},
total: {
show: true,
label: 'Umsatz',
color: '#7ebd0b',
formatter: function (chart) {
let seriesToShowId = 0
let val = chart.config.series[seriesToShowId]
let valPercent = val/chart.config.series.reduce((a, b) => a + b, 0)*100;
return Math.round(valPercent) + "%"
}
}
}
I´m using Echarts for data visualisation, documentation is not clear to me ;(
What I need is basically change of width and height of chart. I tried to change height of pie-chart div but as a consequences only div height is changed without change of chart dimensions. If anyone know solution i would really appreciate.
<div class="card grid-stack-item-content cd-example" id="dashboard-header">
<div class="card-header container-fluid">
<div class="row dashboard-row">
<div class="col-3 dashboard-icon-div text-center">
<h1 class="dashboard-h1"><i class="fa fa-tags dashboard-logo"></i></h1>
</div>
<div class="col-5">
<h4 class="card-title dashboard-card-title">{{trans('app.icd10_codes')}}</h4>
<h6 class="card-subtitle text-muted">
#if (count($binnedIcds['targetIcds']['codes']) > 0)
<span class="info-box-number">
{{count($binnedIcds['targetIcds']['codes'])}}
{{trans('app.skin_disease_groups')}}
</span>
#endif
</h6>
</div>
</div>
</div>
<div class="card-body">
<div class="row">
<div class="col-lg-12 col-md-12 col-sm-12">
<div id="pie-chart" style="width:100%; min-height: 500px;"></div>
</div>
</div>
</div>
</div>
NewIcdChart.js
class NewIcdChart
{
constructor(ctx, targetsLabels, othersLabel, undefLabel, targetsTooltips, othersTooltip,
undefTooltip, nTargets, nOthers, nTotal)
{
this.othersColor = '#888888';
this.undefColor = '#cccccc';
var labels = {
targetsLabels,
othersLabel,
undefLabel
};
var tooltips = {
targetsTooltips,
othersTooltip,
undefTooltip,
};
var nTargetImages = nTargets.reduce((a,b) => a + b, 0);
var nUndef = nTotal - nTargetImages - nOthers;
var counts = {
nTargets,
nOthers,
nTotal,
nUndef,
};
this.chart;
this.hasOthers = false;
this.hasUndef = false;
this.drawChart(ctx, labels, tooltips, counts);
}
drawChart(ctx, labels, tooltips, counts){
var otherValue=counts.nOthers;
var otherLabel=labels.othersLabel;
var undefinedValue=counts.nUndef;
var undefinedLabel=labels.undefLabel;
var targetValues=counts.nTargets;
var targetLabels=labels.targetsLabels;
var finalChartValue=[];
for(var i=0; i<targetValues.length; i++){
for(var i=0; i<targetLabels.length; i++){
var obj = {"value": targetValues[i], "name": targetLabels[i]};
finalChartValue.push(obj);
}
}
var otherObject={
value: otherValue,
name : otherLabel
};
var undefinedObject={
value: undefinedValue,
name : undefinedLabel
};
finalChartValue.unshift(otherObject, undefinedObject);
var finalChartLables=[];
finalChartValue.forEach(function(res) {
finalChartLables.push(res.name);
});
function sum(arrayData, key){
return arrayData.reduce((a,b) => {
return {value : a.value + b.value}
})
}
var tempSumObjectElements=sum(finalChartValue);
var sumObjectElements=tempSumObjectElements.value;
var finalPercentage=[];
finalChartValue.forEach(function(res) {
var result=res.value/sumObjectElements *100;
var percentage = result.toFixed(2);
finalPercentage.push(percentage);
});
// specify chart configuration item and data
var option = {
tooltip: {
trigger: 'item',
formatter: "{a} <br/>{b} : {c} ({d}%)",
},
legend: {
x : 'center',
y : 'bottom',
formatter: function(name) {
var data = this.getSeries()[0].data;
var totalValue = data.reduce((acc, item) => {
acc += item.value;
return acc;
}, 0)
var targetValue;
data.map(item => {
if (item.name == name) {
targetValue = item.value;
}
})
var p = (targetValue / totalValue * 100).toFixed(2);
return name + ' ' + p + '%';
},
data:finalChartLables
},
toolbox: {
show: true,
feature: {
dataView: { show: true, readOnly: false },
magicType: {
show: true,
type: ['pie']
},
restore: { show: true },
saveAsImage: { show: true }
}
},
color: ["#f62d51", "#dddddd", "#ffbc34", "#7460ee", "#009efb", "#2f3d4a", "#90a4ae", "#55ce63"],
calculable: true,
series: [{
name: 'ICD',
type: 'pie',
radius: [20, 110],
center : ['50%', '50%'],
roseType: 'radius',
itemStyle: {
normal: {
label: {
show: false,
formatter: "{b} : \n ({d}%)",
fontWeight: 100
},
labelLine: {
show: false,
formatter: "{b} : \n ({d}%)",
fontWeight: 100
}
},
emphasis: {
label: {
show: true,
formatter: "{b} : \n ({d}%)",
fontWeight: 100
},
labelLine: {
show: true,
formatter: "{b} : \n ({d}%)",
fontWeight: 100
}
}
},
data: finalChartValue
},
]
};
// use configuration item and data specified to show chart
ctx.setOption(option, true), $(function() {
function resize() {
setTimeout(function() {
ctx.resize()
}, 100)
}
$(window).on("resize", resize), $(".sidebartoggler").on("click", resize)
});
}
}
Try in your option variable;
responsive: true,
maintainAspectRatio: false
I found a solution, basically the radius command is used to configure the graph
radius: [20, 180],
docs here: https://echarts.apache.org/en/option.html#series-pie.emphasis
inside your series
...
emphasis: {
scale: true, <-----
scaleSize: 20, <-----
label: {
show: true,
fontSize: '30',
fontWeight: 'bold'
},
itemStyle: {
// Color in emphasis state.
color: 'blue',
},
},
...
You can set the width in your option variable, for example:
width: '50%'
docs: https://echarts.apache.org/en/option.html#series-pie.width
I'm using flotCharts and when i use two or more bar graphs, on hovering the bar it shows the value of the last graph loaded only, and the other graphs get the same value of the first. Here is the code:
HTML:
<div class="flot-chart">
<div class="flot-chart-content" id="flot-chart-#ControlID"></div>
</div>
JavaScript:
var series_#ControlID = [
#foreach (var serie in Model.Series)
{
<text>
{
label: '#serie.Name',
#DisplayGraphType(serie)
data: [
#foreach (var point in serie)
{
<text>
[#point.Item1, #point.Item2],
</text>
}
]
},
</text>
}
];
var xlabels = [
#foreach (var lbl in Model.Labels)
{
<text>[#lbl.Item1, "#lbl.Item2"],</text>
}
];
function getLabel(xval) {
var lbl = xval;
xlabels.forEach(function(e){
console.log(parseInt(e[0]) == parseInt(xval));
if (parseInt(e[0]) == parseInt(xval)) {
lbl = e[1];
}
});
return lbl;
}
$(function () {
$.plot($("#flot-chart-#ControlID"), series_#ControlID, {
series: {
lines: {
lineWidth: 2,
fill: #((Model.Series.Count() == 1).ToString().ToLower()),
},
bars: {
barWidth: 0.6,
align: "center"
},
points: {
fill: #((Model.Series.Count() == 1).ToString().ToLower()),
}
},
xaxis: {
ticks: xlabels,
tickDecimals: 0
},
colors: #Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject(Model.Series.Select(o => o.Color).ToArray())),
grid: {
color: "#999999",
hoverable: true,
clickable: true,
borderWidth: 0,
},
legend: {
show: true
},
tooltip: true,
tooltipOpts: {
content: function(label, xval, yval) {
var content = getLabel(xval) + ": " + yval;
return content;
},
}
});
});
the
#ControlID value is a Guid and it is automatically generated randomly and it's always different between charts.
In the example below, when i hover to the second bar of the graph, it shows the second bar value of the other graph (only the xaxes is wrong):
I fixed it, the problem was that i was overwriting the same variable because i included them more than once for each graph. The solution is to change the method names to make them unique using he IDs, as Raidri said in the comments:
var series_#ControlID = [
#foreach (var serie in Model.Series)
{
<text>
{
label: '#serie.Name',
#DisplayGraphType(serie)
data: [
#foreach (var point in serie)
{
<text>
[#point.Item1, #point.Item2],
</text>
}
]
},
</text>
}
];
var xlabels_#ControlID = [
#foreach (var lbl in Model.Labels)
{
<text>[#lbl.Item1, "#lbl.Item2"],</text>
}
];
function getLabel_#(ControlID)(xval) {
var lbl = xval;
xlabels_#(ControlID).forEach(function(e){
console.log(parseInt(e[0]) == parseInt(xval));
if (parseInt(e[0]) == parseInt(xval)) {
lbl = e[1];
}
});
return lbl;
}
$(function () {
$.plot($("#flot-chart-#ControlID"), series_#ControlID, {
series: {
lines: {
lineWidth: 2,
fill: #((Model.Series.Count() == 1).ToString().ToLower()),
},
bars: {
barWidth: 0.6,
align: "center"
},
points: {
fill: #((Model.Series.Count() == 1).ToString().ToLower()),
}
},
xaxis: {
ticks: xlabels_#ControlID,
tickDecimals: 0
},
colors: #Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject(Model.Series.Select(o => o.Color).ToArray())),
grid: {
color: "#999999",
hoverable: true,
clickable: true,
borderWidth: 0,
#if (Model.LimitLine != null)
{
<text>
markings: [
{ color: '#000', lineWidth: 1, yaxis: { from: #Model.LimitLine, to: #Model.LimitLine }},
]
</text>
}
},
legend: {
show: true
},
tooltip: true,
tooltipOpts: {
content: function(label, xval, yval) {
var content = getLabel_#(ControlID)(xval) + ": " + yval;
return content;
},
}
});
});
I have a stacked Column chart which gives my a list of columns. Each column has a name.
What I need to is is to get the name of the column that has been clicked on.
I have a couple of alerts in the series section which is where I want to data to be called from.
Here is the code:
var chart;
$(function () {
$.ajax({
url: 'url here',
method: 'GET',
async: false,
success: function(result) {
themainData = result;
}
});
var mainData = [themainData];
var chlist=[];
var votList=[];
var comList=[];
for (var i = 0; i < mainData[0].cha.length; i++) {
var obj = mainData[0].cha[i];
var chlst = obj.name;
var vl = obj.sta.vot;
var cl = obj.sta.com;
chlist.push(chlst);
votList.push(vl);
comList.push(cl);
}
//var chlist = ['Ch 1', 'Ch 2', 'Ch 3', 'Ch 4'];
////var votList = [10, 9, 8, 7];
//var comList = [10, 9, 8, 7];
var chart = {
type: 'column',
};
var title = {
text: 'vot and com'
};
var xAxis = {
categories: chlist
};
var yAxis ={
min: 0,
title: {
text: 'cha'
},
stackLabels: {
enabled: true,
style: {
fontWeight: 'bold',
color: (Highcharts.theme && Highcharts.theme.textColor) || 'gray'
}
}
};
var legend = {
align: 'right',
x: -30,
verticalAlign: 'top',
y: 25,
floating: true,
backgroundColor: (Highcharts.theme && Highcharts.theme.background2) || 'white',
borderColor: '#CCC',
borderWidth: 1,
shadow: false
};
var tooltip = {
formatter: function () {
return '<b>' + this.x + '</b><br/>' +
this.series.name + ': ' + this.y + '<br/>' +
'Total: ' + this.point.stackTotal;
}
};
var plotOptions = {
column: {
stacking: 'normal',
dataLabels: {
enabled: true,
color: (Highcharts.theme && Highcharts.theme.dataLabelsColor) || 'white',
style: {
textShadow: '0 0 3px black'
}
}
}
};
var credits = {
enabled: false
};
var series= [{
name: 'vot',
data: votList,
events: {
click: function (event) {
alert('vot Here');
alert ('show: '+ this.cha +', value: '+ this.y);
}
}
}, {
name: 'com',
data: comList,
events: {
click: function (event) {
alert('com Here');
alert ('show: '+ this.cha +', value: '+ this.y);
}
}
}];
var json = {};
json.chart = chart;
json.title = title;
json.xAxis = xAxis;
json.yAxis = yAxis;
json.legend = legend;
json.tooltip = tooltip;
json.plotOptions = plotOptions;
json.credits = credits;
json.series = series;
$('#container').highcharts(json);
//end
});
How can I do this?
You can add column.point.click event callback function and inside this function alert points name using alert(this.name)
plotOptions: {
column: {
stacking: 'normal',
keys: ['x', 'y', 'name'],
point: {
events: {
click: function() {
alert(this.name)
}
}
}
}
},
Here you can find an example how it can work:
http://jsfiddle.net/grz4zaLc/1/
I want to add data tables to Charts.
I tried the implementation shown here: http://jsfiddle.net/highcharts/z9zXM/
but it didnt work for me.
I suspect its because how I instantiate highcharts.
in the example above the chart is generated by instantiating the Highcharts object.
my code:
// data from an ajax call
$.each(data, function(indicator, questions) {
indicator_type = "";
$.each(questions, function(question, value) {
dataChartType = "column";
series = [];
categories = [];
category_totals = {};
if(value.programs == null) {
return true;
}
$.each(value.programs, function(program, body) {
total = 0;
values = [];
$.each(body, function(j, k) {
if (categories.indexOf(j) == -1) {
categories.push(j);
category_totals[j] = 0;
}
if(k != 0) {
values.push(k);
} else {
values.push(null);
}
category_totals[j] += parseInt(k, 10);
total += k;
});
series.push({
data: values,
total: total,
name: program //question
});
}); // eo each program
var chartDiv = document.createElement('div');
chartDiv.className = "chart";
$('.charts_wrap').append(chartDiv);
$(chartDiv).highcharts({
events: {
load: Highcharts.drawTable
},
chart: {
type: dataChartType
},
xAxis: {
categories: categories
},
legend: {
layout: 'vertical',
backgroundColor: '#FFFFFF',
align: 'right',
verticalAlign: 'top',
y: 60,
x: -60
},
tooltip: {
formatter: function () {
return '<strong>' + this.series.name + '</strong><br/>' + this.x + ': ' + this.y;
}
},
plotOptions: {
line: {
connectNulls: true
},
column: {
stacking: 'normal',
dataLabels: {
enabled: false,
color: (Highcharts.theme && Highcharts.theme.dataLabelsColor) || 'white',
style: {
textShadow: '0 0 3px w'
}
}
}
},
series: series,
title:{ text: indicator },
subtitle:{ text: question }
});
}); // EO each question
}); // eo each indicator
When instantiating highcharts like this:
$("#container").highcharts({ ...
The events option needs to be included inside the charts option:
$("#container").highcharts({
chart: {
type: 'column',
events: {
load: Highcharts.drawTable
},
},
...