【问题标题】:d3 getting invert value of Band Scalesd3 获得波段尺度的反转值
【发布时间】:2016-12-02 15:38:46
【问题描述】:

我正在使用 d3 编写甘特图

我有 xScale 和时间刻度(时间)

this.xScale = d3.scaleTime()
            .domain([this.startDate,this.endDate])
            .range([0,this.getWidth()]);

和 yScale 作为波段规模(资源)

this.yScale = d3.scaleBand()
        .domain(resources.map(function(res){
            return res.res_num;
        }))
        .rangeRound([0,this.getHeight()])
        .paddingInner(.3)

问题是我需要将任务(SVG Rect)从一个资源拖放到另一个资源

当我拖动时,我使用的是 transfrom,所以它在 SVG 上移动

_onDrag : function(d)
    {
        var x = d3.event.dx+d3.event.x;
        var y = d3.event.dy+d3.event.y;
        d3.select(this).raise().attr("transform","translate(" + [x,y] + ")");
    },

但在放置时我必须处理如下逻辑:

  1. 矩形不应该在资源之间,所以需要转换到基于 d3.event.y 的任意波段
    1. 在 xAxis 中,时间刻度具有反转,但 yScale 没有。这个怎么做?

【问题讨论】:

    标签: javascript d3.js svg transform scaletransform


    【解决方案1】:

    当图表在左右两边都有填充时,如果值在图表的条形之外,答案会给出undefined 作为结果。以下函数可用于考虑此填充并将索引限制为domain 的有效值。

    function scaleBandInvert(scale) {
      var domain = scale.domain();
      var paddingOuter = scale(domain[0]);
      var eachBand = scale.step();
      return function (value) {
        var index = Math.floor(((value - paddingOuter) / eachBand));
        return domain[Math.max(0,Math.min(index, domain.length-1))];
      }
    }
    

    可以这样使用:

    var xScale = d3.scaleBand().domain(...).rangeRound([a,b]);
    ....
    var dvalX = scaleBandInvert(xScale)(value);  // single invert
    ....
    var dRangeX = d3.event.selection.map(scaleBandInvert(xScale));  // in a brush event handler
    

    【讨论】:

    • 感谢您:var paddingOuter = scale(domain[0]);
    • 我发现为了让等分线在条形之间切换,我必须使用Math.roundpaddingInnervar paddingInner = scale.step() * scale.paddingInner();然后var index = Math.round((x - scaleStart - paddingInner / 2) / eachBand);
    【解决方案2】:

    对已接受的答案进行调整 - 您可能希望使用 Math.floor 而不是 Math.round,因为如果您碰巧在项目的中心点下方选择,前者将返回下一个级别。因此修改后的解决方案是:

    var eachBand = self.yScale.step();
    var index = Math.floor((d3.event.y / eachBand));
    var val = self.yScale.domain()[index];
    

    【讨论】:

      【解决方案3】:

      按以下方式解决了这个问题,但我不知道这是标准方式,如果有其他方式请回答。

      var eachBand = self.yScale.step();
      var index = Math.round((d3.event.y / eachBand));
      var val = self.yScale.domain()[index];
      

      eachBand 以像素为单位给出波段的大小 如果我将 y 值(拖动事件)除以 eachBand,我将得到给出 yScale 值的索引

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-03-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-11-17
        相关资源
        最近更新 更多