[解決済み] キャンバス上のマウスの実位置
質問
HTML5 のキャンバスの上にマウスで描画しようとしているのですが、キャンバスの位置が 0,0 (左上隅) のときだけうまく動作するようです。以下は私のコードです。
function createImageOnCanvas(imageId){
document.getElementById("imgCanvas").style.display = "block";
document.getElementById("images").style.overflowY= "hidden";
var canvas = document.getElementById("imgCanvas");
var context = canvas.getContext("2d");
var img = new Image(300,300);
img.src = document.getElementById(imageId).src;
context.drawImage(img, (0),(0));
}
function draw(e){
var canvas = document.getElementById("imgCanvas");
var context = canvas.getContext("2d");
posx = e.clientX;
posy = e.clientY;
context.fillStyle = "#000000";
context.fillRect (posx, posy, 4, 4);
}
HTML部分
<body>
<div id="images">
</div>
<canvas onmousemove="draw(event)" style="margin:0;padding:0;" id="imgCanvas"
class="canvasView" width="250" height="250"></canvas>
JavaScriptで簡単な関数を作って正しい位置を取得する方法があると読んだことがありますが、その方法について全くわかりません。
どのように解決するのでしょうか?
シンプルな1:1シナリオ
canvas 要素とビットマップのサイズが 1:1 の場合、次のスニペットを使用してマウスの位置を取得することができます。
function getMousePos(canvas, evt) {
var rect = canvas.getBoundingClientRect();
return {
x: evt.clientX - rect.left,
y: evt.clientY - rect.top
};
}
イベントとcanvasを引数として、イベントから呼び出すだけです。マウスの位置を表すxとyを含むオブジェクトを返します。
取得するマウスの位置はクライアントウィンドウからの相対位置なので、canvas 要素の位置を差し引いて要素自体からの相対位置に変換する必要があります。
コードでの統合の例です。
//put this outside the event loop..
var canvas = document.getElementById("imgCanvas");
var context = canvas.getContext("2d");
function draw(evt) {
var pos = getMousePos(canvas, evt);
context.fillStyle = "#000000";
context.fillRect (pos.x, pos.y, 4, 4);
}
注意:canvas 要素に直接適用すると、ボーダーとパディングが位置に影響するため、これらは
getComputedStyle()
- を使用するか、これらのスタイルを親 div に適用する必要があります。
要素とビットマップの大きさが異なる場合
要素がCSSで拡大縮小されている、ピクセルアスペクト比があるなど、要素とビットマップの大きさが異なる場合は、対応する必要があります。
例
function getMousePos(canvas, evt) {
var rect = canvas.getBoundingClientRect(), // abs. size of element
scaleX = canvas.width / rect.width, // relationship bitmap vs. element for X
scaleY = canvas.height / rect.height; // relationship bitmap vs. element for Y
return {
x: (evt.clientX - rect.left) * scaleX, // scale mouse coordinates after they have
y: (evt.clientY - rect.top) * scaleY // been adjusted to be relative to element
}
}
コンテキストに適用される変換(拡大縮小、回転など)を持つ
次に、回転、傾き/せん断、スケール、平行移動などのコンテキストに変換を適用した、より複雑なケースがあります。これに対処するために、現在の行列の逆行列を計算することができます。
新しいブラウザでは、現在の行列を
currentTransform
. しかし、Firefox では
mozCurrentTransformInverted
を使うと、配列が返され
mozCurrentTransform
を返します。Chrome では、実験的なフラグで有効にした場合、どちらも
DOMMatrix
を返しますが
DOMMatrix
.
しかし、ほとんどの場合、独自のカスタム行列ソリューションを実装する必要があります(例えば、私のソリューションである ここで - free/MITプロジェクト) を実装する必要があります。
どのような経路で行列を取得したかにかかわらず、最終的に行列を取得したら、それを反転してマウス座標に適用する必要があります。座標は次にキャンバスに渡され、キャンバスはその行列を使用して、その時点のどこにいても元に戻すように変換されます。
このようにして、点はマウスに対して正しい位置になります。また、ここで座標を(逆行列を適用する前に)要素からの相対位置に調整する必要があります。
行列のステップを示すだけの例
SVGMatrix
の使用例
function draw(evt) {
var pos = getMousePos(canvas, evt); // get adjusted coordinates as above
var imatrix = matrix.inverse(); // get inverted matrix somehow
pos = imatrix.applyToPoint(pos.x, pos.y); // apply to adjusted coordinate
context.fillStyle = "#000000";
context.fillRect(pos.x-1, pos.y-1, 2, 2);
}
を実装した場合、次のようになります。
currentTransform
更新 これらのステップを一つの使いやすいオブジェクトに埋め込むフリーソリューション(MIT)を作りました。 ここで で見ることができ、また、ほとんどの人が無視するような他のいくつかの細かな点にも気を配っています。
関連
-
fetch ネットワークリクエストラッパーの説明例
-
VUEグローバルフィルターの概念と留意点、基本的な使い方
-
[解決済み】JavaScriptエラー(Uncaught SyntaxError: Unexpected end of input)
-
[解決済み】 Uncaught TypeError : undefined のプロパティ 'replace' を読み取れない In Grid
-
[解決済み] HTML5 canvas をウィンドウに合わせてリサイズする
-
JavaScriptのgetElementById()メソッド入門
-
[解決済み] 再描画のためにキャンバスをクリアする方法
-
[解決済み] HTML5/Canvas/JavaScriptを使用してブラウザ内のスクリーンショットを撮影する
-
[解決済み] HTML Canvas を gif/jpg/png/pdf としてキャプチャしますか?
-
[解決済み] HTML5 CanvasとSVGとdivの比較
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
親子コンポーネント通信を解決する3つのVueスロット
-
Vueがechartsのtooltipにクリックイベントを追加するケーススタディ
-
元のイベントが実行されなかった後に要素を追加するためのjQueryソリューション
-
vue for 登録ページ効果 vue for sms 認証コードログイン
-
vueのグローバルがscss(mixin)を導入。
-
vue+webrtc(Tencent cloud)ライブ機能の実践を実現するために
-
Vueの「データを聴く」原則を解説
-
[解決済み】Node.jsで "Cannot find module "エラーを解決するには?
-
jq は html ページとデータを動的に分割する。
-
[解決済み】キャンバス要素でマウスをクリックしたときの座標を取得するには?[重複しています]。