def calc_pan_pct(self, viewer, pad=0):
        """Calculate values for vertical/horizontal panning by percentages
        from the current pan position.
        """
        limits = viewer.get_limits()

        tr = viewer.tform['data_to_scrollbar']

        # calculate the corners of the entire image in unscaled cartesian
        mxwd, mxht = limits[1][:2]
        mxwd, mxht = mxwd + pad, mxht + pad
        mnwd, mnht = limits[0][:2]
        mnwd, mnht = mnwd - pad, mnht - pad

        arr = np.array([(mnwd, mnht), (mxwd, mnht),
                        (mxwd, mxht), (mnwd, mxht)],
                       dtype=np.float)
        x, y = tr.to_(arr).T

        rx1, rx2 = np.min(x), np.max(x)
        ry1, ry2 = np.min(y), np.max(y)

        rect = viewer.get_pan_rect()
        arr = np.array(rect, dtype=np.float)
        x, y = tr.to_(arr).T

        qx1, qx2 = np.min(x), np.max(x)
        qy1, qy2 = np.min(y), np.max(y)

        # this is the range of X and Y of the entire image
        # in the viewer (unscaled)
        rng_x, rng_y = abs(rx2 - rx1), abs(ry2 - ry1)

        # this is the *visually shown* range of X and Y
        abs_x, abs_y = abs(qx2 - qx1), abs(qy2 - qy1)

        # calculate the width of the slider arms as a ratio
        min_pct = self.settings.get('pan_min_scroll_thumb_pct', 0.0)
        max_pct = self.settings.get('pan_max_scroll_thumb_pct', 0.9)
        xthm_pct = max(min_pct, min(abs_x / (rx2 - rx1), max_pct))
        ythm_pct = max(min_pct, min(abs_y / (ry2 - ry1), max_pct))

        # calculate the pan position as a ratio
        pct_x = min(max(0.0, abs(0.0 - rx1) / rng_x), 1.0)
        pct_y = min(max(0.0, abs(0.0 - ry1) / rng_y), 1.0)

        bnch = Bunch.Bunch(rng_x=rng_x, rng_y=rng_y, vis_x=abs_x, vis_y=abs_y,
                           thm_pct_x=xthm_pct, thm_pct_y=ythm_pct,
                           pan_pct_x=pct_x, pan_pct_y=pct_y)
        return bnch
Calculate values for vertical/horizontal panning by percentages
        from the current pan position.