I embed an ImageView inside a ScrollPane and make it zoomable with the following code:
Now I want to zoom with the mouse cursor as the zoom origin by modifying the event to set the ScrollPane's HPosition and VPosition:
The result is okay. But it is not accurately using the cursor as the zoom origin. Could someone help me improve the code?
I cannot get a good result using AI.
B4X:
#Region Project Attributes
#MainFormWidth: 600
#MainFormHeight: 600
#End Region
Sub Process_Globals
Private fx As JFX
Private MainForm As Form
Private xui As XUI
Private Button1 As B4XView
Private ScrollPane1 As ScrollPane
Private ImageView1 As ImageView
Private percentage As Int = 100
Private CheckBox1 As CheckBox
End Sub
Sub AppStart (Form1 As Form, Args() As String)
MainForm = Form1
MainForm.RootPane.LoadLayout("Layout1")
MainForm.Show
ScrollPane1.LoadLayout("ImageView",600,600)
ImageView1.SetImage(fx.LoadImage(File.DirApp,"test.png"))
Dim r As Reflector
r.Target = ScrollPane1
r.AddEventFilter("scroll", "javafx.scene.input.ScrollEvent.SCROLL")
End Sub
Sub scroll_Filter (EventData As Event)
Dim se As JavaObject = EventData
se.RunMethod("consume", Null)
Dim DeltaY As Double = se.RunMethod("getDeltaY", Null)
Dim img As Image = ImageView1.GetImage
If DeltaY > 0 Then
percentage = percentage + 5
Else
percentage = percentage - 5
End If
ImageView1.Width = img.Width * percentage / 100
ImageView1.Height = img.Height * percentage / 100
ScrollPane1.InnerNode.PrefWidth = ImageView1.Width
ScrollPane1.InnerNode.PrefHeight = ImageView1.Height
End Sub
Sub Button1_Click
xui.MsgboxAsync("Hello World!", "B4X")
End Sub
Now I want to zoom with the mouse cursor as the zoom origin by modifying the event to set the ScrollPane's HPosition and VPosition:
B4X:
Sub scroll_Filter (EventData As Event)
Dim se As JavaObject = EventData
se.RunMethod("consume", Null)
' ===== 1. Scene XY =====
Dim sceneX As Double = se.RunMethod("getSceneX", Null)
Dim sceneY As Double = se.RunMethod("getSceneY", Null)
' ===== 2. scene → innerNode local (before zoom) =====
Dim innerJO As JavaObject = ScrollPane1.InnerNode
Dim p As JavaObject = innerJO.RunMethod("sceneToLocal", Array(sceneX, sceneY))
Dim localX As Double = p.RunMethod("getX", Null)
Dim localY As Double = p.RunMethod("getY", Null)
' ===== 3. zoom =====
Dim DeltaY As Double = se.RunMethod("getDeltaY", Null)
Dim img As Image = ImageView1.GetImage
Dim oldWidth As Double = ImageView1.Width
Dim oldHeight As Double = ImageView1.Height
If DeltaY > 0 Then
percentage = percentage + 5
Else
percentage = percentage - 5
End If
ImageView1.Width = img.Width * percentage / 100
ImageView1.Height = img.Height * percentage / 100
ScrollPane1.InnerNode.PrefWidth = ImageView1.Width
ScrollPane1.InnerNode.PrefHeight = ImageView1.Height
If CheckBox1.Checked Then
' ===== 4. calculate scale X Y =====
Dim scaleX As Double = ImageView1.Width / oldWidth
Dim scaleY As Double = ImageView1.Height / oldHeight
' ===== 5. new cursor position in innerNode =====
Dim newLocalX As Double = localX * scaleX
Dim newLocalY As Double = localY * scaleY
' ===== 6. calculate ScrollPane H/V offsets =====
Dim contentWidth As Double = ScrollPane1.InnerNode.PrefWidth
Dim contentHeight As Double = ScrollPane1.InnerNode.PrefHeight
Dim viewportWidth As Double = ScrollPane1.Width
Dim viewportHeight As Double = ScrollPane1.Height
Dim newHPos As Double = (newLocalX - localX + ScrollPane1.HPosition * (contentWidth - viewportWidth)) / (contentWidth - viewportWidth)
Dim newVPos As Double = (newLocalY - localY + ScrollPane1.VPosition * (contentHeight - viewportHeight)) / (contentHeight - viewportHeight)
' 0~1
If newHPos < 0 Then newHPos = 0
If newHPos > 1 Then newHPos = 1
If newVPos < 0 Then newVPos = 0
If newVPos > 1 Then newVPos = 1
ScrollPane1.HPosition = newHPos
ScrollPane1.VPosition = newVPos
End If
End Sub
The result is okay. But it is not accurately using the cursor as the zoom origin. Could someone help me improve the code?
I cannot get a good result using AI.