【问题标题】:How to get axis ticks out of d3 without rendering in SVG?如何在不渲染 SVG 的情况下从 d3 中获取轴刻度?
【发布时间】:2017-11-21 23:29:21
【问题描述】:

我正在使用画布实现 2d 图表。我想重用 d3 的逻辑来生成图表的轴。 d3 在生成轴方面做了很多出色的工作,我想利用它。

(注意:出于向后兼容的原因,我暂时无法使用 d3v3。)

考虑以下 d3 代码:

let scale = d3.time.scale()
    .range([0, width])
    .domain([lo, hi]);
let axis = d3.svg.axis()
    .scale(scale)
    .ticks(num_ticks)
    .tickSize(10)
    .orient("bottom");

我可以将其渲染为图表 div:

svg.selectAll('.x-axis').call(axis);

我希望能够通过编写一个行为如下的函数以编程方式从axis 中获取刻度数据,包括格式化的标签:

ticks = get_axis_ticks(axis)

ticks 应保存每个刻度位置(在此特定情况下为 Date)和相应的 d3 生成的标签。

[[Date(...), "Wed 19"],
 [Date(...), "Fri 21"],
 [Date(...), "Apr 23"],
 [Date(...), "Tue 25"],
 ...]

然后我可以使用这些数据在我的画布上绘制一个轴。

我已经深入研究了 d3v3 源代码(尤其是这里:https://github.com/d3/d3/blob/v3.5.17/src/svg/axis.js),但我发现很难将逻辑与 SVG 操作区分开来。

我们将不胜感激。

【问题讨论】:

    标签: javascript d3.js


    【解决方案1】:

    我的一个想法是使用您创建的刻度函数来生成您想要的刻度并将它们推送到数组中。

    作为一个非常简单的例子,如果您想要 10 个刻度,每个刻度以 1 为单位递增,您可以执行以下操作:https://jsfiddle.net/Q5Jag/3148/

    //define dummy values
    var lo = 1;
    var hi = 10;
    var width = 512
    var scale = d3.time.scale()
        .range([0, width])
        .domain([lo, hi]);
    
    //define your function
    var get_x_axis = function() {
        let axisArr = [];
        for(var i = 0; i < 10; i++ ) {
        //calculate your value
        axisArr.push(scale(i))
      }
      return axisArr
    }
    
    //call it
    let axisTicks = get_x_axis()
    
    //log it
    console.log(axisTicks)
    

    我不确定这是否是您正在寻找的,但如果您需要进一步的帮助,请询问。

    【讨论】:

    • 谢谢亚历克斯!我发现 scale.ticks(10) 基本上按照您的建议进行,但返回的位置在整齐的边界上对齐。例如。如果您正在处理时间,它们会在日期边界、小时边界等上对齐。
    【解决方案2】:

    我能够得到这个工作。我在 d3 文档中找到了时间格式化策略:https://github.com/d3/d3-3.x-api-reference/blob/master/Time-Formatting.md#format_multi 我相信这是 d3 本身在用户不提供自定义格式时默认使用的策略。

    我了解到,只需调用 scale.ticks(N) 将返回适合在轴上渲染的 Nish 刻度。这些刻度值是在自然边界上选择的。例如,如果您使用时间轴,这些刻度将在分钟、小时、天的边界上对齐。

    这里有一个解决方案:

    let time_format = d3.time.format.multi([
      [".%L", d => d.getMilliseconds()],
      [":%S", d => d.getSeconds()],
      ["%I:%M", d => d.getMinutes()],
      ["%I %p", d => d.getHours()],
      ["%a %d", d => d.getDay() && d.getDate() !== 1],
      ["%b %d", d => d.getDate() !== 1],
      ["%B", d => d.getMonth()],
      ["%Y", () => true]
    ]);
    
    let get_ticks = (width, lo, hi, num_ticks) => {
      let scale = d3.time.scale().range([0, width]).domain([lo, hi]);
      return scale.ticks(num_ticks).map(t => [t, time_format(t)]);
    };
    

    【讨论】:

      猜你喜欢
      • 2014-12-14
      • 1970-01-01
      • 2016-03-23
      • 2012-11-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-04-19
      相关资源
      最近更新 更多