example - Edge Labels with ForceDirected Layout

1,131 views
Skip to first unread message

Michael

unread,
Feb 10, 2012, 2:45:44 AM2/10/12
to JavaScript InfoVis Toolkit
Hi,

here my version of the custom edgeType for jit-2.0.0b:

function init(){
...

//label placement on edges
$jit.ForceDirected.Plot.EdgeTypes.implement({
'labeled-arrow': {
'render': function(adj, canvas) {
//plot arrow edge
this.edgeTypes.arrow.render.call(this, adj, canvas);

//get nodes cartesian coordinates
var pos = adj.nodeFrom.pos.getc(true);
var posChild = adj.nodeTo.pos.getc(true);

//check for edge label in data
var data = adj.data;
if(data.$labelid && data.$labeltext) {

//if the label doesn't exist create it and append it to the
label container
var domlabel = document.getElementById(data.$labelid);
if(!domlabel) {
domlabel = document.createElement('span');
domlabel.id = data.$labelid;
domlabel.className = 'arrow-label';
domlabel.innerHTML = data.$labeltext;

//if defined set same color as edge
//if(data.$color) {
// domlabel.style.color = data.$color;
//}

//append the label to the labelcontainer
this.labels.getLabelContainer().appendChild(domlabel);
}

//now adjust the label placement
var ox = canvas.translateOffsetX,
oy = canvas.translateOffsetY,
sx = canvas.scaleOffsetX,
sy = canvas.scaleOffsetY,
posx = (pos.x + posChild.x) / 2 * sx + ox,
posy = (pos.y + posChild.y) / 2 * sy + oy,
s = canvas.getSize();

var labelPos = {
x: Math.round(posx - domlabel.offsetWidth / 2 +
s.width / 2),
y: Math.round(posy - domlabel.offsetHeight / 2 +
s.height / 2)
};

domlabel.style.left = labelPos.x + 'px';
domlabel.style.top = labelPos.y + 'px';
}
}
}
});

...
// init ForceDirected
var fd = new $jit.ForceDirected({
...


Don't forget to change the edge type:

...
Edge: {
// Define edge as a labeled arrow
type: 'labeled-arrow',
...


And here is a json node example for this:

...
{
"id": "host1",
"name": "host1",
"data": {
// "$color": "#EBB056",
"$type": "square"
},
"adjacencies": [
{
"nodeTo": "host2",
"nodeFrom": "host1",
"data": {
"$labelid": "arrow1",
"$labeltext": "somelabel",
"$color": "#C74243",
"$direction": ["host1", "host2"]
}
}
]
}
...


Jebbie

unread,
Mar 6, 2012, 10:55:35 AM3/6/12
to JavaScript InfoVis Toolkit
Thanks Michael for this example.
It might be dated but it is most useful to get started with labeling
edges.

I tried to extend it to Hypertree, with no success so far as all I get
is the regular arrow (and nodes) but no label is visible anywhere...


Any idea what I am doing wrong ? Is this example not applicable to the
latest JIT, or to Hypertree ?



Thanks anyone for a reply.

Below is my script which is VERY similar to yours on top of the
Hypertree example 1:

function init(){

//label placement on edges
$jit.Hypertree.Plot.EdgeTypes.implement({
'labeled-arrow': {
'render': function(adj, canvas) {
//plot arrow edge
this.edgeTypes.arrow.render.call(this, adj, canvas);
//get nodes cartesian coordinates
var pos = adj.nodeFrom.pos.getc(true);
var posChild = adj.nodeTo.pos.getc(true);
//check for edge label in data
var data = adj.data;
if(data.$labelid && data.$labeltext) {
//if the label doesn't exist create it and append it to the
label container
var domlabel = document.getElementById(data.$labelid);
if(!domlabel) {
domlabel = document.createElement('span');
domlabel.id = data.$labelid;
domlabel.className = 'arrow-label';
domlabel.innerHTML = data.$labeltext;
//if defined set same color as edge
if(data.$color) {
domlabel.style.color = data.$color;
}
//append the label to the labelcontainer
this.labels.getLabelContainer().appendChild(domlabel);
}
//now adjust the label placement
var ox = canvas.translateOffsetX,
oy = canvas.translateOffsetY,
sx = canvas.scaleOffsetX,
sy = canvas.scaleOffsetY,
posx = (pos.x + posChild.x) / 2 * sx + ox,
posy = (pos.y + posChild.y) / 2 * sy + oy,
s = canvas.getSize();
var labelPos = {
x: Math.round(posx - domlabel.offsetWidth / 2 +
s.width / 2),
y: Math.round(posy - domlabel.offsetHeight / 2 +
s.height / 2)
};
domlabel.style.left = labelPos.x + 'px';
domlabel.style.top = labelPos.y + 'px';
}
}
}
});

var json = {
"id": "host1", "name": "HOST1", "data":
{"$type":"square"}, "adjacencies":
[{"nodeTo":"host2","nodeFrom":"host1","data":
{"$labelid":"arrow1","$labeltext":"somelabel","$color":"#ff0","$direction":
["host1","host2"]}}],"children":[{"id":"host2","name":"HOST2"}]};
var infovis = document.getElementById('infovis');
var w = infovis.offsetWidth - 50, h = infovis.offsetHeight - 50;

//init Hypertree
var ht = new $jit.Hypertree({
...



Michael

unread,
Mar 6, 2012, 2:00:11 PM3/6/12
to JavaScript InfoVis Toolkit
Hi,

did you change the edge type?

In the Hypertree example 1 it shoud look like this:

...
//color, width and dimensions.
Node: {
dim: 9,
color: "#f00"
},
Edge: {
// Define edge as a labeled arrow
type: 'labeled-arrow',
lineWidth: 2,
color: "#088"
},
onBeforeCompute: function(node){
Log.write("centering");
},
//Attach event handlers and add text to the
...

Jebbie

unread,
Mar 6, 2012, 4:32:37 PM3/6/12
to JavaScript InfoVis Toolkit
Yes. I am afraid I did.
So all I get is the usual arrow and nothing more.

Thanks

Any other idea ?

BTW, can I edit my posts to correct/add little details

Michael Göhler

unread,
Mar 6, 2012, 8:23:08 PM3/6/12
to javascript-information...@googlegroups.com
For some reason adj.data is an empty object in your Hypertree example.
You can see this if you debug the object like this and have a look in
your firebug or chrome console:

...
var data = adj.data;
console.log(adj.data);
if(data.$labelid && data.$labeltext) {
...

In the example 1 code the "adjacencies" property is not used in the JSON
data. So maybe it is not fully implemented in Hypertree.

This issue is hiding somewhere deep in the library and im currently a
little short on time. *sorry*

Maybe Nico can have a look on that and give us a hint about the missing
attributes? :)

Regarding your other question:
I'm new to Google groups too, but I think since this is a Mailing-list
you can reply to it only. -> If you send an eMail it is send and can't
be edited again.

Regards,
Michael

Jebbie

unread,
Mar 7, 2012, 3:41:48 AM3/7/12
to JavaScript InfoVis Toolkit
Thanks Michael,

This skip over the "if(data.$labelid & data.$labeltext)" confirms my
observations.
However if I look at the jit.js source code I see little difference in
the definition of arrow between ForceDirected and Hypertree.
Both appear to use the 'adj' field in a very similar way.

ForceDirect:
'arrow': {
'render': function(adj, canvas) {
var from = adj.nodeFrom.pos.getc(true),
to =
adj.nodeTo.pos.getc(true),
dim = adj.getData('dim'),
direction = adj.data.$direction,
inv = (direction && direction.length>1 && direction[0] !=
adj.nodeFrom.id);
this.edgeHelper.arrow.render(from, to, dim, inv, canvas);
},
'contains': function(adj, pos) {
var from = adj.nodeFrom.pos.getc(true),
to = adj.nodeTo.pos.getc(true);
return this.edgeHelper.arrow.contains(from, to, pos,
this.edge.epsilon);
}
}


HyperTree:
'arrow': {
'render': function(adj, canvas) {
var from = adj.nodeFrom.pos.getc(true),
to = adj.nodeTo.pos.getc(true),
r = adj.nodeFrom.scale,
dim = adj.getData('dim'),
direction = adj.data.$direction,
inv = (direction && direction.length>1 && direction[0] !=
adj.nodeFrom.id);
this.edgeHelper.arrow.render({x:from.x*r, y:from.y*r},
{x:to.x*r, y:to.y*r}, dim, inv, canvas);
},
'contains': function(adj, pos) {
var from = adj.nodeFrom.pos.getc(true),
to = adj.nodeTo.pos.getc(true),
r = adj.nodeFrom.scale;
this.edgeHelper.arrow.contains({x:from.x*r, y:from.y*r},
{x:to.x*r, y:to.y*r}, pos, this.edge.epsilon);
}
},

So it must be even deeper under the hood than I thought. Unless my
JSON definition is somewhat wrong.
Thanks again very much for taking of your precious time to look into
my problem.

I hope Nico, or someone else, can give some hint on where to look.

Cheers !
JB

Jebbie

unread,
Jun 22, 2012, 10:55:49 AM6/22/12
to javascript-information...@googlegroups.com
Dear all, 

Any new solution to this problem of labeling edges in Hypertree ?

Thanks

Cheers
JB

nguyen dang Thanh

unread,
Jan 6, 2014, 8:56:26 PM1/6/14
to javascript-information...@googlegroups.com, somebo...@gmx.de
Is it available in version 2.0.1
I have copied your example but it is not working
Reply all
Reply to author
Forward
0 new messages