Create a square with additional data node data - cytoscape.js

I am pretty much a javascript noob, and very new to cytoscape (but i code in other languages)...
I am trying to use Cytoscape to graph out the servers available in my network. Creating a node per server and their relationship was straightforward actually.
I would like to add the possibility than when I click a node (let's say server12345) that it would open kind of a table with data associated with that server (servertype etc...).
Do you have any idea / examples / guidance on how I could:
add functionality on that click event of a specific node ?
how to create a 'details' table using cytoscope?
Thank you guys so much in advance!
(Ps: My first post on StackOverflow...)

Nice question.
Firstly, you can capture the click event of cytoscape.js like below
cy.nodes().on('click', function(e){
var clickedNode = e.target;
console.log(clickedNode.id());
});
or you can also use the tap event of cytoscape.js
cy.on('tap', 'node', function(evt){
var node = evt.target;
console.log( 'tapped ' + node.id() );
});
You can read events section of the documentation for more details
After you capture this event, I see to ways.
1-) Just modify an existing HTML element on the UI. For example in here you can see on the left side there are some other elements.
So you can write your code like
cy.on('tap', 'node', function(evt){
var node = evt.target;
document.getElementById('someOtherElementOnUI').innerHTML = JSON.stringfy(node.data());
});
This will simply modify some other UI element (HTML element) and changes its content to the data of the selected node.
2-) You can use some extensions like Cytoscape.js-popper and show data dynamically like a tooltip. You can check my answer https://stackoverflow.com/a/66813720/3209523

Related

dijit/Tree is not updated when connected to a dojo/store/JsonRest

I have modified the dojo tutorial at http://dojotoolkit.org/documentation/tutorials/1.10/store_driven_tree/demo/demo.html to read from a JsonRest store.
The problem is that the tree display doesn't update when I click "Add new child to selected item" e.g. on the root element, although the update worked in the original tutorial.
I have compared what dojo/store/Memory (from the original tutorial) and dojo/store/JsonRest return after the "put" request:
Memory returns the id of the new object.
JsonRest ends with "return xhr(...)", so it returns a Deferred instead of the new id, which seems not not be understood by the Observable. I can make it work, if I change dojo/store/JsonRest.js to end with:
...
return xhr(...).then(function(data){
return data.id;
};
}
I hope there is a solution without modifying the dojo sources?!
Some more details follow:
This is the definition of my store instead of the original Memory store:
var governmentStore = new JsonRest({
target : "http://localhost:8080/test/gov",
getChildren : function(object) {
return this.query({
parent : object.id
});
}
});
var governmentStore = new Cache(governmentStore,new Memory({}));
(If I remove the Cache and use the JsonRest directly, even the modified JsonRest.js doesn't make the Tree update).
This is the reply from a PUT request to the json server:
{"name":"New Child", "id":0.7243958345}
Please help to allow a dijit/Tree to react on changes of the underlying JsonRest store without messing around with the dojo sources.
Thank you
Dominic
Try wrapping your JsonRest store with an Observable wrapper and seeing if that helps the tree update properly. Also make sure that the model of the tree is functioning properly as that is what should be handling when and where the tree updates by listening to the store.
var memStore = new Memory({});
var store = new Observable(memStore); //Use this store for your tree
var cacheStore = new Cache(governmentStore,memStore);
The idea here is that when you do a PUT, you should be putting into the cacheStore and not the governmentStore. The Cache will do a PUT on the governmentStore but also update the memStore when the PUT is complete which should then trigger the notify in the Observable and pass that information along to the tree.
Using jquery instead of dojo was the solution. I found that I could solve in a few hours of learning jquery all problems that occurred when using dojo. This is mostly due to the quality of the documentation of both libraries and also because dojo seems to have too many bugs to react on new bug reports.

Google plus share button, current URL instead of Specified URL?

If clarification is needed, please let me know. If it can't be done, please let me know this as well. I am desperately trying to figure this out still
I was following Google's Dev guide to the Share button at the following site:
https://developers.google.com/+/web/share/
and I can not seem to figure out how, if it's even possible, to use a custom icon AND use the current URL instead of having to specify a URL.
I found this section of their site that specifies an anchor tag address:
"https://plus.google.com/share?url={URL}"
This would allow me to use a custom icon (and the only way I can use a custom icon as far as I can tell) and a few other custom parameters as well. But it looks like this method requires a specified URL and, as far as I can tell, provides no method to dynamically create the link depending on the current page.
If I use the code generator at the top, it will use the current page, but it calls on a Google hosted Java Script and in addition, it is a hover link that pops up when I hover over the icon. And of course, I also can't use a custom icon with the generator either.
I've been Googling every search term I could think of and searching this site as well and I haven't been able to find anyone else asking this question as of yet. I figured after about 20-30 minutes of searching that I wasn't going to find my answer via searching, so i apologize if this has been answered.
Just some background on my experience to give an idea of where I sit: I have a decent grasp of the workings of HTML and CSS. Javascript, however, I understand very very basic theory and that's about it. I definitely intend to learn, however, as it will prove a very valuable skill.
Thank you very much!!
I think I know what needs to be done, but...I don't know how to do it (or if it would even work) :|
my share link needs to link to a script that looks at the current page's URL, and then takes that information, and creates a dynamic link from it that will take the user to the following link: https://plus.google.com/share?url={URL from query will be here}.
I think that might work...it sounds like it would. Any thoughts? If so, any simple scripts around that would do just this?
Double thanks!!
--I finally found something that works, but it uses Javascript and I don't fully understand it, just enough to tweak it. It took me forever to find this, but it works with Google Plus, Facebook, or Twitter! (and I'm sure it will work with any other website that supplies a Share Link that requires a specified URL)
Here it is, I'm still looking for a better solution, but this does exactly what I was looking for:
<a href="javascript:(
function(){
var w=480;var h=380;
var x=Number((window.screen.width-w)/2);
var y=Number((window.screen.height-h)/2);
window.open('https://plus.google.com/share?url='+encodeURIComponent(location.href)+'
&title='+encodeURIComponent(document.title),'','width='+w+',height='+h+',left='+x+',top='+y +',
scrollbars=no');
})();" style="background: url(/wp-content/themes/HTML5/images/googleplus.png) no-repeat scroll left center transparent;">
Share to Google+</a>
EDIT! After spending some months learning Javascript, I've built a solution that is much better than that which is provided below. I'll leave my original answer, however, I want to place this better solution at the top.
This solution should work on ANY social media platform that gives you a custom share URL (that is to say, a url that allows you to manually type in an address to share).
Here is how it all works (and if anyone has any suggestions or tweaks that have more experience with JS, please let me know).
I assign variables to the document.URL and document.titleproperties.
I write a named function (I called mine, socialShare) that is set to run via an anonymous function on the window.onloadevent.
The socialShare function assigns variables to the location of my social button's within the HTML. In my case, I used IDs to locate the elements. The purpose of these variables is purely for aesthetics (I use these variables to re-write the the HTML code dynamically, so that when you hover over the share button, it displays the correct URL for sharing the current page you are on)
var fbShare = document.getElementById("fbShare");
var gplusShare = document.getElementById("gplusShare");
twitterShare = document.getElementById("twitterShare");
I then write three separate anonymous functions, one for each social media platform. Each function has two statements. The functions work as follows: the first part is the variable assigned to the location of the HTML element with the ID fbShare. The second part tells it to run the function when that element is clicked; .onclick. The third part is the anonymous function that will run when that element is clicked. The first statement of this function will open a new window; window.open; and in that new window, it will open the URL that is specified by feeding the window.open method parameters. The parameters are as follows (URL,name,specs) where URL is the URL you want to share, name is optional and left blank as seen by the empty set of quotes, and finally specs is where you specify attributes of the window (IE: width and height). The first parameter, the URL: ("https://www.facebook.com/sharer.php?u="+currentURL, currentURL is the global variable that was assigned earlier and will place whatever the current documents URL is, in place of currentURL. The second parameter, the name: "", This is left blank, as it is optional. The third parameter, the specs: "height=368,width=600,left=100,top=100,menubar=0"); These are a comma-seperated list of items. In my case, I've specified a height, width, and the location of the window, as well as disabled the menubar. Finally, the second statement, return false; tells the browser NOT to follow the link inside the HTML code. If this was not specified, then the browswer would follow the URL in the HTML, AND open a new window. For more information on the window.open method, please see the link at the bottom of this new answer.
fbShare.onclick = function() {
window.open("https://www.facebook.com/sharer.php?u="+currentURL,"","height=368,width=600,left=100,top=100,menubar=0");
return false;
}
gplusShare.onclick = function() {
window.open("https://plus.google.com/share?url="+currentURL,"","height=550,width=525,left=100,top=100,menubar=0");
return false;
}
twitterShare.onclick = function() {
window.open("https://twitter.com/share?url="+currentURL+"&text="+currentTitle,"","height=260,width=500,left=100,top=100,menubar=0");
return false;
}
And finally, I modify the HTML href elements of each social media button so that when the user hovers over the share buttons, they see the correct Share URL displayed in their browsers status bar. The first part of this statement grabs the element id, fbShare and the second part tells it to set an attribute, .setAttribute. Then we pass in the attribute name that we want to change, ("href", in this case, and then we pass in what we would like the new attribute value to be, "http://www.facebook.com/sharer.php?u="+currentURL); currentURL is the same here, as earlier. It is the variable that holds the value for whatever the current page's URL is.
fbShare.setAttribute("href","http://www.facebook.com/sharer.php?u="+currentURL);
gplusShare.setAttribute("href","https://plus.google.com/share?url="+currentURL);
twitterShare.setAttribute("href","https://twitter.com/share?url="+currentURL+"&text="+currentTitle);
That's about all there is to it! I hope I wrote this well and I hope it is relatively easy to follow. If any pros out there have any suggestions, please feel free to toss in and give your advice! :)
My JS file
http://jrltest.host-ed.me/_js/share.js
Link to information on the window.open method at w3schools.com
http://www.w3schools.com/jsref/met_win_open.asp
Link to information on the .setattribute method at w3schools.com
http://www.w3schools.com/jsref/met_element_setattribute.asp
OLD ANSWER: I figured I'd add this as an answer. It does the trick and solves the exact problem that I had. The URL after 'window.open' would be the social media's Share Link (in the case of the example, it's google plus' Share Link. There are a few variables that can be either modified or removed. Anyone that's good with scripting could probably create a PHP version (which I would LOVE) or modify it to better suite their needs. At any rate, I hope this will help someone out!
<a href="javascript:(
function(){
var w=480;var h=380;
var x=Number((window.screen.width-w)/2);
var y=Number((window.screen.height-h)/2);
window.open('https://plus.google.com/share?url='+encodeURIComponent(location.href)+'
&title='+encodeURIComponent(document.title),'','width='+w+',height='+h+',left='+x+',top='+y+',
scrollbars=no');
})();" style="background: url(/wp-content/themes/HTML5/images/googleplus.png) no-repeat scroll left center transparent;">
Share to Google+</a>
Native Window Open function its not a good idea, browsers like Mozilla and Chrome block pop up. I think its better use a plugin to open a new windows with the share url, like jquery popup plugin. Work very fine for me and browser cant block it.
Copy an paste into a new js file like original name: 'jquery.popup.js'
jQuery.fn.popup = function(options) {
var defaults = {
width: screen.width/2,
height: screen.height/2,
titlebar: false,
status: false,
resizable: true,
toolbar: false,
scrollbars: true,
menubar: false
};
var options = jQuery.extend(defaults, options);
Boolean.prototype.setProperty = function() {
if (this == true) { return "yes"; } else { return "no"; }
};
jQuery(this).click( function() {
var target = this.target;
var href = this.href;
var posY = (parseInt(screen.height/2)) - (parseInt(options.height/2));
var posX = (parseInt(screen.width/2)) - (parseInt(options.width/2));
var win = window.open(href, target, 'titlebar=' + options.titlebar.setProperty() + ', screenX='+ posX +', screenY='+ posY +', left='+ posX +', top='+ posY +', status=' + options.status.setProperty() + ', resizable=' + options.resizable.setProperty() + ', toolbar=' + options.toolbar.setProperty() + ', scrollbars=' + options.scrollbars.setProperty() + ', menubar=' + options.menubar.setProperty() + ', width='+ options.width +', height='+ options.height);
win.focus();
return false;
});
return this;
};
USAGE:
<script src="jquery.last.js"></script>
<script src="jquery.popup.js"></script>
<script>
jQuery(function(){
//simple load
jQuery(".popupLink").popup({ width: 640, height: 480 });
});
</script>
<a class='popupLink' href="https://www.facebook.com/share.php?u=<?php echo URL;?>">Share Facebook</a>
ALSO YOU CAN PASS OPTIONS LIKE THE PLUGIN EXAMPLE OPTIONS
<script>
jQuery(".popupLink").popup({ width: 640, height: 480, resizable: false, menubar: true });
</script>
The author website dont exist any more. This are the information that comes with the plugin comments
/*
* jQuery popup v1 - A jQuery popup plugin.
* By Jordan Thomas - http://labs.wondergroup.com
* Licensed under the do whatever you want to license.
* If you like, keep this message intact so
* someone else can find the origin.
*/
You can also use PHP to resize the window but here is the PHP version... Have fun :)
See Also: PHP - Getting Current URL
<?
echo '<a href="https://plus.google.com/share?url='.$_SERVER[HTTP_HOST].$_SERVER[REQUEST_URI].'"
target="_blank"><img src="images/google-custom-icon.png"></a>';
?>

Dynamically add regions to Marionette layout

I have a layout, but cannot define all of its regions in advance because they are not known.
So later on an ItemView is created and I'd like to create a new region in the layout using the view's ID as the region's name so I can then say:
layout.dynamicRegionName.show(newItemView);
But there is cyclic dependency here.
I haven't rendered the view yet, so I cannot make a reference to its DOM element to be used in the layout's call to .addRegion()
I cannot render it, precisely because I want it to get attached to the DOM tree through the dynamically added region by calling its .show()
#DerickBailey In the Marionette.Layout docs in github I believe there is an error in the example that has: layout.show(new MenuView());
but technically this is close to what we'd need here i.e. to be able to do:
layout.addRegion(VAR_WITH_NEW_REGION_NAME, aViewInstance);
and have this add a new Region into the layout rendering inside it directly the view instance.
Am I missing some other obvious way to achieve this? Is that a known missing functionality? Is there a reason not to have it?
I'm aware of this previous Q: "Dynamically add/remove regions to a layout"
but don't see any clear/definite answer to it.
Marionette v1.0 (v1.0.2 is latest, right now) supports dynamic regions in Layouts.
var MyLayout = Marionette.Layout.extend({
template: "#some-template"
});
var layout = new MyLayout();
layout.render();
layout.addRegion("someRegion", "#some-element");
layout.someRegion.show(new MyView());
In one of my projects, I faced a similar issue. I needed to create a form dynamically, i.e the form would contain different field views that could not be determined prior runtime. I needed the fields to be Marionette views because they had pretty complicated behaviour.
The way I have done it in Marionette 1.4 in CoffeeScript:
class Module.AdditionalOptionsLayout extends Marionette.Layout
tagName: 'form'
initialize: (options = {}) ->
#_fieldViews = options.fieldViews || []
onRender: ->
#_showFields #_fieldViews
_showFields: (fieldViews) ->
fieldViews.forEach (fieldView) => #_addRegion().show fieldView
_addRegion: ->
regionClass = _.uniqueId('field-region__')
#$el.append $("<div class=\"#{regionClass}\"></div>")
#addRegion regionClass, '.' + regionClass
Please, let me know if it needs further explanation or I can clarify this in JS. I am also aware that it is a late answer, however, hope somebody could find it still useful. Also, note - the answer is relevant only for Marionette 1.x

Dojo dnd (drag and drop) 1.7.2 - How to maintain a separate (non-dojo-dnd) list?

I'm using Dojo dnd version 1.7.2 and it's generally working really well. I'm happy.
My app maintains many arrays of items, and as the user drags and drops items around, I need to ensure that my arrays are updated to reflect the contents the user is seeing.
In order to accomplish this, I think I need to run some code around the time of Source.onDndDrop
If I use dojo.connect to set up a handler on my Source for onDndDrop or onDrop, my code seems to get called too late. That is, the source that's passed to the handler doesn't actually have the item in it any more.
This is a problem because I want to call source.getItem(nodes[0].id) to get at the actual data that's being dragged around so I can find it in my arrays and update those arrays to reflect the change the user is making.
Perhaps I'm going about this wrong; and there's a better way?
Ok, I found a good way to do this. A hint was found in this answer to a different question:
https://stackoverflow.com/a/1635554/573110
My successful sequence of calls is basically:
var source = new dojo.dnd.Source( element, creationParams );
var dropHandler = function(source,nodes,copy){
var o = source.getItem(nodes[0].id); // 0 is cool here because singular:true.
// party on o.data ...
this.oldDrop(source,nodes,copy);
}
source.oldDrop = source.onDrop;
source.onDrop = dropHandler;
This ensures that the new implementation of onDrop (dropHandler) is called right before the previously installed one.
Kind'a shooting a blank i guess, there are a few different implementations of the dndSource. But there are a some things one needs to know about the events / checkfunctions that are called during the mouseover / dnddrop.
One approach would be to setup checkAcceptance(source, nodes) for any target you may have. Then keep a reference of the nodes currently dragged. Gets tricky though, with multiple containers that has dynamic contents.
Setup your Source, whilst overriding the checkAcceptance and use a known, (perhaps global) variable to keep track.
var lastReference = null;
var target = dojo.dnd.Source(node, {
checkAcceptance(source, nodes) : function() {
// this is called when 'nodes' are attempted dropped - on mouseover
lastReference = source.getItem(nodes[0].id)
// returning boolean here will either green-light or deny your drop
// use fallback (default) behavior like so:
return this.inhertied(arguments);
}
});
Best approach might just be like this - you get both target and source plus nodes at hand, however you need to find out which is the right stack to look for the node in. I believe it is published at same time as the event (onDrop) youre allready using:
dojo.subscribe("/dnd/drop", function(source, nodes, copy, target) {
// figure out your source container id and target dropzone id
// do stuff with nodes
var itemId = nodes[0].id
}
Available mechanics/topics through dojo.subscribe and events are listed here
http://dojotoolkit.org/reference-guide/1.7/dojo/dnd.html#manager

Can we have nested targets in Dojo?

I have two divs nested under a parent div and I want all these to be source as well as targets for dojo.dnd.
I want to be able to add nodes to the div over which the content was dropped and also allow the user to move this in between the 3 divs.
Something like this -
http://www.upscale.utoronto.ca/test/dojo/tests/dnd/test_nested_drop_targets.html
This is I gues implemented in older version of Dojo and doesn' seem to work with 1.4
Is the support for nested targets removed? Is there any way to achieve this?
Nested sources/targets are not supported currently. In most cases you can work around this restriction by using independent sources/targets, yet positioning them as you wish with CSS.
I used a workaround for this case. I create another DIV element which positioned at the same place of the nested target with same width and height but with higher z-Index value. Then the new DIV element covers the nested target. When user is trying to drop on the nested target, he actually drops to the above new DIV element. As long as the new DIV element is not nested in the parent drop target, Dojo's dnd operation works well. I usually put the new DIV element as a child of the body element.
What you need to do is to create the new DIV in onDndStart and destroy it in onDndCancel, then everything should work well.
Dojo version 1.10 still does not support nested Dnd.
CSS positioning and overlay div's didn't work for me. But I noticed that dragging an element out of a dndContainer into a parent dndContainer doesn't trigger onMouseOverEvent for the parent.
In case someone is still using dojo and has the same problem, here is my approach to solve this:
Declare your own dndSource e.g. nestedDndSource.js
define([
"dojo/_base/declare",
"dojo/dnd/Source",
"dojo/dnd/Manager"
], function(declare,dndSource, Manager){
var Source = declare("dojo.dnd.Source", dndSource, {
parentSource: null,
onOutEvent: function(){
if(this.parentSource != undefined)
Manager.manager().overSource(this.parentSource)
Source.superclass.onOutEvent.call(this);
}
});
return Source;
})
Use that nestedDndSource for the children instead of dojos and make sure to provide the dndSource of the parent as parentSource-Parameter:
var parentDndSource = new dojoDndSource(parentNode, {..});
var childDnDSource = new nestedDndSource(childNode,{
parentSource: parentDndSource,
onDropExternal: ...
});
Working example: https://jsfiddle.net/teano87/s4pe2jjz/1/