Anychart doughnut chart standalone label - javascript

I'm trying to use a standalone label in the middle of the chart to display the "win %".
Right now it is hard coded, but would like it to obviously based on the chart data..
label.text("80%");
Here my code
<html>
<head>
<script src="https://cdn.anychart.com/releases/8.11.0/js/anychart-core.min.js"></script>
<script src="https://cdn.anychart.com/releases/8.11.0/js/anychart-pie.min.js"></script>
</head>
<body>
<script>
anychart.onDocumentReady(function () {
// create pie chart with passed data
var chart = anychart.pie([
['Winner', 12],
['Looser', 3]
]);
// set chart title text settings
chart
.title('% WIN RATIO')
// set chart radius
.radius('50%')
// create empty area in pie chart
.innerRadius('60%');
// enable labels for a series
// Centered label ---------------------------------------------------
// create and configure a label
var label = anychart.standalones.label();
label.text("80%");
label.width("100%");
label.height("100%");
label.fontColor("grey");
label.hAlign("center");
label.vAlign("middle");
label.fontSize("22");
// disable legend
var legend = chart.legend();
legend.enabled(false);
// set the label as the center content
chart.center().content(label);
// ------------------------------------------------------------------
// Information on hover ---------------------------------------------
// configure tooltips on the chart
chart.tooltip().title("Volume");
chart.tooltip().format("{%value} Trades");
// ------------------------------------------------------------------
// Labels -----------------------------------------------------------
// set chart labels position to outside
//chart.labels().position('outside');
chart.labels(false);
// font labels font settings
//chart.labels().fontFamily("Menlo");
//chart.labels().fontSize(18);
//chart.labels().fontDecoration("underline");
//chart.labels().fontWeight(900);
// ------------------------------------------------------------------
// set container id for the chart
chart.container('container');
// initiate chart drawing
chart.draw();
});
</script>
<div id="container">
</div>
</body>
</html>

Showing dynamic winrate percent is possible by accessing actual data. It is good practice to make a data set first in case you want to access and manipulate data later.
//Create dataset
var dataSet = anychart.data.set([
['Winner', 50],
['Looser', 3]
])
dataSet.mapAs({x: 0, value: 1})
var chart = anychart.pie(dataSet);
When you have your data set, you can easily access certain points by using the getPoint() method.
//Get numbers of winners and losers
var winnerCount = chart.getPoint(0).get("value")
var loserCount = chart.getPoint(1).get("value")
//Calculate winrate
var winRate = ((winnerCount*100)/(loserCount+winnerCount))
//Trim number and make it a String
var winRateString = winRate.toFixed(1).toString() + "%"
Using this approach, you can easily visualize dynamic variables in your charts.
Feel free to explore how to extract data from points in a data set on our playground.

Related

Amchart switch bullet on/off

have some graph with bullet displayed:
my chart is created wit JSON script:
var chart2 = AmCharts.makeChart("idchart",.....);
How to disable bullets with javascript accessing object chart2?
thank you
Just remove the value of bullet on each graphs.
$.each(chart2.graphs, function(key, value){
value.bullet = 'none';
});

google chart pass segment value

I am trying to figure out how to pass value from segment from google donut chart through javascript. Following this example (the donut one), I modified html like: onmouseover="segmentMouseOver(event)"
to pass the event onMouseOver. Although, I cannot find a way to pass the value of donut's segment, on which is mouse over.
Any help is welcome!
// Instantiate and draw our chart, passing in some options.
var chart = new google.visualization.PieChart(document.getElementById('donutchart'));
function selectHandler() {
var selectedItem = chart.getSelection()[0];
if (selectedItem) {
var topping = data.getValue(selectedItem.row, 0);
alert('The user selected ' + topping);
}
}
google.visualization.events.addListener(chart, 'select', selectHandler);
chart.draw(data, options);
you can find out more here.

Multiple charts in background ChartJS

Im having an issue when i generate one chart with chart.js, but when i generate another chart from the menu in the same page, it generates the chart, but when i move the move over the chart it changes to previous one.
UPDATE
After some research in chart.js documentation found an method that clear the chart data, ive applied to the controller before getting new data, unfortunately continues to get the previous charts in background when mouse over the chart ive made a console log of the array that contains the values, and that is updated with the data of the most recent request.
Code from the controller
$scope.getChart = function (report) {
$scope.modalLabels = [];
$scope.data = {values: ([])}; //Array that contains the data recieved from the server
if($('#chartBar')!=null){
$('#chartBar').removeData();
}
/*Function to request data to server*/
//If data recieved
var avgCapacity = [];
for (var i = 0, length = data.length; i < length; i++) {
avgCapacity.push(data[i].Volume);
$scope.modalLabels.push(data[i].Day + "/" + data[i].Month);
}
$scope.data.values = ([avgCapacity]);
This is the html behind:
<div ng-hide="data==0">
<h4 id="chartTitle"><b>{{Title}}</b></h4>
<canvas id="ChartBar" class="chart chart-bar" chart-data="data" chart-options="options"
chart-labels="modalLabels" chart-legend="true" chart-series="series">
</canvas>
</div>
You need to destroy the previous chart instance by calling .destroy() before you generate the new chart.

How to clear a chart from a canvas so that hover events cannot be triggered?

I'm using Chartjs to display a Line Chart and this works fine:
// get line chart canvas
var targetCanvas = document.getElementById('chartCanvas').getContext('2d');
// draw line chart
var chart = new Chart(targetCanvas).Line(chartData);
But the problem occurs when I try to change the data for the Chart. I update the graph by creating a new instance of a Chart with the new data points, and thus reinitializing the canvas.
This works fine. However, when I hover over the new chart, if I happen to go over specific locations corresponding to points displayed on the old chart, the hover/label is still triggered and suddenly the old chart is visible. It remains visible while my mouse is at this location and disappears when move off that point. I don't want the old chart to display. I want to remove it completely.
I've tried to clear both the canvas and the existing chart before loading the new one. Like:
targetCanvas.clearRect(0,0, targetCanvas.canvas.width, targetCanvas.canvas.height);
and
chart.clear();
But none of these have worked so far. Any ideas about how I can stop this from happening?
I had huge problems with this
First I tried .clear() then I tried .destroy() and I tried setting my chart reference to null
What finally fixed the issue for me: deleting the <canvas> element and then reappending a new <canvas> to the parent container
My specific code (obviously there's a million ways to do this):
var resetCanvas = function(){
$('#results-graph').remove(); // this is my <canvas> element
$('#graph-container').append('<canvas id="results-graph"><canvas>');
canvas = document.querySelector('#results-graph');
ctx = canvas.getContext('2d');
ctx.canvas.width = $('#graph').width(); // resize to parent width
ctx.canvas.height = $('#graph').height(); // resize to parent height
var x = canvas.width/2;
var y = canvas.height/2;
ctx.font = '10pt Verdana';
ctx.textAlign = 'center';
ctx.fillText('This text is centered on the canvas', x, y);
};
I have faced the same problem few hours ago.
The ".clear()" method actually clears the canvas, but (evidently) it leaves the object alive and reactive.
Reading carefully the official documentation, in the "Advanced usage" section, I have noticed the method ".destroy()", described as follows:
"Use this to destroy any chart instances that are created. This will
clean up any references stored to the chart object within Chart.js,
along with any associated event listeners attached by Chart.js."
It actually does what it claims and it has worked fine for me, I suggest you to give it a try.
var myPieChart=null;
function drawChart(objChart,data){
if(myPieChart!=null){
myPieChart.destroy();
}
// Get the context of the canvas element we want to select
var ctx = objChart.getContext("2d");
myPieChart = new Chart(ctx).Pie(data, {animateScale: true});
}
This is the only thing that worked for me:
document.getElementById("chartContainer").innerHTML = ' ';
document.getElementById("chartContainer").innerHTML = '<canvas id="myCanvas"></canvas>';
var ctx = document.getElementById("myCanvas").getContext("2d");
We can update the chart data in Chart.js V2.0 as follows:
var myChart = new Chart(ctx, data);
myChart.config.data = new_data;
myChart.update();
I had the same problem here... I tried to use destroy() and clear() method, but without success.
I resolved it the next way:
HTML:
<div id="pieChartContent">
<canvas id="pieChart" width="300" height="300"></canvas>
</div>
Javascript:
var pieChartContent = document.getElementById('pieChartContent');
pieChartContent.innerHTML = ' ';
$('#pieChartContent').append('<canvas id="pieChart" width="300" height="300"><canvas>');
ctx = $("#pieChart").get(0).getContext("2d");
var myPieChart = new Chart(ctx).Pie(data, options);
It works perfect to me... I hope that It helps.
This worked very well for me
var ctx = $("#mycanvas");
var LineGraph = new Chart(ctx, {
type: 'line',
data: chartdata});
LineGraph.destroy();
Use .destroy this to destroy any chart instances that are created. This will clean up any references stored to the chart object within Chart.js, along with any associated event listeners attached by Chart.js. This must be called before the canvas is reused for a new chart.
It's best to use Chart.js specific functionalities to initially check for the existing chart instance and then perform destroy or clear in order to reuse the same canvas element for rendering another chart, instead of handlding HTML elements from within JS.
ChartJs's getChart(key) - finds the chart instance from the given key.
If the key is a string, it is interpreted as the ID of the Canvas element for the Chart.
The key can also be a CanvasRenderingContext2D or an HTMLDOMElement.
Note: This will return undefined if no Chart is found. If the instance of the chart is found, it signifies that the chart must have previously been created.
// JS - Destroy exiting Chart Instance to reuse <canvas> element
let chartStatus = Chart.getChart("myChart"); // <canvas> id
if (chartStatus != undefined) {
chartStatus.destroy();
//(or)
// chartStatus.clear();
}
//-- End of chart destroy
var chartCanvas = $('#myChart'); //<canvas> id
chartInstance = new Chart(chartCanvas, {
type: 'line',
data: data
});
<!-- HTML -Line Graph - Chart.js -->
<div class="container-fluid" id="chartContainer">
<canvas id="myChart" width="400" height="150"> </canvas>
</div>
This approach would save you from remove - create - append a Canvas element into DIV from inside JS.
Simple edit for 2020:
This worked for me. Change the chart to global by making it window owned (Change the declaration from var myChart to window myChart)
Check whether the chart variable is already initialized as Chart, if so, destroy it and create a new one, even you can create another one on the same name. Below is the code:
if(window.myChart instanceof Chart)
{
window.myChart.destroy();
}
var ctx = document.getElementById('myChart').getContext("2d");
Hope it works!
Complementing Adam's Answer
With Vanilla JS:
document.getElementById("results-graph").remove(); //canvas
div = document.querySelector("#graph-container"); //canvas parent element
div.insertAdjacentHTML("afterbegin", "<canvas id='results-graph'></canvas>"); //adding the canvas again
Using CanvasJS, this works for me clearing chart and everything else, might work for you as well, granting you set your canvas/chart up fully before each processing elsewhere:
var myDiv= document.getElementById("my_chart_container{0}";
myDiv.innerHTML = "";
I couldn't get .destroy() to work either so this is what I'm doing. The chart_parent div is where I want the canvas to show up. I need the canvas to resize each time, so this answer is an extension of the above one.
HTML:
<div class="main_section" >
<div id="chart_parent"></div>
<div id="legend"></div>
</div>
JQuery:
$('#chart').remove(); // this is my <canvas> element
$('#chart_parent').append('<label for = "chart">Total<br /><canvas class="chart" id="chart" width='+$('#chart_parent').width()+'><canvas></label>');
When you create one new chart.js canvas, this generate one new iframe hidden, you need delete the canvas and the olds iframes.
$('#canvasChart').remove();
$('iframe.chartjs-hidden-iframe').remove();
$('#graph-container').append('<canvas id="canvasChart"><canvas>');
var ctx = document.getElementById("canvasChart");
var myChart = new Chart(ctx, { blablabla });
reference:
https://github.com/zebus3d/javascript/blob/master/chartJS_filtering_with_checkboxs.html
This worked for me.
Add a call to clearChart, at the top oF your updateChart()
`function clearChart() {
event.preventDefault();
var parent = document.getElementById('parent-canvas');
var child = document.getElementById('myChart');
parent.removeChild(child);
parent.innerHTML ='<canvas id="myChart" width="350" height="99" ></canvas>';
return;
}`
Since destroy kind of destroys "everything", a cheap and simple solution when all you really want is to just "reset the data". Resetting your datasets to an empty array will work perfectly fine as well. So, if you have a dataset with labels, and an axis on each side:
window.myLine2.data.labels = [];
window.myLine2.data.datasets[0].data = [];
window.myLine2.data.datasets[1].data = [];
After this, you can simply call:
window.myLine2.data.labels.push(x);
window.myLine2.data.datasets[0].data.push(y);
or, depending whether you're using a 2d dataset:
window.myLine2.data.datasets[0].data.push({ x: x, y: y});
It'll be a lot more lightweight than completely destroying your whole chart/dataset, and rebuilding everything.
If you are using chart.js in an Angular project with Typescript, the you can try the following;
Import the library:
import { Chart } from 'chart.js';
In your Component Class declare the variable and define a method:
chart: Chart;
drawGraph(): void {
if (this.chart) {
this.chart.destroy();
}
this.chart = new Chart('myChart', {
.........
});
}
In HTML Template:
<canvas id="myChart"></canvas>
What we did is, before initialization of new chart, remove/destroy the previews Chart instance, if exist already, then create a new chart, for example
if(myGraf != undefined)
myGraf.destroy();
myGraf= new Chart(document.getElementById("CanvasID"),
{
...
}
Hope this helps.
First put chart in some variable then history it next time before init
#Check if myChart object exist then distort it
if($scope.myChart) {
$scope.myChart.destroy();
}
$scope.myChart = new Chart(targetCanvas
You should save the chart as a variable.
On global scope, if its pure javascript, or as a class property, if its Angular.
Then you'll be able to use this reference to call destroy().
Pure Javascript:
var chart;
function startChart() {
// Code for chart initialization
chart = new Chart(...); // Replace ... with your chart parameters
}
function destroyChart() {
chart.destroy();
}
Angular:
export class MyComponent {
chart;
constructor() {
// Your constructor code goes here
}
ngOnInit() {
// Probably you'll start your chart here
// Code for chart initialization
this.chart = new Chart(...); // Replace ... with your chart parameters
}
destroyChart() {
this.chart.destroy();
}
}
For me this worked:
var in_canvas = document.getElementById('chart_holder');
//remove canvas if present
while (in_canvas.hasChildNodes()) {
in_canvas.removeChild(in_canvas.lastChild);
}
//insert canvas
var newDiv = document.createElement('canvas');
in_canvas.appendChild(newDiv);
newDiv.id = "myChart";
Chart.js has a bug:
Chart.controller(instance) registers any new chart in a global property Chart.instances[] and deletes it from this property on .destroy().
But at chart creation Chart.js also writes ._meta property to dataset variable:
var meta = dataset._meta[me.id];
if (!meta) {
meta = dataset._meta[me.id] = {
type: null,
data: [],
dataset: null,
controller: null,
hidden: null, // See isDatasetVisible() comment
xAxisID: null,
yAxisID: null
};
and it doesn't delete this property on destroy().
If you use your old dataset object without removing ._meta property, Chart.js will add new dataset to ._meta without deletion previous data. Thus, at each chart's re-initialization your dataset object accumulates all previous data.
In order to avoid this, destroy dataset object after calling Chart.destroy().
for those who like me use a function to create several graphics and want to update them a block too, only the function .destroy() worked for me, I would have liked to make an .update(), which seems cleaner but ... here is a code snippet that may help.
var SNS_Chart = {};
// IF LABELS IS EMPTY (after update my datas)
if( labels.length != 0 ){
if( Object.entries(SNS_Chart).length != 0 ){
array_items_datas.forEach(function(for_item, k_arr){
SNS_Chart[''+for_item+''].destroy();
});
}
// LOOP OVER ARRAY_ITEMS
array_items_datas.forEach(function(for_item, k_arr){
// chart
OPTIONS.title.text = array_str[k_arr];
var elem = document.getElementById(for_item);
SNS_Chart[''+for_item+''] = new Chart(elem, {
type: 'doughnut',
data: {
labels: labels[''+for_item+''],
datasets: [{
// label: '',
backgroundColor: [
'#5b9aa0',
'#c6bcb6',
'#eeac99',
'#a79e84',
'#dbceb0',
'#8ca3a3',
'#82b74b',
'#454140',
'#c1502e',
'#bd5734'
],
borderColor: '#757575',
borderWidth : 2,
// hoverBackgroundColor : '#616161',
data: datas[''+for_item+''],
}]
},
options: OPTIONS
});
// chart
});
// END LOOP ARRAY_ITEMS
}
// END IF LABELS IS EMPTY ...
just declare let doughnut = null before creating your chart
const doughnutDriverStatsChartCanvas = $('#dougnautChartDriverStats').get(0).getContext('2d')
const doughnutOptionsDriverStats = {
maintainAspectRatio: false,
responsive: true,
}
let doughnut = null
doughnut = new Chart(doughnutDriverStatsChartCanvas, {
type: 'doughnut',
data: doughnutChartDriverStats,
options: doughnutOptionsDriverStats
})

How to get two different google charts on one page from two separate spreadsheet data sources

I'm trying to get multiple chats on the same page, each one using a different spreadsheet url for its data source.
The code below works ok, but I really want to have multiple urls for different data ranges and show a different chart each time.
When I tried this originally, it only ever showed the last chart I tried to draw.
I’ve reworked the script (which still works) to move closer to a situation where I’ve got multiple sets of data for the multiple charts and their locations. It’s not quite there though. This was based on the following post:
How to add two Google charts on the one page?
I think I need to pass the multiple sets of data as attributes of the handleQueryResponse function but I don’t know how to do that.
I was trying to get it to work for just one set of data first, and if that works ok, add multiple sets of data into it.
<script type="text/javascript" src="https://www.google.com/jsapi"></script>
<script type="text/javascript">
(function() { // Begin scoping function
// vars Global to my code, invisible outside the scoping function
// Set chart options
// I'll be using multiple options for different charts, options1, options2 etc.
var options1 = {'title':'Light & Temperature data - Last 24 Hours',
'width':750,
'height':400,
'curveType': 'function',
'backgroundColor':'ffe599',
"hAxes":[{"title":"Time"}],
"vAxes":[{"title":"Temp in °C -- Light Levels"}]};
//I think I will need containerID1, containerID2 etc. one for each chart
var containerID = 'chart_div1';
//same for chartType1, chartType2
var chartType = 'LINECHART';
// Load the Visualization API and the core chart package.
google.load('visualization', '1.0', {'packages':['corechart']});
// Set a callback to run when the Google Visualization API is loaded.
google.setOnLoadCallback(drawChart);
// Callback that creates and populates a data table,
// instantiates the chart, passes in the data and
// draws it.
function drawChart() {
//I'm going to have multiple urls and each one will be the source for a seperate chart
var query1 = new google.visualization.Query(
'https://docs.google.com/spreadsheet/ccc?key=0ArGuv......&transpose=0&headers=1&range=L1%3AN500&gid=1');
query1.send(handleQueryResponse);
}
// how do I get containerID1, containerID2, chartType1, ChartType2 Options1, Options2 etc. into this function?
function handleQueryResponse(response) {
if (response.isError()) {
alert('Error in query: ' + response.getMessage() + ' ' + response.getDetailedMessage());
return;
}
var data = response.getDataTable();
var containerDiv = document.getElementById(containerID);
var chart = false;
// Instantiate and draw the chart, based on some the chartType and passing in the options.
if (chartType.toUpperCase() == 'BARCHART') {
chart = new google.visualization.BarChart(containerDiv);
}
else if (chartType.toUpperCase() == 'COLUMNCHART') {
chart = new google.visualization.ColumnChart(containerDiv);
}
else if (chartType.toUpperCase() == 'PIECHART') {
chart = new google.visualization.PieChart(containerDiv);
}
else if (chartType.toUpperCase() == 'LINECHART'){
chart = new google.visualization.LineChart(containerDiv);
}
if (chart == false) {
return false;
}
chart.draw(data, options1);
}
})(); // End scoping function
</script>
<!--Divs that will hold the charts - Only chart_div1 is in effect at the moment -->
<div id="chart_div1"></div>
<div id="chart_div2"></div>
You need two response handlers and two queries if you are querying two different data sources:
function drawChart() {
var query1 = new google.visualization.Query(url1);
query1.send(handleQueryResponse1);
var query2 = new google.visualization.Query(url2);
query2.send(handleQueryResponse2);
}

Categories