Ember.js 当余烬处理数据连接时,d3在余烬中转换

Ember.js 当余烬处理数据连接时,d3在余烬中转换,ember.js,d3.js,Ember.js,D3.js,我喜欢在我的手柄文件中定义我的Ember中的d3图表,并尽可能避免d3.select和数据连接。我不想使用d3的数据联接,而是想依赖于Ember的计算属性。实际上,在Ember中的d3可视化中,我倾向于将数据点封装在{{each}}循环中,并且Ember负责在底层数据发生变化时更新图表。这一切都很好,但有一个重要的d3功能,我觉得我正在失去这种方式,即。我喜欢在基础数据的两种状态之间进行转换。有没有办法,同时,依靠余烬进行数据连接,避免d3.select.data舞蹈,并以某种方式仍然能够应用d

我喜欢在我的手柄文件中定义我的Ember中的d3图表,并尽可能避免d3.select和数据连接。我不想使用d3的数据联接,而是想依赖于Ember的计算属性。实际上,在Ember中的d3可视化中,我倾向于将数据点封装在{{each}}循环中,并且Ember负责在底层数据发生变化时更新图表。这一切都很好,但有一个重要的d3功能,我觉得我正在失去这种方式,即。我喜欢在基础数据的两种状态之间进行转换。有没有办法,同时,依靠余烬进行数据连接,避免d3.select.data舞蹈,并以某种方式仍然能够应用d3转换

下面是一个示例代码,我想在更改高度时将条形图从一种状态转换为另一种状态。这是一个很小的示例,但我认为它是说明性的。提前感谢您的帮助

// bar-chart.js

export default Ember.Component.extend({
    tagName: "svg",
    attributeBindings: ["width", "height"],
    width: 950,
    height: 600,
    padding: { top:..., bottom:..., left:..., right:... },
    transformG: function() {
        var padding = this.get("padding");
        return "translate(%@,%@)".fmt(padding.left, padding.top);
    }.property(),
    chartW: function() {
        ...
    }.property("width"),
    chartH: function() {
        ...
    }.property("height"),
    yScale: function() {
        var data = this.get("data");
        return d3.scale.linear().domain(d3.extent(data, function(d) { return d.value; })).range([...]);
    }.property("data", "chartH"),
    xScale: function() {
        ...
    }.property("data", "width"),
    actions: {
        // Some action that modifies the height of the svg
    }
});

// bar-chart.hbs

<g class="axis x"></g>
<g class="axis y"></g>
<g class="bars" {{bind-attr transform=transformG width=chartW height=chartH}}>
    {{#each d in data}}
        {{vertical-bar value=d.value timestamp=d.timestamp yScale=yScale xScale=xScale}}
    {{/each}}
<g>

假设子组件{{vertical bar}}负责计算与每个条相关的一些属性。

虽然d3进入/更新/退出范例可能会令人困惑/麻烦,但它确实是d3的核心,试图覆盖它,但仍然使用d3的其他部分,如转换,可能会给您带来很多麻烦

例如:

d3只绑定一次svg元素,但我认为您在这里所做的工作会在每次数据更改时重新加载元素,而这可能不是您想要的。如果您尝试使用transition,同时还更新了Ember中的数据,那么事情可能会爆炸

我很熟悉d3.select.data舞蹈中令人头疼的问题,但最终这通常意味着我对数据的形状理解不太清楚。您不想这样做有什么技术原因吗?或者,数据中的每个d只是在概念上更简单

替代方案 您可能需要考虑一组中间数据,这些数据由d3生成,但由Ember控制。我目前使用的一种策略是创建一个ObjectProxy数组来包装一些自定义属性,然后将整个内容传递给它d3:

创建{content:{timestamp:d.x,some_属性:d.foo,type:bar}

当您更新这个中间集合时,您可以简单地将整个集合再次传递给d3,并且如果您的输入/更新/退出选择设置正确,它将执行正确的操作

确保这一点的一个技巧是在基准上设置一个唯一的ID,并在选择过程中使用该ID:

svg.selectAllrect。data@getmyData,d->d.getid

小心:咖啡脚本=

灰烬w/D3 我认为,在使用D3完成其余工作之前,允许Ember控制输入的数据是您想要做的,否则您只是混淆了职责,您也可以滚动您自己的图形库。上述替代方案为您提供了更多的控制,并将计算属性添加到您的基准中,可以这样使用:

selection.transition.attr{x:d->d.getend_x},其中end_x是Ember为您处理的东西


或者:.onclick,d,i=>d.getcontroller.transitionorRouteMyRoute,d.id

我很感谢你的回答。我觉得你是对的,但我很想知道别人怎么想。你建议的替代模式实际上或多或少是我一直遵循的模式,直到我考虑让余烬承担更多的责任。正如你所说,没有真正的技术原因,只是在概念上对我更清楚。关于重新渲染,你有一个很好的观点,但没有考虑这个问题。我想知道Netflix的家伙们使用了什么方法,他们是否真的坚持d3连接,而不是让Ember接管。非常感谢。