In my code snippet, a Deferred/Promise returns a configured Highchart Chart object named myChart . First time through, my chart is added to a container and everything renders perfectly. However, on subsequent calls where my logic performs a removeAll to refresh the container, my chart renders gray-out with loadMask ("Loading ...") spinning perpetually.
I've investigated the myChart object data for variance and it seems to be stable. I've even attempted to render far more simplified chart objects and in every case the subsequent renderings hang with the loadMask spinning.
Any thoughts on why it might be hanging on all the subsequent calls??
I've read in somewhat-related threads that buffering can be an issue, but I don't think that applies since I am using arrays and using store objects to load the data into the chart.
Thanks in advance for any hints or pointers!
// Set chart data
that._setChartData().then({
success: function( myChart ) {
// Render chart
if (gridContainer.items.length > 0) {
// Remove/Clear container objects ... if exists
Ext.Array.each( gridContainer.items, function( aItm ) {
switch( aItm.itemId ) {
case 'topbox':
break;
case 'buttonBox':
if ( aItm.items.length > 0 ) {
aItm.removeAll( true );
}
break;
case 'sliderBox':
if ( aItm.items.length > 0 ) {
aItm.removeAll( true );
}
break;
case 'chartbox':
if ( aItm.items.length > 0 ) {
aItm.removeAll();
}
break;
}
});
}
that.down('#chartbox').add(myChart);
}
});
I suspect there's a rendering bug, because when i add this to my code (before defining the app), replacing the chart works:
Ext.override(Rally.ui.chart.Chart,{
onRender: function () {
this.callParent(arguments);
this._unmask();
}
});
Related
I have been trying to solve this problem with ChartJS for a few days now, and I am completely stumped
My program shows the user a set of input elements they use to select data needing to be charted, plus a button that has an event to chart their data. The first chart works great. If they make a change to the data and click the button a second, third, or more time, all the data from the previous charts is plotted, PLUS their most recent selection.
It is behaving exactly like you might expect if the chart.destroy() object is not working, or perhaps would work if I created the chart object using a CONST (and could therefore add new data but not delete the beginning data).
I have tried all combinations of the browsers, chartjs and jquery libraries below:
Three different browsers:
• Chrome: Version 107.0.5304.121 (Official Build) (64-bit)
• Microsoft Edge: Version 107.0.1418.56 (Official build) (64-bit)
• Firefox: 107.0 64-bit
I have tried at least three different versions of Chart.js, including
• Versions 3.9.1
• 3.6.2
• 3.7.0
Jquery.js
• v3.6.1
• v1.11.1
Other things I have tried:
"use strict" (no luck)
In addition to destroying the chart object, removed the div containing the canvas, and appending it again.
using setTimeout() function before updating the chart after destroying it (because I thought maybe giving the destroy method more time might help)
type here
Software:
<script type="text/javascript" src="js/jquery.js"></script>
<script type="text/javascript" src="js/chart.js"></script>
<script type="text/javascript" src="js/dropdownLists.js"></script>
<script type="text/javascript" src="js/chartDataFunctions.js"></script>
<script type="text/javascript" src="js/chartJSFunctions.js"></script>
<body>
<div class = metadatasetup4" id = "buttons">
<button class="download" id="getchart" value="Get Chart">Chart</button>
<button class="download" id="downloadchart" value="Download">Download</button>
</div>
<div id = "bigchartdiv" class="bigchart">
<canvas id="myChart"></canvas>
</div>
</body>
<script>
$(window).on('load',function(){
//NOTE 1: In of my attempts to troubleshoot I tried strict mode (it didn't work)
//"use strict";
let data = {
labels: lbl,
datasets: [
]
};
let config = {
type: 'line',
data: data,
options: {
scales: {
y: {
type: 'linear',
display: true,
position: 'left',
min:0,
pointStyle:'circle',
},
y1: {
type: 'linear',
display: true,
position: 'right',
suggestedMax: 25,
min: 0,
pointStyle: 'cross',
// grid line settings
grid: {
drawOnChartArea: false, // only want the grid lines for one axis to show up
},
},
}
}
};
// NOTE 2: The next line below, beginning with "var bigChartHTML =" was one of my later attempts to
// solve the problem. It didn't work, but my thought process was that if I removed
// the div containing the canvas, AND destroyed the chart object, that appending a "fresh"
// chart div to the body might be a work-around. This did not work.
var bigChartHTML = '<div id = "bigchartdiv" class="bigchart"><canvas id="myChart"></canvas></div>'
let ctx = document.getElementById('myChart').getContext('2d');
let bigChart = null;
// The getChartData() function below uses Ajax to populate various dropdown lists
// which enable the user to select the data is to be charted.
// There are no chartjs-related operations in getChartData()
getChartData();
$('#buttons').on('click','#getchart',function(){
if (bigChart!=null) {
//removeData(bigChart);
bigChart.destroy();
//bigChart = 1;
}
$("#bigchartdiv").empty(); //for this and next 2 lines, see NOTE 2 above
$("#bigchartdiv").remove();
$(bigChartHTML).insertAfter("#chartcontrols");
bigChart = new Chart(document.getElementById('myChart'),config);
//NOTE 3: I thought maybe bigChart.destroy() took time, so I tried
// using the setTimeout function to delay updating the chart
// (didn't work, but I left it in the code, anyway.)
setTimeout(function() {updateChart(bigChart)}, 2000);
//updateChart(bigChart);
});
// NOTE: The updateChart() function is actually included in "js/chartDataFunctions.js"
function updateChart(chart) {
/*
This section of the program reads the HTML elements then uses them
to make an Ajax request to sql server, and these become the
parameters for the newDataSet() function below.
*/
newDataset(chart,firstElement,newdataset,backgroundcolor,color);
}
// NOTE: The newDataSet() function is actually included in "js/chartJSFunctions.js"
// I show it here for brevity.
// It decides which axis (y or y1) to use to plot the datasets
// the dataset is pushed into the data, and chart.update() puts it in the chart object
function newDataset(chart,label,data,bgcolor='white',color='rgb(255,255,255)') {
var maxValue = Math.max(...data);
if (Number.isNaN(maxValue)) {
return;
}
if (maxValue == 0) {
return;
}
var axisID = 'y';
var ptStyle = 'circle';
//var pStyle = 'circle';
if (maxValue < 50) {
axisID = 'y1';
bgcolor = 'white';
//ptStyle = 'Star'
}
chart.data.datasets.push({
label:label,
yAxisID:axisID,
data:data,
borderColor:color,
backgroundColor:bgcolor,
//pointStyle:ptStyle
});
chart.update();
}
});
</script>
I found a work-around that solves my problem, but I still think this is a bug in ChartJS. Before calling bigChart.destroy(), I now do two things: First, reset the data object back to it's original value, and second, reset the config object back to it's original value, THEN call bigChart.destroy().
I think the destroy() method should handle that for me, but in my case, for whatever reason, it doesn't.
So, what I have is a work-around, not really a solution, but I'll take it.
I am using Amcharts plugins in making a graph. But I am having issues in hiding and showing the graph using legends.
This is my function code:
function handleLegendClick( graph ) {
var chart = graph.chart;
for( var i = 0; i < chart.graphs.length; i++ ) {
if ( graph.id == chart.graphs[i].id )
chart.hideGraph(chart.graphs[i]);
else
chart.showGraph(chart.graphs[i]);
}
if (graph.id == chart.graphs['3'].id)
chart.hideGraph(chart.graphs['4']);
if (graph.id ==chart.graphs['4'].id)
chart.hideGraph(chart.graphs['3']);
chart.validateNow();
// return false so that default action is canceled
return true;
}
This code is working but my problem is, it hides only one graph and show the graph again when the user click another legend. What I need to do is to hide multiple graphs by clicking it's assigned label text and marker, and when the graph is hidden I should click the same legend to show the hidden graph.
Please help me. Thank you.
From your description, the default legend behavior does exactly what you're asking for without needing to add your handleClick code. I'm not sure what's the point of it.
var chart = AmCharts.makeChart("chartdiv", {
// ...
"legend": { }, //default setup
});
Here's an example with multiple graphs.
I have a bar chart I built using the 'amcharts' plugin.
The graph updates its values when the a dropdown menu item is selected,
I am trying to get the graph to animate the transition between the values when it changes, currently it either resets the whole animation and animates from '0', or if animateAgain() is commented out (line 142 in js) it jumps to the new value. This code is called after the values have been updated:
// Animate between values instead of resetting animation?
chart.animateAgain(); // Resets animation
chart.validateData(); // redraws the chart with new data
I've searched the docs and google but can't find anything to help with this, anyone have any ideas or pointers in the right direction? Is it possible? Here's the codepen :
http://codepen.io/bananafarma/pen/yewbJQ
Cheers!!
You can use amCharts' own Animate plugin.
It adds a new method to chart objects animateData().
function updateGraph() {
var newData = chart.dataProvider.slice();
if( document.getElementById('data-set').value == 1 ) {
newData[0].gain= 3.8;
newData[1].gain= 8.5;
newData[2].gain= 3;
newData[3].gain= 1.9;
}
else if ( document.getElementById('data-set').value == 2 ) {
console.log("yo");
newData[0].gain= 2.6;
newData[1].gain= 8.6;
newData[2].gain= 13.8;
newData[3].gain= 4;
}
else if ( document.getElementById('data-set').value == 3 ) {
newData[0].gain= 4.8;
newData[1].gain= 10.6;
newData[2].gain= 15.9;
newData[3].gain= 16;
}
// use Animate plugin
chart.animateData( newData, { duration: 1000 } );
}
Here's your updated working demo.
Do you know how to thoroughly remove/clean JQPlot chart. Here is my code to clean it:
$j("#reset").click(function() {
$j("#chart").empty();
if (plot1) {
plot1 = null;
}
});
when I click reset button, the chart can be removed from my page, but when I choose new conditions from drop down lists to generate new chart, the old chart will overlap with the new chart, like this image showed
Do you know how to truly clean the old chart? Thanks!
Maybe you want to use redraw method.
http://www.jqplot.com/docs/files/jqplot-core-js.html#jqPlot.redraw
You can redraw it with empty values using :
$.("#reset").click(function(){
if(plot1){
plot1 = $.jqplot('chart', [[[]]], {});
plot1.redraw();
}
});
Please see working example here
My method is "expensive" but works for me. Use .remove():
if ($("#chart").length) {
$("#chart1").remove();
} else {
$(parent).append("<div id=\"chart1\"></div>");
}
// put $.jqplot below here
You can use the destroy method.
e.g.
if (C.chart != null) {
C.chart.destroy();
C.chart = null;
}
C.chart = $.jqplot("chart", chartData, {
I'm trying to use the CHAP links library timeline (http://almende.github.io/chap-links-library/timeline.html).
Example17 is using JSON, but it's in the html file itself. I'd like to use an external JSON file sitting on the web server instead.
Here's my example.json:
{"timeline":[
{
"start":"2013,7,26",
"end":"2013,7,26",
"content": "Bleah1"
},
{
"start":"2013,7,26",
"end":"2013,8,2",
"content": "Bleah2"
},
{
"start":"2013,7,26",
"end":"2013,8,2",
"content": "Bleah3"
},
{
"start":"2013,7,26",
"end":"2013,8,2",
"content": "Bleah4"
}
]}
I added this:
<script src="http://code.jquery.com/jquery-1.7.1.min.js"></script>
And here's the modified function:
// Called when the Visualization API is loaded.
function drawVisualization() {
// Create a JSON data table
$.getJSON('example.json', function(jsondata) {
data = jsondata.timeline;
});
// specify options
var options = {
'width': '100%',
'height': '300px',
'editable': true, // enable dragging and editing events
'style': 'box'
};
// Instantiate our timeline object.
timeline = new links.Timeline(document.getElementById('mytimeline'));
function onRangeChanged(properties) {
document.getElementById('info').innerHTML += 'rangechanged ' +
properties.start + ' - ' + properties.end + '<br>';
}
// attach an event listener using the links events handler
links.events.addListener(timeline, 'rangechanged', onRangeChanged);
// Draw our timeline with the created data and options
timeline.draw(data, options);
}
Anyone who can tell me what I'm doing wrong gets a cookie! :-)
Update: I should specify that it's rendering the timeline div correctly, I'm just getting no data showing up.
Your start and end dates need to be parsed as Date objects for use in the timeline
I stumbled on this post as I was implementing similar functionality.
In version 2.6.1 of timeline.js, around line 3439 where the function links.Timeline.Item is declared, you'll notice a comment relating to implementing parseJSONDate.
/* TODO: use parseJSONDate as soon as it is tested and working (in two directions)
this.start = links.Timeline.parseJSONDate(data.start);
this.end = links.Timeline.parseJSONDate(data.end);
*/
I enabled the suggested code and it all works!* (go to the parseJSONDate function to see which formats are accepted)
*(works insofar as dates appear on the timeline.. I'm not using therefore not testing any selection/removal features, images, or anything like that..)