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();
}