天天看点

d3.js 操控SVG、坐标轴(02)

前言:本篇主要内容是svg的操控。使用D3获取、修改、删除节点(图元),比例尺,使用d3绘制简单柱状图,引入坐标轴。

一、使用D3查询SVG

1.1 d3.select()

  • d3.select('#red')

    ,即查询Id为‘red’的元素。
  • de.select('.red')

    ,只会返回找到的第一个元素。
    • 因此对于class、标签名称的查询建议使用d3.selectAll
    • 对于特定某个元素的查询建议使用d3.select

1.2 d3.selectAll()

  • d3.selectAll('.green')

    ,即查询所有class是‘green’的元素
  • d3.selectAll('rect')

    ,即查询所有标签是‘rect’的元素(rect为svg中的矩形标签)

1.3基于层级的查询

  • d3.select('#red rect')

    ,即查找id为red的标签,进一步查找id为red的子标签中是rect的。(结果通过父标签做了筛选)
  • 这种形式的查询,经常会在配置坐标轴的代码中使用。

二、使用D3设置svg中的属性

父节点的属性会影响子节点

子节点的属性会相对于父节点

2.1常见的属性

  • id,class(特殊的属性,可以使用.attr设置)
  • x,y,cx,cy(cx,cy为圆的坐标轴)
  • fill(填充),stroke(边缘)
  • height,width,r(圆的半径)
  • transform -> translate ,rotate,scale
  • 其余属性可查阅

https://developer.mozilla.org/zh-CN/docs/Web/SVG/Attribute

2.2 屏幕空间的坐标轴

屏幕空间的坐标轴与常见坐标轴不同

  • 左上方为原定
  • Y、X分别为垂直向下、水平向右
    d3.js 操控SVG、坐标轴(02)

2.3 element.attr

  • 设置元素的属性:

    element.attr('attr_name','attr_value')

  • 获取元素的属性:

    element.attr('attr_name')

  • 注意:数值类型的数据仍在HTML中仍由字符串存储

三、使用D3添加或删除svg元素

不管是添加还是删除,在进行操作前都要先选择元素。

3.1添加 element.append()

const myred = svg.append('rect')  //添加矩形
const myred = d3.select('#mainsvg').append('rect')
const myred = d3.select('#mainsvg').append('rect').attr('x','100')
           

链式添加

以下代码为在选择了id为mainsvg的元素,为他添加组,并为这个组设置id值。

3.2 删除element.remove()

  • 要小心使用,会移除整个标签
  • 在debug的过程中可以考虑使用‘

    opacity

    '属性hack出移除的效果
element.attr('opacity','0')
d3.select('myred').remove
           

四、比例尺

  • 比例尺用于把实际的数据空间映射到屏幕的空间
  • 比例尺非常重要,会经常同时传给坐标轴与数据

4.1Scale是函数

通过

d3.scaleLinear

d3.scaleBand

得到的返回值本质上是函数

  • 给出数据中的值(domain)
  • 返回映射后的值(range)
  • .domain(…)和 .range(…)可以理解为配置这个函数(功能)的过程
  • 比例尺的定义仍适用链式调用
const xScale = d3.scaleLinear()
.domain([0,d3.max(data,datum=>datum.value)])
.range([0,innerWidth]);
const map = xScale(100)
           

一个栗子:

const myred = d3.scaleLinear().domain([0,10]).range([-1000,1000])
myred(5)   //结果是0
myred(9)   //结果是800
myred(2)   //结果是-600
           

五、一个小例子(实现柱状图)

d3.js 操控SVG、坐标轴(02)
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>用d3实现柱状图</title>
    <script src='https://d3js.org/d3.v5.min.js'></script>
</head>
<body>
    <svg width="1600" height="800" id="mainsvg" class="svgs"></svg>
    <script>
        //定义数据
        const data = [{name:'红红',age:18},
        {name:'绿绿',age:20},{name:'泡泡',age:9},{name:'果果',age:1},
        {name:'红泡泡',age:9},{name:'绿果果',age:6},{name:'小明',age:3},
        {name:'小绿绿',age:4},{name:'小果果',age:10},{name:'花花',age:5},
        {name:'小张',age:12},{name:'小结',age:16},{name:'二狗子',age:9}];

        //设置画布的宽高
        const svg = d3.select('#mainsvg');
        const width = +svg.attr('width');
        const height = +svg.attr('height');
        const margin = {top:60,right:30,bottom:60,left:150};
        const innerWidth = width - margin.left - margin.right;
        const innerHeight = height - margin.top - margin.bottom;
        
        //设置xy轴的最大最小值
        const xScale = d3.scaleLinear()
        .domain([0,d3.max(data,d=>d.age)])  //获取数据中的最大值,d=>d.age是一个回调函数
        .range([0,innerWidth]);   //映射的最大值和最小值

        const yScale = d3.scaleBand()
        .domain(data.map(d=>d.name))   //获取y轴的值,data.map
        .range([0,innerHeight])
        .padding(0.1);   //调整条带柱状之间的间隔
        
        //添加坐标轴画布
        const g = svg.append('g').attr('id','maingroup')
        .attr('transform',`translate(${margin.left},${margin.top})`);

        //定义y轴
        const y = d3.axisLeft(yScale);
        g.append('g').call(y);
        //定义x轴
        const x = d3.axisBottom(xScale);
        g.append('g').call(x).attr('transform',`translate(0,${innerHeight})`);
         
        //添加柱状条形图
        data.forEach( d=>{
            g.append('rect')
            .attr('width',xScale(d.age))  //条形柱状的宽度
            .attr('height',yScale.bandwidth())
            .attr('fill','green')
            .attr('y',yScale(d.name))  //映射位置
        });

        //修改坐标轴的字体大小
        d3.selectAll('.tick text').attr('font-size','2rem'); //.tick是d3里给出的属性

        //添加标题
        g.append('text').text('绿泡泡绿泡泡绿绿绿')
        .attr('font-size','3rem')
        .attr('transform',`translate(${innerWidth/2},0)`)  //文字的左边居中
        .attr('text-anchor','middle')    //文字的中心点居中
    </script>
</body>
</html>
           

总结:

  • 要设置画布的宽高、边距、边框等属性、
  • 设置xy轴的最大值
  • 添加坐标轴的画布,定义坐标轴,实际配置的坐标轴、
  • 添加柱状的条形图
  • 修改一些默认的配置等

注意:

  • 实际配置后会发现

    <g>

    中添加了与坐标轴相关的元素
  • 任何坐标轴在初始化之后会默认放置在坐标原点,需要进一步的平移。

继续阅读