-
-
Notifications
You must be signed in to change notification settings - Fork 77
Description
The symptom
Consider the code
import Graphics.UI.Threepenny as UI
import qualified Graphics.UI.Threepenny.SVG as SVG
main :: IO ()
main = startGUI defaultConfig setup
setup :: Window -> UI ()
setup w = do
pure w # set title "Buggy event position in SVG"
elOut <- textarea
elOk <- UI.div #+ [string "non-svg mousedown is ok"]
elBad <- SVG.text # set html "svg mousedown is bad" # set SVG.x "10" # set SVG.y "50"
elSVG <- SVG.svg # set SVG.viewBox "0,0,100,100" # set SVG.width "300" # set SVG.height "100" #+ [pure elBad]
getBody w #+ [grid [[pure elOk, pure elSVG], [string "Event information:", pure elOut]]]
on mousedown elOk $ \p -> pure elOut # set text (show p)
on mousedown elBad $ \p -> pure elOut # set text (show p) -- crashes as fails to parse data as a pair of ints
--on (domEvent "mousedown") elBad $ \p -> pure elOut # set text (show p) -- look at the EventData
pure ()
Running this we find that clicking on the "non-svg mousedown is ok" text behaves well: it dumps the click location into the textbox.
However clicking on the "svg mousedown is bad" behaves poorly: instead of doing the same as above, "crashes" threepenny. By this I mean that it reloads the browser window and we see in the console
Foreign.JavaScript: Browser window disconnected.
src/Graphics/UI/Threepenny/Internal.hs:190:24-55: Non-exhaustive patterns in Success y
The problem
Assuming that on mousedown
is supposed to work within an SVG (if not, what is the alternative?), the problem is that (https://github.com/HeinrichApfelmus/threepenny-gui/blob/master/src/Graphics/UI/Threepenny/Events.hs#L64)
readCoordinates :: EventData -> (Int,Int)
readCoordinates json = (x,y)
where [x,y] = unsafeFromJSON json
-- | Mouse down event.
-- The mouse coordinates are relative to the element.
mousedown :: Element -> Event (Int,Int)
mousedown = fmap readCoordinates . domEvent "mousedown"
assumes that the EventData
are integers, which is false.
To see it is false, comment out the second to last line in the example code and uncomment the penultimate line to see the raw event data.
The workaround
One can work around this simply by writing a version of readCoordinates
which returns (Float,Float)
.
Depending on how we want this event (and also mousedown
and mouseup
) to work, it would be good to either
- document that you cannot use this inside an SVG and give an alternative
- change the assumption that the
EventData
is integral (I worry this may break existing code though)
However, I am unconvinced that this is the correct solution, since the raw javascript event handler seems to only have integers. Unfortunately I don't understand how threepenny-gui calculates its result (presumably) from these raw integers.