I haven't seen this problem with other Google charts before but I am using the Annotation Chart and every time the data is updated the following lines are called which duplicates the chart object in the DOM as a sibling of the parent:
var chart = new google.visualization.AnnotationChart(document.getElementById('chart_' + this.display.displayDivId));
chart.draw(data, options);
This more or less makes sense based on the code but how can I prevent the new method from firing and instead create a chart object out of the existing DOM element and then call the .draw() method on that object?
Is this possible? The only other thing I can think of would be to clear the existing one from the DOM first, and then proceed w/ the logic I illustrated above.
Any thoughts/suggestions would be much appreciated.
Related
I am trying to plot a multiline d3 chart. I have created a method which should take a new dataset and try to plot it in the same d3 frame for new data update changes (possibly filters).
The first draw works fine but the next draw (mocked data: which is a slice of the previous data and few manipulated values) is not showing correct is crossing the x axis.
[See Image below]
Also the starting origin is missing a tick which should also be 2010 in this example
I also want to create few more lines if there is more datapoints in the future which should be dynamic. Current model is {date, actual, projected}, More expected is mean or difference which will only be shown on trigger.
Any help would be appreciated.
Here is a Stackblitz https://stackblitz.com/edit/angular-rhr39p
References:
Animated line chart: http://bl.ocks.org/atmccann/8966400
Multiline chart: https://bl.ocks.org/larsenmtl/e3b8b7c2ca4787f77d78f58d41c3da91
Dataset updates: https://bl.ocks.org/d3noob/7030f35b72de721622b8
Please keep just one problem per question here at Stack Overflow. This answer will deal with problem #1, consider asking separate questions for the other problems.
The issue here is just your enter/update methodology, that is not correct and. Stick with the idiomatic D3, which is along these lines:
const update = this.svg.selectAll('.records')
.data(records);
const enter = update.enter().append('g')
.attr('class', 'records');
Then, you append new paths using enter and update those paths using update.
You can also ditch the groups and create enter/update/exit selections for the paths directly. That will make your code simpler.
Here is the forked code: https://stackblitz.com/edit/angular-lyd79t?file=src%2Fapp%2Flinechart%2Flinechart.component.ts
I have created a BarChart with angular-chart like this:
<canvas id="bar"
chart-data="ctrl.barChartData"
chart-options="ctrl.barChartOptions"
chart-labels="ctrl.barChartLabels"
chart-series="ctrl.barChartSeries"
chart-click="ctrl.chartClick"
class="chart chart-bar">
</canvas>
I have wrote a chartClick function based on some example and looks like this:
vm.chartClick = function(evt){
var myBarChart = //how I can obtain a access to my created bar chart?
var activePoints = myBarChart.getPointsAtEvent(evt);
console.log("active: "+activePoints);
}
My question is: how can I obtain an access to chart I have created and assign it to myBarChart?
I have found solution for Highcharts however I can't find it for Chart.js
UPDATE:
Based on link provided by #IBarros I have manage to wrote following few lines of code:
$scope.$on('chart-create', function (event, chart) {
//console.log(chart);
myBarChart = chart;
});
I have 2 charts - one pie chart, one bar chart. What is more the event can be emitted multiple times for each chart so as a result I have a 7 charts printed into console. My next question is: how to find out what chart is a bar chart I'm looking for?
The reason why the event is fired 7 times was explained in this issue: How to get chart instance? #464
If options or other optional attributes are set after the data is set
the chart will be destroyed and recreated. This logic is what allows
the chart to be automatically updated everytime something changes in
the chart settings.
When that happens you should just update the reference on your side.
To figure out which chart object is the one you want, just look for the chart directive id (or chart type) in the chart object.
Example:
Use an object as an associative array
$scope.myCharts = {};
Save object reference in the associative array
$scope.$on('chart-create', function (event, chart) {
console.log(chart.chart.canvas.id);
console.log(chart.chart.config.type);
//If id is the same, reference will be updated
$scope.myCharts[chart.chart.canvas.id] = chart;
});
Access chart object by its directive id
console.log($scope.myCharts[id]);
I have a highchart that generates data like so:
What I want to do is when I click the Major Versions drop down button and select a version, the version is displayed and the rest of the series points are removed like so:
As reference, I've used this stackoverflow question as a guide removing datapoints. However when I try to implement this in coffeescript like so:
chart = $('#vulnerability_version_chart').highcharts()
chart.series[0].setData([])
chart.series[1].setData([])
chart.series[2].setData([])
chart.xAxis[0].setCategories(calculateCategory(releases))
chart.series[0].setData(calculateY(releases), calculateHighVulns(releases))
chart.series[1].setData(calculateY(releases), calculateMediumVulns(releases))
chart.series[2].setData(calculateY(releases), calculateLowVulns(releases))
All that this code does is remove all the data points and it doesn't rerender with the new points. I've looked into update(), redraw, reflow and I am still unable to get it to render. What am I missing here?
HOw can I remove the points after 1.4.4? I've tried `setData and for loops. This doesn't seem to work.
im having a issue with Chart.js.
Firts, I set a data, and then when a parameter change, I want rebind the entire chart.
This work, but its like the chart with the old data still behind the new one.
first ->
chart.Line(data, options);
in a event ->
chart.Line(newdata, options);
I saw this solution
chart.js load totally new data
but I dont like this way. Im in a angular directive context, so it's not the best aproach.
I tried without results
.update( ), .removeData( ), .clear(), .destroy(), etc
here its my current directive
http://plnkr.co/edit/qn2UUyznonKm6zgEi8FW?p=catalogue
Any Idea ?
You are creating a new chart, that's why you end up with the old chart behind the new one.
One simple option that I've used:
Remove the old chart from the canvas that you are using for the chart:
$('#canvas').replaceWith('<canvas id="canvas"></canvas>');
And now create the chart with the new data in the same canvas
var ctxChart = document.getElementById("canvas").getContext("2d");
window.myChart = new Chart(ctxChart).Line(newdata, options);
Hope it helps!
For those of you wondering the same thing with Pie charts, doesn't look like there's a given public method that works but you can use an easy workaround by removing the data yourself:
var pieChart = new Chart(ctx).Doughnut(undefined, pieChartOptions);
pieChart.segments.splice(0, pieChart.segments.length);
Seems to work ok, wish they would just add a remove all method or make the clear actually work.
You are right, using the .update() function is the correct way to do this. I just answered the question on the other one you referenced but wanted to provide it here as well.
No need to delete the existing chart or do something like removing the canvas element to later append a new one. That works.. but isn't necessary.
Working CodePen: https://codepen.io/vpolston/pen/KKRoEBY
Video walkthrough: https://www.youtube.com/watch?v=Ac5pzmHO3_A
Firstly if you want to know the why then I would recommend doing a console.log(myChart) of your chart object. You'll see all kinds of properties that can be updated by simply assigning it a new value and then calling the myChart.update() on your chart.
Let's say you have a chart that you called myChart when you instantiated it.. this part:
const myChart = new Chart('myChart', {}
The variable name is important. To update the dataset you silo down into what you saw when you console.log'd the chart. So your dataset would be
myChart.config.data.datasets[0].data
Just assign that a new value like this:
const newDatasArray = [1,52,23,23,48];
myChart.config.data.datasets[0].data = newDatasArray;
and then for the labels if you needed to change those:
const newLabelsArray = ["Jan", "Feb", "Mar", "Apr", "May"];
myChart.config.data.labels = newLabelsArray;
And then finally call the update function with myChart.update();
You'll see the chart update to use the new dataset and/or labels.
Hopefully that gives a bit more insight into properly updating a chart. If you have a further question let me know and I'd be glad to try to help.
Thanks,
VP
I want to move nodes in Sigma JS on click event. Say from position x 0.7 to position x -0.7.
Is it possible to move nodes in Sigma js, and if it is, kindly guide me to achieve that.
Yes, it is possible. I created a jsfiddle showing how to change node position, size, and color on mouse click here:
http://jsfiddle.net/kaliatech/P255K/
You can bind to custom "downnodes" events like this:
sigInst.bind('downnodes',onNodeDown);
The event callback contains an array of selected node ids. I don't know when it would be more than one when clicking. Perhaps when zoomed out in a complex graph.
One of the more subtle issues when using sigmajs, is that most methods, such as getNodes, return clones, not the instances themselves. This is to protect "private" data in the graph I think, especially data that can not be redrawn after initialization. To actually modify properties, you need to use the iterator methods. Even then, you are only given clones. The library updates the actual node instances using a list of predefined allowable properties. (See the checkNode function in graph.js).
After properties have been set, you then need to refresh/redraw the graph. While the "refresh" method would seem to be an obvious candidate, it did not work. I was able to get it to redraw using the draw method though. You will need to review the source code to understand the different parameters. Example:
function onNodeDown(evt) {
var sigmajs = evt.target;
var nodeId = evt.content[0];
sigmajs.iterNodes(function(n){
n.size = 10;
n.color = "#0000FF";
},[nodeId]);
sigmajs.draw(2, 2, 2, true);
};
For more advanced needs, the sigmajs website includes plugin examples showing other ways of getting mouse events and updating nodes dynamically. One is the advanced plugin example for a fisheye effect:
http://sigmajs.org/examples/a_plugin_example_advanced.html
Another is the example for accessing node attributes:
http://sigmajs.org/examples/more_node_info.html
The sigmajs documentation is weak, so you will need to review the source code to understand things.
There are plugins permitting to move isolated nodes from the graph.
Check
https://github.com/Linkurious/linkurious.js/blob/develop/examples/lasso.html