2016-04-02 37 views
5

在你认为“为什么这个人在这个问题上寻求帮助,当然这已经实现了1000倍” - 虽然你基本上是正确的,但我试图通过几次打开来解决这个问题源代码库,但我在这里。SVG放大鼠标 - 数学模型

我试图从头开始实现基于SVG的“放大鼠标滚轮,重点放在鼠标上”。

我知道有很多库可以实现这一点,d3和svg-pan-zoom来命名一对夫妇。不幸的是,我使用这些库的实现没有达到我的预期。我希望能从这个社区获得一些帮助,帮助他们了解这种UI功能的基础数学模型。

基本上,所需的行为就像Google地图,用户将鼠标悬停在某个位置上,滚动鼠标滚轮(向内),地图图像的比例增加,而位置悬停的位置成为视口的水平和垂直中心。

当然,我可以访问视口的宽度/高度和鼠标的x/y。

在本例中,我将只集中在x轴上,视口是900个单位宽,正方形为100个单位宽,它的x偏移量是400个单位,和比例为1:1

<g transform="translate(0 0) scale(1)"> 

enter image description here

假设鼠标x位置是在或接近450个单位,如果用户车轮在直到规模达到2:1,我期望的x偏移量达到-450单位,围绕焦点的像这样的点。

<g transform="translate(-450 0) scale(2)"> 

enter image description here

的x和y偏移需要在车轮滚动的每个增量为当前尺度/小鼠偏移的函数重新计算。

我所有的尝试已经完全没有达到预期的行为,任何建议表示赞赏。

虽然我很感激任何帮助,但请不要回答建议第三方库,jQuery插件和这种性质的东西。我的目标是从一般意义上理解这个问题背后的数学模型,我使用SVG主要是说明性的。

回答

5

我通常做的是我维护三个可变的偏移量x偏移量y和比例。它们将作为转换应用于容器组,如元素<g transform="translate(0 0) scale(1)">

如果鼠标位于原点之上,新的转换将会很微不足道。你只是在规模乘以偏移x和y的区别:

offsetX = offsetX * newScale/scale 
offsetY = offsetY * newScale/scale 

你可以做的是翻译的偏移,使鼠标在原点。然后你缩放,然后你把所有的东西都翻译回来。看一看具有scaleRelativeTo方法只是做这个打字稿类,你想要什么:

export class Point implements Interfaces.IPoint { 
    x: number; 
    y: number; 

    public constructor(x: number, y: number) { 
     this.x = x; 
     this.y = y; 
    } 

    add(p: Interfaces.IPoint): Point { 
     return new Point(this.x + p.x, this.y + p.y); 
    } 

    snapTo(gridX: number, gridY: number): Point { 
     var x = Math.round(this.x/gridX) * gridX; 
     var y = Math.round(this.y/gridY) * gridY; 
     return new Point(x, y); 
    } 

    scale(factor: number): Point { 
     return new Point(this.x * factor, this.y * factor); 
    } 

    scaleRelativeTo(point: Interfaces.IPoint, factor: number): Point { 

     return this.subtract(point).scale(factor).add(point); 
    } 

    subtract(p: Interfaces.IPoint): Point { 
     return new Point(this.x - p.x, this.y - p.y); 
    } 

    } 

所以,如果你给变换鉴于translate(offsetX,offsetY) scale(scale)和滚动事件发生在(mouseX, mouseY)引领到一个新的规模newScale你将通过以下方式计算新变换:

offsetX = (offsetX - mouseX) * newScale/scale + mouseX 
offsetY = (offsetY - mouseY) * newScale/scale + mouseY 
+0

在那里,最后,只是美丽 - 谢谢你 – James