more than one set of labels in protovis?
I'd like to have both the values and the data categories on a graph. This is a bar chart and I'd like to have the data values and a string开发者_JAVA技巧 printed in columns off to the left of the bar:
A 1 #
B 3 ###
I tried chaining a two add(pv.Label) calls onto my graph, but it seems to do nothing - the second label set is not added. Is this something that can even be done with protovis? any advice?
vis = new pv.Panel()
.def("j", -1)
.width(800)
.height(50)
.right(3);
vis.add(pv.Bar)
.data(wData)
.bottom(0)
.width(20)
.height(function(d) d[1] * 1.2)
.left(function() this.index * 27)
.fillStyle(function() vis.j() == this.index ? "orange" : "steelblue")
.add(pv.Label) **// does nothing!!**
.bottom(0)
.textAlign("center")
.textStyle("white")
.text(function(d) d[0] )
.event("mouseover", function() vis.j(this.index))
.event("mouseout", function() vis.j(-1))
.anchor("top").add(pv.Label)
.visible(function() vis.j() >= 0)
.textStyle("white")
.text(function(d) d[1]);
vis.render();
I actually did see both labels when I tried this out. But there are a couple of things that could be fixed here. The key point is that when you're chaining methods like this, when you add()
a new mark, you change the context of the following method calls, e.g.:
vis.add(pv.Bar)
// this applies to the Bar
.width(10)
.add(pv.Label)
// this applies to the label
.top(5);
There are a couple issues with this in your code:
Your
event()
handlers are attached to the Label, not to the Bar - unfortunately, Labels can't receive events in Protovis.Your second Label is attached to the first Label. While this actually seems to work somewhat, it's better to avoid it - you really want it attached to the Bar.
The easy way to deal with this is to only chain methods on a single mark. You can do this by assigning the parent mark to a variable, then using that variable several times for different child marks. You also have you first Label attached directly to the Bar, and not to an anchor - attaching it to an anchor will usually give you more predictable results.
Updated code:
// make a new variable to refer to the bars
var bars = vis.add(pv.Bar)
.data(wData)
.bottom(0)
.width(20)
.height(function(d) d[1] * 1.2)
.left(function() this.index * 27)
.fillStyle(function() vis.j() == this.index ? "orange" : "steelblue")
// you need to move the events up to apply
// to the bar - labels can't receive events,
// and the index will always be 0
.event("mouseover", function() vis.j(this.index))
.event("mouseout", function() vis.j(-1));
// now add each label to the bars
bars.anchor('bottom').add(pv.Label)
.bottom(0)
.textAlign("center")
.textStyle("white")
.text(function(d) d[0] );
// and again
bars.anchor("top").add(pv.Label)
.visible(function() vis.j() >= 0)
.textStyle("white")
.text(function(d) d[1]);
There's a working version here: http://jsfiddle.net/nrabinowitz/ABmuq/
精彩评论