Skip to content

bug: The on_interaction_update event of the InteractiveViewer component has an error in the data returned #6469

@Qye-Leisure

Description

@Qye-Leisure

Duplicate Check

Describe the bug

The onInteractionUpdate event of the InteractiveViewer widget returns incorrect data. When the inner content is scaled to its minimum or maximum limit, the scale parameter should return 1, because once the limit is reached the widget actually stops scaling. Instead, the event repeatedly returns a value that is not equal to 1. If we try to determine whether scaling has effectively stopped by checking whether the current scale data equals the previous scale data, this can lead to serious bugs, because it is indeed possible for two consecutive scale values to be equal. As a result, there is no reliable way on the backend to determine whether scaling has truly stopped.

In most use cases of the InteractiveViewer widget, we need to transform coordinates between the viewport and the child widget — for example, in 2D games, infinite canvas scenarios, etc. We require accurate scale data to calculate the real offset of the child space (scaling centered on the mouse pointer causes the child to shift, because the framework’s default scaling is effectively center-based). This bug makes the widget a half-finished component.

My request is that this event return the correct scale data. If possible, please also add the offset delta for each scale operation and scrollbar support, though these are not mandatory.

Code sample

Code
import flet as ft
from typing import  cast


@ft.control
class BaseCanvas(ft.GestureDetector):
    max_scale: float = 3
    scale_step: float = 0.25
    min_scale: float = 0.25

    def init(self):
        self.cumulative_offset_x = self.cumulative_offset_y = 0
        self.current_scale = 1

        self.window_container_size = ()
        self.canvas_size=()
        
        
        self.scaled_canvas_size = ()
        self.scale_offset_x = 0
        self.scale_offset_y = 0

        self.canvas_container = ft.Container(
            bgcolor=ft.Colors.BLUE_100,
            content=ft.Stack(
                controls=[
                    self.module_container((50, 50)),
                    self.module_container((50, 600)),
                    self.module_container((1000, 50)),
                    self.module_container((1000, 600)),
                ],
            ),
        )

        self.content = ft.InteractiveViewer(
            expand=True,
            clip_behavior= ft.ClipBehavior.HARD_EDGE,
            content=self.canvas_container,
            on_size_change = lambda e: self.get_window_container_size(e),
            constrained = False,
            on_interaction_update=lambda e:  print(e),

        )


        self.on_hover = self.mouse_hover_event

    def module_container(self, pos):
        module = ft.Container(
            bgcolor=ft.Colors.GREEN,
            width=70,
            content=ft.Column(
                [
                    ft.Container(width=70, content=ft.Text(f"module {j}"))
                    for j in range(10)
                ]
            ),
        )

        return ft.GestureDetector(
            mouse_cursor=ft.MouseCursor.MOVE,
            drag_interval=5,
            left=pos[0],
            top=pos[1],
            content=module,
        )

    def get_window_container_size(self, e):

        self.window_container_size = (e.width, e.height)
        if not self.canvas_size or self.canvas_size<self.window_container_size:
            self.canvas_size=self.window_container_size


            self.canvas_container.width,self.canvas_container.height=self.window_container_size
            self.canvas_container=cast(ft.Container,self.canvas_container)
            self.canvas_container.update()
        print(self.window_container_size)

    def mouse_hover_event(self, e: ft.HoverEvent[ft.GestureDetector]) -> None:
        """Handle mouse hover, compute canvas coordinates"""
        if e.local_delta is None:
            return







if __name__ == "__main__":

    def main(page: ft.Page):
        canvas = BaseCanvas()
        page.add(
            ft.Container(expand=True,bgcolor=ft.Colors.AMBER, content=canvas),
        )

    ft.run(main)

To reproduce

  1. Run the code
  2. Scale to the maximum size
  3. Observe the scale data returned by the on_interaction_update event.

Expected behavior

No response

Screenshots / Videos

Captures

[Upload media here]

Operating System

Windows

Operating system details

11

Flet version

0.85

Regression

No, it isn't

Suggestions

No response

Logs

Logs
[Paste your logs here]

Additional details

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions