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

Discrete panning in X and Y axes #104

Open
andrey-ananiev opened this issue Dec 29, 2024 · 4 comments
Open

Discrete panning in X and Y axes #104

andrey-ananiev opened this issue Dec 29, 2024 · 4 comments

Comments

@andrey-ananiev
Copy link

In my project, several graphs are located on one screen, one above the other. The user can scroll the screen vertically. However, if panning is enabled in the X-axis model, this blocks vertical scrolling. Is it possible to fix this?

@gsteckman
Copy link
Member

Not sure. I didn't write the gesture handling for the panning and it sounds like it's capturing all mouse drags and not passing them to the parent component. This is a bit of a classic problem when there are scrollable containers inside other scrollable containers. Which one wins?

@andrey-ananiev
Copy link
Author

This is implemented in the VICO library using the scrollable modifier:

internal fun Modifier.chartTouchEvent(
    setTouchPoint: ((Point?) -> Unit)?,
    isScrollEnabled: Boolean,
    scrollableState: ChartScrollState,
    onZoom: OnZoom?,
): Modifier = scrollable(
    state = scrollableState,
    orientation = Orientation.Horizontal,
    reverseDirection = true,
    enabled = isScrollEnabled,
)
    .then(
        if (setTouchPoint != null) {
            pointerInput(setTouchPoint) {
                awaitPointerEventScope {
                    var isNoDrag = true
                    while (true) {
                        val event = awaitPointerEvent()
                        when (event.type) {
                            PointerEventType.Press -> setTouchPoint(null)
                            PointerEventType.Move -> isNoDrag = false
                            PointerEventType.Release -> {
                                if (isNoDrag) {
                                    setTouchPoint(event.changes.first().position.point)
                                } else {
                                    isNoDrag = true
                                }
                            }
                        }
                    }
                }
            }
        } else {
            Modifier
        },
    )
    .then(
        if (isScrollEnabled && onZoom != null) {
            pointerInput(setTouchPoint, onZoom) {
                detectZoomGestures { centroid, zoom ->
                    setTouchPoint?.invoke(null)
                    onZoom(centroid, zoom)
                }
            }
        } else {
            Modifier
        },
    )

@andrey-ananiev
Copy link
Author

I found a temporary solution for myself. Perhaps it will prompt you to think about how to make discrete scrolling along the X and Y axes. In file DefaultTransformGesturesHandler on line 83:

//event.consumeChangedPositions()
event.changes.forEach { change ->
 if (change.position.y == 0f) change.consume()
}

I confirm the use of all changes except those containing changes to the Y position. I think you could discretize zoomLock and panLock on different axes to support the ability to scroll the graph only in the desired direction.

I hope this was helpful to you!

@asynchaizer
Copy link
Contributor

@andrey-ananiev You can view the changes that are related to gestures(#110) and use the gesture configuration panXConsumptionEnabled = false(if you use Android or iOS). For Desktop, everything should work without this flag.

It is currently impossible (or possible, but it would be a serious violation of the internal logic of gesture processing and would be a very bad trick) for mobile platforms, as well as for Desktop (in the case of diagonal panning through the trackpad), because diagonal gestures are possible on mobile platforms, and the gesture API in Compose is designed in such a way that it is impossible to consume only the X-changes or only the Y-changes, that is, we either consume this gesture exactly completely, or we don't consume it.

In most cases, the rule works - if the logic is working and the content is changing to a gesture, it must be consumed, otherwise it will lead to conflicts with the parent container.

As part of the gesture changes, I added the ability to forcibly disable gesture consumption, but at the same time process the gesture, this is useful for mobile platforms when we have horizontal panning enabled, and our list needs to be scrolled vertically, respectively, in this case, you can disable horizontal gesture consumption and the chart will stop consuming horizontal gestures and parent The list will be able to accept and process events.

I also additionally implemented the logic when, when the panning limit is reached, gestures stop being consumed. For example, we scrolled down the charts to the limit and continue scrolling down, in which case the gestures will stop being consumed and the parent container will be able to process them.

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

3 participants