Scrolling a canvas as a shape you're moving approaches its edges

Posted by Steven Sproat on Stack Overflow See other posts from Stack Overflow or by Steven Sproat
Published on 2010-04-18T14:05:10Z Indexed on 2010/04/18 14:13 UTC
Read the original article Hit count: 323

Filed under:
|
|
|

Hi, I develop a Python-based drawing program, Whyteboard. I have tools that the user can create new shapes on the canvas, such as text/images/rectangles/circles/polygons. I also have a Select tool that allows the users to modify these shapes - for example, moving a shape's position, resizing, or editing polygon's points' positions.

I'm adding in a new feature where moving or resizing a point near the canvas edge will automatically scroll the canvas. I think it's a good idea in terms of program usability, and annoys me when other program's don't have this feature.

I've made some good progress on coding this; below is some Python code to demonstrate what I'm doing. These functions demonstrate how some shapes calculate their "edges":

def find_edges(self):
    """A line."""
    self.edges = {EDGE_TOP: min(self.y, self.y2), EDGE_RIGHT: max(self.x, self.x2),
                  EDGE_BOTTOM: max(self.y, self.y2), EDGE_LEFT: min(self. x, self.x2)}


def find_edges(self):
   """An image"""
    self.edges = {EDGE_TOP: self.y, EDGE_RIGHT: self.x + self.image.GetWidth(),
                  EDGE_BOTTOM: self.y + self.image.GetWidth(), EDGE_LEFT: self.x}


def find_edges(self):
    """Get the bounding rectangle for the polygon"""
    xmin = min(x for x, y in self.points)
    ymin = min(y for x, y in self.points)
    xmax = max(x for x, y in self.points)
    ymax = max(y for x, y in self.points)
    self.edges = {EDGE_TOP: ymin, EDGE_RIGHT: xmax, EDGE_BOTTOM: ymax, EDGE_LEFT: xmin}

And here's the code I have so far to implement the scrolling when a shape nears the edge:

def check_canvas_scroll(self, x, y, moving=False):
    """
    We check that the x/y coords are within 50px from the edge of the canvas
    and scroll the canvas accordingly. If the shape is being moved, we need
    to check specific edges of the shape (e.g. left/right side of rectangle)
    """

    size = self.board.GetClientSizeTuple()  # visible area of the canvas
    if not self.board.area > size:  # canvas is too small to need to scroll
        return

    start = self.board.GetViewStart()  # user's starting "viewport"
    scroll = (-1, -1)  # -1 means no change

    if moving:
        if self.shape.edges[EDGE_RIGHT] > start[0] + size[0] - 50:
            scroll = (start[0] + 5, -1)
        if self.shape.edges[EDGE_BOTTOM] > start[1] + size[1] - 50:
            scroll = (-1, start[1] + 5)
        # snip others

    else:
        if x > start[0] + size[0] - 50:
            scroll = (start[0] + 5, -1)
        if y > start[1] + size[1] - 50:
            scroll = (-1, start[1] + 5)
        # snip others

    self.board.Scroll(*scroll)

This code actually works pretty well. If we're moving a shape, then we need to know its edges to calculate when they're coming close to the canvas edge. If we're resizing just a single point, then we just use the x/y coords of that point to see if it's close to the edge.

The problem I'm having is a little tricky to describe - basically, if you move a shape to the left, and stop moving it, if you positioned the shape within the 50px from the canvas, then the next time you go to move the shape, the code that says "ok, is this shape close to the end?" gets triggered, and the canvas scrolls to the left, even if you're moving the shape to the right.

Can anyone think on how to stop this? I created a youtube video to demonstrate the issue. At about 0:54, I move a polygon to the left of the canvas and position it there. The next time I move it, the canvas scrolls to the left even though I'm moving it right

Another thing I'd like to add, but I'm stuck on is the scroll gaining momentum the longer a shape is scrolling? So, with a large canvas, you're not moving a shape for ages, moving 5px at a time, when you need to cover a 2000px distance. Any suggestions there?

Thanks all - sorry for the super long question!

© Stack Overflow or respective owner

Related posts about canvas

Related posts about wxpython