I have an undirected graph in Vis.js and I would like to change the color and size of the adjacent nodes (scaling them according to values in a JS array) when a certain node is selected. How would I go about doing this? The documentation for vis.js network objects is unenlightening beyond the source for this example.
You can listen for click events to know when a user clicked a node.
network.on("click", function (params) {
console.log(params);
});
If you have creates your nodes in a DataSet, you can simply update them and Network will be automatically updated accordingly:
nodes.update({id: 4, label: "changed label"});
Elaborating on this answer in response to this question. The vis.js->Network documentation has all the details, you just have to put them in order.
You use the "on" method of the network instance in order to listen for events. See "Method Reference -> Global" at the link above. This "on" method takes two inputs. The first is the event to be listened for; the second is a function that specifies the action to be taken when the event occurs.
To understand how to use this information, see the "Events" section in the documentation link above. For click events, your code will look something like
network.on("click", function (params) {
console.log(params);
});
The first argument is always a string; in this case we are interested in the "click" event. The second argument is a callback function that takes a single argument (I called this argument "params" in the example above). The "Events" documentation (again, see link above) summarizes this structure for you. Specifically, if the click event is associated with a node, then the ID of the node that was clicked is accessible as params.nodes[0].
Back to the original question. To change the color of adjacent nodes, you first need an array of the adjacent nodes. You do this using the "getConnectedNodes" method (see "Method Reference -> Information" at the link above). This will give you an array of node IDs. Next, for each ID in that array, you need to update the properties you wish to change.
The easiest way to update node properties is to create your nodes using a DataSet. You are probably already doing so. See this example, and notice the lines
var nodes = new vis.DataSet([...]);
This nodes variable has its own update method. So if you have (e.g.,) a variable CurrentID that holds the node ID of a node you wish to modify, and you want to (e.g.,) change the label of that node to the text string stored in another variable newLabel, you would do
nodes.update({id:CurrentID, label:newLabel});
Thanks much for these helpful responses; one of the gotchas is that the assertion that one is probably already creating one's own dataset is likely false if using the Network documentation examples, which mostly do something like the following:
var nodeArr = [...];
var edgeArr = [...];
data = {nodeArr, edgeArr}
network = new vis.Network(container, data, options);
The update function is only available if the nodes are a Dateset rather than an array:
var nodeArr = [...];
var edgeArr = [...];
data = {new vis.DataSet(nodeArr), new vis.DataSet(edgeArr)}
network = new vis.Network(container, data, options);
Related
I wish to get handles of all the charts in a stage in order to modify background settings.
I noticed there is a stage.forEachChild(function(element) { … }) method that allows you to fire up a function for each stage element.
For example:
stage.forEachChild(function(element) {
alert(element.id());
});
The problem is that "element" type is anychart.graphics.vector.Element; instead I need a anychart.core.Chart object in order to call the background() method. Is there a way to do that?
Unfortunately, is a GraphicsJS entity and it returns its graphic vector elements as children. It doesn't control charts. You can store all chart in an object or array and iterate them, or apply a unique ID to every chart and get access to them at any moment by anychart.getChartById('CHART_ID');. For details, check the sample by the link in a comment below.
So, I really love this example from Jake Zieve shown here: https://bl.ocks.org/jjzieve/a743242f46321491a950
Basically, on search for a term, the path to that node is highlighted. I would like to accomplish something similar but with the following caveats:
I would like to stay in D3 v4.
I'm concerned about cases where the path doesn't clear out on next node pick OR what happens when there are two nodes of the same
name (I would ideally like to highlight all paths)
I would like to AVOID using JQuery
Given a set search term (assume you're already getting the string from somewhere) I know I need to make use of the following lines specifically (you can see my stream of consciousness in the comments) but I'm just not quite sure where to start.
// Returns array of link objects between nodes.
var links1 = root.descendants().slice(1); //slice to get rid of company.
console.log(links1); //okay, this one is nice because it gives a depth number, this describes the actual link info, including the value, which I am setting link width on.
var links2 = root.links(); // to get objects with source and target properties. From here, I can pull in the parent name from a selected target, then iterate again back up until I get to source. Problem: what if I have TWO of the same named nodes???
console.log(links2);
Thoughts on this? I'll keep trying on my own, but I keep hitting roadblocks. My code can be found here: https://jsfiddle.net/KateJean/7o3suadx/
[UPDATE]
I was able to add a filter to the links2 to call back a specific entry. See
For example:
var searchTerm = "UX Designer"
var match = links2.filter(el => el.target.data.name === searchTerm); //full entry
console.log(match);
This single entry gives me all associated info, including the full list of all points back up to "COMPANY"
So, I can GET the data. I think the best way to accomplish what I want is to somehow add a class to each of these elements and then style on that "active" class.
Thank you!
I'm struggling with a dijit.Tree and I can't find what I need in the dojo documentation...
I want to change the style of a few elements in my tree, according to some conditions.
I am able to identify the elements through a combination of for loops and if evaluations :
itemList = this.tree.model.store._arrayOfAllItems;
for (var index in itemList) {
item = itemList[index];
if (item.<property> == ...) {
...
//This is where I want to change the style
...
}
...
}
But then, I fail to get the node id to call dojo.addClass(nodeId, newClass).
Am I parsing through the proper list, with the model.store._arrayOfAllItems? Is there a way to parse through the node list instead, and still access the data properties?
Thank you very much for your help!
Edit on 2015-11-23
With Richard's comments, I was able to obtain the result I was looking for. I have added a handler that connects the tree's onOpen event to a method that gets the open node map (from tree._itemNodesMap) and then fetch through the store. For every item in the store, it adjust the css if the id of the item being validated has an associated node in the open node map. It then looks recursively for children.
Thanks Richard for your help!
If you have the id of the node inside the tree, you can use the getNodesByItem function that tree has.
Although if your tree is dynamic and the contents can change, I would suggest writing a function that not only adds to your store but also adds to a class for the node formed in the tree.
I'm attempting to create a d3 plugin ala this stackoverflow question:
How to make a d3 plugin?
But within his shown example
(function() {
d3.selection.prototype.editable = d3.selection.enter.prototype.editable = function() {
return this.attr('data-editable', true);
};
})();
I don't see how he can actually retrieve the data associated with the selection. Is this something that can even be retrieved with this extension of d3.selection? I mucked through the d3 source a little bit but found myself far more confused than before.
Can someone who has written a d3 extension/plugin guide me in the right direction?
In javascript, the object that this refers to is (usually, and in your example code above) determined by the object which calls the function where this appears.
Hence the line return this.attr('data-editable', true); will return the exact same d3 selection object that calls editable.
So you will get back the normal old d3 selection object, just as you would in the ordinary d3 method chaining pattern. Once you have that, getting the data is just a matter of looking up the API for the d3 selection object.
If you are interested specifically in how to get the data back, take a look at the data method. From the link above, when that method is called with no arguments:
If values is not specified, then this method returns the array of data
for the first group in the selection. The length of the returned array
will match the length of the first group, and the index of each datum
in the returned array will match the corresponding index in the
selection. If some of the elements in the selection are null, or if
they have no associated data, then the corresponding element in the
array will be undefined.
I have some objects, that keep created DOMObjects, like here:
function category(){
var domBlock;
this.block = function(){
if (!domBlock){
// Here dom-object constructor $('<div></div>'); etc
}
return domBlock; // jquery object,
// but i test and native document.createElement
}
}
Then i clear category's area, and append old and new received(with Ajax) objects:
area.html('');
for(id in category_list){
area.append( category_list[id].block() );
}
where category_list is list that contain category objects. Area is jQuery object.
In other browsers (except IE) i get area with all needed categories, but in IE i get only new received categories(that just create DomObject), other old objects that keeped old DomObject not show.
I know it possible make with innerHTML, but i wont keep DomObject, not text. Because DomObject keep many events. And it very hard for browser attach events for each DomObject after refresh area.
Like comments suggest you can use .clone() for this, to eliminate your other problem, with events not copying, that's covered as well. .clone() takes a boolean parameter, telling it whether to copy data and events (this is as of jQuery 1.4, it was just events, not data, before then).
To use .clone(bool) and get a copy including event handlers, just do this:
return domBlock.clone(true);