D3.js【学习一】

数据绑定

<p>Hello,World!--------1</p>
<p>Hello,World!--------2</p>
var e = d3.select("body").selectAll("p");
//改变字体颜色,大小和内容
e.style("color", "blue").style("font-size", "72px").text("123");

D3可以将数据绑定到DOM上去(DOM能将HTML文档表达为树结构,数据绑定与DOM绑定即是让HTML标签与数据进行绑定)。比如,让段落元素p标签与字符串变量“Hello”绑定,绑定后,当需要依靠该数据操作元素时,会更为方便。

D3中有两个函数可以绑定数据:
(1)datum():绑定一个数据到选择集上。
(2)data():绑定一个数组到选择集上,数组的各项值分别与选择集的各元素绑定。(更常用)

<p>张三</p>
<p>李四</p>
<p>王五</p>
var str = "China";
var body = d3.select("body");
var p = body.selectAll("p");
p.datum(str);
p.text(function(d, i) {
    return i + ":" + d;
  });

在这里插入图片描述

var arr = ["a", "b", "c"];
var body = d3.select("body");
var p = body.selectAll("p");
p.data(arr);
p.text(function(d, i) {
    return i + ":" + d;
});

在这里插入图片描述

插入元素

插入元素涉及的函数有两个,分别是:
(1)append():在选择集末尾插入元素
(2)insert():在选择集前面插入元素

var body = d3.select("body");
body.append("p").text("赵六");
//在body的末尾append p元素
body.insert("p", "#label").text("insert here");

在这里插入图片描述

删除元素

删除一个元素时,对于选择的元素,使用remove()函数即可

//删除元素
//方法一
var body = d3.select("body");
var p = body.select("#label");
p.remove();

//方法二
var p = d3.select("#label");
p.remove();

enter()和exit()方法

使用D3的enter()和exit()对象选择方法,可以为传入的数据(通常为数组形式)创建新节点,以及删除不再需要的传出节点。

//Case 1:update
var p = d3.select("body")
    .selectAll("p")
    .data([1, 2, 3, 4])
    .text(function(d) {
        return d;
    });
//结果为1  2
//即a和b被替换成了数组中前两个元素
//Case 3:Enter
p.enter().append("p")
    .text(function(d) {
        return d;
    });
//结果为1 2 3 4
//在Case 1 的基础上继续操作
//数组长度大于节点数,通过enter(),3和4成为了附加节点(如果前面的啊,b没有被替换,使用enter最终也没有被替换)

//Case 3:Exit
d3.select("body")
    .selectAll("p")
    .data([8])
    .exit().remove()
    .text(function(d) {
        return d;
    });
//后面的.text部分无效

    // d3.select("body")
    //     .selectAll("p")
    //     .data([8])
    //     .text(function(d) {
    //         return d; //这时结果为8 2 3 4
    //     }).exit().remove()
    //结果为1
    //在Case 2 的基础上继续操作
    //数据长度小于节点数,通过exit(),删除了多余节点,留下了1
    //注:如果先.text,再.exit.remove(),则会因为先赋值了而结果为8

绘制SVG图形

若要进行绘图,首先需要的是一块绘图的“画布”。在HTML5中,提供了两种强有力的“画布”;SVG和Canvas。其中,D3对SVG支持非常好,提供了众多的SVG图形生成器。

什么是SVG?指可缩放矢量图形,是用于描述二维矢量图形的一种图形格式,是由万维网联盟制定的开放标准。SVG使用XML格式来定义图形,除了IE8之前的版本外,绝大部分浏览器都支持SVG,可将SVG文本直接嵌入HTML中显示。
SVG有如下特点:
(1)SVG绘制的是矢量图,因此对图像进行放大不会失真
(2)基于XML,可以为每个元素添加JavaScript事件处理器
(3)每个图形均视为对象,更改对象的属性,图形也会改变

矩形的属性,常用的有4个:
(1)x:矩形左上角的x坐标
(2)y:矩形左上角的y坐标
(3)width:矩形的宽度
(4)height:矩形的高度
要注意的是,在SVG中,x轴的正方向是水平向右,y轴的正方向是垂直向下的。

var arr = [21, 17, 16, 11, 10];
    var width = 300; //画布的宽度
    var height = 300; //画布的高度
    var svg = d3.select("body") //选择文档中的body元素
        .append("svg") //添加一个SVG元素
        .attr("width", width) //设定宽度
        .attr("height", height); //设定高度
    var rectHeight = 25; //每个矩形所占的像素高度(包括空白)
    svg.selectAll("rect")
        .data(arr)
        .enter()
        .append("rect")
        .attr("x", 20)
        .attr("y", function(d, i) {
            return i * rectHeight;
        }) //为各元素的属性赋值
        .attr("width", function(d) {
            return d * 10;
            //为了显示效果对数值进行了缩放
            //更好的方法是通过设置比例尺来优化
        })
        .attr("height", rectHeight - 5)
        .attr("fill", "gold"); //设置填充色为金色

其中应用到了enter()方法,他使得在有数据,而没有足够图形元素的情况下,补充足够的元素(代码里甚至可以没有rect标签,也可以没有svg【画布可以有一些居中效果】)

使用比例尺

比例尺有线性比例尺(连续)、序数比例尺(离散)等多种类型之分。其中线性比例尺能使数据从一个连续的区间(定义域)映射到另一个区间(值域),来解决条形图宽度的问题。

var arr = [21, 17, 16, 11, 10];

var max = d3.max(arr); ///**********选出数组中的最大值**********/
var linear = d3.scaleLinear() // /*******比例尺函数,linear不是一个值而是一个函数********/
        .domain([0, max]) ///*****定义域*****/
        .range([0, 300]); ///*****值域,设置为300使其充满整个画布的宽度*****/

var width = 300; //画布的宽度
var height = 300; //画布的高度
var svg = d3.select("body") //选择文档中的body元素
    .append("svg") //添加一个SVG元素
    .attr("width", width) //设定宽度
    .attr("height", height); //设定高度
var rectHeight = 25; //每个矩形所占的像素高度(包括空白)
svg.selectAll("rect")
    .data(arr)
    .enter()
    .append("rect")
    .attr("x", 20)
    .attr("y", function(d, i) {
        return i * rectHeight;
    }) //为各元素的属性赋值
    .attr("width", function(d) {
        return linear(d); ///********调用linear函数,使得长度最长的矩形占满画布的宽度*********/
        //为了显示效果对数值进行了缩放
        //更好的方法是通过设置比例尺来优化
    })
    .attr("height", rectHeight - 5)
    .attr("fill", "gold"); //设置填充色为金色

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-u6k9wL4k-1648953981895)(C:\Users\31998\AppData\Roaming\Typora\typora-user-images\image-20220312180621438.png)]

坐标轴

坐标轴,是可视化图表中经常出现的一种图形,由轴线、刻度和标签组成,可以分为水平的x轴和垂直方向上的y轴。D3支持了以下四种绘制坐标轴的函数,使用起来很方便。
(1)d3.axisTop():创建顶部坐标轴
(2)d3.axisRight():创建垂直居右坐标轴
(3)d3.axisBottom():创建底部坐标轴
(4)d3.axisLeft():创建垂直居左坐标轴

原点(0,0)在最左上角

//创建x坐标轴
var width = 400; //画布的宽度
var height = 400; //画布的高度
var data = [10, 15, 25, 30];
var svg = d3.select("body") //选择文档中的body元素
    .append("svg") //添加一个SVG元素
    .attr("width", width) //设定宽度
    .attr("height", height); //设定高度
//创建线性比例尺
//设置其宽高、定义域值域
//从定义域到值域:10->0,30->300
var scale = d3
    .scaleLinear()
    .domain([d3.min(data), d3.max(data)])
    .range([0, width - 100]);
//创建横向底部的x轴,并向x轴添加比例尺
var x_axis = d3.axisBottom().scale(scale);
//创建“组”并向其中插入x轴坐标
svg.append("g").call(x_axis);

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-h4UmU9b5-1648953981895)(C:\Users\31998\AppData\Roaming\Typora\typora-user-images\image-20220312210059942.png)]

//创建y坐标轴
    var width = 400; //画布的宽度
    var height = 400; //画布的高度
    var data = [10, 15, 20, 25, 30];
    var svg = d3.select("body") //选择文档中的body元素
        .append("svg") //添加一个SVG元素
        .attr("width", width) //设定宽度
        .attr("height", height); //设定高度
    //创建线性比例尺
    //设置其宽高、定义域值域
    var scale = d3
        .scaleLinear()
        .domain([d3.min(data), d3.max(data)])
        .range([height / 2, 0]);
    var y_axis = d3.axisLeft().scale(scale);
    //创建“组”并向其中插入x轴坐标
    svg.append("g").attr("transform", "translate(50,10)").call(y_axis);
    //translate,transform操作调整了坐标轴在SVG图中的位置

var width = 400; //画布的宽度
var height = 400; //画布的高度
var data = [10, 15, 20, 25, 30];
var svg = d3.select("body") //选择文档中的body元素
    .append("svg") //添加一个SVG元素
    .attr("width", width) //设定宽度
    .attr("height", height); //设定高度

var xscale = d3
    .scaleLinear()
    .domain([0, d3.max(data)])
    .range([0, width - 100]);

var yscale = d3
    .scaleLinear()
    .domain([0, d3.max(data)])
    .range([height / 2, 0]);

var x_axis = d3.axisBottom().scale(xscale);
var y_axis = d3.axisLeft().scale(yscale);
//调整位置transform translate xAxisTranslate
svg.append("g").attr("transform", "translate(50,10)").call(y_axis);
var xAxisTranslate = height / 2 + 10; //横坐标刻度的垂直位置

svg
    .append("g")
    .attr("transform", "translate(50, " + xAxisTranslate + ")")
    .call(x_axis);

绘制条形图

<body>
    <svg width="600" height="500"></svg>
</body>
<script>
//part 1
var svg = d3.select("svg"),
    margin = 200, //通过margin外边距调整位置
    width = svg.attr("width") - margin,
    height = svg.attr("height") - margin;

//scaleBand()序数比例尺常用于离散值,如年份
//padding用于调整条之间的距离
var xScale = d3.scaleBand().range([0, width]).padding(0.4),
    yScale = d3.scaleLinear().range([height, 0]);
//创建“组”元素,调整了图表在SVG中的位置
var g = svg
    .append("g")
    .attr("transform", "translate(" + 100 + "," + 100 + ")");
//part 2
//加载数据并创建坐标轴
d3.csv("data.csv").then(function(data) {
    xScale.domain(
        data.map(function(d) {
            return d.year;
        })
    );
    yScale.domain([
        0,
        d3.max(data, function(d) {
            return d.value;
        }),
    ]);
    g.append("g")
        .attr("transform", "translate(0," + height + ")")
        .call(d3.axisBottom(xScale));

    g.append("g").call(
        d3
        .axisLeft(yScale)
        .tickFormat(function(d) { //都加上$符号
            return "$" + d;
        })
        .ticks(10) //空白间隔数,间隔数越多,越密集
    );

    //part 3
    g.selectAll(".bar") //选择所有class为bar的属性
        .data(data)
        .enter() //没有.bar元素,但是用到了enter方法,让数据和它相对应自动填充
        .append("rect") //添加矩形,使用enter()绑定数据
        .attr("class", "bar") //添加class属性
        .attr("x", function(d) {
            return xScale(d.year);
        }) //x轴坐标为年份
        .attr("y", function(d) {
            return yScale(d.value);
        }) //y轴坐标为股票价格
        .attr("width", xScale.bandwidth())
        //和x轴下的scaleBand()对应
        .attr("height", function(d) {
            return height - yScale(d.value);
        })
        .attr("fill", "grey");
    //使用灰色填充,也可以根据.bar写css样式来改变颜色
    //给坐标轴添加“年份”和“股价”
    // 这一部分代码部分在前面出现过,可以替换前面的代码,现在是覆盖的形式
    g.append("g")
        .attr("transform", "translate(0," + height + ")")
        .call(d3.axisBottom(xScale))
        .append("text")
        .attr("y", height - 280)
        .attr("x", width - 0)
        .attr("text-anchor", "end") //方向,注释不影响
        .attr("stroke", "black") //黑色字体显示
        .text("年份");

    g.append("g")
        .call(
            d3.axisLeft(yScale)
            .tickFormat(function(d) {
                return "$" + d;
            })
            .ticks(10)
        )
        .append("text")
        .attr("transform", "rotate(-90)") //字体旋转,垂直展示
        .attr("y", -16)
        .attr("x", 15)
        .attr("dy", "-5.lem") //注释不影响
        .attr("text-anchor", "end") //方向,注释不影响
        .attr("stroke", "black")
        .text("股价");
});
//part 4
//为图表添加标签,如标题、坐标轴上的单位
svg
    .append("text")
    .attr("transform", "translate(100,0)")
    .attr("x", 115)
    .attr("y", 50)
    .attr("font-size", "24px")
    .text("X 公司股票价格");
<script/>

添加part 3 绘制矩形,形成条形图

为图表添加标签,如标题,坐标轴上的单位等

绘制饼图

使用D3绘制饼图做数据可视化
(1)SVG路径:使用预定义的命令来创建SVG路径
(2)d3.scaleOrdinal():创建序数比例尺
(3)d3.pie():饼图生成器
(4)d3.arc():弧生成器

(1)路径元素用于在SVG上创建路径。使用命令在SVG中绘制出路径
【代码定义了一条从起点(150,0)开始,经过(75,200),(225,200)的路径,并在起点处汇合

<body>
    <svg height="210" width="400">
        <path d="M150 0 L75 200 L225 200 Z"/>
    </svg>
</body>

(2)d3.scaleOrdinal()序数比例尺

在这里插入图片描述

代码中定义了5种颜色,并进行了枚举遍历。当遍历到第6个值时,超出了颜色总数量会回到起点,即循环序数

 var color = d3.scaleOrdinal(['#4daf4a', '#377eb8', '#ff7f00', '#984ea3', '#e41a1c']);
    console.log(color(0));  //#4daf4a
    console.log(color(1));  //#377eb8
    console.log(color(2));  //#ff7f00
    console.log(color(3));  //#984ea3
    console.log(color(4));  //#e41a1c
    console.log(color(5));  //#4daf4a,循环序数

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7ooMAzPa-1648953981898)(C:\Users\31998\AppData\Roaming\Typora\typora-user-images\image-20220313102250777.png)]

(3)d3.pie()
d3.pie()函数根据给定的数据,生成SVG中的饼图对象(楔形)。对每一个楔形计算了初始角度和结束角度,而这便能被用于创建SVG中楔形的实际路径

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-U3qt2Uaj-1648953981899)(C:\Users\31998\AppData\Roaming\Typora\typora-user-images\image-20220313103201565.png)]

(4)d3.arc()
d3.arc()函数生成弧,具体楔形的路径。弧需要一个内经和外径。如果内径为0,则结果将是饼图,否则结果将是环形图。我们需要用到这些生成的弧线提供给我们的 SVG路径元素。

<body>
    <svg width="300" height="200"></svg>
</body>
 <script>
 var data = [2, 4, 8, 10];
    //定义宽、高、半径变量
    var svg = d3.select("svg"),
        width = svg.attr("width"),
        height = svg.attr("height"),
        radius = Math.min(width, height) / 2, //保证不会超出SVG画布边界
        g = svg
        .append("g")
        .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
    //添加组元素

    //对颜色使用序数比例尺
    var color = d3.scaleOrdinal(['#4daf4a', '#377eb8', '#ff7f00', '#984ea3', '#e41a1c']);
    //生成饼
    var pie = d3.pie();
    //生成弧,设置内径和外径
    var arc = d3.arc().innerRadius(0).outerRadius(radius);
    //生成组
    var arcs = g
        .selectAll("arc")
        .data(pie(data))
        .enter()
        .append("g")
        .attr("class", "arc");

    //绘制路径,枚举序数填充颜色
    arcs
        .append("path") //添加SVG路径
        .attr("fill", function(d, i) {
            return color(i);
        })
        .attr("d", arc); //svg路径的d标签元素和arc对应起来
 <script/>

在这里插入图片描述

举例:

<body>
    <svg width="500" height="400"></svg>
</body>
<script>   
var svg = d3.select("svg"),
        width = svg.attr("width"),
        height = svg.attr("height"),
        radius = Math.min(width, height) / 2, //保证不会超出SVG画布边界
        g = svg
        .append("g")
        .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
    //添加组元素

    //对颜色使用序数比例尺
    var color = d3.scaleOrdinal(['#4daf4a', '#377eb8', '#ff7f00', '#984ea3', '#e41a1c']);

    //创建匿名函数返回数据中百分比的值
    var pie = d3.pie().value(function(d) {
        return d.percent;
    });

    //生成弧,设置内径和外径
    var arc = d3
        .arc()
        .innerRadius(90) //0时为饼图,非0时为环形图
        .outerRadius(radius - 30);

    //定义标签所在位置
    var label = d3
        .arc()
        .outerRadius(radius)
        .innerRadius(radius - 100);

    //读取csv文件
    d3.csv("browser_share.csv").then(function(data) {
        //为每个data创建组元素
        var arcs = g
            .selectAll(".arc")
            .data(pie(data))
            .enter()
            .append("g")
            .attr("class", "arc");

        //将路径元素添加进组中
        //使用序数比例尺添加颜色
        arcs
            .append("path")
            .attr("d", arc)
            .attr("fill", function(d) {
                return color(d.data.browser);
            });

        //在每个楔形中填写标签为浏览器名
        arcs
            .append("text")
            .attr("transform", function(d) {
                return "translate(" + label.centroid(d) + ")"; //对应前面的label函数
            })
            .text(function(d) {
                return d.data.browser;
            });
    });
    //添加图表标题
    svg
        .append("g")
        .attr("transform", "translate(" + (width / 2 - 150) + "," + 20 + ")")
        .append("text")
        .text("桌面端浏览器市场份额统计(截至2021年7月)")
        .attr("class", "title");
</script>

<style>
    .arc text {
        font: 8px sans-serif;
        text-anchor: middle;
    }
    
    .arc path {
        stroke: #fff;
    }
    
    .title {
        fill: rgb(20, 32, 28);
        font-weight: bold;
    }
</style>

动态交互

D3支持制作动态的图表。有时候,图表的变化需要缓慢的发生,以便于让用户看清楚变化的过程。此外,用户还可能会对图表中的部分元素进行点击,而图表会对不同的事件作出反应。D3提供了这些能提升交互式的用户体验的方法和操作。

什么是动态效果?动态的图表,是指图表在某一段时间会发生某种变化,可能是形状、颜色、位置等,用户能够看到变化的过程。

实现动态的方法:
D3提供了4个方法用于实现图形的过渡:从状态A变为状态B
(1)transition()
transition()用于启动过渡效果。其前后是图形变化前后的状态(形状、位置、颜色等)

(2)duration()
duration()用来指定过渡的持续时间,单位为毫秒

(3)delay()
delay()指定延迟的时间,表示一定时间后才开始转变,单位为毫秒。此函数可以对整体指定延迟,也可以对个别制定延迟。

图形整体会在延迟500毫秒后发生变化,变化的时长为1000ms,因此,过渡的总时长为1500ms。

(4)ease()
ease()指定过渡的缓动函数。常用的有:
① d3.easeLinear:普通的线性变换
② d3.easeCircle:慢慢地到达变换的最终状态
③ d3.easeElastic:带有弹跳的到达终点
④ d3.easeBounce:在最终状态处弹跳几次
调用方式如 .ease(d3.easeLinear)

交互

什么是交互?交互,是指用户输入了某种指令,程序接受到指令之后必须做出某种响应。对可视化图标来说,交互能使图表更加生动,能表现更多内容。例如,拖动图表中某些图形,鼠标滑到图形上出现提示框,用触屏放大或缩小图形等等。
用户用于交互的工具一般有三种:鼠标,键盘,触屏

如何添加交互?
通过on()添加了一个监听器。在D3中,每一个选择集都有on()函数,用于添加事件监听器。
其中,on()的第一个参数是监听的事件,第二个参数是监听到事件后响应的内容,第二个参数是一个函数。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-M6uMpqUH-1648953981900)(C:\Users\31998\AppData\Roaming\Typora\typora-user-images\image-20220313135858207.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Sk1UqL4X-1648953981901)(C:\Users\31998\AppData\Roaming\Typora\typora-user-images\image-20220313135454943.png)]

注:

(1)报错【跨域问题】
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MqAh5X6t-1648953981902)(C:\Users\31998\AppData\Roaming\Typora\typora-user-images\image-20220313110942155.png)]

解决:修改设置,并且使用live server运行代码
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FpFjAgS2-1648953981902)(C:\Users\31998\AppData\Roaming\Typora\typora-user-images\image-20220313111003127.png)]

(2)学习D3过程中遇到的比例尺总结:https://ld246.com/article/1591517347481

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值