d3 获取 Band Scales 的反转值

d3 getting invert value of Band Scales

我正在使用 d3 编写甘特图

我有 xScale with Time Scale(Time)

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. rect 不应该在资源之间,所以需要根据 d3.event.y 转换到任何波段
    1. 在 xAxis 中的时间尺度有反转但 yScale 没有这个。这该怎么做?

如下解决这个问题,但我不知道这是标准方法,如果有任何其他方法请回答这个问题。

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

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

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

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

当图表的左右两侧有填充时,如果值在图表的条形之外,答案将给出 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