Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Differentiate between scroll and pinch-to-zoom #133

Open
elizabethprins opened this issue Mar 21, 2022 · 2 comments
Open

Differentiate between scroll and pinch-to-zoom #133

elizabethprins opened this issue Mar 21, 2022 · 2 comments

Comments

@elizabethprins
Copy link

Hi, thank you for all the great work! I use this package for zooming and panning in a user interface, and it works wonderfully.

The only issue I have is that the onWheel event handles both the scrolling and the pinch-to-zoom gestures, whereas it would be preferable if scrolling were still possible, as it is for example in the zoom-and-pan interfaces of Sketch and Metro.io.

According to this article, the solution could be to add (D.field "ctrlKey" D.bool) to the decoder in the onWheel function:

When you perform a pinch-zoom gesture, Firefox and Chrome produce a wheel event with a deltaY: ±scale, ctrlKey: true.

If ctrlKey is False, the message could be a NoOp and the preventDefault in the event listener could be removed to allow scrolling.

@gampleman
Copy link
Owner

Probably it would make sense to make this customisable. For some use cases scrolling to zoom is kind of what you want (i.e. maps), others not so much.

Alternatively we could do the Google Maps sort of thing where a little message pops up when you scroll over the interactive area telling the user to hold ctrl to zoom.

@elizabethprins
Copy link
Author

Thanks for responding! Yes, I agree that scrolling to zoom can still be the best choice in some use cases.

Also, it turns out I oversimplified the scrolling solution. Because with a regular scroll window, it's possible to drag your canvas out of view and not be able to scroll back to it. So you need a function that actually handles 'panning on scroll'.

It would be great if the onWheel event could be customized to allow for this! I wouldn't know the best way to implement this, but here is a (still non-customizable) solution that I found works for my case:

onWheel : Zoom -> (OnZoom -> msg) -> Attribute msg
onWheel _ tagger =
    custom "wheel"
        (D.field "ctrlKey" D.bool
            |> D.andThen
                (\isCtrlKeyPressed ->
                    let
                        decoder =
                            if isCtrlKeyPressed then
                                zoomOnWheelDecoder

                            else
                                panOnWheelDecoder
                    in
                    D.map
                        (\onZoom ->
                            { message = tagger onZoom
                            , stopPropagation = True
                            , preventDefault = True
                            }
                        )
                        decoder
                )
        )


zoomOnWheelDecoder : Decoder OnZoom
zoomOnWheelDecoder =
    D.map3
        (\deltaY deltaMode position ->
            Wheeled
                (-deltaY
                    * (if deltaMode == 0 then
                        0.004

                       else if deltaMode == 1 then
                        0.05

                       else
                        1
                      )
                )
                position
        )
        (D.field "deltaY" D.float)
        (D.field "deltaMode" D.int)
        Events.decodeMousePosition


panOnWheelDecoder : Decoder OnZoom
panOnWheelDecoder =
    D.map3
        (\scrollX scrollY position ->
            Scrolled position scrollX scrollY
        )
        (D.field "wheelDeltaX" D.int)
        (D.field "wheelDeltaY" D.int)
        Events.decodeMousePosition

where Scrolled does the following:

Scrolled position0 scrollX scrollY ->
    let
        position1 =
            Transform.invert
                ( Tuple.first position0 - (toFloat scrollX / 4)
                , Tuple.second position0 - (toFloat scrollY / 4)
                )
                model.transform

        transform_ =
            translate position0 position1 model.transform
    in
    Zoom
        { model
            | transform = transform_ |> constrain model.extent model.translateExtent
            , transition = Nothing
        }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants