d3知识

d3文档介绍

d3各版本变化

官网英文

d3小知识点或技巧

gx.call(xAxis)与xAxis(gx)相等

1
2
3
4
5
6
//生成底部轴线
const xAxis = d3.axisBottom(xScale);
//设置轴线偏移位置
const gx = svg.append('g').attr('transform', `translate(${padding.left},${height - padding.bottom})`);
//也可以写成xAxis(gx)
gx.call(xAxis);

d3的图形与布局

柱状图、折线图、散点图 是d3常见的图形。
除以上三种图形外,还有很多图形他们位置不固定(还有其他说法),比如饼图,饼图可以在任意位置,这个时候,就需要一种其他的画图方式,这种方式就是d3的布局。
d3的布局用法为 d3.layout.pie,d3的布局有12种,饼图是其中最简单一个。

d3的坐标轴方向

如图,d3的坐标轴,默认原点在左上角,y的正值是向下的。

transition 动画

概述

transition用来定义动画,点击看完整demo

1
2
3
4
5
6
7
8
9
10
11
12
circle1.transition()
.duration(3000)
.attr("cx",200)
.delay(2000)
.transition()
.duration(3000)
.attr("cx",400)
.each("start",function () { d3.select(this).attr("fill","blue");} )
.transition()
.duration(3000)
.attr("cy",400)
.each("start",function () { d3.select(this).attr("fill","red");} )

duration

duration定义延迟

each

each可以定义start、end等行为

生成坐标轴

概述和代码

坐标轴一般用比例尺来做,用到比例尺就要用到两个概念 domain 与 range。
domain为实际数据范围,range为坐标轴的刻度范围,这个刻度范围是用来表示数据范围的。
所以数据范围与刻度范围形成一定比例。

以下都基于以下两个demo:
参考demo一
参考demo二

生成坐标轴的完整代码如下:
代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const dataset = [50, 43, 120, 87, 99, 167, 142];
//scaleBand生成序数分段比例尺,x轴通常使用scaleBand
const xScale = d3.scaleBand().domain(dataset.map((d, i) => i)).range([0, xAxisWidth]).padding(0.1);
//scaleLinear生成线性比例尺,y轴通常使用这个
const yScale = d3.scaleLinear().domain([d3.max(dataset, d => d), 0]).range([0, yAxisWidth]);

//生成底部轴线
const xAxis = d3.axisBottom(xScale);
//生成左侧轴线
const yAxis = d3.axisLeft(yScale);

//设置轴线偏移位置
const gx = svg.append('g').attr('transform', `translate(${padding.left},${height - padding.bottom})`);
const gy = svg.append('g').attr('transform', `translate(${padding.left},${height - padding.bottom - yAxisWidth})`);
gx.call(xAxis);
gy.call(yAxis);

生成比例尺的方法 scaleLinear\scaleBand

这两个方法都是生成比例尺的方法,见《概述和代码》

domain range

见《概述和代码》;
除代码中外,还可以这样用:

1
2
const xScale = d3.scaleBand().domain([1,2,3,4]).range([11,23,25,67]);
xScale(2)//23 一一对应关系

ticks 不是一个确数

ticks设置坐标轴的刻度数量,但不是你设置几个,最终显示几个,d3会自动设置在设置数的上下。
参考《groud 与 g》的demo

domain range 的单位

如下, domain是值域,没有单位,纯粹代表数值大小;range是地域范围,单位是px,用来限定坐标轴占地面积大小。
demo 参考《groud 与 g》的demo。

1
2
3
var scalewidth = d3.scale.linear()
.domain([0,80])
.range([0,500])

生成对角线(直线)–d3.svg.diagonal

使用d3.svg.diagonal实现

1
2
3
4
5
6
7
8
9
10
11
12
var canvas = d3.select("body")
.append("svg")
.attr("width",500)
.attr("height",500);

var diagonal = d3.svg.diagonal()
.source({ x: 10 , y:10})
.target({ x: 300 , y: 300})
canvas.append("path")
.attr("fill","none")
.attr("stroke","black")
.attr("d",diagonal);

使用source和target定义起始和终点位置

参考上面代码。

生成折线图

概述

如图,坐标轴生成代码同《生成坐标轴》。下面的代码主要介绍生成折线图的折线。
demo地址
视频讲解

1
2
3
4
5
6
//使用d3的方法来生成折线的path
const linePath = d3.line().x((d, i) => xScale(i) + padding.left + xScale.bandwidth() / 2)
.y(d => height - padding.bottom - (yScale(0) - yScale(d)));
//将数据传给上面写好的 d3生成线的path方法,避免手动写繁杂的path(而这正是d3的本职工作)
const line = svg.append('path').attr('d', linePath(dataset)).attr('stroke', '#000')
.attr('stroke-width', '3px').attr('fill', 'none');

手工写生成折线的path

svg的path手动写非常繁杂,手工写不现实,而这正是d3存在的原因之一,d3提供了丰富的方法用于生成path,也就是下面介绍到的d3.line()。

d3.line()生成折线

参考本节的《概述》

生成直方图

概述

如图,坐标轴生成代码同《生成坐标轴》。
直方图主要是绘制矩形柱状图 和 text的显示,具体下来就是如何确定柱状图的 x、y坐标,宽高度。
demo地址
视频讲解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
 //标尺
const xScale = d3.scaleBand().domain(dataset.map((o, i) => i))
.range([0, xAxisWidth]).padding(0.1);
const yScale = d3.scaleLinear().domain([0, d3.max(dataset)]).rangeRound([yAxisWidth, 0]);
//绘制矩形柱状图 的方法,
const updateRect = svg.selectAll("rect").data(dataset)
.attr("fill", (d, i) => color(i))
.attr("x", (d, i) => padding.left + xScale(i))
.attr("y", (d, i) => height - padding.bottom)
.attr("width", xScale.bandwidth())
.attr("height", 0)
.transition().duration(1000) //重新赋值y,height 过渡效果
.attr("y", (d, i) => height - padding.bottom - (yScale(0) - yScale(d)))
.attr("height", d => yScale(0) - yScale(d));

设置x,y坐标、宽高度

见上面代码

svg的rect与text的运用

见上面代码

比例尺与柱状图的绘制密切联系

本示例中,柱状图的x、y坐标的确定与标尺xScale等相关联,这也是坐标轴图的套路,上面的《生成折线图》也有映射。

x、y值使用比例尺表示

见上面代码

update、enter、exit的经典运用

详见上面提到的demo地址,这个简洁demo介绍了这三种状态的渲染。

生成饼状图

饼状图的一些概念

  • outerRadius 外半径
  • innerRadius 内半径
  • startAngle 起始角度
  • endAngle 结束角度

    单段饼图

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     const svg = d3.select("#svg").append("svg").attr("width", "300").attr("height", "300");
    const dataset = {startAngle:0, endAngle: Math.PI*0.75};
    const arcPath = d3.arc() //弧生成器
    .innerRadius(50) //设置内半径
    .outerRadius(100); //设置外半径
    svg.append("path")
    .attr("d", arcPath(dataset)) // 用弧生成器生成弧线数据,赋值给SVG的d属性
    .attr("transform", 'translate(200, 200)') // 填充颜色
    .attr("stroke", '#000').attr('stroke-width', '3px') // 填充颜色
    .attr("fill", 'blue') // 填充颜色

效果如图:

多个饼图拼成一个完整饼图

一个饼图其实是由上面说到的一个个分段的饼图拼接而成:

svg
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
const pie = d3.pie();
const dataset = [30, 10, 43, 55, 13];
const piedata = pie(dataset);
const outerRadius = 150; //外半径
const innerRadius = 0; //内半径,为0则中间没有空白
const arc = d3.arc() //弧生成器
.innerRadius(innerRadius) //设置内半径
.outerRadius(outerRadius); //设置外半径
const arcs = svg.selectAll("g") // 存放弧的容器
.data(piedata) //绑定pie数据
.enter() // 数据进入
.append("g") // 生成g
.attr("transform", "translate(" + (300 / 2) + "," + (300 / 2) + ")"); // 偏移
const color = d3.scaleOrdinal(d3.schemeCategory10);
arcs.append("path")
.attr("fill", (d, i) => color(i)) // 填充颜色
.attr("d", d => {
return arc(d)
}); // 用弧生成器生成弧线数据,赋值给SVG的d属性
arcs.append("text")
.attr("transform", d => "translate(" + arc.centroid(d) + ")") // 设置文本至扇区中心
.attr("text-anchor", "middle") //设置文本锚点
.attr("fill", "#fff") //设置文字颜色
.text(d => d.data);

获取圆弧中心点

主要运用arc的centroid API

1
2
3
4
5
6
7
8
9
10
11
12
var arcFn = d3.svg.arc()
.innerRadius(innerRadius)
.outerRadius(outerRadius);

arcs.append("text")
.attr("class","MyText")
.attr("transform", function(d){
var center = arcFn.centroid(d);
return "translate(" +
center[0] * 1.4 + "," +
center[1] * 1.4 + ")";
})

参考demo — 功能更丰富的的完整饼图

熟练运用arc.centroid圆弧中心

饼图的文字或者标注线,都需要依赖圆弧中心点的运用,所以涉及到饼图时,需要重度使用圆弧中心点,以及如何凭借这个圆弧中间点,延伸画出一条中心线的技巧, 详细参考demo

demo地址与参考

单段饼图 demo地址
完整饼图 demo地址
视频讲解

arc 与 pie 关系

arc是用来画弧的,arc用来画饼图(pie)时,要设置起始角度startAngle、endAngle,为了省去这些麻烦,配合使用pie可以完美画饼图。

功能更丰富的的完整饼图

生成线段

完整代码如下,主要运用d3.svg.line,另外interpolate是生成不同类型连接线类型的,参考文档

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//v3.x
var svg = d3.select("body").append("svg")
.attr("width", 400)
.attr("height", 400);
var data = [
{"x": 10, "y": 200},
{"x": 50, "y": 260},
{"x": 90, "y": 120}
]
var line = d3.svg.line()
.x( function(d){ return d.x; } )
.y( function(d){ return d.y; } )
.interpolate("line");
svg.append("path")
.attr("class","MyPath")
.attr("d", line(data) )

生成线段 与 fill none

如下,没有使用fill none时,效果如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
var canvas = d3.select("body")
.append("svg")
.attr("width",500)
.attr("height",500);

var data2 = [
{x : 10 , y : 20},
{x : 10 , y : 260},
{x : 250 , y : 260}
];

var group = canvas.append("g")
.attr("transform", "translate(100,200)");

var line = d3.svg.line()
.x(function(d) { return d.x;})
.y(function(d) { return d.y;});

group.selectAll("path")
.data([data2])
.enter()
.append("path")
.attr("d",line)
//.attr("fill","none")
.attr("stroke" , "#000")
.attr("stroke-width", 10 );

将上面代码的//.attr("fill","none")解注后,效果如下:

生成散点图

概述

散点图比较简单,主要代码如下,demo地址点击这里

这里要注意的是比例尺与圆心cx cy的结合使用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//v3.x

var xScale = d3.scale.linear()
.domain([0, 100])
.range([0,300]);

var points = svg.selectAll(".MyCircle")
.data(dataset)
.enter()
.append("circle")
.attr("class","MyCircle")
.attr("transform","translate(30,50)")
.attr("r", 10)
.attr("cx", function(d){ return xScale(d.x); })
.attr("cy", function(d){ return yScale(d.y); });

比例尺与圆心cx cy的结合使用

参考上面。

比例尺

一个简单的比例尺

1
2
3
var linear = d3.scale.linear()
.domain([0,20]) //定义域
.range([0,100]); //值域

比例尺使用情况

序数比例尺与线性比例尺用的最多;
序数比例尺用来做x轴;线性做y轴;
另外一个用的多的是量子比例尺:

1
2
var quantize= d3.scale.quantize().domain([0, 10]).range(['red','green','blue','yellow'])
quantize(1)//'red'

scale比例尺的作用

参考《scale比例尺的作用》

d3.event d3.mouse(this) d3.touches(this)

一般的监听和事件绑定中都可以通过d3.event获取想要的值,
具体的事件或监听中,可通过d3.mouse(this) d3.touches(this)获取值;
demo参考 《精通d3.js》的第八章。

scale比例尺的作用

没有比例尺

如下,没有比例尺时,下面两个柱形图太长了,而svg只是一个500*500的容器,大于500的,无法显示,为了自适应,引入比例尺。

1
2
3
4
5
6
7
8
9
10
11
var canvas = d3.select("body")
.append("svg")
.attr("width",500)
.attr("height",500);
var bar1= canvas.selectAll("rect")
.data([20,40,60,80,150])
.enter()
.append("rect")
.attr("width",function(d) { return d*8})
.attr("height",30)
.attr("y",function(d, i) { return (i+1)*65; })

使用比例尺

1
2
3
4
5
6
7
8
9
10
11
12
//d3.scale.linear比例尺
var scalewidth = d3.scale.linear()
.domain([0,140])
.range([0,500])
var bar1= canvas.selectAll("rect")
.data([20,40,60,80,150])
.enter()
.append("rect")
//使用比例尺来生成width
.attr("width",function(d) { return scalewidth(d)})
.attr("height",30)
.attr("y",function(d, i) { return (i+1)*65; })

groud 与 g

分组 与 div

groud就是分组,缩写就是 g,这也是d3上常用到的g标签。
如下面代码,加g后,可以统一设置g分组内的所有rect,所有g相当于html中的div

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
var scalewidth = d3.scale.linear()
.domain([0,80])
.range([0,500])

var axis = d3.svg.axis()
.ticks(10)
.scale(scalewidth)

var canvas = d3.select("body")
.append("svg")
.attr("width",500)
.attr("height",500)
// 这里是否加g进行分组,效果是一样的,但是加g后,可以在g上统一对下面的rect设置样式:
.append("g")

var color = d3.scale.linear()
.domain([0,140])
.range(["red","blue"])

var bar1= canvas.selectAll("rect")
.data([20,40,60,80,])
.enter()
.append("rect")
.attr("width",function(d) { return scalewidth(d)})
.attr("height",40)
.attr("fill",function(d) { return color(d)})
.attr("y",function(d) { return d * 3});

例子二 – 坐标轴是否分组

对上面的代码进行延伸,加一个坐标轴,坐标轴分组和不分组,区别很大,分组后,更容易设置样式。

1
2
3
4
5
6
7
8
9
10
11
12
var canvas = d3.select("body")
.append("svg")
.attr("width",500)
.attr("height",500)
.append("g")
// 不推荐写法---未将坐标轴分组,不容易设置样式:
// .call(axis)
;
// 推荐写法---将坐标轴分组,更容易设置样式:
// canvas.append("g")
// .attr("transform","translate(0,300)")
// .call(axis)

demo地址

demo地址

d3.json d3.csv d3.xml d3.html d3.text

上面几种是d3请求外部文件的方式。
demo 参考

svg导出为png/svg

主要运用 d3-downloadable,demo 参考,此demo也提供了一种方案,如何自定义右键菜单,并且另存为(下载)图片。

d3黑知识

d3.event.dx 鼠标偏移量

鼠标每次偏移量,通过试验发现,偏移量基本上是三个值:-1 0 1;
这个用处非常多,通过叠加偏移量的方式,可以画一种时刻跟随鼠标的动作,比如拖动图片时,图片跟随鼠标显示。等等,拖拽饼状图 demo

d 自定义属性的传递使用

如下,在选择集中定义的customDx123属性,在arcs.append(“path”)和d3.behavior.drag()都能使用,这二者有一个共性,那就是都使用了arcs对象。
完整demo参考:拖拽饼状图 demo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
//添加对应数目的弧组,即<g>元素
var arcs = svg.selectAll("g")
.data(piedata) //绑定转换后的数据piedata
.enter()
.append("g")
.each(function(d){
//customDx123 这个属性是自己加和命名的
d.customDx123 = width/2;
d.customDy123 = height/2;
})
.attr("transform","translate("+( width/2 )+","+ ( height/2 ) +")");
//绘制弧
arcs.append("path")
.attr("fill",function(d,i){
return color(i); //设定弧的颜色
})
.attr("d",function(d){
console.log(d.customDx123);
return arc(d); //使用弧生成器
});

//4. 交互式
var drag = d3.behavior.drag()
.origin(null)
.on("drag", dragmove);
function dragmove(d) {
//customDx123 这个属性是自己加和命名的
d.customDx123 += d3.event.dx;
d.customDy123 += d3.event.dy;
d3.select(this)
.attr("transform","translate("+d.customDx123+","+d.customDy123+")");
}

arcs.call(drag);

d3.svg.brush 区域选中

简介

效果如下,完整demo:

使用方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
var xScale = d3.scale.linear()
.domain([0,width])
.range([0, width]);

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

var brush = d3.svg.brush()
.x(xScale)
.y(yScale)
.extent([[0, 0], [100, 100]])
.on("brush",brushed);

function brushed(){
var extent = brush.extent();
console.log( "x方向的下限: " + extent[0][0] );
console.log( "x方向的上限: " + extent[1][0] );
console.log( "y方向的下限: " + extent[0][1] );
console.log( "y方向的上限: " + extent[1][1] );
}

svg.append("g")
.call(brush)
.selectAll("rect")
.style("fill-opacity",0.3);

必须配合比例尺使用

参考上面一节代码。

监听三种事件类型

  • brushstart 鼠标键按下时
  • brush 鼠标键按下拖拽时
  • brushend 鼠标键放开时

    brush.extent 获取选中区域的x y上下限

    1
    2
    3
    4
    5
    var extent = brush.extent();
    console.log( "x方向的下限: " + extent[0][0] );
    console.log( "x方向的上限: " + extent[1][0] );
    console.log( "y方向的下限: " + extent[0][1] );
    console.log( "y方向的上限: " + extent[1][1] );

创建 线性渐变颜色

如下,线性渐变的颜色,需要借助 url来使用。详细参考 《值域与线性渐变 – 创建 线性渐变颜色》

1
2
3
4
5
6
7
//常规的颜色填充
svgNode
.style("fill","red");

//线性渐变颜色填充 (线性渐变的颜色 使用 url)
svgNode
.style("fill","url(#" + linearGradient.attr("id") + ")");

利用投影函数转换经纬度成坐标

其实GeoJSON文件的地理信息也是经纬度,也是通过投影函数得到地图路径坐标的。所以可以通过投影函数获得经纬度对应的地图像素坐标。
demo参考:地图上标注地点 demo

1
2
3
4
5
6
7
8
9
10
var projection = d3.geo.mercator()
.center([107, 31])
.scale(600)
.translate([width/2, height/2]);

var path = d3.geo.path()
.projection(projection);

//d.log, d.lat :经纬度 计算标注点的位置
var coor = projection([d.log, d.lat]);

d3生成器

生成器就是生成svg的path路径,svg通过生成器生成的path绘制不同图形,d3提供了直线、四边形(区域)、弦、符号、折线、对角线等生成器。

svg.area 区域生成器

svg.area的原理是通过两条线 确定一个四边形;好比 两个点确定一条线的道理。
所以svg.area 都是画一条线,需要画两条线,即可确定一个四边形。
详细demo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//创建一个区域生成器
//svg.area的原理是通过两条线 确定一个四边形;好比 两个点确定一条线的道理。
//svg.area一次性设置两个点 x0 y0; x1 y1; 通过 x 一次性设置 x0 和 y0;
var areaPath = d3.svg.area()
.x(function(d,i){ return 50 + i * 80; })
.y0(function(d,i){ return height/2; })
.y1(function(d,i){ return height/2 - d; })
// .interpolate("step");

//添加路径
svg.append("path")
.attr("d",areaPath(dataset))
.attr("stroke","black")
.attr("stroke-width","3px")
.attr("fill","yellow");

d3交互

折线图的焦点

完整demo,效果如下:

设置透明度为0的矩形

设置透明度为0的矩形,覆盖整个图,获取鼠标的焦点位置。

1
2
3
//获取鼠标相对于透明矩形左上角的坐标,左上角坐标为(0,0)
var mouseX = d3.mouse(this)[0] - padding.left;
var mouseY = d3.mouse(this)[1] - padding.top;

焦点位置 反射出 对应坐标值

使用函数 xScale.invert:

1
var x0 = xScale.invert( mouseX );

根据坐标值 找出 实际值域内的值

实际的坐标值可能没有对应的值,那么此时应该通过逻辑找到临近的 值域内的值:

1
2
3
4
5
6
7
8
//对x0四舍五入,如果x0是2005.6,则返回2006;如果是2005.2,则返回2005
x0 = Math.round(x0);

//查找在原数组中x0的值,并返回索引号
var bisect = d3.bisector( function(d) { return d[0]; }).left;
var index = bisect(data, x0) ;
// 找到对应的实际定义的值
dataset[k].gdp[index]

绘制

有了坐标值,就知道所有的信息,就可以绘图了。

地图

地图数据下载地址(GeoJSON)

地图数据下载地址,这个网址下载的数据是一个zip包,里面有一个.shp文件,地图数据在这个文件中,需要解压这个数据。

从.shp提取数据

需要通过此网址从.shp文件中提取json数据的获取。提取出来的数据通常很大,需要简化使用,更加高效。

简化数据

点击查看简化数据网址

TopoJSON

TopoJSON 是d3作者制定,表达同样的地图信息,TopoJSON文件的体积要比GeoJSON小百分之八十,当GeoJSON文件达到20M以上时,节省下来的体积更加明显,网络请求更加快速。
因此在服务器端可放置TopoJSON文件,因为文件小,请求快速,请求回来后,在前端转换为 GeoJSON 文件,然后使用GeoJSON画图。因为画图还是使用GeoJSON的。

地理路径生成器

d3.geo.path()

这是绘制地图的核心,地图基本路径都是这个;参考demo

d3.geo.graticule()

用于绘制经线和纬线;参考demo

d3.geo.circle()

用于以某一地点为中心绘制圆形圆格,一般用得少。参考demo

d3.geo.projection

用于创建投影。一般用默认的投影即可,用得少。参考demo

demo

GeoJSON demo

一个简单的GeoJSON demo

TopoJSON demo

一个简单的TopoJSON demo

地图demo讲解

值域与线性渐变

参考《值域与线性渐变》

夜光图

完整demo与效果

完整 demo

在svg中添加滤镜

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var defs = svg.append("defs");

var gaussian = defs.append("filter")
.attr("id","gaussian");

gaussian.append("feGaussianBlur")
.attr("in","SourceGraphic")
.attr("stdDeviation","1");

var points = svg.selectAll("circle")
.data(cities) //绑定数组
.enter()
.append("circle")
.attr("class","point")
//设定过滤器
.style("filter","url(#"+ gaussian.attr("id") +")");

标线

完整demo与效果

本例主要考察 如何创建一个标线,主要利用了 line 标签, marker-end,mark-start 属性。
完整 demo

线段的起始位置添加标记图标

本例中,线段起始位置分别添加圆点与箭头标记。

1
2
3
4
5
6
7
8
svg.append("line")
.attr("class","route")
.attr("x1",guilin[0])
.attr("y1",guilin[1])
.attr("x2",peking[0])
.attr("y2",peking[1])
.attr("marker-end","url(#arrow)")
.attr("marker-start","url(#startPoint)");

line的 mark-start 确定起始位置

参考上面代码

line的 marker-end 确定终点位置

参考上面代码

d3标记图标的使用

如下,就是本例效果图中的箭头图标使用方法,在defs上创建,添加marker标签:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var defs = svg.append("defs");

var arrowMarker = defs.append("marker")
.attr("id","arrow")
.attr("markerUnits","strokeWidth")
.attr("markerWidth","12")
.attr("markerHeight","12")
.attr("viewBox","0 0 12 12")
.attr("refX","6")
.attr("refY","6")
.attr("orient","auto");

var arrow_path = "M2,2 L10,6 L2,10 L6,6 L2,2";

arrowMarker.append("path")
.attr("d",arrow_path)
.attr("fill","#000");

缩放与平移

完整demo与效果

本例主要考察 如何创建一个标线,主要利用了 line 标签, marker-end,mark-start 属性。
完整 demo

定义透明矩形,设置zoom行为

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
var zoom = d3.behavior.zoom()
.scaleExtent([1, 10])
.on("zoom", function(d){
//更新投影函数的平移量
projection.translate([ initTran[0] + d3.event.translate[0],
initTran[1] + d3.event.translate[1] ]);
//更新投影函数的缩放量
projection.scale( initScale * d3.event.scale );

//重绘地图
countries.attr("d",path);

//重绘经纬度网格
gridPath.attr("d",path);
});

svg.append("rect")
.attr("class","overlay")
.attr("x", 0)
.attr("y", 0)
.attr("width",width)
.attr("height",height)
.call(zoom);

利用投影函数的translate和scale

如上面代码

值域与线性渐变

完整demo与效果

完整 demo

通过值域创建颜色

实现代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//定义一个线性比例尺,将最小值和最大值之间的值映射到[0, 1]
var linear = d3.scale.linear()
.domain([minvalue, maxvalue])
.range([0, 1]);

//定义最小值和最大值对应的颜色
var a = d3.rgb(0,255,255); //浅蓝色
var b = d3.rgb(0,0,255); //蓝色

//颜色插值函数
var computeColor = d3.interpolate(a,b);

//设定各省份的填充色
provinces.style("fill", function(d,i){
var t = linear( values[d.properties.name] );
var color = computeColor(t);
return color.toString();
});

d3.scale.linear创建[0,1]范围的比例尺

参考上面代码

d3.interpolate(a,b)接受两个极限颜色

参考上面代码

创建 线性渐变颜色

实现代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
//定义最小值和最大值对应的颜色
var a = d3.rgb(0,255,255); //浅蓝色
var b = d3.rgb(0,0,255); //蓝色
//定义一个线性渐变
var defs = svg.append("defs");

var linearGradient = defs.append("linearGradient")
.attr("id","linearColor")
.attr("x1","0%")
.attr("y1","0%")
.attr("x2","100%")
.attr("y2","0%");

var stop1 = linearGradient.append("stop")
.attr("offset","0%")
.style("stop-color",a.toString());

var stop2 = linearGradient.append("stop")
.attr("offset","100%")
.style("stop-color",b.toString());

//添加一个矩形,并应用线性渐变
var colorRect = svg.append("rect")
.attr("x", 20)
.attr("y", 490)
.attr("width", 140)
.attr("height", 30)
.style("fill","url(#" + linearGradient.attr("id") + ")");

线性渐变定义在 defs 标签中

线性渐变就是上图 下面的那个渐变矩形框。
线性渐变定义在 defs 标签中。参考上面代码。

定义一个带id的linearGradient

如上,通过id来引用这个渐变颜色

渐变颜色使用url fill

参考上面代码

通过stop添加极限颜色

参考上面代码

参考

视频教程有7个,在这个网站上是能找到这七个视频的
D3.js 4.x API中文手册
D3.js 3.x API英文文档
D3.js 中文文档(包含最新版本中文文档,同时放出中英文各版本地址)