Skip to content

How to zoom on a particular point with Kivy in python

So I need to create an interactive game map for other players. They could add some markers on it locally.

I imported the image of the map and saw a stackoverflow subject with someone having the same problem. I got the solution but it’s zooming at the center of the picture.

It’s a very large picture so i need to make the zoom possible on the cursor of the mouse.

Here’s the code I’ve already made :

from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.scatterlayout import ScatterLayout
from kivy.uix.scatter import Scatter
from kivy.core.window import Window
from kivy.graphics.transformation import Matrix
from kivy.lang import Builder
Builder.load_file('map.kv')
class Zoom(ScatterLayout):
    def on_touch_down(self, touch):
        x, y = touch.x, touch.y
        self.prev_x = touch.x
        self.prev_y = touch.y
        if touch.is_mouse_scrolling:
            if touch.button == 'scrolldown':
                print('down')
                ## zoom in
                if self.scale < 10:
                    self.scale = self.scale * 1.1
            elif touch.button == 'scrollup':
                print('up')  ## zoom out
                if self.scale > 1:
                    self.scale = self.scale * 0.9
        # if the touch isn't on the widget we do nothing
        if not self.do_collide_after_children:
            if not self.collide_point(x, y):
                return False
        if 'multitouch_sim' in touch.profile:
            touch.multitouch_sim = True
        # grab the touch so we get all it later move events for sure
        self._bring_to_front(touch)
        touch.grab(self)
        self._touches.append(touch)
        self._last_touch_pos[touch] = touch.pos
        return True
class Main_app(BoxLayout):
    pass
class Stacked(App):
    def build(self):
        Window.clearcolor = (1, 1, 1, 1)
        Window.size = (1000, 700)

Answer

Seems like that should be an option for Scatter and ScatterPlane, but it isn’t. Here is a hack I have used to accomplish what you asked about:

class MyScatterPlane(ScatterPlane):
    def on_touch_up(self, touch):
        if self.collide_point(*touch.pos):
            if touch.is_mouse_scrolling:
                if touch.button == 'scrolldown':
                    mat = Matrix().scale(.9, .9, .9)
                    self.apply_transform(mat, anchor=touch.pos)
                elif touch.button == 'scrollup':
                    mat = Matrix().scale(1.1, 1.1, 1.1)
                    self.apply_transform(mat, anchor=touch.pos)
        return super().on_touch_up(touch)

This is an extension of ScatterPlane, but it is not extensively tested. Use at your own risk.