javascript - 在 RAW 中添加 d3.js 交互式可缩放树形图

标签 javascript d3.js charts

有没有办法在RAW中添加可缩放树形图。使用 d3.js 的进入-更新-退出模式在 RAW 中没有意义,因此如果没有此功能,是否可以在 RAW.js 中添加 d3.js 可缩放树形图

RAW文档位于adding new chart

In this way, D3's enter-update-exit pattern does not make too much sense within RAW's charts, since the selection is always empty when passed to the draw function. Since RAW is meant to be a tool for the production of non-interactive visualizations, to be elaborated using vector-graphics tools, this should not be perceived as a limitation, but, at the contrary, as a way to simplify charts' drawing code.

最佳答案

我已经能够在 RAW 中添加可缩放树形图。以下是代码。

zoomableTreemap.js

(function(){

    var tree = raw.models.tree();

    var chart = raw.chart()
        .title('Zoomable Treemap')
        .description(
        "A space filling visualization of data hierarchies and proportion between elements. The different hierarchical levels create visual clusters through the subdivision into rectangles proportionally to each element's value. Treemaps are useful to represent the different proportion of nested hierarchical data structures.<br/>Based on <a href='http://bl.ocks.org/mbostock/4063582'>http://bl.ocks.org/mbostock/4063582</a>")
        .thumbnail("/raw/imgs/treemap.png")
        .category('Hierarchies')
        .model(tree)

    var rawWidth = chart.number()
        .title('Width')
        .defaultValue(100)
        .fitToWidth(true)

    var rawHeight = chart.number()
        .title("Height")
        .defaultValue(500)

    var padding = chart.number()
        .title("Padding")
        .defaultValue(0)

    var colors = chart.color()
        .title("Color scale")

    chart.draw(function (selection, root){

        root.name = 'ZoomableTree';

        var margin = {top: 20, right: 0, bottom: 0, left: 0},
            width = +rawWidth(),
            height = +rawHeight() - margin.top - margin.bottom,
            formatNumber = d3.format(",d"),
            transitioning;

        var x = d3.scale.linear()
            .domain([0, width])
            .range([0, width]);

        var y = d3.scale.linear()
            .domain([0, height])
            .range([0, height]);

        console.log(padding());
        console.log(+padding());
        var treemap = d3.layout.treemap()
            .padding(+padding())
            .children(function(d, depth) { return depth ? null : d._children; })
            .sort(function(a, b) { return a.value - b.value; })
            .ratio(height / width * 0.5 * (1 + Math.sqrt(5)))
            // Values are required in d3 treemap layout
            // and our DB table do not have values field in it, so we are going to use 1 for all nodes.
            // The value decides the size/area of rectangle in d3 treemap layout so effectively we are going to have
            // even sized rectangles
            .value(function(d) { return 1; })
            .round(false);

        var svg = selection
            .attr("width", width + margin.left + margin.right)
            .attr("height", height + margin.bottom + margin.top)
            .style("margin-left", -margin.left + "px")
            .style("margin.right", -margin.right + "px")
            .append("g")
            .attr("transform", "translate(" + margin.left + "," + margin.top + ")")
            .style("shape-rendering", "crispEdges")


        var grandparent = svg.append("g")
            .attr("class", "grandparent");

        grandparent.append("rect")
            .attr("y", -margin.top)
            .attr("width", width)
            .attr("height", margin.top)
            .style("fill", function (d) { return colors()(d.color); })
            .style("stroke","#fff")

        grandparent.append("text")
            .attr("x", 6)
            .attr("y", 6 - margin.top)
            .attr("dy", ".75em");

            initialize(root);
            //console.log(root);
            //throw '';
            accumulate(root);
            layout(root);
            display(root);

            function initialize(root) {
                root.x = root.y = 0;
                root.dx = width;
                root.dy = height;
                root.depth = 0;
            }

            // Aggregate the values for internal nodes. This is normally done by the
            // treemap layout, but not here because  of our custom implementation.
            // We also take a snapshot of the original children (_children) to avoid
            // the children being overwritten when when layout is computed.
            function accumulate(d) {
                return (d._children = d.children)
                    ? d.value = d.children.reduce(function(p, v) { return p + accumulate(v); }, 0)
                    : d.value;
            }

            // Compute the treemap layout recursively such that each group of siblings
            // uses the same size (1×1) rather than the dimensions of the parent cell.
            // This optimizes the layout for the current zoom state. Note that a wrapper
            // object is created for the parent node for each group of siblings so that
            // the parent’s dimensions are not discarded as we recurse. Since each group
            // of sibling was laid out in 1×1, we must rescale to fit using absolute
            // coordinates. This lets us use a viewport to zoom.
            function layout(d) {
                if (d._children) {
                    //console.log(d);
                    //throw 'stop';
                    treemap.nodes({_children: d._children});
                    d._children.forEach(function(c) {
                        //console.log(d);
                        c.x = d.x + c.x * d.dx;
                        c.y = d.y + c.y * d.dy;
                        c.dx *= d.dx;
                        c.dy *= d.dy;
                        c.parent = d;
                        //console.log(c);
                        layout(c);
                    });
                }
            }

            function display(d) {
                grandparent
                    .datum(d.parent)
                    .on("click", transition)
                    .select("text")
                    .text(name(d));

                var g1 = svg.insert("g", ".grandparent")
                    .datum(d)
                    .attr("class", "depth");

                var g = g1.selectAll("g")
                    .data(d._children)
                    .enter().append("g");

                g.filter(function(d) { return d._children; })
                    .classed("children", true)
                    .on("click", transition);

                g.selectAll(".child")
                    .data(function(d) { return d._children || [d]; })
                    .enter().append("rect")
                    .attr("class", "child")
                    .call(rect);

                g.append("rect")
                    .attr("class", "parent")
                    .call(rect)
                    .append("title")
                    .text(function(d) { return formatNumber(d.value); })
                    .style("fill", function (d) { return colors()(d.color); })
                    .style("stroke","#fff")

                g.append("text")
                    .attr("dy", ".75em")
                    .text(function(d) { return d.name; })
                    .call(text);

                function transition(d) {
                    if (transitioning || !d) return;
                    transitioning = true;

                    var g2 = display(d),
                        t1 = g1.transition().duration(750),
                        t2 = g2.transition().duration(750);

                    // Update the domain only after entering new elements.
                    x.domain([d.x, d.x + d.dx]);
                    y.domain([d.y, d.y + d.dy]);

                    // Enable anti-aliasing during the transition.
                    svg.style("shape-rendering", null);

                    // Draw child nodes on top of parent nodes.
                    svg.selectAll(".depth").sort(function(a, b) { return a.depth - b.depth; });

                    // Fade-in entering text.
                    g2.selectAll("text").style("fill-opacity", 0);

                    // Transition to the new view.
                    t1.selectAll("text").call(text).style("fill-opacity", 0);
                    t2.selectAll("text").call(text).style("fill-opacity", 1);
                    t1.selectAll("rect").call(rect);
                    t2.selectAll("rect").call(rect);

                    // Remove the old node when the transition is finished.
                    t1.remove().each("end", function() {
                        svg.style("shape-rendering", "crispEdges");
                        transitioning = false;
                    });
                }

                return g;
            }

            function text(text) {
                text.attr("x", function(d) { return x(d.x) + 6; })
                    .attr("y", function(d) { return y(d.y) + 6; });
            }

            function rect(rect) {
                rect.attr("x", function(d) { return x(d.x); })
                    .attr("y", function(d) { return y(d.y); })
                    .attr("width", function(d) { return x(d.x + d.dx) - x(d.x); })
                    .attr("height", function(d) { return y(d.y + d.dy) - y(d.y); })
                    .style("fill", function (d) { return colors()(d.color); })
                    .style("stroke","#fff");
            }

            function name(d) {
                return d.parent
                    ? name(d.parent) + "." + d.name
                    : d.name;
            }


    })
})();

chart.css

#chart {
    background: #ddd;
}

text {
    pointer-events: none;
}

.grandparent text {
    font-weight: bold;
}

rect {
    fill: none;
    stroke: #fff;
}

rect.parent,
.grandparent rect {
    stroke-width: 2px;
}

.grandparent rect {
    fill: orange;
}

.grandparent:hover rect {
    fill: #ee9700;
}

.children rect.parent,
.grandparent rect {
    cursor: pointer;
}

.children rect.parent {
    fill: #bbb;
    fill-opacity: .5;
}

.children:hover rect.child {
    fill: #bbb;
}

Index.html

只需在 raw 的索引页中包含 css 和 js 即可。

关于javascript - 在 RAW 中添加 d3.js 交互式可缩放树形图,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31982847/

相关文章:

javascript - Prestashop 1.6.1.6 使用 javascript 的简短描述产品无效

javascript - 使用 javascript 和 Asp.Net 从其文件夹中删除图像

javascript - 如何计算字符串javascript函数中的特殊字符,该函数只接受@#

javascript - D3 v4 .rangeBand() 等效项

jquery - FlotChart 0.8.2 时间模式需要 flot.time 插件

html - 我可以使用 CSS 更改 telerik html 图表的颜色/渐变等吗?

javascript - ENTER 到 TAB 重定向问题 : submit form at the end of cycle

d3.js - 鼠标仅悬停在 d3 中的路径上

javascript - 具有多色段的折线图

JavaScript 变量赋值/返回