我目前在画布上有一个d3分层圆包图(在this awesome tutorial!的帮助下)
除了放大节点外,我还想使图形也可以用鼠标平移并用滚轮缩放。 I used this.
现在,当我第一次平移然后使用初始比例缩放到节点时(页面首次加载时),它会按预期工作。它会从图形的最后平移位置放大到该节点。
但是,当我尝试从缩放状态进行平移和缩放时,视图将在一个完全不同的位置开始,然后在预期的节点处结束。如果从缩放状态不平移,而是从一个节点跳转/缩放到另一个节点,则过渡将按预期工作。我不确定为什么会这样。谁能帮我弄清楚我在做什么错?预先感谢!
(很抱歉有任何假冒行为-这是我的第一个堆栈溢出问题...)
@ViewChild('myCanvas') canvas: ElementRef;
@ViewChild('myCanvas') hiddenCanvas: ElementRef;
public context: CanvasRenderingContext2D;
public hiddenContext: CanvasRenderingContext2D;
public focus;
public xleftView = 0;
public ytopView = 0;
public widthViewOriginal = window.innerWidth;
public heightViewOriginal = window.innerHeight;
public widthView = this.widthViewOriginal;
public heightView = this.heightViewOriginal;
public widthCanvas = window.innerWidth;
public heightCanvas = window.innerHeight;
public mouseDown = false;
public movedCoordinatesX;
public movedCoordinatesY;
public lastX = 0;
public lastY = 0;
public zoomInfo = {
centerX: window.innerWidth / 2,
centerY: window.innerHeight / 2,
scale: 1
};
public handleMouseDown(event) {
// get where the mouse first clicked to pan the graph
this.movedCoordinatesX = event.clientX
this.movedCoordinatesY = event.clientY
if (event.which === 1) {
this.mouseDown = true;
}
}
public handleMouseUp(event) {
this.mouseDown = false;
// Get the distance moved in the x & y direction from the initial click to the end mouse position
this.movedCoordinatesX = this.movedCoordinatesX - event.clientX
this.movedCoordinatesY = this.movedCoordinatesY - event.clientY
// add distance in the X & Y to the old view's X & Y (to make the transition happen from the current position
this.vOld[0] = (this.vOld[0] + this.movedCoordinatesX)
this.vOld[1] = (this.vOld[1] + this.movedCoordinatesY)
}
public handleMouseMove(event) {
var X = event.clientX - this.context.canvas.offsetLeft - this.context.canvas.clientLeft + this.context.canvas.scrollLeft;
var Y = event.clientY - this.context.canvas.offsetTop - this.context.canvas.clientTop + this.context.canvas.scrollTop;
if (this.mouseDown) {
var dx = (X - this.lastX) / this.widthCanvas * this.widthView;
var dy = (Y - this.lastY)/ this.heightCanvas * this.heightView;
this.xleftView -= dx;
this.ytopView -= dy;
}
this.lastX = X;
this.lastY = Y;
}
// Listen for clicks on the main canvas
public zoomInToNode(e) {
// We actually only need to draw the hidden canvas when there is an interaction.
// This sketch can draw it on each loop, but that is only for demonstration.
this.drawCanvas(this.hiddenContext, true);
//Figure out where the mouse click occurred.
var mouseX = e.layerX;
var mouseY = e.layerY;
this.lastX = mouseX
this.lastY = mouseY
// Get the corresponding pixel color on the hidden canvas and look up the node in our map.
// This will return that pixel's color
var col = this.hiddenContext.getImageData(mouseX, mouseY, 1, 1).data;
//Our map uses these rgb strings as keys to nodes.
var colString = "rgb(" + col[0] + "," + col[1] + ","+ col[2] + ")";
var node = this.colToCircle[colString];
if(node) {
if (this.focus !== node) {
this.xleftView = 0
this.ytopView = 0
this.hiddenContext.setTransform(1, 0, 0, 1, 0, 0);
this.zoomToCanvas(node);
}
else {
this.xleftView = 0
this.ytopView = 0
this.hiddenContext.setTransform(1, 0, 0, 1, 0, 0);
this. widthView = this.widthViewOriginal;
this. heightView = this.heightViewOriginal;
this. widthCanvas = window.innerWidth;
this. heightCanvas = window.innerHeight;
this.zoomToCanvas(this.rooting);
}
}//if
};
public zoomToCanvas(focusNode) {
// the node that we want to zoom to
this.focus = focusNode;
var v = [this.focus.x, this.focus.y, this.focus.r * 2.05]; //The center and width of the new "viewport"
this.interpolator = d3.interpolateZoom(this.vOld, v); //Create interpolation between current and new "viewport"
this.duration = this.interpolator.duration; //Interpolation gives back a suggested duration
this.timeElapsed = 0; //Set the time elapsed for the interpolateZoom function to 0
this.vOld = v; //Save the "viewport" of the next state as the next "old" state
}//function zoomToCanvas
// Perform the interpolation and continuously change the zoomInfo while the "transition" occurs
public interpolateZoom(dt) {
if (this.interpolator) {
this.timeElapsed += dt;
var t = this.ease(this.timeElapsed / this.duration);
if(isFinite(t)) {
this.zoomInfo.centerX = this.interpolator(t)[0];
this.zoomInfo.centerY = this.interpolator(t)[1];
this.zoomInfo.scale = this.diameter / this.interpolator(t)[2];
if (this.timeElapsed >= this.duration) this.interpolator = null;
}
}//if
}//function zoomToCanvas
public drawCanvas(chosenContext, hidden) {
chosenContext.save();
chosenContext.setTransform(1,0,0,1,0,0);
chosenContext.clearRect(0, 0, this.canvas.nativeElement.width, this.canvas.nativeElement.height);
chosenContext.scale(this.widthCanvas/this.widthView, this.heightCanvas/this.heightView);
chosenContext.translate(-this.xleftView,-this.ytopView);
chosenContext.restore();
}
答案 0 :(得分:0)
所以我想通了...我应该除以总体规模。
我真的很感谢this answer给我的启发!
public handleMouseUp(event) {
this.mouseDown = false;
this.movedCoordinatesX = this.movedCoordinatesX - event.clientX
this.movedCoordinatesY = this.movedCoordinatesY - event.clientY
if(this.zoomInfo.scale == 1) {
this.vOld[0] = (this.vOld[0] + this.movedCoordinatesX)
this.vOld[1] = (this.vOld[1] + this.movedCoordinatesY)
} else {
this.vOld[0] = (this.vOld[0] + (this.movedCoordinatesX/this.zoomInfo.scale))
this.vOld[1] = (this.vOld[1] + (this.movedCoordinatesY/this.zoomInfo.scale))
}
}