d3 概述

官网
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>







d3 SVG


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%)。







d3 加载数据

将数据集绑定到元素列表上,并选出未创建元素的选集,通过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生效/失效

-------------------------------------------------------------------------







d3 line


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");











d3 rect

//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");

d3 bar

随机生成一组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");

d3 circle


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

d3 scatterplot

散点的半径大小体现数值的大小


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");

d3 scale

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 数轴优化:增加竖线 

定义刻度尺

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

d3 更新过渡及动画

简单条形图回顾 
使用分档比例尺 


简单条形图回顾:没有使用比例尺,使用数据本身做简单处理

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

});





参考