d3绘图笔记

  1. 目录

    D3绘图笔记

    安装与引用

    选择器

    添加svg标签

    添加绘图位置

    比例尺

    定义比例尺

    插入比例尺

    连续比例尺

    定义比例尺

    自定义要显示的刻度以及刻度标签

    调整刻度高度与标签位置

     比例尺均匀分布ticks

    绘制矩形图

    源码

    绘制线条

    x轴网格线

    绘制椭圆

    d3内置函数

    获取最大值与最小值

    创建范围值

    数据循环each函数

    颜色类型转换函数d3.color转rgb格式


    D3绘图笔记

      1. 安装与引用

npm install d3 --save-dev

import * as d3 from 'd3';

      1. 选择器

d3.select()    可直接接元素名,也可以接属性与类

      1. 添加svg标签

this.d3 = d3.select('.myd3')

let svg = this.d3.append("svg") // 添加svg并设置好高宽

    .attr("width", 600)

.attr("height", 600)

注意:没有这个svg标签后续的操作都无法显示。g标签 rect标签都需要在svg标签里才有效。

      1. 添加绘图位置

let g = svg.append("g").attr("transform", "translate(" + 30 + "," +30 + ")") // 绘图区域

位置如下:上30与左30的位置。注意:这里的左边位置是以竖线为参考而不是坐标值。

  1. 比例尺

    1. 定义比例尺

let scaleX = d3.scaleBand()

    .domain(d3.range(0,5))

.rangeRound([0,500]);

scaleBand为序数比例尺,也就是可以自己设置内容

而domain则表示精度,d3.range其实就是[0,1,2,3,4,5]

所以这块也可以手动添加数组进去[‘a’,’b’,’c’,’d’]

rangeRound则是比例尺显示的实际范围,单位为像素。也就是500像素的宽度用来均匀分布比例尺

      1. 插入比例尺

let axisX = d3.axisBottom(scaleX);

g.append('g').attr("transform", "translate(0, " + 300 + ")").call(axisX)

axisBottom 定义比例尺方向,插入比例尺的位置为坐标下方

最后再插入到绘图标签中。位置也需要用translate重新调整。

连续比例尺

定义比例尺

let scaleY = d3.scaleLinear()

    .domain([0, d3.max(this.data)])

.range([100, 0]);

let axisY = d3.axisLeft(scaleY);

g.append('g').attr("transform", "translate(0,0)").call(axisY);

d3.max则是从数组中找到数值最大的数。

连续比例尺 会根据范围比如0与 100 而自动设置尺度

而这边的range第一个参数为100则表示从100像素位置往0像素位置绘制比例尺。如下图

 

注意:如果设置为0到100 则坐标会从0 20 60这样由上往下递增。

只有将这两边的值对应起来才刚好绘制出正常的效果来

自定义要显示的刻度以及刻度标签

有些只是展示其中部分刻度的,如0,0.3,0.5,1

可以设置如下参数.tickValues([0,0.3,0.5,1])

此时显示的刻度,如果想换成文字呢?比如0.5的时候显示 中年人,0的时候显示少儿,1的时候显示百岁老人。

通过如下代码
 

 .tickFormat(i => {
        let str = '少儿'
        switch(i){
          case 0:
            str = '少儿'
          break;
          case 0.3:
            str = '儿童'
            break;
          case 0.5:
            str = '中年'
            break;
        }
        return str
      }) // 通过i一个个展示文本

 

调整刻度高度与标签位置

如这种特殊需求如何实现呢?

首先是刻度,刻度绘制结束自带的path路径会将 横线左右两边都带上竖线,所以我们得先去掉竖线,也就是设置竖线的高度为0即可。

.tickSizeInner(0) // 去掉自带刻度内高度
.tickSizeOuter(0) // 去掉自带刻度外高度

如下图

最后移动标签的位置与刻度的位置即可

let _g = axisG.append("g").call(_axisX)
    _g.attr("transform", "translate(" + 0 + "," + position.top + ")"); // 移动刻度位置
    _g.selectAll(".tick line") // 移动最左边刻度位置
      .attr("y2", item => {
        // console.log(item)
        if (item === 0) {
          return 6
        } else {
          return -6
        }
      })
    _g.selectAll(".tick text") // 移动最左边刻度对应的文字
      .attr("y", item => {
        // console.log(item)
        if (item === 0) {
          return 16
        } else {
          return -10
        }
      })
  }

比例尺位置竖向排列

在之前的方案是先进行旋转,旋转之后在获取比例尺中的g标签的高度,然后再进行一次重新覆盖旋转再将要移动的高度加上去,这里就需要绘制两次。这个方案不太行,以下方案可以解决坐标旋转的问题代码如下:

_axisG.selectAll("text").attr('text-anchor', 'end').attr('y', 6).attr('transform', (d, index) => {
                if (isXRoate) {
                    return 'translate(-10,' + 5 + ') rotate(-90)'
                } else {
                    return 'translate(0,0)'
                }
            })

 以上代码只需两步即可搞定,首先是将文字让其末尾对齐,也就是text-anchor:end

然后再进行旋转即可。 这里的-10是旋转之后与坐标的距离存在的偏差值,比如你当前的字体是14px,可能要往左移动7px才能达到居中,这里的5则为与上边的高度距离。最终结果如下:

比例尺均匀分布ticks

代码如下:

let axisX = d3
    .axisBottom(scaleX) // 创建比例尺
    .ticks(4)

 这里的ticks是将连续比例尺均匀分布多少分,比如传递4则表示分布为四分。

如下图

注意:这个函数是在创建比例尺的时候调用的也不是定义比例尺时调用。(不是在scalex里调用的)

注意:这个函数也只对连续比例尺才有效,其他的无效

    1. 绘制矩形图

      1. 源码

g.selectAll("rect")

  .data([{

    name:'a',

    value:100

  },{

    name:'b',

    value:20

  },{

    name:'c',

    value:50

  },{

    name:'d',

    value:80

  },{

    name:'e',

    value:200

  }])

  .enter()

  .append("rect")

  .attr("x", function(d) { return scaleX(d.name); })

  .attr("y", function(d) { return scaleY(Math.max(0, d.value)); })

  .attr("width", scaleX.bandwidth()*0.8)

  .attr("height", function(d) { return Math.abs(scaleY(d.value) - scaleY(0)); })

  .attr("fill", function(d) { return d.value < 0 ? "#f44336" : "#4caf50"; });

g.selecltAll这里也要注意矩形图绘制的地方在哪里,这里是选择的是g元素。

这个selectAl(“rect”)相当于创建了一个正方形

data 这表示里面筛入的数据,数组类型格式都不重要,重要的是数据先塞进去,后续再处理。

enter 将数据挂载进去,也就是绑定进去。

append(‘rect’) 将正方形塞进去,也就是渲染dom节点。

attr("x", function(d) { return scaleX(d.name); }) 塞进去之后在调整x轴的位置,这里第二个参数则可以接函数来动态设置值,而scaleX(d.name)函数则表示从上面的x轴中找到该名称对应的位置。比如d.name为a 则会寻找上面的 d3.scaleBand() .domain([‘a’,’b’,’c’]) 这块a对应的位置。

.attr("y", function(d) { return scaleY(Math.max(0, d.value)); })同理y轴位置也是如此。

.attr("width", scaleX.bandwidth()*0.8) 矩形的宽度

.attr("height", function(d) { return Math.abs(scaleY(d.value) - scaleY(0)); }) 矩形的高度,这边的属性其实都支持动态函数变化。

.attr("fill", function(d) { return d.value < 0 ? "#f44336" : "#4caf50"; }); 则为填充色

绘制线条

x轴网格线

代码如下:

let lineXdata = d3.range(-3, 4, 1)  // x轴参考线
g.selectAll('xLine')
        .data(lineXdata)
        .enter()
        .append('line')
        .attr('x1', (d) => {
            return scaleX(d)
        })
        .attr('y1', scaleY(maxY))
        .attr('x2', (d) => {
            return scaleX(d)
        })
        .attr('y2', scaleY(minY))
        .attr('stroke', '#CCC')
        .attr('stroke-width', '1')

加上此属性可改为虚线绘制

.attr("stroke-dasharray", "5,5");

以上代码则是绘制x轴网格线

绘制椭圆

代码如下:

var ellipseGenerator = d3.line() // 创建一个椭圆生成器函数
            .x(function (d) { return scaleX(d[0]); })
            .y(function (d) { return scaleY(d[1]); })
            .curve(d3.curveLinearClosed);
        var ellipsePath = g.append("path")
            .attr("d", ellipseGenerator(data.circle[key]))
            .attr("fill", function (d) {
                var color = d3.color(otherConfig[key].color);
                return `rgba(${color.r}, ${color.g}, ${color.b}, 0.5)`;
            })
            .style("stroke", function (d) {
                return otherConfig[key].color;
            })
            .style("stroke-opacity", 0.7);

先定义一个椭圆函数,然后筛入数据将数据用椭圆函数处理, 最后用path将处理后端数据连接起来。这里的data.circle[key]的数据结果为[[1,1],[2,2],[3,1]...]二位坐标数组

fill则为椭圆的填充色

stroke则为边框线的颜色

绘制圆

cellg.append("circle")

        .attr("transform", (d) => {

          return `translate(${-circleSize/2},${-circleSize/2})`; // x轴根据次数来移动过,y轴根据坐标来移动

        })

        .attr("cx", function (d) {

          return circleSize;

        })

        .attr("cy", function (d) {

          return circleSize - circleSize / 2;

        })

        .attr("r", function (d) {

          return circleSize;

        })

        .attr("fill", function (d) {

            return colors[d.groupName].color

        });

绘制方块

cellg.append("rect") // 添加一个白色背景

    .attr("width", width)

    .attr("height", height)

    .attr("fill", "#fff")

    .attr("x", 0)

    .attr("y", 0);

d3内置函数

获取最大值与最小值

let arr = [0,2,54,13,66]
d3.max(arr) // 66
d3.min(arr) // 0

创建范围值

d3.range

三个参数,第一个是起始位置,第二个是结束位置,第三个是步数代码如下

d3.range(5) // [0,1,2,3,4]
d3.range(5,10) //  [5, 6, 7, 8, 9]
d3.range(5,10,2) // [5, 7, 9]

数据循环each函数

在以上示例中我们可以看到几乎所有的属性都支持设置函数定义

append(‘rect’).attr("x", function(d)

而如果我想实现不同的数据类型,绘制不同的形状,或者添加不同的线条等,如何实现呢?

这里我们就可以用到each函数了。代码如下:

const pointG = g
  .selectAll(".point")
  .data(data.point)
  .enter()
  .append("g")
  .attr("transform", (d) => {
    return `translate(${scaleX(d.x)}, ${scaleY(d.y)})`;
  });
pointG.each(function(d) {
  let shape;
  if (d.type === "rect") {
    shape = "rect";
    d3.select(this).append(shape)
      .attr("width", 20)
      .attr("height", 20)
      .style("fill", "steelblue");
  } else if (d.type === "circle") {
    shape = "circle";
    d3.select(this).append(shape)
      .attr("r", 10)
      .style("fill", "steelblue");
  } else if (d.type === "triangle") {
    shape = "polygon";
    const points = "0,-10 10,10 -10,10"; // 定义三角形的顶点坐标
    d3.select(this).append(shape)
      .attr("points", points)
      .style("fill", "steelblue");
  }
});

也就是数据塞进去之后,我们可以通过each函数来循环数据,

而不是自己手动将数据进行过滤,再判断形状,再重新筛入过滤之后的数据来重新绘制了。

颜色类型转换函数d3.color转rgb格式

如下图

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

web前端神器

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值