Ich möchte eine kleine Mal-App mit Leinwand machen. Also muss ich die Position der Maus auf der Leinwand finden.
Ich möchte eine kleine Mal-App mit Leinwand machen. Also muss ich die Position der Maus auf der Leinwand finden.
Antworten:
Für Benutzer von JQuery:
Wenn Sie verschachtelte Elemente haben, von denen eines mit dem Ereignis verknüpft ist, kann es manchmal verwirrend sein, zu verstehen, was Ihr Browser als übergeordnetes Element ansieht. Hier können Sie angeben, welcher Elternteil.
Sie nehmen die Mausposition und subtrahieren sie dann von der Versatzposition des übergeordneten Elements.
var x = evt.pageX - $('#element').offset().left;
var y = evt.pageY - $('#element').offset().top;
Wenn Sie versuchen, die Mausposition auf einer Seite in einem Bildlaufbereich zu ermitteln:
var x = (evt.pageX - $('#element').offset().left) + self.frame.scrollLeft();
var y = (evt.pageY - $('#element').offset().top) + self.frame.scrollTop();
Oder die Position relativ zur Seite:
var x = (evt.pageX - $('#element').offset().left) + $(window).scrollLeft();
var y = (evt.pageY - $('#element').offset().top) + $(window).scrollTop();
Beachten Sie die folgende Leistungsoptimierung:
var offset = $('#element').offset();
// Then refer to
var x = evt.pageX - offset.left;
Auf diese Weise muss JQuery nicht #elementfür jede Zeile nachschlagen .
Es gibt eine neuere JavaScript-Version von @anytimecoder für Browser, die getBoundingClientRect () unterstützen .
var y = (evt.pageY - $('#element').offset().left) + $(window).scrollTop();zuvar y = (evt.pageY - $('#element').offset().top) + $(window).scrollTop();
Da ich keine jQuery-freie Antwort gefunden habe, die ich kopieren / einfügen konnte, habe ich folgende Lösung verwendet:
function clickEvent(e) {
// e = Mouse click event.
var rect = e.target.getBoundingClientRect();
var x = e.clientX - rect.left; //x position within the element.
var y = e.clientY - rect.top; //y position within the element.
}
e.currentTargetnicht e.target. Andernfalls werden Kinderelemente davon betroffen sein
Im Folgenden wird die Mauspositionsbeziehung zum Canvas-Element berechnet:
var example = document.getElementById('example');
example.onmousemove = function(e) {
var x = e.pageX - this.offsetLeft;
var y = e.pageY - this.offsetTop;
}
In diesem Beispiel thisbezieht sich auf das exampleElement und eist das onmousemoveEreignis.
var example = document.getElementById('example'); example.onmousemove = function(e) { var X = e.pageX - this.offsetLeft; var Y = e.pageY - this.offsetTop; }
thisan e.currentTarget, dass Sie die Position in Bezug auf das Element erhalten , dass Sie den Ereignis - Listener hinzugefügt.
In reinem Javascript gibt es keine Antwort, die relative Koordinaten zurückgibt, wenn das Referenzelement in anderen verschachtelt ist, was absolut positioniert sein kann. Hier ist eine Lösung für dieses Szenario:
function getRelativeCoordinates (event, referenceElement) {
const position = {
x: event.pageX,
y: event.pageY
};
const offset = {
left: referenceElement.offsetLeft,
top: referenceElement.offsetTop
};
let reference = referenceElement.offsetParent;
while(reference){
offset.left += reference.offsetLeft;
offset.top += reference.offsetTop;
reference = reference.offsetParent;
}
return {
x: position.x - offset.left,
y: position.y - offset.top,
};
}
htmlElement Offset
while(reference !== undefined)durch while(reference). Zumindest in Chrome wird der offsetParent nicht undefined, sondern null. Nur zu überprüfen, ob referencees wahr ist, stellt sicher, dass es mit beiden undefinedund funktioniert null.
offsetParentEigenschaft gibt, die sich auch in anderen Situationen als sehr nützlich herausstellt!
scrollLeftund scrollTopkompensieren.
Eine gute Beschreibung der Schwierigkeit dieses Problems finden Sie hier: http://www.quirksmode.org/js/events_properties.html#position
Mit der dort beschriebenen Technik finden Sie die Position der Maus im Dokument. Dann überprüfen Sie einfach, ob es sich innerhalb des Begrenzungsrahmens Ihres Elements befindet, den Sie durch Aufrufen element.getBoundingClientRect()eines Objekts mit den folgenden Eigenschaften finden können : { bottom, height, left, right, top, width }. Von dort aus ist es trivial herauszufinden, ob das überhaupt in Ihrem Element passiert ist oder nicht.
Ich habe alle diese Lösungen ausprobiert und aufgrund meines speziellen Setups mit einem matrixtransformierten Container (Panzoom-Bibliothek) hat keiner funktioniert. Dies gibt den korrekten Wert zurück, auch wenn gezoomt und geschwenkt wird:
mouseevent(e) {
const x = e.offsetX,
y = e.offsetY
}
Aber nur, wenn keine untergeordneten Elemente im Weg sind. Dies kann umgangen werden, indem sie mithilfe von CSS für das Ereignis "unsichtbar" gemacht werden:
.child {
pointer-events: none;
}
Ich kam in dieser Frage, aber um es für meinen Fall arbeiten zu lassen (mit dragover- auf einem DOM-Elemente (nicht in meinem Fall sein Leinwand)), fand ich , dass Sie nur noch verwenden offsetXund offsetYauf dem dragover-Maus - Ereignisse .
onDragOver(event){
var x = event.offsetX;
var y = event.offsetY;
}
Ich +1 'Mark van Wyks Antwort, als sie mich in die richtige Richtung brachte, aber nicht ganz für mich löste. Ich hatte immer noch einen Versatz beim Malen in Elementen, die in einem anderen Element enthalten waren.
Fllowing löste es für mich:
x = e.pageX - this.offsetLeft - $(elem).offset().left;
y = e.pageY - this.offsetTop - $(elem).offset().top;
Mit anderen Worten - ich habe einfach alle Offsets aller verschachtelten Elemente gestapelt
Keine der oben genannten Antworten ist IMO zufriedenstellend, daher verwende ich Folgendes:
// Cross-browser AddEventListener
function ael(e, n, h){
if( e.addEventListener ){
e.addEventListener(n, h, true);
}else{
e.attachEvent('on'+n, h);
}
}
var touch = 'ontouchstart' in document.documentElement; // true if touch device
var mx, my; // always has current mouse position IN WINDOW
if(touch){
ael(document, 'touchmove', function(e){var ori=e;mx=ori.changedTouches[0].pageX;my=ori.changedTouches[0].pageY} );
}else{
ael(document, 'mousemove', function(e){mx=e.clientX;my=e.clientY} );
}
// local mouse X,Y position in element
function showLocalPos(e){
document.title = (mx - e.getBoundingClientRect().left)
+ 'x'
+ Math.round(my - e.getBoundingClientRect().top);
}
Und wenn Sie jemals die aktuelle Y-Bildlaufposition der Seite kennen müssen:
var yscroll = window.pageYOffset
|| (document.documentElement && document.documentElement.scrollTop)
|| document.body.scrollTop; // scroll Y position in page
Wenn Sie regelmäßig Websites oder PWAs (Progressive Web Apps) für mobile Geräte und / oder Laptops / Monitore mit Touchscreens entwickeln, sind Sie hier gelandet, weil Sie möglicherweise an Mausereignisse gewöhnt sind und die manchmal schmerzhafte Erfahrung von Touch noch nicht kennen Ereignisse ... yay!
Es gibt nur 3 Regeln:
mousemoveoder während der touchmoveVeranstaltungen so wenig wie möglich .mousedownoder während der touchstartVeranstaltungen so viel wie möglich .Es ist unnötig zu erwähnen, dass touchEreignisse komplizierter sind , da es mehrere geben kann und sie flexibler (komplizierter) sind als Mausereignisse. Ich werde hier nur eine einzige Berührung behandeln. Ja, ich bin faul, aber es ist die häufigste Art der Berührung.
var posTop;
var posLeft;
function handleMouseDown(evt) {
var e = evt || window.event; // Because Firefox, etc.
posTop = e.target.offsetTop;
posLeft = e.target.offsetLeft;
e.target.style.background = "red";
// The statement above would be better handled by CSS
// but it's just an example of a generic visible indicator.
}
function handleMouseMove(evt) {
var e = evt || window.event;
var x = e.offsetX; // Wonderfully
var y = e.offsetY; // Simple!
e.target.innerHTML = "Mouse: " + x + ", " + y;
if (posTop)
e.target.innerHTML += "<br>" + (x + posLeft) + ", " + (y + posTop);
}
function handleMouseOut(evt) {
var e = evt || window.event;
e.target.innerHTML = "";
}
function handleMouseUp(evt) {
var e = evt || window.event;
e.target.style.background = "yellow";
}
function handleTouchStart(evt) {
var e = evt || window.event;
var rect = e.target.getBoundingClientRect();
posTop = rect.top;
posLeft = rect.left;
e.target.style.background = "green";
e.preventDefault(); // Unnecessary if using Vue.js
e.stopPropagation(); // Same deal here
}
function handleTouchMove(evt) {
var e = evt || window.event;
var pageX = e.touches[0].clientX; // Touches are page-relative
var pageY = e.touches[0].clientY; // not target-relative
var x = pageX - posLeft;
var y = pageY - posTop;
e.target.innerHTML = "Touch: " + x + ", " + y;
e.target.innerHTML += "<br>" + pageX + ", " + pageY;
e.preventDefault();
e.stopPropagation();
}
function handleTouchEnd(evt) {
var e = evt || window.event;
e.target.style.background = "yellow";
// Yes, I'm being lazy and doing the same as mouseout here
// but obviously you could do something different if needed.
e.preventDefault();
e.stopPropagation();
}
div {
background: yellow;
height: 100px;
left: 50px;
position: absolute;
top: 80px;
user-select: none; /* Disable text selection */
-ms-user-select: none;
width: 100px;
}
<div
onmousedown="handleMouseDown()"
onmousemove="handleMouseMove()"
onmouseout="handleMouseOut()"
onmouseup="handleMouseUp()"
ontouchstart="handleTouchStart()"
ontouchmove="handleTouchMove()"
ontouchend="handleTouchEnd()">
</div>
Move over box for coordinates relative to top left of box.<br>
Hold mouse down or touch to change color.<br>
Drag to turn on coordinates relative to top left of page.
Verwenden Sie lieber Vue.js ? Ich mache! Dann würde Ihr HTML so aussehen:
<div @mousedown="handleMouseDown"
@mousemove="handleMouseMove"
@mouseup="handleMouseUp"
@touchstart.stop.prevent="handleTouchStart"
@touchmove.stop.prevent="handleTouchMove"
@touchend.stop.prevent="handleTouchEnd">
Sie können es durch bekommen
var element = document.getElementById(canvasId);
element.onmousemove = function(e) {
var xCoor = e.clientX;
var yCoor = e.clientY;
}
Entnommen aus diesem Tutorial , mit Korrekturen dank des Top-Kommentars:
function getMousePos( canvas, evt ) {
var rect = canvas.getBoundingClientRect();
return {
x: Math.floor( ( evt.clientX - rect.left ) / ( rect.right - rect.left ) * canvas.width ),
y: Math.floor( ( evt.clientY - rect.top ) / ( rect.bottom - rect.top ) * canvas.height )
};
}
Verwenden Sie auf einer Leinwand wie folgt:
var canvas = document.getElementById( 'myCanvas' );
canvas.addEventListener( 'mousemove', function( evt ) {
var mousePos = getMousePos( canvas, evt );
} );
Mir ist klar, dass ich etwas spät dran bin, aber dies funktioniert mit PURE-Javascript und gibt Ihnen sogar die Koordinaten des Zeigers innerhalb des Elements an, wenn das Element größer als das Ansichtsfenster ist und der Benutzer einen Bildlauf durchgeführt hat.
var element_offset_x ; // The distance from the left side of the element to the left of the content area
....// some code here (function declaration or element lookup )
element_offset_x = element.getBoundingClientRect().left - document.getElementsByTagName("html")[0].getBoundingClientRect().left ;
....// code here
function mouseMoveEvent(event)
{
var pointer_location = (event.clientX + window.pageXOffset) - element_offset_x ;
}
Wie es funktioniert.
Als erstes ermitteln wir die Position des HTML-Elements (des Inhaltsbereichs) relativ zum aktuellen Ansichtsfenster. Wenn die Seite Bildlaufleisten hat und gescrollt wird, wird die Nummer von zurückgegebengetBoundingClientRect().left für das HTML-Tag zurückgegebene negativ. Wir verwenden diese Zahl dann, um den Abstand zwischen dem Element und der linken Seite des Inhaltsbereichs zu berechnen. Mitelement_offset_x = element.getBoundingClientRect().left......;
Kenntnis des Abstands des Elements vom Inhaltsbereich. event.clientXgibt uns den Abstand des Zeigers vom Ansichtsfenster. Es ist wichtig zu verstehen, dass das Ansichtsfenster und der Inhaltsbereich zwei verschiedene Entitäten sind. Das Ansichtsfenster kann verschoben werden, wenn die Seite gescrollt wird. Daher gibt clientX die gleiche Nummer zurück, auch wenn die Seite gescrollt wird.
Um dies zu kompensieren, müssen wir die x-Position des Zeigers (relativ zum Ansichtsfenster) zur x-Position des Ansichtsfensters (relativ zum Inhaltsbereich) hinzufügen. Die X-Position des Ansichtsfensters wird mit gefunden window.pageXOffset.
Basierend auf der Lösung von @ Spider lautet meine Nicht-JQuery-Version wie folgt:
// Get the container element's bounding box
var sides = document.getElementById("container").getBoundingClientRect();
// Apply the mouse event listener
document.getElementById("canvas").onmousemove = (e) => {
// Here 'self' is simply the current window's context
var x = (e.clientX - sides.left) + self.pageXOffset;
var y = (e.clientY - sides.top) + self.pageYOffset;
}
Dies funktioniert sowohl beim Scrollen als auch beim Zoomen (in diesem Fall werden manchmal Floats zurückgegeben).
Die Mauskoordinaten innerhalb einer Zeichenfläche können dank event.offsetX und event.offsetY abgerufen werden. Hier ist ein kleiner Ausschnitt, um meinen Standpunkt zu beweisen:
c=document.getElementById("c");
ctx=c.getContext("2d");
ctx.fillStyle="black";
ctx.fillRect(0,0,100,100);
c.addEventListener("mousemove",function(mouseEvt){
// the mouse's coordinates on the canvas are just below
x=mouseEvt.offsetX;
y=mouseEvt.offsetY;
// the following lines draw a red square around the mouse to prove it
ctx.fillStyle="black";
ctx.fillRect(0,0,100,100);
ctx.fillStyle="red";
ctx.fillRect(x-5,y-5,10,10);
});
body {
background-color: blue;
}
canvas {
position: absolute;
top: 50px;
left: 100px;
}
<canvas id="c" width="100" height="100"></canvas>
canvas.onmousedown = function(e) {
pos_left = e.pageX - e.currentTarget.offsetLeft;
pos_top = e.pageY - e.currentTarget.offsetTop;
console.log(pos_left, pos_top)
}
HTMLElement.offsetLeft
Die HTMLElement.offsetLeftschreibgeschützte Eigenschaft gibt die Anzahl der Pixel zurück, um die die obere linke Ecke des aktuellen Elements innerhalb der nach links versetzt istHTMLElement.offsetParent Knotens .
Für Block-Elemente, offsetTop, offsetLeft, offsetWidth, und offsetHeightdie Grenze Kasten eines Elements relativ zum beschreiben offsetParent.
Für Elemente auf Inline-Ebene (z. B. span), die von einer Zeile zur nächsten umbrechen können offsetTopund offsetLeftdie Positionen des ersten Rahmenrahmens beschreiben (verwenden Element.getClientRects(), um dessen Breite und Höhe zu ermitteln), während offsetWidthund offsetHeightdie Abmessungen des Begrenzungsrahmens beschreiben (verwenden Element.getBoundingClientRect(), um seine Position zu erhalten). Daher ist ein Kasten mit der linken, oberen, Breite und Höhe offsetLeft, offsetTop, offsetWidthund offsetHeightnicht ein Begrenzungsrahmen für eine Spanne mit umwickeltem Text sein.
HTMLElement.offsetTop
Die HTMLElement.offsetTopschreibgeschützte Eigenschaft gibt den Abstand des aktuellen Elements zum oberen Rand des offsetParentKnotens zurück.
MouseEvent.pageX
Die pageXschreibgeschützte Eigenschaft gibt die X-Koordinate (horizontal) in Pixel des Ereignisses relativ zum gesamten Dokument zurück. Diese Eigenschaft berücksichtigt jedes horizontale Scrollen der Seite.
MouseEvent.pageY
Die MouseEvent.pageYschreibgeschützte Eigenschaft gibt die Y-Koordinate (vertikal) in Pixel des Ereignisses relativ zum gesamten Dokument zurück. Diese Eigenschaft berücksichtigt jedes vertikale Scrollen der Seite.
Weitere Erläuterungen finden Sie im Mozilla Developer Network:
https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/pageX https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/pageY https: // developer.mozilla.org/en-US/docs/Web/API/HTMLElement/offsetLeft https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/offsetTop
pageund offsetwäre für mich sehr hilfreich. Vielen Dank, dass Sie diese Anfrage berücksichtigt haben!
Ich habe eine andere Lösung implementiert, die ich für sehr einfach halte, also dachte ich, ich würde sie mit euch teilen.
Das Problem für mich war also, dass das gezogene Div für den Mauszeiger auf 0,0 springen würde . Also musste ich die Position der Maus auf dem Div erfassen, um die neue Position des Divs anzupassen.
Ich lese die Divs PageX und PageY und setze den oberen und linken Rand entsprechend ein. Um dann die Werte zum Anpassen der Koordinaten zu erhalten, um den Cursor an der Anfangsposition im Div zu halten, verwende ich einen onDragStart-Listener und speichere das e.nativeEvent .layerX und e.nativeEvent.layerY , die nur im anfänglichen Trigger die Position der Maus innerhalb des ziehbaren Div angeben.
Beispielcode:
onDrag={(e) => {
let newCoords;
newCoords = { x: e.pageX - this.state.correctionX, y: e.pageY - this.state.correctionY };
this.props.onDrag(newCoords, e, item.id);
}}
onDragStart={
(e) => {
this.setState({
correctionX: e.nativeEvent.layerX,
correctionY: e.nativeEvent.layerY,
});
}
Ich hoffe, das hilft jemandem, der die gleichen Probleme hatte wie ich :)
Sie müssen die Struktur Ihrer Seite kennen, denn wenn Ihre Leinwand ein Kind eines Div ist, das wiederum ein Kind eines anderen Div ist, wird die Geschichte komplizierter. Hier ist mein Code für eine Leinwand, die sich innerhalb von 2 Ebenen von div s befindet:
canvas.addEventListener("click", function(event) {
var x = event.pageX - (this.offsetLeft + this.parentElement.offsetLeft);
var y = event.pageY - (this.offsetTop + this.parentElement.offsetTop);
console.log("relative x=" + x, "relative y" + y);
});
Ursprüngliche Antwort sagte, es in einen Iframe zu setzen. Die bessere Lösung besteht darin, die Ereignisse offsetX und offsetY auf einer Zeichenfläche zu verwenden, deren Auffüllung auf 0px festgelegt ist.
<html>
<body>
<script>
var main=document.createElement('canvas');
main.width="200";
main.height="300";
main.style="padding:0px;margin:30px;border:thick dashed red";
document.body.appendChild(main);
// adding event listener
main.addEventListener('mousemove',function(e){
var ctx=e.target.getContext('2d');
var c=Math.floor(Math.random()*0xFFFFFF);
c=c.toString(16); for(;c.length<6;) c='0'+c;
ctx.strokeStyle='#'+c;
ctx.beginPath();
ctx.arc(e.offsetX,e.offsetY,3,0,2*Math.PI);
ctx.stroke();
e.target.title=e.offsetX+' '+e.offsetY;
});
// it worked! move mouse over window
</script>
</body>
</html>
Sie können getBoudingClientRect()das relativeübergeordnete Element verwenden.
document.addEventListener("mousemove", (e) => {
let xCoord = e.clientX - e.target.getBoundingClientRect().left + e.offsetX
let yCoord = e.clientY - e.target.getBoundingClientRect().top + e.offsetY
console.log("xCoord", xCoord, "yCoord", yCoord)
})