How to make a custom legend in angular-chart.js Pie Chart - angularjs

I used angular-chart.js in my website to create a Pie chart, and I would like to customize the legend. By default, the legend shows the color and the label. (As shown in the picture below) I would like to add the value/data of that label, like what it shown in the tooltip of the chart.
This is my HTML code:
<canvas id="pie" class="chart chart-pie"
chart-data="chartData" chart-labels="chartLabels" chart-options="chartOptions">
</canvas>
Based on the angular-chart.js documentation, legend is now a Chart.js option so the chart-legend attribute has been removed.
That is why, in my JS code I've tried to add generateLabels, just in case this is what I need to customize the legend:
$scope.chartOptions = {
legend: {
display: true,
labels: {
generateLabels: function(chart){
console.log(chart.config);
}
}
}
};
But whenever I add this lines, it will not show the chart. I think it is an error or something. And I'm not sure, if generateLabels is the right option that I needed.
Can somebody teach me the right way to customize the legend to achieve what I wanted?
Thanks in advance!

Let me try shedding some light/answering your question:
generateLabels: does make custom labels,and replaces templates from v1 but in order to use it you have to get your chart information and reimplement legend labels adhering to the Legend Item Interface found in the docs and code. Sounds a bit cryptic, but in practice is somehow simple and goes like this:
var theHelp = Chart.helpers;
// You need this for later
// Inside Options:
legend: {
display: true,
// generateLabels changes from chart to chart, check the source,
// this one is from the doughnut :
// https://github.com/chartjs/Chart.js/blob/master/src/controllers/controller.doughnut.js#L42
labels: {
generateLabels: function(chart) {
var data = chart.data;
if (data.labels.length && data.datasets.length) {
return data.labels.map(function(label, i) {
var meta = chart.getDatasetMeta(0);
var ds = data.datasets[0];
var arc = meta.data[i];
var custom = arc && arc.custom || {};
var getValueAtIndexOrDefault = theHelp.getValueAtIndexOrDefault;
var arcOpts = chart.options.elements.arc;
var fill = custom.backgroundColor ? custom.backgroundColor : getValueAtIndexOrDefault(ds.backgroundColor, i, arcOpts.backgroundColor);
var stroke = custom.borderColor ? custom.borderColor : getValueAtIndexOrDefault(ds.borderColor, i, arcOpts.borderColor);
var bw = custom.borderWidth ? custom.borderWidth : getValueAtIndexOrDefault(ds.borderWidth, i, arcOpts.borderWidth);
return {
// And finally :
text: ds.data[i] + "% of the time " + label,
fillStyle: fill,
strokeStyle: stroke,
lineWidth: bw,
hidden: isNaN(ds.data[i]) || meta.data[i].hidden,
index: i
};
});
}
return [];
}
}
}
Result:
Codepen: Chart.js Pie Chart Custom Legend Labels
There are other alternatives, if you notice on the pen/pie, the slices also have data information, that is from a plugin (check the pen)
Still another option, is to render the legend labels off canvas,for instance:
myPieChart.generateLegend();
Which gives you this Html:
"<ul class='0-legend'><li><span style='background-color:black'> </span>she returns it </li><li><span style='background-color:white'></span>she keeps it</li></ul>"
I haven't tried it, but I think you can modify it with the global method for your data Legend on the callback an it will give you a block of Html you can insert off canvas.

Related

Hiding single series label in legend on apex charts

I'm using heatmap chart (https://apexcharts.com/docs/chart-types/heatmap-chart/) and i would like to hide a single item in legend: the series 1 label called "label1".
The results would be something like:
So, i just want to hide a single item in legend and not the entire series
Easiest way would be to use pure js to hide first legend item after chart renders, like this
document.querySelectorAll("#chart .apexcharts-legend-series")[0].style.display = "none";
Second solution to hide first series using options
legend: {
formatter: (seriesName, opts)=>{
if(opts.seriesIndex==0) return '' // hides first label
return seriesName;
},
markers: {
width: [0,12,12,12], // hides first marker
}
}

Google chart range selector chart type as column chart

In the example I added a column chart with range selector. I changed the chartType of range selector to ColumnChart. But its not changing to column chart. can some one help on this.
Also is there is any way to customize the design of the range selector as in this image.
valid chart types for the ChartRangeFilter are...
ui.chartType = 'AreaChart', 'LineChart', 'ComboChart' or 'ScatterChart'
in this case, use...
'ComboChart'
then set chart option...
ui.chartOptions.seriesType = 'bars'
e.g.
var control = new google.visualization.ControlWrapper({
controlType: 'ChartRangeFilter',
containerId: 'control',
options: {
filterColumnIndex: 0,
ui: {
chartType: 'ComboChart',
chartOptions: {
seriesType: 'bars'
}
}
}
});

How to add a vertical plot line in multiple line series and show the tooltip on Plot line in highchart

I am trying to add a plotline on click in multiple series line chart in reactjs. I am using stockchart of high chart, Please let me know how to add plotline with tooltip.
Sample Screenshot:
I prepared a demo which shows how to add the plotLine dynamically with the custom tooltip.
Demo: https://jsfiddle.net/BlackLabel/Lyr82a5x/
btn.addEventListener('click', function() {
chart.xAxis[0].addPlotLine({
value: 5.5,
color: 'red',
width: 2,
id: 'plot-line-1',
events: {
mouseover() {
let lineBBox = this.svgElem.getBBox();
tooltip.style.display = 'block';
tooltip.style.left = lineBBox.x + 'px';
},
mouseout() {
tooltip.style.display = 'none'
}
}
})
})
If something is unclear - feel free to ask.
API: https://api.highcharts.com/highcharts/xAxis.plotLines.events.mouseout
API: https://api.highcharts.com/class-reference/Highcharts.Axis#addPlotLine

How to add scroll-bar in the chart

Hi I have created a sample chart using public data, but it has more data to display in the chart, so I'm trying to add scroll-bar along x-axis so that all the data are displayed neatly. But I'm finding it difficult to add the scroll-bar to x-axis, so how to add scroll-bar to the chart. I have attached a plnkr for viewing. Please help me.Thank you :)
Controller:
var myApp = angular.module('app',["chart.js"]);
myApp.controller("chartController",function($scope,$http){
$scope.totalDocks = [];
$scope.availDocks =[];
$http.get("http://citibikenyc.com/stations/json")
.then(function(item){
var dataFetched = item;
console.log(dataFetched.data.stationBeanList[0]);
for(var i=0; i < 100 ; i++){
$scope.totalDocks.push(dataFetched.data.stationBeanList[i].totalDocks);
$scope.availDocks.push(dataFetched.data.stationBeanList[i].availableDocks);
}
})
})
Plunker File
Since angular.chart is responsive by itself, you do not have to add scroll bar manually, instead inorder to make chart to appear claerly you can make ticks along x axis to be skipped.
Add this to your options config,
$scope.options = {
scales: {
xAxes: [{
ticks: {
autoSkipPadding: 100
}
}]
},
responsive: true,
maintainAspectRatio: true
};
DEMO

ExtJS 6 toggle legend fields

Now legend in EXTJS works in such way: it shows all available legend fields and appropriate series and you can enable/disable any of them. I want to make that only one legend item can be enabled in one time. E.g. you have chart with 2 legend items (with 2 series), only first item is active on chart load and then if you want to active second item then first item becomes automatically disabled.
Here is chart fiddle with native ExtJS behaviour:
https://fiddle.sencha.com/#fiddle/1b7d
Please, post ideas how can I make it work as I described before.
If you have a look at the legend source code, freely available in your Ext directory or in the Sencha docs, you find that you can override that toggleItem method in such a way that only one selection is allowed.
The basics should be something like
toggleItem: function (index) {
var store = this.getStore(),
record = store.getAt(index);
store.query("disabled", false).each(function(record) {record.set("disabled", true) });
record.set("disabled", false);
}
but it doesn't work exactly as expected. Perhaps you can pave your way along from there.
this can be easily achieved with using legend type dom, and looping and setting every other legend (button) disabled, as followed -
legend: {
docked: 'bottom',
type: 'dom',
listeners: {
itemclick: function(obj, record, item, index) {
var i = 0,
records = obj.getStore().getRange();
for(i=0; i < records.length; i++){
i === index ? records[i].set('disabled', false) : records[i].set('disabled', true);
}
}
}
}

Resources