Skip to content

layout: post title: "d3" subtitle: "d3" date: 2019-05-31 14:27:18 author: "none" header-img: "img/posts/default_post.jpg" catalog: true tags: - tag


https://github.com/d3/d3/blob/master/API.md

selection

append  添加html元素
attr    添加或修改元素属性

使用示例

d3.select("#timeline3")
.append("svg")
.attr("width", 500)

// 添加了svg标签,并设定了属性
<div id="timeline3">
    <svg witdth="500"> </svg> 
</div>

update、enter、exit

update 选中有数据对应的元素

enter 选中有数据但没有的元素,可以append添加相应的元素

exit 选中没有数据对应的元素, 可以使用remove删除元素

call

call的参数为函数, 函数的第一个参数为selection

// 函数定义
function name(selection, first, last) {
  selection
      .attr("first-name", first)
      .attr("last-name", last);
}

d3.selectAll("div").call(name, "John", "Snow");
// This is roughly equivalent to:
name(d3.selectAll("div"), "John", "Snow");

brush

Select a one- or two-dimensional region using the mouse or touch

https://github.com/d3/d3-brush

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

var brush = d3.svg.brush()
                    .x(x)
                    .on("brush", display);

.(x)

        <script type="text/javascript">
        // lanes 三个时间线
        var lanes = ["Chinese","Japanese","Korean"],
            laneLength = lanes.length,
            timeBegin = 0,
            timeEnd = 2000;

        // margin
        // miniHeight, 每个时间线占12个单位高度, 
        var m = [20, 15, 15, 120], //top right bottom left
            w = 960 - m[1] - m[3],
            h = 500 - m[0] - m[2],
            miniHeight = laneLength * 12 + 50,
            mainHeight = h - miniHeight - 50;

        // w=960, miniHeight=3*12+50, mainHeight=500-miniHeight-50
        // scales 坐标轴 (x1, y1) 为main, (x, y2)为mini
        // main 的坐标轴x1在display中使用, mini的x在设置画刷时使用
        // y轴映射时间线的id
        var x = d3.scale.linear()
                .domain([timeBegin, timeEnd])
                .range([0, w]);
        var x1 = d3.scale.linear()
                .range([0, w]);
        var y1 = d3.scale.linear()
                .domain([0, laneLength])
                .range([0, mainHeight]);
        var y2 = d3.scale.linear()
                .domain([0, laneLength])
                .range([0, miniHeight]);

        // svg标签, width=960, height=500
        var chart = d3.select("body")
                    .append("svg")
                    .attr("width", w + m[1] + m[3])
                    .attr("height", h + m[0] + m[2])
                    .attr("class", "chart");

        // defs 定义svg的预定义元素, 
        chart.append("defs").append("clipPath")
            .attr("id", "clip")
            .append("rect")
            .attr("width", w)
            .attr("height", mainHeight);

        // main chart, 坐标系translate(120, 20)
        var main = chart.append("g")
                    .attr("transform", "translate(" + m[3] + "," + m[0] + ")")
                    .attr("width", w)
                    .attr("height", mainHeight)
                    .attr("class", "main");

        // mini chart, 坐标系translate(120, 349)
        var mini = chart.append("g")
                    .attr("transform", "translate(" + m[3] + "," + (mainHeight + m[0]) + ")")
                    .attr("width", w)
                    .attr("height", miniHeight)
                    .attr("class", "mini");

        // items的每个数据为字典,
        // main char 根据数据构建line, line将main chart 三条时间线分隔
        // 分割线的起点为(x1,y1), 终点为(x2, y2)
        // m[1]为right margin
        //main lanes and texts
        main.append("g").selectAll(".laneLines")
            .data(items)
            .enter().append("line")
            .attr("x1", m[1])
            .attr("y1", function(d) {return y1(d.lane);})
            .attr("x2", w)
            .attr("y2", function(d) {return y1(d.lane);})
            .attr("stroke", "lightgray")

        // main chart 时间线的名称标签
        main.append("g").selectAll(".laneText")
            .data(lanes)
            .enter().append("text")
            .text(function(d) {return d;})
            .attr("x", -m[1])
            .attr("y", function(d, i) {return y1(i + .5);})
            .attr("dy", ".5ex")
            .attr("text-anchor", "end")
            .attr("class", "laneText");

        //mini lanes and texts
        mini.append("g").selectAll(".laneLines")
            .data(items)
            .enter().append("line")
            .attr("x1", m[1])
            .attr("y1", function(d) {return y2(d.lane);})
            .attr("x2", w)
            .attr("y2", function(d) {return y2(d.lane);})
            .attr("stroke", "lightgray");

        mini.append("g").selectAll(".laneText")
            .data(lanes)
            .enter().append("text")
            .text(function(d) {return d;})
            .attr("x", -m[1])
            .attr("y", function(d, i) {return y2(i + .5);})
            .attr("dy", ".5ex")
            .attr("text-anchor", "end")
            .attr("class", "laneText");

        var itemRects = main.append("g")
                            .attr("clip-path", "url(#clip)");

        // 矩形背景 和 文字标签
        //mini item rects
        mini.append("g").selectAll("miniItems")
            .data(items)
            .enter().append("rect")
            .attr("class", function(d) {return "miniItem" + d.lane;})
            .attr("x", function(d) {return x(d.start);})
            .attr("y", function(d) {return y2(d.lane + .5) - 5;})
            .attr("width", function(d) {return x(d.end - d.start);})
            .attr("height", 10);

        //mini labels
        mini.append("g").selectAll(".miniLabels")
            .data(items)
            .enter().append("text")
            .text(function(d) {return d.id;})
            .attr("x", function(d) {return x(d.start);})
            .attr("y", function(d) {return y2(d.lane + .5);})
            .attr("dy", ".5ex");

        //brush
        var brush = d3.svg.brush()
                            .x(x)
                            .on("brush", display);

        // mini chart 上设置brush
        mini.append("g")
            .attr("class", "x brush")
            .call(brush)
            .selectAll("rect")
            .attr("y", 1)
            .attr("height", miniHeight - 1);

        display();

        // 当brush的"brush"事件发生是, 调用该函数
        function display() {
            // brush.extent() 获取画刷范围, 过滤数据
            var rects, labels,
                minExtent = brush.extent()[0],
                maxExtent = brush.extent()[1],
                visItems = items.filter(function(d) {return d.start < maxExtent && d.end > minExtent;});

            mini.select(".brush")
                .call(brush.extent([minExtent, maxExtent]));

            // 设置main chart的横坐标轴
            x1.domain([minExtent, maxExtent]);

            //update main item rects
            // itemRects 设置有clip-path, 
            rects = itemRects.selectAll("rect")
                    .data(visItems, function(d) { return d.id; })
                .attr("x", function(d) {return x1(d.start);})
                .attr("width", function(d) {return x1(d.end) - x1(d.start);});

            rects.enter().append("rect")
                .attr("class", function(d) {return "miniItem" + d.lane;})
                .attr("x", function(d) {return x1(d.start);})
                .attr("y", function(d) {return y1(d.lane) + 10;})
                .attr("width", function(d) {return x1(d.end) - x1(d.start);})
                .attr("height", function(d) {return .8 * y1(1);});

            rects.exit().remove();

            //update the item labels
            labels = itemRects.selectAll("text")
                .data(visItems, function (d) { return d.id; })
                .attr("x", function(d) {return x1(Math.max(d.start, minExtent) + 2);});

            // d.id 为文本标签
            labels.enter().append("text")
                .text(function(d) {return d.id;})
                .attr("x", function(d) {return x1(Math.max(d.start, minExtent));})
                .attr("y", function(d) {return y1(d.lane + .5);})
                .attr("text-anchor", "start");

            labels.exit().remove();

        }