繁体   English   中英

是否可以在D3中使用Knockout Observables

[英]Is it possible to use Knockout Observables within D3

我有一个单页应用程序,我正在构建使用D3Knockout的组合。 目前他们正在分开工作并处理他们自己的数据绑定,但我们必须处理一些交叉。

这让我思考,如果这个交叉可以自动处理并且KnockoutD3可以很好地一起玩,那就太棒了。 以下是我想做的几个简短示例:

绑定单个值

在这种情况下,我有一个文本项,我想直接将值绑定到我的observable

d3.select("text").text(myObservable);

绑定多个值

在这种情况下,我有很多文本项,并希望绑定到驻留在数据元素上的observable:

d3.select("text").text(function(d) { return d.myObservable(); });

将单个值与函数绑定(和转换)

这是两种情况之间的交叉(但我认为类似于绑定到多个值),因为我现在有一个项目,但我需要能够执行一个函数来正确地获取我的值。 在这里,如果观察者要改变,这将激发动画以改变笔画风格。

d3.select("path")
  .style("stroke", "white")
  .transition()
  .duration(1000)
  .style("stroke", function(d) { 
    var value = d.myObservable();
    if(value < 0) return "red";
    if(value === 0) return "orange";
    return "green";
});

就解决方案而言,我正在d3.selection.prototype.text覆盖d3.selection.prototype.text函数(可能还有其他整个版本)的行:

var setText = d3.selection.prototype.setText;
d3.selection.prototype.setText = function(value, index, groupIndex) {

    var selection = this;
    if(value && ko.isObservable(value)) {
       value.subscribe(function() {
          setText.call(selection, value(), index, groupIndex);
       });
       setText.call(selection, value(), index, groupIndex);
       return;
    }

    if(typeof value === function) {
        var result = value();

        // Not sure how to achieve this bit
        if(value used an observable) {
           allObservablesUsedInFunction.subscribe(function() {
              result = value();
              setText.call(selection, value(), index, groupIndex);
           });
        }

        setText.call(selection, result, index, groupIndex);
        return;
    }

    setText.call(selection, value, index, groupIndex);
};

我不确定如何监视函数中使用的observable,或者之后如何获取它们用于订阅。 我的直觉也是我要努力d3.transition()那个我非常喜欢的那个中风的d3.transition() 所以我想知道是否还有其他方法可以达到我想要的效果?

我已经简要地考虑了对任何更改的订阅 - 这将触发典型的D3更新操作 - 但是我的一些动画只有在上次更新后值发生变化时才需要触发,我不知道我怎么能够确定。 例如 - 如果当前可观察值与前一个值相同,我不希望触发笔划过渡(红色 - >白色 - >红色看起来很傻)。

有一点需要注意,我对d3的理解与新生小猫的理解大致相同,我现在给你半个答案,希望我稍后会有一些时间让它更具实质性。

由于d3是一个面向DOM的包,因此将其与Knockout一起使用的方法是将其转换为自定义绑定处理程序 这就是DOM操纵的地方。 这将有效地让您订阅相关的可观察量,您不应该与d3的原型混合。

对于你的颜色变化示例,我认为如果你做了一个计算来返回颜色值,并订阅了那个计算的,那么如果颜色没有实际改变,你的订阅就不会被激活。

更新:我为您编写了一个通用的“d3”绑定处理程序。 它将script和该脚本的options作为参数。 该脚本应该采用一个d3对象(绑定处理程序将从它绑定的元素构造)和一个options对象。 绑定处理程序解包options任何observable,以便脚本看到普通值。

对于此处的示例,我已将其绑定到路径元素并从您的问题中提供了颜色更改脚本。 因为我使用计算器来确定颜色,所以当颜色实际上没有变化时,您可以看到没有过渡。

 ko.bindingHandlers.d3 = { update: function(element, valueAccessor, allBindingsAccessor, data, context) { var d3element = d3.select(element), params = valueAccessor(); for (opt in params.options) { params.options[opt] = ko.utils.unwrapObservable(params.options[opt]); } params.script(d3element, params.options); } }; vm = (function() { var v = ko.observable(3), color = ko.computed(function() { if (v() < 0) return 'red'; if (v() === 0) return 'orange'; return 'green'; }); return { v: v, color: color, d3script: function(d3element, options) { d3element.style("stroke", "black") .transition() .duration(1000) .style("stroke", options.color); }, decrement: function() { v(v() - 1); }, increment: function() { v(v() + 1); } }; }()); ko.applyBindings(vm); 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.3.3/d3.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script> <button data-bind="click:decrement">-</button> <span data-bind="text:v"></span> <button data-bind="click:increment">+</button> <svg width="4cm" height="4cm" viewBox="0 0 400 400" xmlns="http://www.w3.org/2000/svg" version="1.1"> <title>Example triangle01- simple example of a 'path'</title> <desc>A path that draws a triangle</desc> <rect x="1" y="1" width="398" height="398" fill="none" stroke="blue" /> <path data-bind="d3:{script: d3script, options: {color:color}}" d="M 100 100 L 300 100 L 200 300 z" fill="#fdd" stroke="blue" stroke-width="7" /> </svg> 

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM