【问题标题】:d3 can't edit children cssd3无法编辑儿童CSS
【发布时间】:2015-12-28 20:44:10
【问题描述】:

我是使用 d3 的新手,但看起来如此简单的东西有点让我抓狂,基本上我使用的是 d3 的分区图,我的想法是当我单击一个元素时,我会更改它的填充颜色到红色,这不是问题,很容易,但是我也想将其所有后代填充颜色更改为红色。我可以访问子数据和子数据的子数据,并且只需要一个递归函数来更改颜色,但是我似乎无法访问的是与每个孩子关联的 rect 元素。我已经尝试了 d3.select(child).style("fill", "red") 功能,但它不起作用,我猜我做错了什么,但有人能指出我正确的方向吗?

我在本地有这个,但我基本上使用的是相同的示例(我将 jquery 添加到我的解决方案中)http://mbostock.github.io/d3/talk/20111018/partition.html

在那里,我使用 firebug 在第 84 行的 partition.html 中设置了一个断点。要点击该断点,我只需单击图表中的一个蓝色框,然后从那里我想要能够选择 rect 或g 与我点击的元素相关联的元素。

再次,我现在可以执行 d.children[0] 来获取第一个孩子的数据,但我不知道如何从那里访问/编辑它的 css 以更改其填充颜色。

任何帮助都将不胜感激,此外,我知道我可能没有给出最好的解释,我很乐意回答任何问题或尝试澄清任何困惑。

提前致谢。

【问题讨论】:

  • 我想这已经被问过了。见this answer
  • 我不确定它是否是同一件事,基本上这给了我所有子节点,但是我看不到选择给定“g”元素的子元素的方法。因为 d3 的结构比其他任何东西都更“线性”。或者也许我理解这个答案是错误的,我会继续研究。
  • 看看 devtools 中选择对象的结构——或者你正在使用的任何东西——来帮助你思考它。并注意数据是如何绑定到节点的,以及节点是如何被选择结构引用的。您不会看到 d3 为父节点提供的对子节点的任何引用。 DOM 已经有了childNodes。 D3 不是将节点连接在一起,而是在基于数据结构的选择结构中捕获它们。

标签: javascript d3.js


【解决方案1】:

分区布局

与迄今为止我使用过的所有 d3 布局一样,分区布局都是关于数据的,而不是 DOM 元素。不幸的是,就像我迄今为止使用的所有布局一样,文档一开始就错误地陈述了完全相反的内容......

分区布局产生邻接图:节点链接树图的空间填充变体。节点不是在层次结构中绘制父节点和子节点之间的链接,而是绘制为实心区域(弧形或矩形),它们相对于其他节点的位置显示了它们在层次结构中的位置。节点的大小编码了一个很难在节点链接图中显示的量化维度。

它没有这样的事情:)
您将在example you linked 中找到对分区对象的唯一引用是在容器选择的数据方法中。

[59]  var g = vis.selectAll("g")
[60]      .data(partition.nodes(root))

布局的真正作用是……

分区布局产生支持生成邻接图的数据结构和方法:节点链接树图的空间填充变体。而不是在层次结构中绘制父子节点之间的链接, 可以是 绘制为实心区域(弧形或矩形), 它们相对于其他节点的位置显示 显示它们在层次结构中的位置。节点的大小编码了一个很难在节点链接图中显示的量化维度。

然后您可以使用 d3 使用该数据结构为树生成 DOM 结构。

我的观点是(除其他外)没有节点结构 - 如在节点之间的引用中 - 由布局创建。那取决于你。

partition.nodes(root) 返回的对象只是 js object 类型的平面数组,没有对任何 DOM 元素的引用。但是,它确实具有一组丰富的状态,可为您提供构建 DOM 结构所需的所有定位信息。

选择子节点

如果你研究渲染的结构,你会注意到所有节点在任何给定时间都在 DOM 结构中;只有它们的大小和位置被调整以适应可视化。您还会注意到,子节点和父节点之间存在严格的空间关系:特定节点右侧的任何节点如果垂直位置在所述节点的高度范围内,它就是子节点。此外,如果您查看绑定到每个节点的数据的结构,您将看到这些成员:xydxdy。这些是节点的标准化空间特征,因此,给定所选节点的此状态,您可以过滤 DOM 结构中的所有节点以返回子节点的节点列表。

使用 d3 实现此目的的方法不止一种,但一种方法是使用 selection.classed 方法...

    function hover(dActive){
        var x0 = dActive.x, y0 = dActive.y,
            x1 = x0 + dActive.dx, y1 = dActive.dy;
        g.classed("highlighted", function(d){
            return (d.y > y0) && (d.x >= x0) && (d.x < x1)
        })
    }

这是示例的修改版本,在悬停时突出显示子项,使用上述策略...

    var w = 600, //1120,
        h = 200, //600,
        x = d3.scale.linear().range([0, w]),
        y = d3.scale.linear().range([0, h]);

    var vis = d3.select("body").append("div")
        .attr("class", "chart")
        .style("width", w + "px")
        .style("height", h + "px")
        .append("svg:svg")
        .attr("width", w)
        .attr("height", h);

    var partition = d3.layout.partition()
        .value(function(d) { return d.size; });

    d3.json("https://rawgit.com/cool-Blue/SO-Questions/master/partition/flare.json", function(root) {
        var g = vis.selectAll("g")
            .data(partition.nodes(root))
            .enter().append("svg:g")
            .attr("transform", function(d) { return "translate(" + x(d.y) + "," + y(d.x) + ")"; })
            .on("click", click)
            .on("mouseover", hover)
            .on("mouseout", function(){g.classed("highlighted", false)});

        var kx = w / root.dx,
            ky = h / 1;

        g.append("svg:rect")
            .attr("width", root.dy * kx)
            .attr("height", function(d) { return d.dx * ky; })
            .attr("class", function(d) {
                return d.children ? "parent" : "child";
            });

        g.append("svg:text")
            .attr("transform", transform)
            .attr("dy", ".35em")
            .style("opacity", function(d) { return d.dx * ky > 12 ? 1 : 0; })
            .text(function(d) { return d.name; })

        d3.select(window)
            .on("click", function() { click(root); })

        function click(d) {
            if(!d.children) return;

            kx = (d.y ? w - 40 : w) / (1 - d.y);
            ky = h / d.dx;
            x.domain([d.y, 1]).range([d.y ? 40 : 0, w]);
            y.domain([d.x, d.x + d.dx]);

            var t = g.transition()
                .duration(d3.event.altKey ? 7500 : 750)
                .attr("transform", function(d) { return "translate(" + x(d.y) + "," + y(d.x) + ")"; });

            t.select("rect")
                .attr("width", d.dy * kx)
                .attr("height", function(d) { return d.dx * ky; });

            t.select("text")
                .attr("transform", transform)
                .style("opacity", function(d) { return d.dx * ky > 12 ? 1 : 0; });

            d3.event.stopPropagation();
        }

        function hover(dActive){
            var x0 = dActive.x, y0 = dActive.y,
                x1 = x0 + dActive.dx, y1 = dActive.dy;
            g.classed("highlighted", function(d){
                return (d.y > y0) && (d.x >= x0) && (d.x < x1)
            })
        }

        function transform(d) {
            return "translate(8," + d.dx * ky / 2 + ")";
        }
    });
body {margin: 0;}
        .chart {
            display: block;
            margin: auto;
            margin-top: 0;
            font-size: 11px;
        }

        rect {
            stroke: #eee;
            fill: #aaa;
            fill-opacity: .3;
        }

        rect.parent {
            cursor: pointer;
            fill: steelblue;
        }

        text {
            pointer-events: none;
        }
        .highlighted rect {
            /*outline: 1px solid red;*/
            fill-opacity: 1;
        }
&lt;script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js"&gt;&lt;/script&gt;

【讨论】:

  • 我确实接受了这个作为答案,因为它确实有效,但是我最终使用的有点不同,因为我的 json 数据包括我去的 id 并将 id 添加到每个矩形元素(我正在使用分区图,也可以将 id 添加到 g 元素),然后我使用 jquery 与 d3 为单击的元素返回的数据配对。
  • @apachecoq 是的,有很多方法,这已经是其中的两种。我专注于这种方式的原因是因为它利用了树本身的抽象特征_使用现有状态_并且还因为它在某种程度上解释了树背后的原理(尽可能多地向我自己解释)。我分享的你的方法的好处是它们都是软引用,不会导致潜在的内存泄漏。
猜你喜欢
  • 2017-10-24
  • 2021-11-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多