Using KO with visualization libraries like JIT or D3.js?

760 views
Skip to first unread message

Sam Imberman

unread,
Oct 21, 2011, 3:19:18 PM10/21/11
to KnockoutJS
Hi there,

Just wondering if anyone has any experience using Knockout alongside
visualization libraries like JIT or D3?

I'm trying to generate a tree visualization based on a deeply nested
set of observable arrays. I've found a way to create the tree:
starting from sample code on the JIT website (http://thejit.org/static/
v20/Jit/Examples/Spacetree/example1.html) I created a dependent
observable which recursively descends my tree and generates a new tree
of a format that JIT can deal with.

There are lots of limitations to this approach though. For one thing
it's pretty hard to link the generated tree nodes back to the spots in
the DOM where I use KO to modify the underlying data structure.
Secondly, the entire tree is regenerated every time anything is
modified in KO, which means that I lose any selections on the tree
that the user may have made. So it would be better if I could find a
way to update the tree incrementally.

I'm thinking of trying out an implementation in D3.js; Raphael is a
little lower-level than I wanted to go.

At any rate I was just curious if the gurus here on the KO list had
already tried to do anything like this... or if anyone had any
experience with integrating KO with other visualization libraries!

Sam

ky...@janrain.com

unread,
Oct 17, 2012, 1:56:57 PM10/17/12
to knock...@googlegroups.com, simb...@gmail.com
Im currently in the process of integrating KO with RickshawJS(d3 toolkit), so far it works pretty well together. 

Denys Khanzhiyev

unread,
Oct 18, 2012, 4:05:36 AM10/18/12
to knock...@googlegroups.com
I tried with d3. In fact d3 is pretty low level too. You have to build your chart in code. There are no predefined charts to use. You have only tools to build charts. So with KO you should build viewmodel for chart and bind it to d3 chart and yes it will rebuild node tree on each update. Another approach (I ended up with it) is to build charts entirely with KO I only look in d3 samples and code for ideas. I use separate viewmodel and template for each chart component. For example for tree diagram i have 3 view models:

1. Chart node viewmodel which at minimum should have node coordinates as ko.observable.
2. Node link viewmodel containing references to nodes it links to as ko.observables and start/end coordinates as ko.observables. Based on start/end coordinates I build link path (ko.computed).
3. Chart viewmodel with 2 observable arrayas - Nodes and Links.

So chart template looks like:

<script id='stateChartTemplate' type='text/html'>
 <g class="container" transform="translate(0,0)" data-bind="autoStretch:{ width: width, height: height, updateElement: false}">
        
    <!-- ko foreach: links -->
          <path class="link" data-bind="attr: { d:path }" />
    <!-- /ko -->
   
    <!-- ko foreach: nodes -->
    <!-- ko template: {name: 'svgQueue', templateEngine: SVGTemplateEngine} -->
   
    <!-- /ko -->
    <!-- /ko -->
   
 </g>
</script>

<script id='svgQueue' type='text/html'>
    <g class="node" data-bind="attr: { transform: 'translate('+rx()+','+ry()+')' }">
     <rect class="node-rect" width="150" height="50" data-bind="sizeFromAttr: { width: width, height: height}" />
     <text text-anchor="start" dx="3" dy="15" data-bind="text: name"></text>
     
    </g>
</script>   

sizeFromAttr binding just gets width and height from attributes and places it into viewmodel.

So in fact there is no need in d3 itself with that approach.

SVGTemplateEngine is a hack for KO native template engine to properly render svg (I have googled it):

var SVGTemplateEngine = function () {
    this['allowTemplateRewriting'] = false;
}

SVGTemplateEngine.prototype = new ko.templateEngine();
SVGTemplateEngine.prototype.renderTemplateSource = function (templateSource, bindingContext, options) {
    var nodes = templateSource.nodes();
    if (nodes)
        return nodes;
    var div = document.createElement('div');
    var text = '<svg xmlns="http://www.w3.org/2000/svg">' + templateSource.text() + '</svg>';
    div.innerHTML = text;
    return ko.utils.arrayPushAll([], div.childNodes[0].childNodes);
};

window.SVGTemplateEngine = new SVGTemplateEngine();


2012/10/17 <ky...@janrain.com>
Reply all
Reply to author
Forward
0 new messages