Dynamically adding and refreshing charts

96 views
Skip to first unread message

spark343

unread,
Mar 23, 2011, 12:11:43 PM3/23/11
to protovis
Is there an elegant way of dynamically adding and later refresh charts
using AJAX calls for new data?

I've dug into the protovis code and it adds a "load" event that scans
scripts of type javascript+protovis. Here's the excerpt from protovis-
d3.2.js:

pv.listen(window, "load", function() {
pv.$ = {i:0, x:document.getElementsByTagName("script")};
for (; pv.$.i < pv.$.x.length; pv.$.i++) {
pv.$.s = pv.$.x[pv.$.i];
if (pv.$.s.type == "text/javascript+protovis") {
try {
window.eval(pv.parse(pv.$.s.text));
} catch (e) {
pv.error(e);
}
}
}
delete pv.$;
});

So I've tried just calling window.eval on a javascript+protovis script
element that's generated dynamically and inserted into the DOM where I
need the dynamic chart... but I'm not having much luck. Possibly I
need to add the dynamic chart to the array as is done in the load
script... I'm not sure what this array does though, exactly.

Can anyone point me to some examples of dynamically loading charts, or
dynamically refreshing charts?

Thanks!

Peter

Chris Hunter

unread,
Mar 24, 2011, 10:35:16 AM3/24/11
to prot...@googlegroups.com, spark343
Peter.

While protovis has the convenience support for evaluating
javascript+protovis scripts inline (using the braceless 1.8 javascript
syntax), you can call protovis functions normally if you avoid the 1.8
syntax. Here's an example (this is extracted from a web page, so it
may need some tweaking to work):

// Using jQuery's dom:ready but should work with any framework
$(function(){

// Data defined statically but could be pulled in via AJAX
var data = [
{value:10, label:'New'},
{value:20, label:'Existing'}
];

// Draw the chart into targetElem
var w = 200,
h = 200,
r = w / 2,
max = pv.sum(data, function(d){ return d.value; }),
a = pv.Scale.linear(0, max).range(0, 2 * Math.PI);

var vis = new pv.Panel()
.canvas('targetElem')
.width(w)
.height(h);

vis.add(pv.Wedge)
.data(data)
.outerRadius(r)
.angle(function(d) { return a(d.value); })
.title(function(d) { return d.value; })
.add(pv.Wedge) // invisible wedge to offset label
.visible(function(d) { return d.value > 0.15; })
.innerRadius(0.25 * r)
.outerRadius(0.75 * r)
.fillStyle(null)
.anchor("center").add(pv.Label)
.textAngle(0)
.text(function(d) { return d.label; });

vis.render();

})

At minimum for refresh, you should be able to redraw the entire chart,
although I suspect there's a more efficient way to do it.

Hope that helps,

Chris Hunter

> --
> You received this message because you are subscribed to the Google Groups "protovis" group.
> To post to this group, send email to prot...@googlegroups.com.
> To unsubscribe from this group, send email to protovis+u...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/protovis?hl=en.
>
>

spark343

unread,
Mar 24, 2011, 2:33:53 PM3/24/11
to protovis
Thanks Chris!

As a feature request, I'd love to see a way to pass the constructor a
DOM element as the container rather than the current implicit
detection based on the location of the script element.

I'm looking at using protovis for a dashboard and it's a major hack to
workaround how the charts are positioned right now. I don't want to
write out a script for every chart -- I want to have a chart making
template, and feed it data as the charts arrive and have the charts
end up in the right position. I can work around that by overriding
the $dom before rendering the chart and creating a phony child element
(instead of a script tag) inside of the my desired target container...
but, this isn't really a clean way of doing things. :)

Best,

Peter

Chris Hunter

unread,
Mar 25, 2011, 12:09:01 PM3/25/11
to prot...@googlegroups.com, spark343
On Thu, Mar 24, 2011 at 1:33 PM, spark343 <spar...@gmail.com> wrote:
> Thanks Chris!
>
> As a feature request, I'd love to see a way to pass the constructor a
> DOM element as the container rather than the current implicit
> detection based on the location of the script element.

It's not exactly passing it to the constructor but you can use a call
to the 'canvas'
method to specify a DOM element as the container. From my example:

var vis = new pv.Panel()
.canvas('targetElem')

'targetElem' is the id of a div nested in my page's DOM.

> I'm looking at using protovis for a dashboard and it's a major hack to
> workaround how the charts are positioned right now.  I don't want to
> write out a script for every chart -- I want to have a chart making
> template, and feed it data as the charts arrive and have the charts
> end up in the right position.  I can work around that by overriding
> the $dom before rendering the chart and creating a phony child element
> (instead of a script tag) inside of the my desired target container...
> but, this isn't really a clean way of doing things. :)

You shouldn't have to be doing this. I'm using code very much like that
from my original response, wrapped in a utility function that takes a
data argument,
element, width and height. Then you just make multiple calls to that
function on page load
(or whenever your data is ready).

Does that make more sense?

--Chris

Reply all
Reply to author
Forward
0 new messages