Skip to content

Mousedown event in SVG "crashes" Threepenny #238

@brprice

Description

@brprice

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.

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions