svg的基本形状
- line 线条
- x1 定义线条起点的 x 坐标
- y1 定义线条起点的 y 坐标
- x2 定义线条终点的 x 坐标
- y2 定义线条终点的 y 坐标
- polyline 折线
- points 定义折线的一系列点坐标,坐标间用空格隔开
- circle 圆
- cx 定义圆心的 x 坐标
- cy 定义圆心的 y 坐标
- r 定义圆的半径 r
- ellipse 椭圆
- cx 定义圆心的 x 坐标
- cy 定义圆心的 y 坐标
- rx 定义椭圆在 x 轴方向上的半径
- ry 定义椭圆在 y 轴方向上的半径
- rect 矩形
- x 定义矩形的左上角的 x 坐标
- y 定义矩形的左上角的 y 坐标
- width 定义矩形的宽
- height 定义矩形的高
- polygon 多边形
- points 定义多边形的顶点坐标,坐标间用空格隔开
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
.line,
.polyline {
fill: none;
stroke: steelblue;
stroke-width: 2;
}
.circle {
stroke: steelblue;
stroke-width: 2;
fill: red;
fill-opacity: .7;
}
.ellipse {
stroke: steelblue;
stroke-width: 2;
fill: yellow;
fill-opacity: .7;
}
.rect,
.polygon {
stroke: steelblue;
stroke-width: 2;
fill: pink;
fill-opacity: .7;
}
</style>
</head>
<body>
<script src="../d3.js"></script>
<script>
const svg = d3.select('body').append('svg')
svg.attr('width', 1000)
.attr('height', 400)
svg.append('line')
.attr('x1', 0)
.attr('y1', 200)
.attr('x2', 100)
.attr('y2', 100)
.classed('line', true)
svg.append('circle')
.attr('cx', 200)
.attr('cy', 150)
.attr('r', 50)
.classed('circle', true)
svg.append('ellipse')
.attr('cx', 350)
.attr('cy', 150)
.attr('rx', 75)
.attr('ry', 50)
.classed('ellipse', true)
svg.append('rect')
.attr('x', 450)
.attr('y', 100)
.attr('width', 100)
.attr('height', 100)
.attr('rx', 10)
.attr('ry', 20)
.classed('rect', true)
svg.append('polygon')
.attr('points', '600,200 650,100 700,200')
.classed('polygon', true)
svg.append('polyline')
.attr('points', '750,133 780,100 850,155 900,122')
.classed('polyline', true)
</script>
</body>
</html>
效果如下:
线条生成器 line()
d3 的生成器可以帮助我们将数据映射到svg的属性中,简化了我们对svg的操作。线条生成器就可以帮助我们十分简单的绘制路径。
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
.line {
fill: none;
stroke-width: 2;
stroke: steelblue;
}
.dot {
fill: #fff;
stroke: steelblue;
}
</style>
</head>
<body>
<h4>Interpolation Mode:</h4>
<div class="control-group">
<button onclick="render(d3.curveLinear)">linear</button>
<button onclick="render(d3.curveLinearClosed)"> linear closed</button>
<button onclick="render(d3.curveStepBefore)">step before</button>
<button onclick="render(d3.curveStepAfter)">step after</button>
<button onclick="render(d3.curveBasis)">basic</button>
<button onclick="render(d3.curveBasisOpen)">basic open</button>
<button onclick="render(d3.curveBasisClosed)">basic closed</button>
<button onclick="render(d3.curveBundle)">bundle</button>
<button onclick="render(d3.curveCardinal)">cardinal</button>
<button onclick="render(d3.curveCardinalOpen)">cardinal open</button>
<button onclick="render(d3.curveCardinalClosed)">cardinal closed</button>
<button onclick="render(d3.curveMonotoneY)">monotone y</button>
<button onclick="render(d3.curveCatmullRom)">catmull rom</button>
</div>
<script src="../d3.js"></script>
<script>
const width = 500,
height = 500,
margin = 50,
x = d3.scaleLinear()
.domain([0, 10])
.range([margin, width - margin]),
y = d3.scaleLinear()
.domain([0, 10])
.range([height - margin, margin])
const data = [
[
{x: 0, y: 5},
{x: 1, y: 9},
{x: 2, y: 7},
{x: 3, y: 5},
{x: 4, y: 3},
{x: 6, y: 4},
{x: 7, y: 2},
{x: 8, y: 3},
{x: 9, y: 2}
],
d3.range(10).map(function (i) {
return {x: i, y: Math.sin(i) + 5}
})
]
const svg = d3.select('body')
.append('svg')
.attr('width', width)
.attr('height', height)
const xScale = d3.scaleLinear()
.domain([0, 10])
.range([0, width - 2 * margin])
const xAxis = d3.axisBottom()
.scale(xScale)
svg.append('g')
.classed('x-axis', true)
.attr('transform', function () {
return `translate(${margin}, ${height - margin})`
})
.call(xAxis)
const yScale = d3.scaleLinear()
.domain([10, 0])
.range([0, height - 2 * margin])
const yAxis = d3.axisLeft()
.scale(yScale)
svg.append('g')
.classed('y-axis', true)
.attr('transform', function () {
return `translate(${margin}, ${margin})`
})
.call(yAxis)
function render(mode) {
const line = d3.line()
.x(function (d) {
return x(d.x)
})
.y(function (d) {
return y(d.y)
})
.curve(mode)
const lines = svg.selectAll('path.line')
.data(data)
lines.enter()
.append('path')
.classed('line', true)
.merge(lines)
.attr('d', function (d) {
return line(d)
})
}
function renderDots() {
data.forEach(function (item) {
svg.append('g').selectAll('circle')
.data(item)
.enter()
.append('circle')
.classed('dot', true)
.attr('cx', function (d) {
return x(d.x)
})
.attr('cy', function (d) {
return y(d.y)
})
.attr('r', 4.5)
})
}
render(d3.curveLinear)
renderDots()
</script>
</body>
</html>
效果如下:
在图表中,我们的线条是用 path 绘制的而不是 line,我们用line生成器来对数据进行处理,直接生成了 path 的 d 属性而不用我们去计算。
const line = d3.line()
.x(function (d) {
return x(d.x)
})
.y(function (d) {
return y(d.y)
})
.curve(mode)
上面这段代码就定义了一个线条生成器,我们通过 x() y() 去指定拿来计算坐标的 x y 值,返回数据在尺度中的对应值,因为这才是对应到图表中的坐标,然后 curve() 可以指定线条的类型。
查看内置的曲线类型可以在 github.com/d3/d3-shape…
区域生成器 area()
代码和线条生成器的示例一样,在 render 函数里加入以下:
const area = d3.area()
.x(function (d) {
return x(d.x)
})
.y0(y(0))
.y1(function (d) {
return y(d.y)
})
.curve(mode)
const areas = svg.selectAll('path.area')
.data([data])
areas.enter()
.append('path')
.classed('area', true)
.merge(areas)
.attr('d', function (d) {
return area(d)
})
效果如下:
在线图的基础上,我们在其中多渲染了面积的部分,同样是借助于 path 元素。
区域生成器需要我们去定义上边界和下边界 x0() x1() y0() y1(),这里因为我们的 x0() x1()是同样的,可以用 x() 方法统一指定。
curve() 指定区域生成器的曲线类型,和线条生成器一般用同种。
圆弧生成器 arc()
圆弧生成器同样要和 path 一起使用。
常使用的设置有:
- arc.innerRadius() 设置环的内半径
- arc.outerRadius() 设置环的外半径
- arc.cornerRadius() 设置拐角半径
- arc.startAngle() 设置起始角度的取值,默认读取数据中的 startAngle 属性
- arc.endAngle() 设置终止角度的取值,默认读取数据中的 endAngle 属性
- arc.padAngle() 设置相邻两个环之间的间隙角度,默认读取数据中的 padAngle 属性
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div class="control-group">
<button onclick="render(0)">circle</button>
<button onclick="render(100)">annulus</button>
<button onclick="render(0, Math.PI)">circle sector</button>
<button onclick="render(100, Math.PI)">annulus sector</button>
</div>
<script src="../d3.js"></script>
<script>
const width = 400,
height = 400,
colors = d3.scaleOrdinal(d3.schemeCategory10)
const svg = d3.select('body').append('svg')
.classed('pie', true)
.attr('height', height)
.attr('width', width)
function render(innerRadius, endAngle) {
if (!endAngle) {
endAngle = 2 * Math.PI
}
const data = [
{startAngle: 0, endAngle: 0.1 * endAngle},
{startAngle: 0.1 * endAngle, endAngle: 0.2 * endAngle},
{startAngle: 0.2 * endAngle, endAngle: 0.4 * endAngle},
{startAngle: 0.4 * endAngle, endAngle: 0.6 * endAngle},
{startAngle: 0.6 * endAngle, endAngle: 0.7 * endAngle},
{startAngle: 0.7 * endAngle, endAngle: 0.9 * endAngle},
{startAngle: 0.9 * endAngle, endAngle: endAngle}
]
const arc = d3.arc()
.outerRadius(200)
.innerRadius(innerRadius)
svg.select('g').remove()
svg.append('g')
.attr('transform', 'translate(200, 200)')
.selectAll('path')
.data(data)
.enter()
.append('path')
.classed('arc', true)
.attr('fill', function (d, i) {
return colors(i)
})
.attr('d', function (d, i) {
return arc(d)
})
}
render(0)
</script>
</body>
</html>
效果如下:
圆弧的过渡
给圆弧添加过渡效果时,要使用中间帧 attrTween()。
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<script src="../d3.js"></script>
<script>
const width = 400,
height = 400,
endAngle = 2 * Math.PI,
colors = d3.scaleOrdinal(d3.schemeCategory10)
const svg = d3.select('body').append('svg')
.classed('pie', true)
.attr('width', width)
.attr('height', height)
function render(innerRadius) {
const data = [
{startAngle: 0, endAngle: 0.1 * endAngle},
{startAngle: 0.1 * endAngle, endAngle: 0.2 * endAngle},
{startAngle: 0.2 * endAngle, endAngle: 0.4 * endAngle},
{startAngle: 0.4 * endAngle, endAngle: 0.6 * endAngle},
{startAngle: 0.6 * endAngle, endAngle: 0.7 * endAngle},
{startAngle: 0.7 * endAngle, endAngle: 0.9 * endAngle},
{startAngle: 0.9 * endAngle, endAngle: endAngle}
]
const arc = d3.arc().outerRadius(200).innerRadius(innerRadius)
svg.select('g').remove()
svg.append('g')
.attr('transform', 'translate(200, 200)')
.selectAll('path')
.data(data)
.enter()
.append('path')
.classed('arc', true)
.attr('fill', (d, i) => colors(i))
.transition().duration(1000).delay(3000)
.attrTween('d', d => {
const scale = d3.scaleLinear().domain([0, 1]).range([{startAngle: 0, endAngle: 0}, d])
return t => arc(scale(t))
})
}
render(100)
</script>
</body>
</html>
效果如下: