almende / vis

⚠️ This project is not maintained anymore! Please go to https://github.com/visjs
7.86k stars 1.48k forks source link

Network - nodes - url #2975

Closed nigelhorne closed 7 years ago

nigelhorne commented 7 years ago

Please add an option "url" which adds a hyperlink which the browser goes to when you to click on a node.

I can't see that option at the 'full options' tab of http://visjs.org/docs/network/nodes.html#, so I am assuming that isn't currently supported.

nigelhorne commented 7 years ago

For a use case see https://genealogy.nigelhorne.com/cgi-bin/page.fcgi?page=descendants&entry=I12

wimrijnders commented 7 years ago

I noticed on your genealogy site that you have pop-ups on the nodes. These contain links, but they are unclickable because the pop-ups disappear as soon as you move the mouse away from the node.

Is this perhaps the issue?

nigelhorne commented 7 years ago

No, that's a different issue that I was going to raise later, because it's less important to me.

rasmusblockzero commented 7 years ago

An alternative might be to feed a onclick function() option on a node - where the app could open a new tab, new window or what ever, just a thought.

nigelhorne commented 7 years ago

Isn't there already an onclick function? If you click on a node it highlights it and the line to it. Really what I'm after is a URL on the text in the node, perhaps, so supporting HTML in the node text may be the best way to go. I don't know.

wimrijnders commented 7 years ago

...so supporting HTML in the node text may be the best way to go.

This will not work, because the networks are not HTML-tags, but drawn on a canvas. This includes the node text.

The suggestion of @rasmusblockzero is actually a good one; It's fairly easy to associate opening a new browser window with clicking on a node. Taking example interactionEvents as basis, you can do:

// Assuming that node with `id: 2` has an associated URL
network.on("click", function (params) {
  var id = params.nodes[0];
  if (id === 2) {
    window.open('http://your.url.here', '_blank');
  }
});

I prefer this approach over adding similar functionality to network.

rasmusblockzero commented 7 years ago

I have in my application added a clientData attribute to the nodes to be able to store in the node and get it back in callbacks. using that the lookup table can be avoid such as

network.on("click", function (params) { var node = nodeDataSet.get( params.nodes[0], {‘clientData’}); window.open(node.clientData.url, '_blank'); });

Mainly to avoid storing a second lookup table elsewhere.

If that a solution that would benefit others I can make a PR.

nigelhorne commented 7 years ago

Thinking about this, this may be a dup of 1965.

wimrijnders commented 7 years ago

@nigelhorne Nice of you to check; but, no, it isn't a duplicate. That issue is using any kind of HTML in the nodes, this issue is about adding links.

....which, I might add, is never going to be possible by way of #1965. Another approach is required.

rasmusblockzero commented 7 years ago

Is there anything more to discuss here? What is the procedure, can it be closed or made into a request for an example? @nigelhorne what do you think of the suggestions?

nigelhorne commented 7 years ago

Not quite sure what you're asking me @rasmusblockzero - are you after an example from me? If so, an example of what?

rasmusblockzero commented 7 years ago

Sorry, that was unclear.

My question was firstly if you ( @nigelhorne ) are with us on the solutions and think this would work for you.

The second more general question is if this is something more people want to do and we should take the snippet from @wimrijnders and make a simple example in the example suite

nigelhorne commented 7 years ago

I'm not sure where you're saying "clientData" should go, so I put it into the node array like this:

var graph = { nodes: new vis.DataSet([ {"id": "0", "label": "Eliza Parr", "level": 0, "title": "Eliza Parr", "URL": "http://www.google.com"}, .... ]); ...

Then I added this: var network = new vis.Network(document.getElementById("network"), graph, options); network.on("click", function(params) { var node = nodeDataSet.get(params.nodes[0], {'URL'}); window.open(node.URL,'_blank'); });

But that stops the map displaying, and Firefox's debugger says:

SyntaxError: missing : after property id

nigelhorne commented 7 years ago

I changed it to this and it worked :-)

            network.on("click", function(params) {
                    var node = graph.nodes.get(params.nodes[0], 'URL');
                    window.open(node.URL,'_blank');
            });
nigelhorne commented 7 years ago

See https://genealogy.nigelhorne.com/cgi-bin/page.fcgi?page=descendants&entry=I1170

rasmusblockzero commented 7 years ago

Excellent @nigelhorne !

I didn't realize you could just set any option - if you do the same thing on all nodes ( network.setOptions() ) you would get the warning

Unknown option detected: "URL". Did you mean "id"?

Problem value found at: options = { nodes: { URL } }

And I actually just assumed that the same evaluation was turned on for individual nodes.

@wimrijnders would you say that this is a loop hole or an intended feature that any property can be set on individual nodes but not on the collective?

wimrijnders commented 7 years ago

@rasmusblockzero it's a loop hole. There is in fact another running issue which has similar characteristics: #3036. It appears that the validation for options is not run when setting individual nodes. I am gearing up to address this.

nigelhorne commented 7 years ago

I hope you're not going to close a loop-hole and break my code :-)

rasmusblockzero commented 7 years ago

@wimrijnders I think that @nigelhorne has an important point here. I think it's a bug that validation is not active for individual nodes but there are valid cases - like we discuss here where that could be considered a feature. If/When that validation is enabled I think we should consider a possibility to do what @nigelhorne does here - including doing so for all nodes and groups.

Worst case with a global flag to not validate or as I proposed earlier with a dedicated space for values that visjs doesn't touch but returns upon request (like clientData)

wimrijnders commented 7 years ago

OK fair enough.

My ideal situation would be to allow any kind of field in DataSet - this is user-data, so users should be free to go wild here - but have a strict validation on the option fields in it. The question 'is this possible?' is an oxymoron, of course it is, but I need to wrap my brain around it for a decent implementation. Your thoughts are welcome.

rasmusblockzero commented 7 years ago

But the item entries in data set are the actual nodes, right? For the nodes (and edges) there are only 'data', this data is either read as options by the node/shape or ignored. There is no structural difference between data and options for individual nodes. Options for the dataSet object is another thing and options for the network.nodes yet another

wimrijnders commented 7 years ago

I'm coming back on the 'loop-hole' thing; data in DataSet can be anything the user pleases (insight due to #3096). So @nigelhorne your addition of a url field is perfectly valid.

I'd still like to have a check on the regular option data in a node though. Things like 'an x or y coordinate must be a number`. For all unregistered options, anything goes, it's the users responsibility.

rasmusblockzero commented 7 years ago

Sure, that's a decent compromise, the only thing you loose then is suggestion of misspelled options but maybe that is ok. An alternative approach is to allow for user added options:

networkOptions.nodes: { userDefined: { URL: 'string', port: 'number' } }

Then you can have best of both worlds but will be a bit more work both for visjs implementation and for application developers.

One really nice benefit with this approach though is that it lends it self well to split functionality into modules and some plugin system.

wimrijnders commented 7 years ago

@nigelhorne Your solution here is a good one; is there a need to keep this issue open? If not, please close it.

nigelhorne commented 7 years ago

I think we're done here. Thanks for your help.