我是TypeScript的新手,正在尝试使用D3.js创建一个具有两个句柄的简单范围滑块。
我为滑块对象创建了一个基本类:
export class VerticalRangeSlider{
private sliderContainer: d3.Selection<SVGGElement, any, HTMLDivElement, any>;
private scale: d3.ScaleLinear<number, number>;
private sliderTopBound: number;
private sliderBottomBound: number;
private handleTopY: number;
private handleBottomY: number;
private handleTop: d3.Selection<SVGCircleElement, any, HTMLDivElement, any>;
private handleBottom: d3.Selection<SVGCircleElement, any, HTMLDivElement, any>;
constructor(slContainer: d3.Selection<SVGGElement, any, HTMLDivElement, any>, scl: d3.ScaleLinear<number, number>){
this.sliderContainer = slContainer;
this.scale = scl;
this.sliderTopBound = 0;
this.sliderBottomBound = scl.range()[0];
this.handleTopY = this.sliderTopBound;
this.handleBottomY = this.sliderBottomBound;
this.initSlider();
}
这两个句柄是在initSlider方法中创建的。我有一个用于处理拖动事件的匿名函数,该函数调用moveHandle方法来重新渲染圆圈。
因为我发现 this。在匿名函数中具有不同的上下文,所以我在initSlider中声明了一个变量来保存指向父对象的指针:var parentObject = this;
。
this.handleTop = this.sliderContainer.insert("circle", ".track-overlay")
.attr("class", "handle")
.attr("r", 9)
.attr("cy", this.handleTopY)
.attr("desc", this.handleTopY)
.call(d3.drag()
.on('drag', function(){
parentObject.moveHandle(parentObject.handleTop, parentObject.handleTopY, d3.event.dy, parentObject.sliderTopBound, parentObject.handleBottomY);
}));
this.handleBottom = this.sliderContainer.insert("circle", ".track-overlay")
.attr("class", "handle")
.attr("r", 9)
.attr("cy", this.handleBottomY)
.attr("desc", this.handleBottomY)
.call(d3.drag()
.on('drag', function(){
parentObject.moveHandle(parentObject.handleBottom, parentObject.handleBottomY, d3.event.dy, parentObject.handleTopY, parentObject.sliderBottomBound);
}));
我遇到了moveHandle方法的问题:
private moveHandle(handle: d3.Selection<SVGCircleElement, any, HTMLDivElement, any>, currentPosition: number, increment: number, topBound: number, bottomBound:number): void {
var legalIncrement: number;
//upward movement
if(Math.sign(increment) === -1){
legalIncrement = increment <= (currentPosition - topBound) ? increment : (currentPosition - topBound);
console.log("allowed increment: "+legalIncrement);
}
//downward movement
else {
legalIncrement = increment <= (bottomBound - currentPosition) ? increment : (bottomBound - currentPosition);
console.log("allowed increment: "+legalIncrement);
}
if(legalIncrement !== 0){
currentPosition = (currentPosition + legalIncrement)
handle.attr("transform", "translate(0," + currentPosition + ")");
}
}
当我尝试拖动圆时,它们会按预期进行短暂渲染,但随后会立即捕捉回到其原始位置。
但是,当我直接将指向父对象的指针传递到moveHandle中时,一切正常:parentObject: VerticalRangeSlider): void {
parentObject.handleBottomY = parentObject.handleBottomY + increment; parentObject.handleBottom.attr("cy", parentObject.handleBottomY);
最初的假设是我将指向父对象属性的指针传递给方法,但事实并非如此。我最好的理论是改为创建新对象。
我非常感谢对此行为的任何见解(以及为更好地构建我的JS / TS代码而提供的任何反馈)。
谢谢!
答案 0 :(得分:0)
在您的代码中,最终需要引用父级。要变通解决此问题,您可以使用arrow functions。用function () {}
格式定义的函数将创建自己的this
,因此像您使用this
一样,保留对父级parentObject
的引用
另一方面,箭头功能(=>
形式)不绑定自己的this
。这意味着箭头功能中的this
指向父级this
,您不需要引用:您可以直接使用this
我们也可以将drag
处理程序更改为箭头函数。
这是您的代码,但有一些更改。这可能并不完全正确,因为我可能错过了一些意思:让我知道。
this.handleTop = this.sliderContainer.insert("circle", ".track-overlay")
.attr("class", "handle")
.attr("r", 9)
.attr("cy", this.handleTopY)
.attr("desc", this.handleTopY)
.call(d3.drag()
.on('drag', () =>
this.moveHandle(this.handleTop, this.handleTopY, d3.event.dy, this.sliderTopBound, this.handleBottomY);
);
this.handleBottom = this.sliderContainer.insert("circle", ".track-overlay")
.attr("class", "handle")
.attr("r", 9)
.attr("cy", this.handleBottomY)
.attr("desc", this.handleBottomY)
.call(d3.drag()
.on('drag', () => this.moveHandle(this.handleBottomY, this.handleTopY, d3.event.y, this.sliderBottomBound);
);
private moveHandle = (currentPosition: number, topBound: number, increment:number, bottomBound:number): void => {
var legalIncrement: number;
//upward movement
if(Math.sign(increment) === -1){
legalIncrement = increment <= (currentPosition - topBound) ? increment : (currentPosition - topBound);
console.log("allowed increment: "+legalIncrement);
}
//downward movement
else {
legalIncrement = increment <= (bottomBound - currentPosition) ? increment : (bottomBound - currentPosition);
console.log("allowed increment: "+legalIncrement);
}
if(legalIncrement !== 0){
currentPosition = (currentPosition + legalIncrement)
this.attr("transform", "translate(0," + currentPosition + ")");
}
}