I have a map where the user can build cities and move around their units and attack other player's units. The mouse wheel can be used to zoom in or out. No matter what the level of zoom is, I want to be able to see the original map coordinates, for example, to send messages like "Unit X was seen/attacked at coordinates (200, 400)". But I can't make it work for all cases. Here is a simplified version of the zoomable map. I have placed labels and markers at certain coordinates to illustrate my point. import tkinter as tk from tkinter import ttk class ZoomableCanvas(tk.Tk): def __init__(self): super().__init__() self.title("Zoomable Canvas") self.geometry("700x700") # Create the main canvas frame self.canvas_frame = ttk.Frame(self) self.canvas_frame.pack(fill="both", expand=True) # Create the canvas self.canvas = tk.Canvas(self.canvas_frame, width=600, height=600, bg='white', scrollregion=(0, 0, 800, 800)) self.canvas.pack(side="left", fill="both", expand=True) # Add bottom frame with label self.bottom_frame = ttk.Frame(self) self.bottom_frame.pack(side="bottom", fill="x") self.coordinates_label = ttk.Label(self.bottom_frame, text="Mouse Coordinates: (0, 0)") self.coordinates_label.pack() # Generate 9 points, spaced each 200px apart, in a grid pattern for x in range(1, 4): for y in range(1, 4): x_pos = x * 200 y_pos = y * 200 self.draw_cross(x_pos, y_pos, tags='initial_coords', color="red") self.canvas.create_text(x_pos + 10, y_pos + 10, text=f'{x_pos, y_pos}', fill='red', tags='initial_coords') # Bind events for zooming and mouse movement self.canvas.bind("<MouseWheel>", self.zoom) self.canvas.bind("<Motion>", self.update_coordinates_label) # Zoom scale self.scale = 1.0 self.total_zoom = 1.0 self.previous_zoom = 1.0 self.zoom_center = (0, 0) def draw_cross(self, x, y, tags, color="black", size=3): # Draw a cross at the specified coordinates self.canvas.create_line(x - size, y, x + size, y, fill=color, tags=tags) self.canvas.create_line(x, y - size, x, y + size, fill=color, tags=tags) def zoom(self, event): self.canvas.delete('coords') # Clear previous coordinates # Zoom in or out based on mouse wheel direction self.previous_zoom = self.total_zoom if event.delta > 0: self.total_zoom += 0.25 if self.total_zoom > 2.0: self.total_zoom = 2.0 # Limit zooming in to a maximum of 2.0 return else: self.scale = self.total_zoom / self.previous_zoom print(f"Zooming in factor: {self.scale}, Total Zoom: {self.total_zoom}, Prev Zoom: {self.previous_zoom}, Pos: ({event.x}, {event.y})") else: self.total_zoom -= 0.25 if self.total_zoom < 1.0: self.total_zoom = 1.0 # Limit zooming in to a minimum of 1.0 return else: self.scale = self.total_zoom / self.previous_zoom print(f"Zooming out factor: {self.scale}, Total Zoom: {self.total_zoom}, Prev Zoom: {self.previous_zoom}, Pos: ({event.x}, {event.y})") self.zoom_center = (event.x, event.y) self.canvas.scale("all", event.x, event.y, self.scale, self.scale) #self.canvas.configure(scrollregion=self.canvas.bbox("all")) self.previous_scale = self.scale for x in range(1, 4): for y in range(1, 4): x_pos = x * 200 y_pos = y * 200 self.draw_cross(x_pos, y_pos, tags='coords', color="black") self.canvas.create_text(x_pos - 10, y_pos - 10, text=f'{x_pos, y_pos}', fill='black', tags='coords') def update_coordinates_label(self, event): scaled_x = self.zoom_center[0] - (self.zoom_center[0] - event.x) / self.total_zoom scaled_y = self.zoom_center[1] - (self.zoom_center[1] - event.y) / self.total_zoom # Get the mouse position relative to the canvas canvas_x = self.canvas.canvasx(event.x) canvas_y = self.canvas.canvasy(event.y) # Update the coordinates label with the transformed values self.coordinates_label.config( text=f"{event.x=}, {event.y=} {canvas_x=}, {canvas_y=} \nScaled_coords: ({scaled_x:.2f}, {scaled_y:.2f}) \nScale: {self.scale:.2f} Zoom: {self.total_zoom:.2f}" ) if __name__ == "__main__": app = ZoomableCanvas() app.mainloop() If I place the mouse on (200,200) and zoom in once, I can move the mouse over all red crosses in the map and the label shows their original/scaled coordinates (the ones the user is interested in because that's where their cities/units are). I have also shown canvas coordinates with black markers just to help me analyze the problem. If I zoom in/out from the same (200, 200) coordinates, everything is fine. However, if I zoom in from, say, (200, 200) and then I zoom in again from (400, 400), or any other coordinate, now the "Scaled_coords" displayed in the label don't show the red markers' original coordinates. If I zoom in 3-4 times from the same mouse position, the original red marker coordinates are correctly show in the label. Likewise if I zoom out from that same position. But if I zoom somewhere, move the mouse, zoom some more, it doesn't work as I would like it to. Thank you in advance. Continue reading...