I have this (probably weird) setup where I'm ajax'ing a template of sorts into a section of my page, and then trying to draw a chart with D3.js inside one of the elements of that template.
Weirdly, sometimes it renders, others it doesn't, complaining about what I figure out must be the element which holds the chart not being rendered at that moment, as it's coming from an ajax call.
How can I overcome this? I've been reading about jQuery's when() and then() but I can't seem to grasp how it might (if at all) help me in my case.
This is a (simpler) version of my code:
$.get("/url/to/my/template", function(templateData){
// this element is already in the page
$("#elementInThePage").html(templateData);
// this function draws the D3 chart
buildChart();
});
function buildChart(){
// this element comes in the template
// sometimes it's already available, other times it isn't
// and obviously d3 complains about it not being there
var element = d3.select("#elementInTemplate");
// do more stuff (...)
}
To sum it up, how to be sure I only call buildChart() when #elementInTemplate has rendered?
EDIT: I already tried chaining .done() to my $.get, but exactly the same thing happens.
EDIT2: I think I mis-explained my problem. D3.js doesn't complain about it not being there. What actually happens is that it is drawing the chart conditionally in regard to the size (WxH) of the element in the template, and because that element still hasn't rendered, it borks up the chart.
EDIT3: Another (relevant, I think), note: in buildChart(), D3.js depends of the dimensions of the template's element. So, if I
console.log($("#elementInTemplate").width()+" x "+$("#elementInTemplate").height());
If it fails, I get 234 x 0. If it works I get 234 x 456.
Related
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.
TL;DR: Try to figure out what state the radio buttons of this nvd3 multibarchart are in based on the console log - i.e. how can I reliably determine what data streams are currently being shown to the user?
Long version:
I'm trying to figure out which data streams/arrays are displaying in an nvd3 multibar chart so that I can update other DOM nodes with information relevant to those streams. The only trouble is that the chart.state seems to be returning the opposite of what it should: if I toggle a stream "off", chart.state.disabled is true for that stream ... except seemingly the first time something is toggled, when all chart.state.disabled[i] streams is set to false... the entire behaviour of that property seems like it isn't functioning as it should to me. Is it a bug or do I not understand how it's supposed to be used?
Some code to log the state of three streams, for example:
chart.legend.dispatch.on("legendClick", function() {
var state = chart.state;
console.log(state.disabled[0] + ","
+ state.disabled[1] + ","
+ state.disabled[2]);
});
Well, as is typical, I dig around for half an hour, can't get it working, post on SO and then go and try a different approach which immediately works:
chart.dispatch.on("stateChange", function(e){
console.log(JSON.stringify(e.disabled);
}
So I believe it's a bug with the ledgendClick event that doesn't update the chart state correctly.
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
I'm using d3.js to make a simple line graph. I want to know if there's a way to create "holes" in the graph, that is, if the line can be interrupted or cut when there is no data available.
I'm looking into either delete the places I don't need from the domain, or setting the line weight to 0 in specific segments, but I can't find a way to do either of these.
Thanks for your help!
The D3 line generator has a built in function to do just this, line.defined. You can use this function to control where your line is defined and where it is not (like where you have missing data.) If you wanted to make your line undefined whenever the second value in the point array is a javascript NaN value, you could say:
line.defined(function(d) { return !isNaN(d[1]); });
Here is a good example of this in action.
So,
I'm just starting to learn CreateJS and I encountered my first problem: I can't get tweening to work (as I expect it should work).
Here is the example: http://www.hakoniemi.net/labs/createjs-test/
I want to get that cloud to move from right to left - at the moment it only jumps to the target.
The code looks:
createjs.Tween.get(stack["cloud"]).to({"x":25}, 1000).call(test);
where createjs.Tween.get(stack["cloud"]) is valid and function test is executed. However there's no visual effect of 1000ms taking place at all.
I've looked through the tutorials and this is how things should work, but they're not. What am I doing wrong?
Edit: if I re-execute code in console with different value, then tweening and visual effect happens normally (here's a version where setTimeout is used: http://www.hakoniemi.net/labs/createjs-test/index2.html)
You have a type problem when setting the initial x value in
if (this.getAttribute("x")) {
ref.x = this.getAttribute("x");
}
The problem is that getAttribute() returns a string, which you can verify outputing Object.prototype.toString.call(ref.x). This way, it seems the first time the tween tries to run it can't do the proper math. In the end, it correctly updates the value to the end value as a number and that's why next calls to the same method work properly.
You can fix this just by making sure that ref.x is a number. For example:
if (this.getAttribute("x")) {
ref.x = parseInt(this.getAttribute("x"));
}
You can see it working in this fiddle.
One last thing, BitmapImageLoaded is adding the assets to the stage as soon as they are loaded. If your clouds image gets loaded before the background, it will be placed under it and you won't be able to see them. (just in case :))