官网 https://d3js.org/ 历史版本下载,后面换为自己想要版本号 https://registry.npmjs.org/d3/-/d3-7.4.4.tgz |
yarn add d3
import * as d3 from "d3";
import {select, selectAll} from "d3";
import {mean, median} from "d3-array";
D3 in React
import * as d3 from "d3";
export default function LinePlot({
data,
width = 640,
height = 400,
marginTop = 20,
marginRight = 20,
marginBottom = 20,
marginLeft = 20
}) {
const x = d3.scaleLinear([0, data.length - 1], [marginLeft, width - marginRight]);
const y = d3.scaleLinear(d3.extent(data), [height - marginBottom, marginTop]);
const line = d3.line((d, i) => x(i), y);
return (
<svg width={width} height={height}>
<path fill="none" stroke="currentColor" stroke-width="1.5" d={line(data)} />
<g fill="white" stroke="currentColor" stroke-width="1.5">
{data.map((d, i) => (<circle key={i} cx={x(i)} cy={y(d)} r="2.5" />))}
</g>
</svg>
);
}
|
|
HTML直接引入
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>import d3</title>
<link rel='shortcut icon' href='#'></link>
<script type="text/javascript" src="static/d3.744/d3.js"></script>
</head>
<body>
<svg width="50" height="50">
<circle cx="25" cy="25" r="22" fill="pink" stroke="gray" stroke-width="2"/>
</svg>
<script type="text/javascript">
d3.select("body").append("p").text("d3 demo");
</script>
</body>
</html>
|
|
|
|
|
SVG(Scalable Vector Graphics,可缩放矢量图形),等比缩放不失真,兼容多种浏览器 相当于画布,指定width和height属性 <svg width="500" height="50"> </svg> 像素px是默认的度量单位,除了px之外,还支持em、pt、in、cm和mm等其他单位。 <rect x="0" y="0" width="500" height="50"/> <circle cx="250" cy="25" r="25"/> <ellipse cx="250" cy="25" rx="100" ry="25"/> <line x1="0" y1="0" x2="500" y2="50" stroke="black"/> stroke指定直线的颜色 |
|
SVG的样式
SVG的text会继承CSS为父元素指定的字体样式,除非另有指定
<text x="250" y="25" font-family="serif" font-size="25" fill="gray">好好学习 </text>
要防止任何可见的元素跑到SVG画布外面,否则会被裁切掉
<text x="250" y="50" font-family="serif" font-size="25" fill="gray">天天向上 </text>
为SVG元素添加样式
SVG的默认样式是黑色填充,没有描边。如果你想要其他样式,必须自己给元素添加
fill
区域颜色值。与CSS用法一样,可以使用颜色名、十六进制值,或RGB、RGBA值
stroke
边的颜色值
stroke-width
边的宽度,带单位的数值(通常单位是像素)
opacity
0.0(完全透明)到1.0(完全不透明)之间的数值。
text元素还可以使用下面这些属性,用法与CSS的类似:
font-family
font-size
<circle cx="25" cy="25" r="22" fill="yellow" stroke="orange" stroke-width="5"/>
<circle cx="25" cy="25" r="22" class="aaa"/>
svg .aaa {
/* ... */
}
|
|
重叠与透明度
d3 svg画面默认在HTML层的更上一层,并且相互之间可位置重叠,可设置透明度
<circle cx="25" cy="25" r="20" fill="rgba(128, 0, 128, 1.0)"/>
<circle cx="50" cy="25" r="20" fill="rgba(0, 0, 255, 0.75)"/>
<circle cx="75" cy="25" r="20" fill="rgba(0, 255, 0, 0.5)"/>
<circle cx="100" cy="25" r="20" fill="rgba(255, 255, 0, 0.25)"/>
<circle cx="125" cy="25" r="20" fill="rgba(255, 0, 0, 0.1)"/>
<circle cx="25" cy="25" r="20" fill="purple" stroke="green" stroke-width="10"
opacity="0.9"/>
<circle cx="65" cy="25" r="20" fill="green" stroke="blue" stroke-width="10"
opacity="0.5"/>
<circle cx="105" cy="25" r="20" fill="yellow" stroke="red" stroke-width="10"
opacity="0.1"/>
以第三个圆形为例,其opacity值是0.2(20%)。而紫色填充已经设置了0.75(75%)的透明通道值。
结果,紫色区域最终的透明度就是0.2 × 0.75 = 0.15(15%)。
|
|
|
|
|
|
将数据集绑定到元素列表上,并选出未创建元素的选集,通过append添加元素
let dataset = [ 1,2,3 ];
d3.select("body").selectAll("p")
.data(dataset)
.enter()
.append("p")
.text("day day up");
d3.select("body")
选择DOM中的body元素,将其引用交给调用链中的下一个方法
.selectAll("p")
选择DOM中的所有段落。因为还没有任何段落,所以返回空选集。可以认为空选集代表接下来会创建的段落。
.data(dataset)
遍历解析并输出数据值。dataset数组中有n个值,此后的所有方法都将执行5n遍,每次针对一个值。
.enter()
无数据的占位元素对象选集
如果数据值比对应的DOM元素多,就创建一个新的占位元素。
然后把这个新占位元素的引用交给链中的下一个方法。
.append("p")
取得enter()创建的空占位符选集,并把一个p元素附加到相应的DOM中。
然后它再把自己刚创建的元素的引用交给链中的下一个方法。
.text("day day up")
取得新创建的p元素的引用,插入文本值
每一步返回的都是对象的引用,其中从data方法开始循环遍历
通常情况下,DOM元素个数少于数据集的元素个数, 无法完成DOM元素与数据集元素的一一绑定, 所以.data绑定数据时,D3先创建一个空的DOM元素对象,绑定数据 enter()可以将空的DOM元素选取出来 再通过append追加元素,完成DOM元素与数据集元素的一一绑定 |
|
属性/样式与匿名函数
let dataset = [ 1,2,3 ];
d3.select("body").selectAll("p")
.data(dataset)
.enter()
.append("p")
.style("color", function(d) {
if (d > 1) {
return "red";
} else {
return "black";
}
}).text(function(d){
return "day day up "+d;
});
attr()和style()可以分别用来设置选集的HTML属性和CSS属性
.classed("bar", true) 可以让一个css class生效/失效
------------------------------------------------------------------------- |
|
|
|
|
|
|
|
stroke 英/strəʊk/ 美/stroʊk/ n.(打、击等的)一下;击球(动作);一笔;
//Width and height
var w = 600;
var h = 100;
var barPadding = 1;
//Create SVG element
var svg = d3.select("#line_div")
.append("svg")
.attr("width", w)
.attr("height", h);
var dataset = [[30,10,200,50]];
svg.selectAll("line")
.data(dataset)
.enter()
.append("line")
.attr("x1", function(d, i) {
return d[0];
})
.attr("y1", function(d,i) {
return d[1];
})
.attr("x2", function(d, i) {
return d[2];
})
.attr("y2", function(d,i) {
return d[3];
})
.attr("stroke", "black")
.attr("stroke-width", "3");
svg.selectAll("text")
.data(dataset)
.enter()
.append("text")
.text("线")
.attr("text-anchor", "middle")
.attr("x", function(d, i) {
return (d[0]+d[2])/2;
})
.attr("y", function(d) {
return d[1]+8;
})
.attr("font-family", "sans-serif")
.attr("font-size", "14px")
.attr("fill", "blue");
|
|
|
|
|
|
|
|
|
//Width and height
var w = 600;
var h = 100;
var barPadding = 1;
//Create SVG element
var svg = d3.select("#rectaa_div")
.append("svg")
.attr("width", w)
.attr("height", h);
var dataset = [[50,30,60,240]];
svg.selectAll("rect")
.data(dataset)
.enter()
.append("rect")
.attr("x", function(d, i) {
return d[0];
})
.attr("y", function(d,i) {
return d[1];
})
.attr("height", function(d, i) {
return d[2];
})
.attr("width", function(d,i) {
return d[3];
}).attr("fill","#efef77")
.attr("stroke", "#778899")
.attr("stroke-width", "3");
svg.selectAll("text")
.data(dataset)
.enter()
.append("text")
.text("矩形")
.attr("text-anchor", "middle")
.attr("x", function(d, i) {
return (d[0]+d[2])/2 + 30;
})
.attr("y", function(d) {
return d[1]-10;
})
.attr("font-family", "sans-serif")
.attr("font-size", "14px")
.attr("fill", "#357210");
随机生成一组bar
div.bar {
display: inline-block;
width: 20px;
height: 75px;
margin-right: 2px;
background-color: teal;
}
var dataset = []; //Initialize empty array
for (var i = 0; i < 25; i++) { //Loop 25 times
var newNumber = Math.floor(Math.random() * 30); //New random integer (0-29)
dataset.push(newNumber); //Add new number to array
}
d3.select("body").selectAll("div")
.data(dataset)
.enter()
.append("div")
.attr("class", "bar")
.style("height",function (d) {
var barHeight = d * 5;
return barHeight + "px";
});
svg绘制条形图+text
//Width and height
var w = 660;
var h = 120;
var barPadding = 8;
var dataset = [ 5, 10, 13, 19, 21, 25, 22, 18, 15, 13,
11, 12, 15, 20, 18, 17, 16, 18, 23, 25 ];
//Create SVG element
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h);
svg.selectAll("rect")
.data(dataset)
.enter()
.append("rect")
.attr("x", function(d, i) {
return i * (w / dataset.length);//等分
})
.attr("y", function(d) {
return h - (d * 4);//左上角为起点
})
.attr("width", w / dataset.length - barPadding)
.attr("height", function(d) {
return d * 4;//与h-d*4形成一个统一高度h
})
.attr("fill",function (d) {
return "rgb(0, "+Math.round(d * 4)+", " + Math.round(d * 10) + ")";
});
svg.selectAll("text")
.data(dataset)
.enter()
.append("text")
.text(function(d) {
return d;
})
.attr("text-anchor", "middle")
.attr("x", function(d, i) {
return i * (w / dataset.length) + (w / dataset.length - barPadding) / 2;
})
.attr("y", function(d) {
return h - (d * 4) + 14;
})
.attr("font-family", "sans-serif")
.attr("font-size", "11px")
.attr("fill", "white");
//Width and height
var w = 500;
var h = 150;
//Data
var dataset = [ 5, 10, 15, 20, 25 ];
//Create SVG element
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h);
var circles = svg.selectAll("circle")
.data(dataset)
.enter()
.append("circle");
circles.attr("cx", function(d, i) {
return (i * 50) + 25;
})
.attr("cy", h/2)
.attr("r", function(d) {
return d;
})
.attr("fill", "yellow")
.attr("stroke", "orange")
.attr("stroke-width", function(d) {
return d/2;
});
// 宽度和高度
var width = 700;
var height = 300;
var svg = d3.select("body")
.append("svg")
.attr("width", width)
.attr("height", height);
let dataset = [ 5, 10, 15, 20, 25 ];
svg.selectAll("circle")
.data(dataset)
.enter()
.append("circle")
.attr("cx", function(d, i) {
return (i * 50) + 25;
})
.attr("cy", height/2)
.attr("r", function(d) {
return d;
})
.attr("fill","pink")
.attr("stroke", "orange")
.attr("stroke-width", function(d) {
return d/2;
});
散点的半径大小体现数值的大小
var w = 600;
var h = 100;
var dataset = [
[5, 20], [480, 90], [250, 50], [100, 33], [330, 95],
[410, 12], [475, 44], [25, 67], [85, 21], [220, 88]
];
//Create SVG element
var svg = d3.select("#d307_scatterplot")
.append("svg")
.attr("width", w)
.attr("height", h);
svg.selectAll("circle")
.data(dataset)
.enter()
.append("circle")
.attr("cx", function(d) {
return d[0];
})
.attr("cy", function(d) {
return d[1];
})
.attr("r", function(d) {
return Math.sqrt(h - d[1]);
})
.attr("fill","#999");
svg.selectAll("text")
.data(dataset)
.enter()
.append("text")
.text(function(d) {
return d[0] + "," + d[1];
})
.attr("x", function(d) {
return d[0];
})
.attr("y", function(d) {
return d[1];
})
.attr("font-family", "sans-serif")
.attr("font-size", "11px")
.attr("fill", "blue");
scale:比例尺,同比/等比映射,将domain([100, 300])同比映射到range([10, 30])
let scale = d3.scaleLinear()
.domain([100, 300])
.range([10, 30]);
console.log(scale(200));//20
d3.max
let simpleDataset = [7, 8, 4, 5, 2];
d3.max(simpleDataset); // 返回8
let dataset = [
[5, 20], [480, 90], [250, 50], [100, 33], [330, 95],
[410, 12], [475, 44], [25, 67], [85, 21], [220, 88]
];
d3.max(dataset, function(d) {
return d[0];
});
动态同比缩放:将svg画布映射到 [padding, w - padding * 2]的范围内,但相对大小/位置 不变
//Width and height
var w = 600;
var h = 300;
var padding = 30;
var dataset = [
[5, 20], [480, 90], [250, 50], [100, 33], [330, 95],
[410, 12], [475, 44], [25, 67], [85, 21], [220, 88],
[500, 150]
];
//Create scale functions
var xScale = d3.scaleLinear()
.domain([0, d3.max(dataset, function(d) { return d[0]; })])
.range([padding, w - padding * 2]);
var yScale = d3.scaleLinear()
.domain([0, d3.max(dataset, function(d) { return d[1]; })])
.range([h - padding, padding]);
var rScale = d3.scaleLinear()
.domain([0, d3.max(dataset, function(d) { return d[1]; })])
.range([2, 5]);
//Create SVG element
var svg = d3.select("#d3scatterplotdt")
.append("svg")
.attr("width", w)
.attr("height", h);
//Create circles
svg.selectAll("circle")
.data(dataset)
.enter()
.append("circle")
.attr("cx", function(d) {
return xScale(d[0]);
})
.attr("cy", function(d) {
return yScale(d[1]);
})
.attr("r", function(d) {
return rScale(d[1]);
})
.attr("fill","#999");
//Create labels
svg.selectAll("text")
.data(dataset)
.enter()
.append("text")
.text(function(d) {
return d[0] + "," + d[1];
})
.attr("x", function(d) {
return xScale(d[0]);
})
.attr("y", function(d) {
return yScale(d[1]);
})
.attr("font-family", "sans-serif")
.attr("font-size", "11px")
.attr("fill", "red");
比例尺举例
平方根比例尺
var aScale = d3.scaleSqrt() // -- 新代码!
.domain([0, d3.max(dataset, function(d) { return d[1]; })])
.range([0, 10]); // -- 新代码!
时间比例尺
//Width and height
var w = 500;
var h = 300;
var padding = 40;
var dataset, xScale, yScale; //Empty, for now
//For converting strings to Dates
// 01/01/17格式的时间
var parseTime = d3.timeParse("%m/%d/%y");
//For converting Dates to strings
var formatTime = d3.timeFormat("%b %e");
dataset = [];
d3.csv("static/data/time_scale_data.csv",function(d,i){
var di = {
Date: parseTime(d.Date),
Amount: parseInt(d.Amount)
}
dataset.push(di);
});
setTimeout(function() {
console.log(dataset);
aa();
}, 2000);
function aa(){
//Create scale functions
xScale = d3.scaleTime()
.domain([
d3.min(dataset, function(d) { return d.Date; }),
d3.max(dataset, function(d) { return d.Date; })
])
.range([padding, w - padding]);
yScale = d3.scaleLinear()
.domain([
d3.min(dataset, function(d) { return d.Amount; }),
d3.max(dataset, function(d) { return d.Amount; })
])
.range([h - padding, padding]);
//Create SVG element
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h);
//Generate date labels first, so they are in back
svg.selectAll("text")
.data(dataset)
.enter()
.append("text")
.text(function(d) {
return formatTime(d.Date);
})
.attr("x", function(d) {
return xScale(d.Date) + 4;
})
.attr("y", function(d) {
return yScale(d.Amount) + 4;
})
.attr("font-family", "sans-serif")
.attr("font-size", "11px")
.attr("fill", "#bbb");
//Generate circles last, so they appear in front
svg.selectAll("circle")
.data(dataset)
.enter()
.append("circle")
.attr("cx", function(d) {
return xScale(d.Date);
})
.attr("cy", function(d) {
return yScale(d.Amount);
})
.attr("r", 2);
}
本节摘要列表
d3 时间数轴 d3 数轴优化:增加竖线
定义刻度尺
d3.axisLeft和d3.axisRight可以生成垂直数轴,
d3.axisTop和d3.axisBottom可以生成水平数轴,
Left,Right,Top,Bottom指的是数轴上刻度标,就是个那个小竖条的方向,
而整个数轴顶点的默认坐标都是[0,0]
//axisBottom,水平方向,起点为[0,0]的一段线段
var xAxis = d3.axisBottom()
.scale(xScale);
等效于
var xAxis = d3.axisBottom(xScale);
调用刻度尺
创建一个层叫g,用于分组,
坐标轴绘制需要放到后面,即先绘制其他图形,然后再绘制坐标轴
svg.append("g")
.attr("class", "axis")
.attr("transform", "translate(0," + (h - padding) + ")")
.call(xAxis);
优化刻度尺
var xAxis = d3.axisBottom()
.scale(xScale)
.ticks(5); // 粗略地设置刻度线的数量
刻度数字格式化
var formatAsPercentage = d3.format(".1%");
xAxis.tickFormat(formatAsPercentage);
// 宽度和高度
//Width and height
var w = 600;
var h = 200;
var padding = 30;
var dataset = [
[5, 20], [480, 90], [250, 50], [100, 33], [330, 95],
[410, 12], [475, 44], [25, 67], [85, 21], [220, 88],
[600, 150]
];
var formatAsPercentage = d3.format("1");
//Create scale functions
var xScale = d3.scaleLinear()
.domain([0, d3.max(dataset, function(d) { return d[0]; })])
.range([padding, w - padding * 2]);
var yScale = d3.scaleLinear()
.domain([0, d3.max(dataset, function(d) { return d[1]; })])
.range([h - padding, padding]);
//Define X axis
var xAxis = d3.axisBottom()
.scale(xScale)
.ticks(5).tickFormat(formatAsPercentage);
//这里D3根据值的分布会进行区间的调整,tick是建议,不是绝对
var yAxis = d3.axisLeft()
.scale(yScale)
.ticks(5).tickFormat(formatAsPercentage);
//Create SVG element
var svg = d3.select("#svg_keduchi111")
.append("svg")
.attr("width", w)
.attr("height", h);
var aScale = d3.scaleSqrt()
.domain([0, d3.max(dataset, function(d) { return d[1]; })])
.range([0, 10]);
//Create circles
svg.selectAll("circle")
.data(dataset)
.enter()
.append("circle")
.attr("cx", function(d) {
return xScale(d[0]);
})
.attr("cy", function(d) {
return yScale(d[1]);
})
.attr("r", function(d) {
return aScale(d[1]);
}).attr("fill","pink");
//Create labels
svg.selectAll("text")
.data(dataset)
.enter()
.append("text")
.text(function(d) {
return d[0] + "," + d[1];
})
.attr("x", function(d) {
return xScale(d[0]);
})
.attr("y", function(d) {
return yScale(d[1]);
})
.attr("font-family", "sans-serif")
.attr("font-size", "11px")
.attr("fill", "blue");
//Create X axis
svg.append("g")
.attr("class", "axis")
.attr("transform", "translate(0," + (h - padding) + ")")
.call(xAxis);
svg.append("g")
.attr("class", "axis")
.attr("transform", "translate(" + (padding) + ",0)")
.call(yAxis);
随机数轴
//Width and height
var w = 500;
var h = 300;
var padding = 30;
/*
//Static dataset
var dataset = [
[5, 20], [480, 90], [250, 50], [100, 33], [330, 95],
[410, 12], [475, 44], [25, 67], [85, 21], [220, 88],
[600, 150]
];
*/
//Dynamic, random dataset
var dataset = []; //Initialize empty array
var numDataPoints = 12; //Number of dummy data points to create
var xRange = Math.random() * 1000; //Max range of new x values
var yRange = Math.random() * 1000; //Max range of new y values
for (var i = 0; i < numDataPoints; i++) { //Loop numDataPoints times
var newNumber1 = Math.floor(Math.random() * xRange); //New random integer
var newNumber2 = Math.floor(Math.random() * yRange); //New random integer
dataset.push([newNumber1, newNumber2]); //Add new number to array
}
//Create scale functions
var xScale = d3.scaleLinear()
.domain([0, d3.max(dataset, function(d) { return d[0]; })])
.range([padding, w - padding * 2]);
var yScale = d3.scaleLinear()
.domain([0, d3.max(dataset, function(d) { return d[1]; })])
.range([h - padding, padding]);
var aScale = d3.scaleSqrt()
.domain([0, d3.max(dataset, function(d) { return d[1]; })])
.range([0, 10]);
//Define X axis
var xAxis = d3.axisBottom()
.scale(xScale)
.ticks(5);
//Define Y axis
var yAxis = d3.axisLeft()
.scale(yScale)
.ticks(5);
//Create SVG element
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h);
//Create circles
svg.selectAll("circle")
.data(dataset)
.enter()
.append("circle")
.attr("cx", function(d) {
return xScale(d[0]);
})
.attr("cy", function(d) {
return yScale(d[1]);
})
.attr("r", function(d) {
return aScale(d[1]);
})
.attr("fill","#abc");
//Create labels
svg.selectAll("text")
.data(dataset)
.enter()
.append("text")
.text(function(d) {
return d[0] + "," + d[1];
})
.attr("x", function(d) {
return xScale(d[0]);
})
.attr("y", function(d) {
return yScale(d[1]);
})
.attr("font-family", "sans-serif")
.attr("font-size", "11px")
.attr("fill", "#889");
//Create X axis
svg.append("g")
.attr("class", "axis")
.attr("transform", "translate(0," + (h - padding) + ")")
.call(xAxis);
//Create Y axis
svg.append("g")
.attr("class", "axis")
.attr("transform", "translate(" + padding + ",0)")
.call(yAxis);
时间数轴
//Width and height
var w = 500;
var h = 300;
var padding = 40;
var dataset, xScale, yScale, xAxis, yAxis; //Empty, for now
//For converting strings to Dates
var parseTime = d3.timeParse("%Y-%m-%d");
//For converting Dates to strings
var formatTime = d3.timeFormat("%b %e");
dataset = [];
let a1 = [{"Date":"2016-12-31","Amount":35},{"Date":"2017-01-01","Amount":30},{"Date":"2017-01-02","Amount":24},{"Date":"2017-01-03","Amount":37},{"Date":"2017-01-04","Amount":54},{"Date":"2017-01-05","Amount":55},{"Date":"2017-01-06","Amount":62},{"Date":"2017-01-07","Amount":62},{"Date":"2017-01-08","Amount":70},{"Date":"2017-01-09","Amount":66},{"Date":"2017-01-10","Amount":51},{"Date":"2017-01-11","Amount":63},{"Date":"2017-01-12","Amount":74},{"Date":"2017-01-13","Amount":58},{"Date":"2017-01-14","Amount":69},{"Date":"2017-01-15","Amount":56},{"Date":"2017-01-16","Amount":56},{"Date":"2017-01-17","Amount":50},{"Date":"2017-01-18","Amount":52},{"Date":"2017-01-19","Amount":48},{"Date":"2017-01-20","Amount":55},{"Date":"2017-01-21","Amount":44},{"Date":"2017-01-22","Amount":35},{"Date":"2017-01-23","Amount":32},{"Date":"2017-01-24","Amount":35},{"Date":"2017-01-25","Amount":21},{"Date":"2017-01-26","Amount":15},{"Date":"2017-01-27","Amount":32},{"Date":"2017-01-28","Amount":21},{"Date":"2017-01-29","Amount":12},{"Date":"2017-01-30","Amount":23}];
dataset = a1.map(function(d,i){
return {
Date: parseTime(d.Date),
Amount: parseInt(d.Amount)
};
});
function aa(){
//Create scale functions
xScale = d3.scaleTime()
.domain([
d3.min(dataset, function(d) { return d.Date; }),
d3.max(dataset, function(d) { return d.Date; })
])
.range([padding, w - padding]);
yScale = d3.scaleLinear()
.domain([
d3.min(dataset, function(d) { return d.Amount; }),
d3.max(dataset, function(d) { return d.Amount; })
])
.range([h - padding, padding]);
//Create SVG element
var svg = d3.select("#svg_timsaxi")
.append("svg")
.attr("width", w)
.attr("height", h);
//Generate date labels first, so they are in back
svg.selectAll("text")
.data(dataset)
.enter()
.append("text")
.text(function(d) {
return formatTime(d.Date);
})
.attr("x", function(d) {
return xScale(d.Date) + 4;
})
.attr("y", function(d) {
return yScale(d.Amount) + 4;
})
.attr("font-family", "sans-serif")
.attr("font-size", "11px")
.attr("fill", "#bbb");
//Generate circles last, so they appear in front
svg.selectAll("circle")
.data(dataset)
.enter()
.append("circle")
.attr("cx", function(d) {
return xScale(d.Date);
})
.attr("cy", function(d) {
return yScale(d.Amount);
})
.attr("r", 2);
//Define X axis
xAxis = d3.axisBottom()
.scale(xScale)
.ticks(5);
//Define Y axis
yAxis = d3.axisLeft()
.scale(yScale)
.ticks(5);
//Create X axis
svg.append("g")
.attr("class", "axis")
.attr("transform", "translate(0," + (h - padding) + ")")
.call(xAxis);
//Create Y axis
svg.append("g")
.attr("class", "axis")
.attr("transform", "translate(" + padding + ",0)")
.call(yAxis);
}
aa();
时间数轴优化:增加竖线
//Width and height
var w = 700;
var h = 300;
var padding = 60;
var dataset, xScale, yScale, xAxis, yAxis; //Empty, for now
//For converting strings to Dates
var parseTime = d3.timeParse("%Y-%m-%d");
//For converting Dates to strings
// var formatTime = d3.timeFormat("%b %e");
//For converting Dates to strings
var formatTime = d3.timeFormat("%e");
dataset = [];
// d3.csv("static/data/time_scale_data.csv",function(d,i){
// var di = {
// Date: parseTime(d.Date),
// Amount: parseInt(d.Amount)
// }
// dataset.push(di);
// // alert(i);
// });
a1 = [{"Date":"2016-12-31","Amount":35},{"Date":"2017-01-01","Amount":30},{"Date":"2017-01-02","Amount":24},{"Date":"2017-01-03","Amount":37},{"Date":"2017-01-04","Amount":54},{"Date":"2017-01-05","Amount":55},{"Date":"2017-01-06","Amount":62},{"Date":"2017-01-07","Amount":62},{"Date":"2017-01-08","Amount":70},{"Date":"2017-01-09","Amount":66},{"Date":"2017-01-10","Amount":51},{"Date":"2017-01-11","Amount":63},{"Date":"2017-01-12","Amount":74},{"Date":"2017-01-13","Amount":58},{"Date":"2017-01-14","Amount":69},{"Date":"2017-01-15","Amount":56},{"Date":"2017-01-16","Amount":56},{"Date":"2017-01-17","Amount":50},{"Date":"2017-01-18","Amount":52},{"Date":"2017-01-19","Amount":48},{"Date":"2017-01-20","Amount":55},{"Date":"2017-01-21","Amount":44},{"Date":"2017-01-22","Amount":35},{"Date":"2017-01-23","Amount":32},{"Date":"2017-01-24","Amount":35},{"Date":"2017-01-25","Amount":21},{"Date":"2017-01-26","Amount":15},{"Date":"2017-01-27","Amount":32},{"Date":"2017-01-28","Amount":21},{"Date":"2017-01-29","Amount":12},{"Date":"2017-01-30","Amount":23}];
dataset = a1.map(function(d,i){
return {
Date: parseTime(d.Date),
Amount: parseInt(d.Amount)
};
})
function aa2(){
//Create scale functions
xScale = d3.scaleTime()
.domain([
d3.min(dataset, function(d) { return d.Date; }),
d3.max(dataset, function(d) { return d.Date; })
])
.range([padding, w - padding]);
yScale = d3.scaleLinear()
.domain([
d3.min(dataset, function(d) { return d.Amount; }),
d3.max(dataset, function(d) { return d.Amount; })
])
.range([h - padding, padding]);
//Create SVG element
var svg = d3.select("#svg_ketimyh111")
.append("svg")
.attr("width", w)
.attr("height", h);
//Generate date labels first, so they are in back
svg.selectAll("text")
.data(dataset)
.enter()
.append("text")
.text(function(d) {
return formatTime(d.Date);
})
.attr("x", function(d) {
return xScale(d.Date) + 4;
})
.attr("y", function(d) {
return yScale(d.Amount) + 4;
})
.attr("font-family", "sans-serif")
.attr("font-size", "11px")
.attr("fill", "#bbb");
//Generate guide lines
svg.selectAll("line")
.data(dataset)
.enter()
.append("line")
.attr("x1", function(d) {
return xScale(d.Date);
})
.attr("x2", function(d) {
return xScale(d.Date);
})
.attr("y1", h - padding)
.attr("y2", function(d) {
return yScale(d.Amount);
})
.attr("stroke", "#ddd")
.attr("stroke-width", 1);
//Generate circles last, so they appear in front
svg.selectAll("circle")
.data(dataset)
.enter()
.append("circle")
.attr("cx", function(d) {
return xScale(d.Date);
})
.attr("cy", function(d) {
return yScale(d.Amount);
})
.attr("r", 2).attr("fill","blue");
//Define X axis
xAxis = d3.axisBottom()
.scale(xScale)
.ticks(5).tickFormat(formatTime);
//Define Y axis
yAxis = d3.axisLeft()
.scale(yScale)
.ticks(5);
//Create X axis
svg.append("g")
.attr("class", "axis")
.attr("transform", "translate(0," + (h - padding) + ")")
.call(xAxis);
//Create Y axis
svg.append("g")
.attr("class", "axis")
.attr("transform", "translate(" + padding + ",0)")
.call(yAxis);
}
aa2();
简单条形图回顾 使用分档比例尺
简单条形图回顾:没有使用比例尺,使用数据本身做简单处理
//Width and height
var w = 600;
var h = 200;
var barPadding = 1;
var dataset = [ 5, 10, 13, 19, 21, 25, 22, 18, 15, 13,
11, 12, 15, 20, 18, 17, 16, 18, 23, 25 ];
//Create SVG element
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h);
svg.selectAll("rect")
.data(dataset)
.enter()
.append("rect")
.attr("x", function(d, i) {
return i * (w / dataset.length);
})
.attr("y", function(d) {
return h - (d * 4);
})
.attr("width", w / dataset.length - barPadding)
.attr("height", function(d) {
return d * 4;
})
.attr("fill", function(d) {
return "rgb(0, 0, " + Math.round(d * 10) + ")";
});
svg.selectAll("text")
.data(dataset)
.enter()
.append("text")
.text(function(d) {
return d;
})
.attr("text-anchor", "middle")
.attr("x", function(d, i) {
return i * (w / dataset.length) + (w / dataset.length - barPadding) / 2;
})
.attr("y", function(d) {
return h - (d * 4) + 14;
})
.attr("font-family", "sans-serif")
.attr("font-size", "11px")
.attr("fill", "white");
使用分档比例尺:d3.scaleBand()
点击这一行文本使用新数据更新条形图.
var xScale = d3.scaleBand()
.domain(d3.range(dataset.length))
.rangeRound([0, w])
.paddingInner(0.05);
d3.scaleBand() 是离散范围值
d3.range(dataset.length) = d3.range(20)
数组长度20,分为20档,w=600,一档宽度30
paddingInner(0.05)
30*0.05=1.5的inner padding距离
1.5宽度导致w的宽度出现小数,需要对半个像素值进行抗锯齿处理,否则条形会显得模糊。
rangeRound可以让分档比例尺把输出值四舍五入成最接近的整数,
整数值有助于将视觉元素与像素网格对齐,保证图形的边缘清晰锐利。
添加点击事件
d3.select("p")
.on("click", function() {
// 更新数据,然后重新绘制图形
});
动画:transition
.. // 选择元素的代码 .transition() .duration(2000) .ease(d3.easeLinear) ... // attr()的代码 transition()添加动画效果 duration(time_sec) 指定这个动画持续的时间,单位毫秒 ease(d3.easeCubicOut)指定动画转变的具体细节: d3.easeCubicOut 逐渐加速然后再逐渐减速的效果 d3.easeLinear 线性缓动,动画速度不变 d3.easeCircleIn 元素逐渐进入并加速,最后到达指定位置。 d3.easeElasticOut 描述这个效果最恰当的词是“有弹性”。 d3.easeBounceOut 像皮球落地一样反复弹跳,慢慢停下来
延时时间
ease()负责控制动画性质,delay()用于指定过渡开始的时间。 ... .transition() .delay(1000) // 1000毫秒,即1秒 .duration(2000) // 2000毫秒,即2秒 ...
//Width and height
var w = 600;
var h = 250;
var padding = 50;
var dataset = [ 5, 10, 13, 19, 21, 25, 22, 18, 15, 13,
11, 12, 15, 20, 18, 17, 16, 18, 23, 25 ];
var xScale = d3.scaleBand()
.domain(d3.range(dataset.length))
.rangeRound([0, w])
.paddingInner(0.05);
var yScale = d3.scaleLinear()
.domain([0, d3.max(dataset)])
.range([0, h - padding]);
//Create SVG element
var svg = d3.select("#fendangcs_div")
.append("svg")
.attr("width", w)
.attr("height", h);
//Create bars
svg.selectAll("rect")
.data(dataset)
.enter()
.append("rect")
.attr("x", function(d, i) {
return xScale(i);
})
.attr("y", function(d) {
return h - yScale(d);
})
.attr("width", xScale.bandwidth())
.attr("height", function(d) {
return yScale(d);
})
.attr("fill", function(d) {
return "rgb(0, 0, " + Math.round(d * 10) + ")";
});
//Create labels
svg.selectAll("text")
.data(dataset)
.enter()
.append("text")
.text(function(d) {
return d;
})
.attr("text-anchor", "middle")
.attr("x", function(d, i) {
return xScale(i) + xScale.bandwidth() / 2;
})
.attr("y", function(d) {
return h - yScale(d) + 14;
})
.attr("font-family", "sans-serif")
.attr("font-size", "11px")
.attr("fill", "white");
d3.select("#fendangcsp_click")
.on("click",function () {
//New values for dataset
// dataset = [ 11, 12, 15, 20, 18, 17, 16, 18, 23, 25,
// 5, 10, 13, 19, 21, 25, 22, 18, 15, 13 ];
//New values for dataset
var numValues = dataset.length; //Count original length of dataset
var maxValue = 100;
dataset = []; //Initialize empty array
for (var i = 0; i < numValues; i++) { //Loop numValues times
var newNumber = Math.floor(Math.random() * maxValue); //New random integer (0-24)
dataset.push(newNumber); //Add new number to array
}
yScale.domain([0,d3.max(dataset)]);
d3.select("#fendangcs_div").selectAll("rect")
.data(dataset)
.transition()
.delay(function (d,i) {
return i * 100;
})
.duration(500)
.ease(d3.easeLinear)
.attr("y",function (d) {
return h - padding - yScale(d);
})
.attr("height",function (d) {
return yScale(d);
})
.attr("fill", function(d) {
return "rgb(0, 0, " + Math.round(d * 10) + ")";
});
//Update all labels
svg.selectAll("text")
.data(dataset)
.transition()
.delay(function (d,i) {
return i * 100;
})
.duration(500)
.ease(d3.easeLinear)
.text(function(d) {
return d;
})
.attr("x", function(d, i) {
return xScale(i) + xScale.bandwidth() / 2;
})
.attr("y", function(d) {
return h - padding - yScale(d) + 14;
});
});