2012-04-24 4 views
33

SVGドキュメント内のマウスカーソルの位置に関する問題が発生しています。ドラッグしたときにカーソルに追従するポテンショメータを設計したいのですが、JavaScriptをHTMLページで使用しています。オートスケールされたSVG内のマウスの位置

私はevt.clientX/Yとevt.screenX/Yを試しましたが、私のSVGはのautoscaleであり、私のSVG内の座標は異なります。私は数日間の答えを探していましたが、解決策を見つけることができませんでした(私のSVGリスケーリング因子をリアルタイムで知っているか、SVG座標系でマウスの位置を特定する機能があります)。

単純なルールに従う回転:

IF(evt.screenX < XC)

ANG = Math.atan((evt.screenY - YC)/(evt.screenX - XC ))* 360 /(2 *数学的数値) - 90; (evt.screenX> xc)
ang = Math.atan((evt.screenY-yc)/(evt.screenX-xc))* 360 /(2 * Math.PI)+ 90;

(xc; yc)を回転の中心とし、すべてのevt.screenX/YをSVG内のマウス座標で置き換えます。

+0

正しい座標を取得するには、変換行列を操作する必要があります。 jsfiddleが役に立ちます。 – mihai

答えて

85

グローバルSVG空間にスクリーン空間から変換する方法を示しているが、要素の変換された空間内にSVG空間から点を変換する方法だけでなく、このコードは、参照:要するに
http://phrogz.net/svg/drag_under_transformation.xhtml

を:

// Find your root SVG element 
var svg = document.querySelector('svg'); 

// Create an SVGPoint for future math 
var pt = svg.createSVGPoint(); 

// Get point in global SVG space 
function cursorPoint(evt){ 
    pt.x = evt.clientX; pt.y = evt.clientY; 
    return pt.matrixTransform(svg.getScreenCTM().inverse()); 
} 

svg.addEventListener('mousemove',function(evt){ 
    var loc = cursorPoint(evt); 
    // Use loc.x and loc.y here 
},false); 

編集:私は(唯一のグローバルSVG空間であるものの)自分のニーズに合わせたサンプルを作成しました:
http://phrogz.net/svg/rotate-to-point-at-cursor.svg

これは、上記に次のメソッドを追加します。

function rotateElement(el,originX,originY,towardsX,towardsY){ 
    var angle = Math.atan2(towardsY-originY,towardsX-originX); 
    var degrees = angle*180/Math.PI + 90; 
    el.setAttribute(
    'transform', 
    'translate('+originX+','+originY+') ' + 
     'rotate('+degrees+') ' + 
     'translate('+(-originX)+','+(-originY)+')' 
); 
} 
+1

こんにちは、以前は返答しなかったことを申し訳なく思っています。ファイヤーフォックス(なぜか分かりません)を使うことができなかったことが事実です。だから私はあなたのコードが分離して動作するのを見るが、私はまだいくつかの奇妙な問題に取り組んでいる、私は私のプロジェクトでそれを動作させる方法を見つけるとすぐにあなたに戻ってくるだろう!ありがとう – Riwall

+0

私はあなたが使用する適切な原点を得ることができないので、私のgetBBox()が動作していないようです。(これは要素がinkscapeで簡単に移動でき、 /別のSVGに貼り付ける)。私は多くのことを試してきましたが、何も働かなかった。 – Riwall

+0

@RiwallあなたのBBoxの問題について新しい質問をすることをお勧めします。問題を再現するシンプルで慎重なテストケース(質問内のコードまたはJSFiddle内)を含めるようにして、問題を引き起こすOS /ブラウザ/バージョンを記述してください。 – Phrogz

2

@Phrogz:あなたの素晴らしい例のおかげで、私はそれから学びました。私はそれをちょっと簡単にするために、以下のようにいくつか変更しました。コアJavaでマウスイベントを処理するように、ここでも同じように扱うことができると思うので、あなたの例で私の方法を試しました。

私はそれがいくつか難しいと思うので、私は "rotateElement"機能を削除しました。

はコードの下を参照してください:

var svg=document.getElementById("svg1"); 
var pt=svg.createSVGPoint(); 
var end_small=document.getElementById("end_small"); 
var line=document.getElementById("line1"); 

end_small.addEventListener('mousemove', function(evt) { 

    var loc=getCursor(evt); 
    end_small.setAttribute("cx",loc.x); 
    end_small.setAttribute("cy",loc.y); 

    loc = getCursor(evt); // will get each x,y for mouse move 

    line.setAttribute('x2',loc.x); // apply it as end points of line 
    line.setAttribute('y2',loc.y); // apply it as end points of line 

}, false); 

function getCursor(evt) { 
    pt.x=evt.clientX; 
    pt.y=evt.clientY; 
    return pt.matrixTransform(svg.getScreenCTM().inverse()); 
} 

それでは、私が行っていることは、私はちょうどのみ前述したように、マウスは私がgetCursor()関数からx, yを取得するあなたによって動かさ小さな円全体ではなく、SVGと毎回にリスナーを追加しています私はこのx, yを私の行のx2, y2として与えます。それは翻訳されず、回転しません。マウスを動かしてゆっくりと動かす必要があります。マウスが円を離れると、右の小さな円の上にリスナーが追加されたため、線は移動しません。

0

正しいsvgマウス座標を取得するのは難しいです。まず第一に、共通の方法は、イベントプロパティのclientXとclientYをそれぞれgetBoundingClientRect()とclientLeftで減算し、それぞれclientTopを使用することです。 SVGはゼロより大きいパディングスタイル情報を有する場合

svg.addEventListener('click', event => 
{ 
    let bound = svg.getBoundingClientRect(); 

    let x = event.clientX - bound.left - svg.clientLeft - paddingLeft; 
    let y = event.clientY - bound.top - svg.clientTop - paddingTop; 
} 

しかし、座標がシフトされます。したがって、この情報は、substractでなければなりません:

let paddingLeft = parseFloat(style['padding-left'].replace('px', '')); 
let paddingTop = parseFloat(style['padding-top'].replace('px', '')); 

let x = event.clientX - bound.left - svg.clientLeft - paddingLeft; 
let y = event.clientY - bound.top - svg.clientTop - paddingTop; 

そしてとても素敵ではないと思うが、いくつかのブラウザでborderプロパティも座標ではなく、他にシフトしていること、です。イベントプロパティのxとyがではなく、が利用可能である場合、シフトが行われることがわかりました。

if(event.x === undefined) 
{ 
    x -= parseFloat(style['border-left-width'].replace('px', '')); 
    y -= parseFloat(style['border-top-width'].replace('px', '')); 
} 

この変換の後で、x座標とy座標は外れている可能性があります。しかし、それは考えていない。

let width = svg.width.baseVal.value; 
let height = svg.height.baseVal.value; 

if(x < 0 || y < 0 || x >= width || y >= height) 
{ 
    return; 
} 

このソリューションは、click、mousemove、mousedownなどに使用できます。 ここでライブデモにアクセスできます。https://codepen.io/martinwantke/pen/xpGpZB