Given a HTML structure like so:
<div id="canvas">
<div class="group group-normal" id="1">hello world</div>
<div class="group group-infiltrated" id="2">whats up dogue</div>
</div>
I currently use jsPlumb to create a graph from that structure:
$(function() {
jsPlumb.Defaults.Container = $("div#canvas");
jsPlumb.draggable($("div.group"), {
containment: $("div#canvas")
});
var stateMachineConnector = {
connector: "Bezier",
paintStyle: { lineWidth: 2, strokeStyle: "#056" },
endpoint: "Blank",
anchor: "Continuous",
overlays:[ ["PlainArrow", { location: 1, width: 15, length: 12 } ]]
};
jsPlumb.connect({
source: "1",
target: "2"
}, stateMachineConnector);
});
Which already gives me a nice, draggable graph:
The problem is, that when initialising the graph, all the divs are in the upper left corner of the canvas. I learned that this is due that jsPlumb only provides functionality to layout a graph, but not to position it.
I then went on a scavenger hunt and found many useful libraries that deal with positioning, like springy, sigma and alike. The problem is: Most of the don't operate on divs, but rather on some (for me) instransparent SVG/Canvas object graph.
I like jsPlumb very much and would like to keep using it. The only thing I need from other libraries is the initial positioning of all the elements.
How can I make the elements be positioned more evenly over the space available, maybe even in a way that makes them arrange the same way every time the graph is initialized?
Here is the plugin for positioning DIV's which has connectivity: https://github.com/lndb/jsPlumb_Liviz.js
Basically the plugin is derived from graphviz js library.
You need to pass the connectivity information to the library through a textarea(id=dot-src). So whenever you establish a connection, store the connectivity info in a string and later pass it to the Liviz library for positioning it.
str='digraph MyGraph {'; // This string will be set to the textarea at the end.
// Whenever connection is created update the string.
jsPlumb.bind("jsPlumbConnection", function(ci) {
console.log($('#'+ci.sourceId).data("prop").dn+"->"+$('#'+ci.targetId).data("prop").dn);
str+=ci.sourceId+"->"+ci.targetId+";";
});
// At the end set the string and call Liviz function
$('#dot-src').text(str+"}"); // Set the string
w_launch(); // call the library to position the DIV's based on connectivity.
You can explore graphviz for different types of options to customise positioning.
Related
I'm trying to recreate the animations when loading from this website:
https://uchuhimo.me
I think they are using velocity.js to do the animations.
I tried to recreate some of this and kind of succeeded (though not sure if doing it properly). There is one problem though, that the elements are there and then they animate (slidein), whereas correctly they should be hidden and then they slide in so they become visible (like on the website). I looked into documentation and i think that should be expected behaviour? But here in my example it does not work like that.
https://codepen.io/pokepim/pen/EpyKWR
The sequence of animation I run is the following:
And they should imitate the animation of that website im trying to imitate.
var loading = [
{ elements: $(".logo-line-before"), properties: {width: '100%'}},
{ elements: $(".logo-line-after"), properties: {width: '100%'}, options: { sequenceQueue: false }},
{ elements: $(".ttl"), properties:"transition.slideDownIn"},
{ elements: $(".ui.top.vertical.segment"), properties:"transition.slideDownBigIn"}
];
$.Velocity.RunSequence(loading);
That's all using Velocity V1 so there's limited help available (it's not supported any more), however you do need to pre-load the elements for opacity:0, there's no need for changing the display property on them as it's just a "get it visible" animation on an element that should still take up space.
I'd suggest simply adding a style="opacity:0;" on each of those elements in the HTML source and going from there.
I am calling the following function and passing it the location of an image:
function show_image(source) {
var img = d3.select("#right-section").append("img").attr("src",source)
img.transition().duration(5000).easeLinear;
}
Here is the function that uses some JQuery to empty the relevant HTML div object (right-section) and then show the image:
function Con1aaRight(div) {
$("#right-section").empty();
show_image("images/netflix.jpg");
}
The problem is the image is showing but not fading in like I would like it to (with d3.ease in the show_image function). I probably should be using JQuery but I would like to incorporate d3. Similar transition/animation ideas welcome. I am building a scrolling webpage tutorial on a data science topic with text on the left and images on the right.
The problem here is understanding what is a D3 transition and how it works.
A D3 transition, as the name implies, transitions from one state, or value, to another state.
That being said, you can, for example, transition...
A position: from x = 10 to x = 60.
A color: from green to blue.
A font size: from 10px to 18px.
An opacity: from 0.2 to 0.9.
A stroke width: from 1px to 5px.
... and several other attributes/styles.
However, you cannot transition this:
non-existence ➔ existence
As Bostock, creator of D3, once said (emphasis mine):
When modifying the DOM, use selections for any changes that cannot be interpolated; only use transitions for animation. For example, it is impossible to interpolate the creation of an element: it either exists or it doesn’t. (source)
Solution: transition the opacity of the image:
var body = d3.select("body");
show_image("http://www.defenders.org/sites/default/files/styles/large/public/tiger-dirk-freder-isp.jpg")
function show_image(source) {
var img = body.append("img").attr("src", source).style("opacity", 0)
img.transition().duration(5000).ease(d3.easeLinear).style("opacity", 1)
}
<script src="https://d3js.org/d3.v4.min.js"></script>
PS: get rid of that jQuery code. You don't need jQuery when using D3. Mixing jQuery and D3 is not only unnecessary but also, in some cases, it will make things silently break.
I have a list of charts. I use Chart.js to create those charts. Since my list can have 1 to 100 or more entries initializing all charts at once would not be smart because that would make the ui freeze for a long time. So instead I thought it would be much better to only initialize those charts which are visible inside the view bounds of the browser so that for example only the first chart is getting initialized and when the user scrolls down and the second canvas becomes visible the second is getting initialized and so on.
I have everything setup but the only problem that I have right now is: how can I create an eventlistener or anything similiar which I can add to each canvas element that gets triggered when a canvas becomes visible inside the view bounds of the browser so that i can perform the chart initialization for that canvas?
I'm the author of OnScreen, a small library that can call a callback function when a HTMLElement enters the viewport or the boundaries of its container.
// Uses ES6 syntax
import OnScreen from 'onscreen';
const os = new OnScreen();
os.on('enter', 'canvas', (element) => {
if (!element.chartInitialized) {
// Initialize the chart
// Update the `chartInitialized` property
// to avoid initializing it over and over
element.chartInitialized = true;
}
});
For more information, take a look at the documentation. Don't forget to check the demos repo for a couple simple examples.
I have used the onScreen jQuery plugin.
It is very easy. You just have to call for each canvas this:
$('elements').onScreen({
container: window,
direction: 'vertical',
doIn: function() {
// initialize canvas
},
doOut: function() {
// Do something to the matched elements as they get off scren
},
tolerance: 0,
throttle: 50,
toggleClass: 'onScreen',
lazyAttr: null,
lazyPlaceholder: 'someImage.jpg',
debug: false
});
I'm trying to make a webtool for users to make a flow chart, which is hierachical. I'm trying to visualize the scope for new draggable connections.
Each node has 'startpoints' on the bottom and can receive connections on the top. (this to enhance the hierarchical structure). Now in my jsfiddle
http://jsfiddle.net/SCSaf/
You can see the 'startpoints' as a square and the 'endpoints' as a Dot. If you start dragging a connection from a square, you see a square, which is odd since it should connect to a Dot.
I tied to change this, since that would solve my problem. I couldn't get it right. I tried changing this bit:
var exampleGreyEndpointOptions = {
endpoint:"Rectangle",
paintStyle:{ width:25, height:21, fillStyle:'#666' },
isSource:true,
connectorStyle : { strokeStyle:"#666" },
isTarget:false,
maxConnections:5
};
connectorStyle changes only 'the arrow', I can't find an option to change the square on the tip of the Arrow.
The other option is something similar to the jsPlumb demo for draggable:
http://jsplumbtoolkit.com/draggableConnectors/jquery.html
Here you can see that on a dragstart, the receiving nodes get a red dotted line. If I could apply similar styling to the 'endpoints' that would also be OK. The problem with this example is that it would also highlight 'startpoints' from other nodes/containers. (to which it can not connect)
To be clear, the jsfiddle works as I want, only the Visuals are a bit confusing. Hope you can help.
I quite sure I tried this, but now I got it working:
add CSS:
.dragActive {
border: 2px dotted orange;
}
a var like:
var exampleDropOptions = {
tolerance:"touch",
hoverClass:"dropHover",
activeClass:"dragActive"
};
and change the endpointOptions accordingly:
var endpointOptions = {
// ....
dropOptions: exampleDropOptions
}
here's the updated JS-fiddle. Works!
http://jsfiddle.net/SCSaf/1/
I want to show a unidirectional graph to the user in a webpage. I am currently using JavaScript InfoVis Toolkit (JIT) as the visulization library.
The problem is that the graph has many nodes and edges and the browser cannot keep up with all of it and slows down. Here is a screenshot of part a graph:
I think the problem will be solved if the graph is shown partially. So when user clicks on a node that node and nodes around it should be expanded (shown) and some far nodes should be collapsed (hidden) to prevent performance issues.
Based on this idea I I've written a simple code that expands a node and puts it in center when a user clicks on it and collapse previous centered node. It is not a very efficient and wise way for showing nodes, anyway it doesn't work. It just collapses all the nodes and fails to expand the current clicked node.
Here is the code:
onClick: function(node,eventInfo,e) {
if(node==false)
{
return;
}
if(rgraph.previousexpand!=false)
{
if(rgraph.previousexpand.id!=node.id)
{
rgraph.op.contract(rgraph.previousexpand, {
type: 'animate',
duration: 3000,
hideLabels: true,
transition: $jit.Trans.Quart.easeOut
});
}
}
rgraph.previousexpand = node;
rgraph.op.expand(rgraph.previousexpand, {
type: 'animate',
duration: 3000,
hideLabels: true,
transition: $jit.Trans.Quart.easeOut
});
rgraph.onClick(node.id);
}
And in initialization:
rgraph.previousexpand=false;
First, do you know any better way for showing a very large graph? Is there any other solution in JIT or maybe other library that show graph in this way?
Second, what i am missing in the code?