198 lines
8.1 KiB
Markdown
198 lines
8.1 KiB
Markdown
# Mouse events basics
|
|
|
|
In this chapter we'll get into more details about mouse events and their properties.
|
|
|
|
Please note: such events may come not only from "mouse devices", but are also from other devices, such as phones and tablets, where they are emulated for compatibility.
|
|
|
|
## Mouse event types
|
|
|
|
We can split mouse events into two categories: "simple" and "complex"
|
|
|
|
### Simple events
|
|
|
|
The most used simple events are:
|
|
|
|
`mousedown/mouseup`
|
|
: Mouse button is clicked/released over an element.
|
|
|
|
`mouseover/mouseout`
|
|
: Mouse pointer comes over/out from an element.
|
|
|
|
`mousemove`
|
|
: Every mouse move over an element triggers that event.
|
|
|
|
...There are several other event types too, we'll cover them later.
|
|
|
|
### Complex events
|
|
|
|
`click`
|
|
: Triggers after `mousedown` and then `mouseup` over the same element if the left mouse button was used.
|
|
|
|
`contextmenu`
|
|
: Triggers after `mousedown` if the right mouse button was used.
|
|
|
|
`dblclick`
|
|
: Triggers after a double click over an element.
|
|
|
|
Complex events are made of simple ones, so in theory we could live without them. But they exist, and that's good, because they are convenient.
|
|
|
|
### Events order
|
|
|
|
An action may trigger multiple events.
|
|
|
|
For instance, a click first triggers `mousedown`, when the button is pressed, then `mouseup` and `click` when it's released.
|
|
|
|
In cases when a single action initiates multiple events, their order is fixed. That is, the handlers are called in the order `mousedown` -> `mouseup` -> `click`.
|
|
|
|
```online
|
|
Click the button below and you'll see the events. Try double-click too.
|
|
|
|
On the teststand below all mouse events are logged, and if there are more than 1 second delay between them, then they are separated by a horizontal ruler.
|
|
|
|
Also we can see the `which` property that allows to detect the mouse button.
|
|
|
|
<input onmousedown="return logMouse(event)" onmouseup="return logMouse(event)" onclick="return logMouse(event)" oncontextmenu="return logMouse(event)" ondblclick="return logMouse(event)" value="Click me with the right or the left mouse button" type="button"> <input onclick="logClear('test')" value="Clear" type="button"> <form id="testform" name="testform"> <textarea style="font-size:12px;height:150px;width:360px;"></textarea></form>
|
|
```
|
|
|
|
## Getting the button: which
|
|
|
|
Click-related events always have the `which` property, which allows to get the exact mouse button.
|
|
|
|
It is not used for `click` and `contextmenu` events, because the former happens only on left-click, and the latter -- only on right-click.
|
|
|
|
But if we track `mousedown` and `mouseup`, then we need it, because these events trigger on any button, so `which` allows to distinguish between "right-mousedown" and "left-mousedown".
|
|
|
|
There are the three possible values:
|
|
|
|
- `event.which == 1` -- the left button
|
|
- `event.which == 2` - the middle button
|
|
- `event.which == 3` - the right button
|
|
|
|
The middle button is somewhat exotic right now and is very rarely used.
|
|
|
|
## Modifiers: shift, alt, ctrl and meta
|
|
|
|
All mouse events include the information about pressed modifier keys.
|
|
|
|
Event properties:
|
|
|
|
- `shiftKey`: `key:Shift`
|
|
- `altKey`: `key:Alt` (or `key:Opt` for Mac)
|
|
- `ctrlKey`: `key:Ctrl`
|
|
- `metaKey`: `key:Cmd` for Mac
|
|
|
|
They are `true` if the corresponding key was pressed during the event.
|
|
|
|
For instance, the button below only works on `key:Alt+Shift`+click:
|
|
|
|
```html autorun height=60
|
|
<button id="button">Alt+Shift+Click on me!</button>
|
|
|
|
<script>
|
|
button.onclick = function(event) {
|
|
*!*
|
|
if (event.altKey && event.shiftKey) {
|
|
*/!*
|
|
alert('Hooray!');
|
|
}
|
|
};
|
|
</script>
|
|
```
|
|
|
|
```warn header="Attention: on Mac it's usually `Cmd` instead of `Ctrl`"
|
|
On Windows and Linux there are modifier keys `key:Alt`, `key:Shift` and `key:Ctrl`. On Mac there's one more: `key:Cmd`, corresponding to the property `metaKey`.
|
|
|
|
In most applications, when Windows/Linux uses `key:Ctrl`, on Mac `key:Cmd` is used.
|
|
|
|
That is: where a Windows user presses `key:Ctrl+Enter` or `key:Ctrl+A`, a Mac user would press `key:Cmd+Enter` or `key:Cmd+A`, and so on.
|
|
|
|
So if we want to support combinations like `key:Ctrl`+click, then for Mac it makes sense to use `key:Cmd`+click. That's more comfortable for Mac users.
|
|
|
|
Even if we'd like to force Mac users to `key:Ctrl`+click -- that's kind of difficult. The problem is: a left-click with `key:Ctrl` is interpreted as a *right-click* on MacOS, and it generates the `contextmenu` event, not `click` like Windows/Linux.
|
|
|
|
So if we want users of all operational systems to feel comfortable, then together with `ctrlKey` we should check `metaKey`.
|
|
|
|
For JS-code it means that we should check `if (event.ctrlKey || event.metaKey)`.
|
|
```
|
|
|
|
```warn header="There are also mobile devices"
|
|
Keyboard combinations are good as an addition to the workflow. So that if the visitor has a
|
|
keyboard -- it works. And if their device doesn't have it -- then there should be another way to do the same.
|
|
```
|
|
|
|
## Coordinates: clientX/Y, pageX/Y
|
|
|
|
All mouse events have coordinates in two flavours:
|
|
|
|
1. Window-relative: `clientX` and `clientY`.
|
|
2. Document-relative: `pageX` and `pageY`.
|
|
|
|
For instance, if we have a window of the size 500x500, and the mouse is in the left-upper corner, then `clientX` and `clientY` are `0`. And if the mouse is in the center, then `clientX` and `clientY` are `250`, no matter what place in the document it is, how far the document was scrolled. They are similar to `position:fixed`.
|
|
|
|
````online
|
|
Move the mouse over the input field to see `clientX/clientY` (the example is in the `iframe`, so coordinates are relative to that `iframe`):
|
|
|
|
```html autorun height=50
|
|
<input onmousemove="this.value=event.clientX+':'+event.clientY" value="Mouse over me">
|
|
```
|
|
````
|
|
|
|
Document-relative coordinates `pageX`, `pageY` are counted from the left-upper corner of the document, not the window. You can read more about coordinates in the chapter <info:coordinates>.
|
|
|
|
## Disabling selection
|
|
|
|
Double mouse click has a side-effect that may be disturbing in some interfaces: it selects the text.
|
|
|
|
For instance, a double-click on the text below selects it in addition to our handler:
|
|
|
|
```html autorun height=50
|
|
<span ondblclick="alert('dblclick')">Double-click me</span>
|
|
```
|
|
|
|
If one presses the left mouse button and, without releasing it, moves the mouse, that also makes the selection, often unwanted.
|
|
|
|
There are multiple ways to prevent the selection, that you can read in the chapter <info:selection-range>.
|
|
|
|
In this particular case the most reasonable way is to prevent the browser action on `mousedown`. It prevents both these selections:
|
|
|
|
```html autorun height=50
|
|
Before...
|
|
<b ondblclick="alert('Click!')" *!*onmousedown="return false"*/!*>
|
|
Double-click me
|
|
</b>
|
|
...After
|
|
```
|
|
|
|
Now the bold element is not selected on double clicks, and pressing the left button on it won't start the selection.
|
|
|
|
Please note: the text inside it is still selectable. However, the selection should start not on the text itself, but before or after it. Usually that's fine for users.
|
|
|
|
````smart header="Preventing copying"
|
|
If we want to disable selection to protect our page content from copy-pasting, then we can use another event: `oncopy`.
|
|
|
|
```html autorun height=80 no-beautify
|
|
<div *!*oncopy="alert('Copying forbidden!');return false"*/!*>
|
|
Dear user,
|
|
The copying is forbidden for you.
|
|
If you know JS or HTML, then you can get everything from the page source though.
|
|
</div>
|
|
```
|
|
If you try to copy a piece of text in the `<div>`, that won't work, because the default action `oncopy` is prevented.
|
|
|
|
Surely the user has access to HTML-source of the page, and can take the content from there, but not everyone knows how to do it.
|
|
````
|
|
|
|
## Summary
|
|
|
|
Mouse events have the following properties:
|
|
|
|
- Button: `which`.
|
|
- Modifier keys (`true` if pressed): `altKey`, `ctrlKey`, `shiftKey` and `metaKey` (Mac).
|
|
- If you want to handle `key:Ctrl`, then don't forget Mac users, they usually use `key:Cmd`, so it's better to check `if (e.metaKey || e.ctrlKey)`.
|
|
|
|
- Window-relative coordinates: `clientX/clientY`.
|
|
- Document-relative coordinates: `pageX/pageY`.
|
|
|
|
The default browser action of `mousedown` is text selection, if it's not good for the interface, then it should be prevented.
|
|
|
|
In the next chapter we'll see more details about events that follow pointer movement and how to track element changes under it.
|