2016-04-02 4 views
5

「なぜこの男はこの問題について助けを求めているのですか?これは1000xに実装されています」 - あなたが大抵正しい間に、私はこの問題をいくつか開いて解決しようとしましたソースライブラリはまだここにあります。SVGズームインマウス - 数学モデル

私はSVGベースの「マウスホイールをズームインし、マウスに焦点を当てる」をゼロから実装しようとしています。

これを実現するライブラリがたくさんあることは知っていますが、d3とsvg-pan-zoomはカップルに名前を付けます。残念ながら、これらのライブラリを使用している私の実装は、私の期待に足りないものです。私は、このタイプのUI機能の基礎となる数学的モデルを使ってコミュニティからいくつかの助けを得ることができることを期待していました。

基本的には、Googleマップと同じように、ユーザーがマウスをある場所に置いてマウスホイールを(内向きに)スクロールし、地図画像の縮尺が大きくなります。ビューポートの水平および垂直中心。

もちろん、私はビューポートの幅/高さとマウスのx/yにアクセスできます。この例では

は、私は、正方形は100の単位幅で、ビューポート900の単位幅であるx軸に焦点を当て、それはオフセットXの400個の単位であり、スケールは1:1で

<g transform="translate(0 0) scale(1)"> 
マウスのx位置を仮定 は

enter image description here

、450単位またはその付近であった場合にスケールが2に達するまでにユーザホイール:1、Iだろう期待-450単位に到達するxオフセット、そうのようなフォーカスの点を中心。

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

enter image description here

x及びyオフセットは、現在のスケール/マウスオフセットの関数としてのホイールスクロールの各増分に再計算される必要があります。

すべての私の試みは、望ましい動作に完全に足りなくなっています。アドバイスをいただければ幸いです。

私は助けていただきありがとうございますが、第三者図書館、jQueryプラグイン、そのようなものへの提案にはお答えください。私のここでの目的は、この問題の背後にある数学的モデルを一般的な意味で理解することです。私のSVGの使用は主に例示的なものです。

答えて

5

私は通常、3つの可変オフセットxオフセットyとスケールを維持しています。要素<g transform="translate(0 0) scale(1)">のようなコンテナグループへの変換として適用されます。

マウスが原点を超える場合、新しい翻訳は簡単に計算できます。あなただけの規模の違いによって相殺xとyを掛け:

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

あなたは何ができるか、マウスが原点になるように、オフセット変換です。それから、スケールを調整して、すべてのものを元に戻します。あなたが望むだけ何をすべきかscaleRelativeTo方法があり、このtypescriptですクラスを見てください:

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)によって与えられ、スクロールイベントは、あなたが新しいスケールnewScaleにつながる(mouseX, mouseY)で行われた変換を与えた場合

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

ここで、ちょうど美しい - ありがとうございます – James