To do this, we need to understand the basic idea of the positioning. Items can be positioned using two parameters relative position + offset in px and we also need to consider the zoom effect.
To do this, let's look closer at what px/py and x/y does. px/py set the centre of the item relative to the centre of the node. So, we can use this to put the item at the outside of the node by setting px=-1 and py=1. in this situation, centre of the item is on the left-bottom corner. Now, we can use x and y to move the centre relative to the px/py.
To do this, we need to know the dimensions of the item. There is no public api, but it can be done using some internal methods:
for (var x = 0; x < items.length; x++){
var item = new ZoomCharts.Internal.Base.Label(items[x]);
if (!ctx){
ctx = t._impl.shell.canvas.getContext("2d");
}
var d = t._impl.shell.labelRenderer.measure(ctx, item);
items[x].extra = [item.hwidth, item.hheight];
}
Now, measurement provides us half-height and half-width of the item. When we have it, rest is simple we need to put x as halfwidth (as the px is in the centre) and y for the first item needs to be half-height (to move the centre down). For 1st+ item, we need to add also the height of the previous items, so we keep that in a loop variable.
End result looks like this:
var zoom = t.zoom();
var ctx = null;
function nodeStyle(node) {
node.label = node.data.name;
if (!node.items.length){
let items = [
{
text: "Item 1: Short ",
aspectRatio: 0, //force single line
align: "left",
px: -1, py: 1, x: 0, y: 0,
textStyle: { fillColor: "white", font: "18px Arial" },
backgroundStyle: {
fillColor: "#09c",
lineColor: "rgba(0,0,0,0)"//transparent",
},
scaleWithZoom: true,
},
{
text: "Item 2: A longer one ",
aspectRatio: 0, //force single line
align: "left",
px: -1, py: 1, x: 0, y: 0,
textStyle: { fillColor: "white", font: "18px Arial" },
backgroundStyle: {
fillColor: "#09c",
lineColor: "rgba(0,0,0,0)"//transparent",
},
scaleWithZoom: true
}];
/* get dimensions */
for (var x = 0; x < items.length; x++){
var item = new ZoomCharts.Internal.Base.Label(items[x]);
if (!ctx){
ctx = t._impl.shell.canvas.getContext("2d");
}
var d = t._impl.shell.labelRenderer.measure(ctx, item);
items[x].extra = [item.hwidth, item.hheight];
}
node.items = items;
}
/* update pixels based on zoom */
let offsety = 0;
for (var x = 0; x < node.items.length; x++){
var d = node.items[x].extra;
node.items[x].x = d[0] * zoom;
node.items[x].y = offsety + d[1] * zoom;
offsety += d[1] * zoom * 2;
}
}
Note, x and y are absolute pixels, so we need to adjust it with the zoom level, so, to have the position updated whenever zoom changes, we bind onPositionChange event:
events: {
onPositionChange: function(ev){
zoom = t.zoom();
t.updateStyle();
}
}
Full example here:
http://jsfiddle.net/7gk9trmz/3/
As for hovereffect, in the nodeStyle function you can use node.hovered check to add extra height and or decorations to the labels. Note, that you need to recalculate the size if you do so. You can store extra sizes in the "extra" parameter.
Janis