Update: Added a collage of the images I was going to add to get around reputation block
I've been working on a cytoscape implementation that will dynamically display information I'm pulling from my database onto a webpage. The goal is to be an organization chart, displaying nodes in groups, in a directed tree structure. I've been doing a lot of research, and trying out several different layouts and api options to try and meet the use case, but I'm having issues getting it to work the way I'm intending.
Specifically I want to use compound nodes - the parents being the people's ranks. I've learned that a lot of layouts simply haven't been designed with compound nodes in mind, and I've been trying different implementations, including ones that create an initial layout, and then try to run a secondary layout specifically on the descendants of the parents.
Following are the closest of what I've tried and their issues:
Images of graphs: https://i.stack.imgur.com/6hzVS.png
cose-bilkent:
The main issue with this is that it doesn't seem to be meant for directed trees, but rather decides placement on its own. The bigger issue I've had is that I couldn't find a way to spread the nodes out better within their groups. I've tried to use the node padding options included, but they haven't had an affect, which I'm assuming is due to the compound nature.
grid:
Graph is in a perfectly grid like layout of all the nodes, but ignores parent nodes.
This layout was working for me initially, and would have the benefit of being able to easily change the amount of people per column. As I changed the elements though I realized it was a coincidence that it worked initially - it seems like it's totally ignoring the parent nodes, which is understandable if it wasn't designed with them in mind.
grid - descendants:
Graph is of the two sets of descendants layered on top of each other.
What I tried next was using a different layout to determine the initial placing of the parents, and then performing a grid layout on the descendants to make them organized in their groups. I realized then that parents are simply reacting to their child's placement. Also, it appears that calling layouts on sets of nodes separately for grid was completely ignoring anything else that exists on the graph, causing the groups to be put on top of each other.
cola:
It's close, but the way it puts them on the graph is not well structured, causing the placement in the groups to be jumbled up, though they are spaced out enough.
This appears it would work great if I could figure out how to run a proper layout on the parent nodes, forcing the tree structure that works without compound nodes.
Here is more or less what I'd like to see, though the logic for # of nodes per column isn't that important. As long as they're organized neatly:
https://i.stack.imgur.com/irVaK.png
Is there any advice someone could give on how I could go about making this work? I haven't been able to find any layout setups that work quite right, and I don't really know what to do from here. I would also prefer to avoid creating an entirely new layout from scratch. Any help is greatly appreciated.
If you have a proper tree data structure, you shouldn't be using compound nodes for layout. It's not generally possible to satisfy compound parent position restrictions when there are additional constraints on the children. This is because a parent is naturally constrained by its children -- a parent doesn't have its own position or size, it's children define it implicitly.
The best layouts for compound graphs are force-directed (physics simulation) ones like CoSE or Cola.
In your case, you just have a tree. I would use the breadthfirst or Dagre layouts without any compounds. Each level will naturally indicate rank.
For anyone interested, what I've done to solve this is create my own preset layout function that dictates where (children) nodes go on the graph, using their properties to dictate where they go.
It's designed to only display linear compound graphs, in order based on "level" in the hierarchy. It's capable of displaying the children nodes in grid-like sets within their parent nodes (visually - remember parents simply adjust according to their children), in the order of the mentioned linear levels.
You can also specify the values for how many columns in a set, space between nodes, and space between levels. There's obviously lots of room to make the variables more verbose if you'd like to specify "x-space" and "y-space" between nodes, and things like that.
It assumes the following:
-You know ahead of time what level corresponds to each compound group
-You know ahead of time how many nodes are in each compound group
-If you're making this dynamically, that you have a way to dynamically produce the javascript variables necessary for the dictionary, which tracks the total size of each group and how many nodes of each group have been accounted for.
Here's the code. I know it's a niche case, but if you do have a reason to use it, just keep in mind that it's sure to be bug prone, and is definitely inefficient (Javascript isn't my forte...). I've tested certain edge cases that I feel are common in my project, but there could be others that aren't accounted for.
http://jsbin.com/quyipo/edit
(Also upvotes/comments don't hurt either. I'm curious if this could actually help someone...)
Related
I have data that needs multiple columns. One of the columns (preferably not first, but can be) will display nested tree structure like data.
Both maxazan's TreeGrid.js and Ludo van den Boom's treetable.js accomplish what I want, almost. It can be very hard to distinguish the hierarchy by quick glance:
The data hierarchy is but unclear here
And here would be solution: Adding connectors ->
The visualisation fixed with connectors
The actual data has 7 columns
...but TreeGrid nor Treetable support this functionality. In both, the indentation is accomplished through spans with padding. Treetable uses a single spans, which makes connector implementation near impossible. TreeGrid uses multiple spans, where I could imitate something connector like to distinguish the levels better.
How would I implement connectors to eg. TreeGrid, or are there any similar js libraries for creating tree grids with connectors that I have missed?
If your answer is: "it's semantically incorrect, you should use nested lists" (in which connectors are quite trivial to implement), then my follow-up question is:
What are the different possibilities to vertically align the elements inside list elements inside nested unordered lists? The old version used unordered lists with floating elements, very fiddly code to resize them accordingly if window is resized etc, which broke in way too many cases and was horrible to maintain.
In my application, a graph is loaded initially with the one-net of a particular node. The user can expand the graph by double-clicking any node to add its one-net.
The problem is that every time the user does that, the nodes all jump around, so it's confusing. I don't want to just disable physics, because then the new nodes get jumbled on top of the old ones. For lack of a better explanation, I want to freeze the existing nodes, only using physics to arrange the new nodes (and then freeze them before adding more). I looked at Stop vis.js physics after nodes load but allow drag-able nodes, but that doesn't solve my problem.
I'm pretty clueless about what the various options to the physics solving algorithms mean, and can't find a good description anywhere, so I wonder if there may be tweaks there that would help me.
Thanks!
You can give some of your nodes a fixed x and y position. There are also methods like getPositions() and storePositions() to retrieve or set the positions after the first stabilization or something like that.
I want to display a graph which depicts a timed process. Therefore, it would be desireable to have nodes aligned according to a given timeline.
The time stamps are totally accurate, which is why I chose them to be the keys of my groups. If two nodes have the same time stamp, they get added to the same group.
These groups are aligned by the TreeLayout. Per default they are aligned in the following way:
(Please note that the black boxes depict the groups and their alignment. The red boxes were added for better understanding on which level which group is.
What I would like to have, is a more timelined view of the diagram like so:
I tried setting layerStyle: go.TreeLayout.LayerUniform, and afterwards setting the TreeVertex.level accordingly, but GoJS didn't change its positioning.
Are there any other possibilities to achieve what I want?
Did you assign TreeVertex.level in an override of TreeLayout.assignTreeVertexValues?
You might be interested in the LayeredTreeLayout example classes that are in two different samples: http://gojs.net/temp/swimBands2.html (no Groups) and http://gojs.net/temp/swimBands3.html (with Groups).
I hope the LayeredTreeLayout code in those files isn't too confusing. They are slightly different from each other, due to the absence or presence of Groups, and the corresponding changes in the node data.
I am programming a Javascript game as an exercise in objects and AJAX. It involves movement of wessels around a nautical-themed grid. Although the wessels are in an array of objects, I need to manipulate their graphical representation, their sprites. At the moment I have chosen, from a DOM perspective, to use 'img' elements within 'td' elements.
From a UI continuity perspective, which method of programmatically moving the elements with Javascript would be recommended:
(a) deleting inner html of 'from' cell (td element) and rewriting inner html of 'to' cell,
(b) clone the img node (sprite), delete the original node from its parent, and append it to the 'to' cell, or
(c) using positioning relative to the table element for the sprite, ignoring the td's alltogether (although their background [color] represents the ocean depth).
I would definitely stick with moving the sprite from cell to cell rather than using relative positioning to the table. My reasoning is that the table cell size might vary from browser to browser (given variances in the way padding, margins etc. are rendered - especially with annoying IE) and calculating the exact location to position the sprite in order for it to line up within a given cell might get complicated.
That narrows it down to (a) or (b) for your options. Here let's eliminate option (a), as deleting the HTML from inside is not a clean way of manipulating the DOM. I like the idea of storing the node in an object, and then appending it to the 'to' cell, and then deleting the original node, which your option (b) suggests. This way, you are still dealing with the high-level 'objects' and not the low-level 'text' needlessly. You don't need to mess with the text - for such an application, that would be the dirty 'hackish' way of doing it if you didn't know about the DOM manipulation functions JavaScript already offers.
My answer is (b). However, if you absolutely require speed - though for your game I don't know if you'll really need the extra boost - you may consider option (a). A few sources, such as http://www.quirksmode.org/dom/innerhtml.html contend that the DOM manipulation methods are generally slower than using innerHTML. But that's the general rule with everything. The lower the level you go, the faster you can make your code. The higher the level, the easier to understand and conceptualize the code is, and in my opinion, since speed will not make a huge difference in this case, keep it neat and go with (b).
There's no need to clone the img node, delete the old one and append the clone. Just append the img node to the receiving td. It will automatically be removed from the td it was previously in. Simple, effective and fast.
Put in an answer or link to some page with information about how Layout Managers work (Layout Managers internals)?
in general matter. For laying 2d (normal) components in a browser. I want to build a layout manager for an application framework in javascript
Assuming I have a grasp of your question, the quintessential tasks a layout manager performs are namely:
Keep track of position information for each layout component. In a browser can go as far as meaning you can map the relationship of css positioning top, left, absolute, relative, etc.. including the affects of margins, padding, borders, etc..
This may be viewed as the same point, but keeping track of layers (usually z-index in your case) is also important.
Tracking shape information, usually height and width of a box
Track which components have 'active elements' such as scripts, animations, forms or embeds
Track which components must be attached to others with certain requirements and which are self-contained and widget-like
Often the capability of dynamically updating styling properties and even content within a given layout component
Providing functionality to reposition, align, resize and otherwise adjust tracked properties of one layout component based on the properties of one or more other layout components
If you are capable of handling this, you are on to a good start. Being able to take it a step further by designing layout formats that may be rearranged based on a template or schema can also be very useful.
Update: As far as which size takes
precedence, I'm unsure what you are
looking for. If you are already using
JavaScript it can be good practice to
keep width between min- and max- width
dynamically along side the css to keep
cross-browser.
Reading the node structure and handling it is somewhat a matter of
preference and very much a matter of
design. In my own experience it is
nice to abstract the child-most
'layer' of nodes, well particularly
all the content holding nodes into one
part of code and the parent-most nodes
in another. These are not strictly the
top and bottom nodes however as some
content does have sub-nodes, <b>
tags for instance. After that I fill
in another abstraction for containers
and finally account for all nodes
using the relationship of these three
layers.
If you arrange the 'main' elements using relative lengths such as em, ex,
etc.. or percentages and follow up
using absolute positioning on children
either in a <div style="position:
relative"> wrapper or using margins
to add or subtract from the relative
lengths,.. you are able to produce
closely matching displays across
different browsers and different
end-user screen resolutions.
Also, take a look at basic HTML/CSS design best practices for
reference and try to simply implement
them and you'll be off to a good
start.