Handle mouse, touch, and pen interactions on shapes.
Event handlers receive coordinates in your coordinate space, not raw screen pixels. There are three spaces a position can live in, and the library converts between them for you:
Evg.group [ Transform.translate 50 0 ], local coordinates already
have that translation undone. The simple handlers (like onClick) give you
this, so a click at the visual centre of a shape reports the centre in the
shape's own numbers no matter how it's been moved, scaled, or rotated.Evg.svg, meaning the same
numbers you'd use without any transforms. This is the space to do drag
maths in, because it doesn't move when the thing you're dragging moves.When you use no transforms, local and scene are identical, so you can ignore the distinction until you need it.
import Evg
import Evg.Events as Events
Evg.circle
[ Evg.fillStr "blue"
, Events.onClick (\point -> ClickedAt point)
]
{ r = 30, center = ( 50, 50 ) }These report a single ( x, y ) position in the element's local coordinate
space. They work for mouse, touch, and pen alike.
Fires when a pointer (mouse button, finger, or pen) is pressed on the element. This is where a drag or gesture usually begins.
For touch and pen the browser keeps sending onPointerMove/onPointerUp to
this element even if the pointer leaves it (browsers call this "pointer
capture": the element that received the press keeps receiving the follow-up
events). So touch and pen gestures work without any extra setup. Mouse drags
need whileDragging to follow the cursor off the element.
Pair this with touchAction None so the browser doesn't
treat a touch-drag as a scroll.
Fires when a pressed pointer is released over the element.
Fires continuously as a pointer moves over the element. Use sparingly, since it generates many messages.
Fires once when a pointer enters the element.
Fires once when a pointer leaves the element.
Fires when the browser takes over an in-progress gesture, for example when
a touch turns into a page scroll. Treat it like an interrupted onPointerUp:
end whatever drag was in progress.
Like onPointerDown, but hands you the full
Pointer record. This is where you'd grab .frame and .pointerId
to set up a drag.
Like onPointerUp, but hands you the full
Pointer record.
Like onPointerMove, but hands you the full
Pointer record.
Everything known about a pointer event.
local: position in this element's own coordinate space (see the module
intro).scene: position in the root Evg.svg coordinate space.client: raw browser pixels, measured from the top-left corner of the
browser window.frame: a snapshot of how to convert client pixels to scene coordinates,
for use with whileDragging.pointerType: whether this was a mouse, touch, or pen.pointerId: a number identifying this pointer, so you can track several
fingers independently during a multi-touch gesture.isPrimary: True for the first pointer in a multi-pointer gesture.button: which button triggered the event.modifiers: which keyboard modifier keys were held.The kind of device that produced a pointer event.
Which button was pressed. For touch and pen this is normally Main.
Which modifier keys were held during the event.
Fires when the mouse wheel or trackpad scrolls over the element. Calls
preventDefault, so the page won't scroll while the pointer is over your
drawing. That is handy for zoom, but don't attach it to something the user
needs to be able to scroll past.
Events.onWheel (\wheel -> Zoomed wheel)A mouse-wheel or trackpad scroll event.
local / scene: where the pointer was, in the two coordinate spaces.delta: how far it scrolled, normalised to pixels (positive is
down/right).pinch: True when this is a trackpad pinch-to-zoom rather than a plain
scroll. Browsers report pinches as a scroll with the Ctrl key implicitly
held, which is what this detects.frame: as on Pointer.modifiers: modifier keys held. Note ctrl reads True during a
trackpad pinch even if the physical key isn't down; use pinch to tell
them apart.A mouse drag that leaves the element stops sending events to it, because the
browser delivers them to whatever is now under the cursor. To keep following
the pointer you listen on the window instead, but a window event can't tell
you where your drawing is. A Frame, captured during an ordinary
handler while that information is still available, bridges the gap.
A snapshot of the conversion from client pixels to scene coordinates,
captured at the moment of a pointer event. Pass it to
whileDragging to convert the window-level events that follow.
You get one on every Pointer and Wheel record; store it
in your model when a drag starts.
Convert a client-pixel position to scene coordinates using a captured
Frame.
Track a mouse drag across the whole window, converting each position to
scene coordinates via a Frame you captured on onPointerDown.
Subscribe to it only while a drag is in progress, and only for mouse drags. Touch and pen keep firing on the element itself, so they don't need it:
subscriptions model =
case model.drag of
Just { frame, pointerType } ->
if pointerType == Events.Mouse then
Events.whileDragging frame
{ onMove = DragMoved
, onEnd = DragEnded
}
else
Sub.none
Nothing ->
Sub.noneThe Frame is a snapshot taken when the drag began. If the page scrolls or your
Evg.svg moves during the drag, the converted positions will be off by that
much; capture a fresh Frame if that matters. A Frame also assumes the svg
element itself carries no CSS transform (ordinary positioning is fine).
Declares which touch gestures the browser may handle itself, before your
handlers see them. Set this to None on anything you drag or zoom with touch,
so the browser doesn't scroll or pinch the page instead.
Events.touchAction Events.NoneHow the browser should treat touch gestures on this element.
Sets which parts of a shape can receive pointer events.
VisiblePainted: only the painted (filled/stroked) visible areas (default)Visible: the entire visible area, even transparent partsPainted: all painted areas, even if hiddenAll: the entire area regardless of visibility or paintPointerEventsNone: the shape ignores all pointer eventsControls which parts of a shape respond to pointer events.
Sets the mouse cursor appearance when hovering over the shape.
-- hand cursor, indicating clickable:
Events.cursor Events.PointerCursorThe mouse cursor shape when hovering over the element.
Fires when the element is clicked. Reports the click position in the element's local coordinate space.