weixin_33725270 2015-03-11 13:01 采纳率: 0%
浏览 143

D3和双向数据绑定

I am interested in the current best practices and solutions for using the data driven documents library with two-way AJAX data bindings. More specifically I am wondering how d3 should be best integrated with libs supporting two-way data bindings such as Angular or Knockout.

The obvious conflicts that arise stem from the fact that d3 and the AJAX libs are both inserting data to the DOM, which basically means that one has to wrap the other.

  • 写回答

1条回答 默认 最新

  • weixin_33749242 2015-10-09 03:01
    关注

    About Data on DOM

    You were worried about the data inserted to the DOM. This are some of the properties added:

    • D3js: __data__, __onmouseover.force, __onmouseout.force, __onmousedown.drag, __ontouchstart.drag, __onmousedown
    • AngularJS: value, type, version, align, ng339

    So there's no colisions and no need to wrap one into another. You can test this using Object.keys(SOME_DOM_ELEMENT); and Object.keys(SOME_DOM_ELEMENT.__proto__);

    About Implementation

    Pure javascript

    This is how you assign data to D3js:

    d3selector.data( myNameSpace.myDataObject );
    

    And this is my data binding approach using watch: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/watch

    d3selector
    myNameSpace.watch('myDataObject', function (id, oldval, newval) {
        d3selector.data( newval );
        return newval;
    });
    

    This way, everytime you change myNameSpace.myDataObject the data used by D3js will be updated too. But this will only work on Firefox.

    AngularJS

    There's an answer in this question Angular + d3.js: Data binding with SVG text attr? that explains how to do it using $watch.

    Is similar to the Firefox watch:

    directive('myDirective', function ( /* dependencies */ ) {
    
        // Imagine your $scope has myDataObject
        $scope.$watch('myDataObject', function (newVal, oldVal) {
            d3selector.data(newVal);
        });
    
    }
    

    Now everytime you change myDataObject in the $scope the data of D3js will be updated too.

    More info

    Here is an example of two way data binding using polymer: http://bl.ocks.org/psealock/a4f1e24535f0353d91ea you can test it here: http://bl.ocks.org/psealock/raw/a4f1e24535f0353d91ea/

    As you can see in refreshChart the binding is not really being used. Instead, on the event triggered when the data changes, D3js loads the new data:

    this.g.data(this.pie(this.data));
    

    D3js is not prepared to listen for changes on the data, unless you use the data method. That's why the already rendered data will not change.

    If in the future data bindings were implemented, I guess there will be a new method on selection:

    selection.update - return placeholders for updated elements.

    similar to the current enter and exit:

    selection.enter - returns placeholders for missing elements.

    selection.exit - returns elements that are no longer needed.

    removing the need to create refresh functions.

    评论

报告相同问题?