d3获得Band Scales的反转值

chi*_*igk 9 javascript svg transform scaletransform d3.js

我正在使用d3编写甘特图

我有带时间刻度的xScale(时间)

this.xScale = d3.scaleTime()
            .domain([this.startDate,this.endDate])
            .range([0,this.getWidth()]);
Run Code Online (Sandbox Code Playgroud)

和yScale作为Band Scale(资源)

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

问题是我需要将任务(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] + ")");
    },
Run Code Online (Sandbox Code Playgroud)

但是在下降时我必须处理如下逻辑:

  1. rect不应该在资源之间,因此需要转换为基于d3.event.y的任何band
    1. 在xAx中,时间刻度具有反转但yScale没有这个.这该怎么做?

chi*_*igk 17

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

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

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


Mat*_*Cox 8

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

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


rio*_*oV8 6

当图形左右有填充时,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))];
  }
}
Run Code Online (Sandbox Code Playgroud)

可以如下使用:

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
Run Code Online (Sandbox Code Playgroud)