数据结构 D3 画的 SVG 坐标轴的 HTML 结构如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 <g transform ="translate(20, 300)" class ="myXaxis" fill ="none" font-size ="10" font-family ="sans-serif" text-anchor ="middle" > <path class ="domain" stroke ="currentColor" d ="M20.5,0.5H800.5" style ="color: rgb(181, 181, 183);" > </path > <g class ="tick" opacity ="1" transform ="translate(71.3695652173846,0)" style ="font-weight: bold; font-size: 15px; opacity: 1; color: rgb(112, 113, 125);" > <line stroke ="currentColor" y2 ="0" > </line > <text fill ="currentColor" y ="10" dy ="0.71em" > 2015</text > </g > <g class ="tick" opacity ="1" transform ="translate(240.9347826086923,0)" style ="font-weight: bold; font-size: 15px; opacity: 1; color: rgb(112, 113, 125);" > <line stroke ="currentColor" y2 ="0" > </line > <text fill ="currentColor" y ="10" dy ="0.71em" > 2016</text > </g ></g >
从上述结构可以得出如下结论:
每个坐标轴都包含在一个 g 标签中
每个坐标轴有一个 path 元素,对应轴线,且该元素默认有一个.domain 的样式
坐标轴的.domain,包含有内刻度和外刻度(通过 tickSizeOuter(123)设置)
每个坐标轴有 N 个 g 元素,对应刻度,每个刻度默认有一个.tick 的样式
每个刻度由一个 line 元素(刻度线)和一个 text 元素(每个刻度的值文本)构成
path 的颜色:stroke 和 color 都可以设置
path 的宽度:通过 stroke-width 设置,且不能带 px 单位,只能是纯数值
axis 的样式设置,必须在 call 之后才能生效
实现方案 网格线 按常规思路来看,网格线就是直线/虚线,那么我们只需要计算好位置,然后通过 line 或者 path 画线条即可。不过这里有一个更精妙的方法,就是将刻度长度设置为负数,即反向延长坐标轴的刻度线:
1 2 3 4 5 6 7 yAxis .ticks (5 ) .tickSizeOuter (0 ) .tickSizeInner (-1 * this .maxXPosition + this .minXPosition ) .tickPadding (10 );
指定坐标轴显示的数值 可以通过tickValues()这个方法来指定。但是注意,这个方法对于比例尺有要求,必须是序数比例尺,比如 band、point 比例尺。
1 2 3 4 xAxis .tickValues ([...dates]);
For ordinal scales, such as band and point scales, the scale does not implement scale.ticks because an ordinal scale has no way of knowing which ordinal values from the scale’s domain to prioritize. For an ordinal axis, use axis.tickValues to instead specify which tick values you want.
疑问:序数比例尺可以自动计算显示哪些数值么?
设置坐标轴显示的数值数量 针对 date 类型的 Scale,tickNumber 是无效的。
坐标轴自动填补范围 不能直接用数据的最大值和最小值作为比例尺的范围,否则有些点会超出绘图区域;因此应该需要向上和向下再取一段数值:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 _computeAxisRange (minValue, maxValue, tickNumber ) { let gap = (maxValue - minValue) / tickNumber; const exponent = Math .round (Math .log10 (gap)); gap = 10 ** exponent; const max = (Math .floor (maxValue / gap) + 1 ) * gap; const min = (Math .ceil (minValue / gap) - 1 ) * gap; return { min, max, } }
刻度数值的对齐方式 通过设置 text-anchor 属性来实现:
1 2 3 4 5 6 7 8 9 10 this .group .selectAll ('text' ).style ('text-anchor' , () => { if ( this .option ?.style ?.textAnchor && typeof this .option ?.style ?.textAnchor === 'function' ) { return this .option ?.style ?.textAnchor (); } return this .option ?.style ?.textAnchor ; });
常用代码示例 1 2 3 4 5 6 7 8 9 10 11 12 xAxis .tickValues ([...dates]) .tickSizeOuter (0 ) .tickSizeInner (0 ) .tickPadding (10 );
经验教训 将 X 轴的比例尺设置为了 d3.scaleTime() 这样导致的问题就是组件适配性非常差,因为 X 轴的值很可能并不是一个时间,比如是一个股票代码。
合适的比例尺是 d3.scalePoint()
参考资料 坐标轴的介绍:
http://www.qiutianaimeili.com/html/page/2020/04/2020457heuxpj58al.html
https://juejin.im/post/6844903998772740103