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] + ")");
},
但是在下降时我必须处理如下逻辑:
- rect 不应该在资源之间,所以需要根据 d3.event.y 转换到任何波段
- 在 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
我正在使用 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] + ")");
},
但是在下降时我必须处理如下逻辑:
- rect 不应该在资源之间,所以需要根据 d3.event.y 转换到任何波段
- 在 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