Я хочу реализовать панорамирование и масштабирование с использованием текущей позиции мыши. Мой вариант использования особенно прост, учитывая, что я хочу реализовать его только по оси X.
Я попробовал несколько подходов, последний из которых обсуждался здесь:
Масштабирование графика, основанная на текущем положении мыши
Но безрезультатно, масштабирование и панорамирование не работают правильно и плавно на нескольких этапах.
Суть проблемы должна составлять ie в как я выполняю преобразования в методах on_mouse_wheel
и scr2obj
и obj2scr
.
import numpy as np
import math
from vispy import app, gloo, visuals
from vispy.visuals.transforms import STTransform
# Number of displayed lines
x_size = 50
# window size
canvas_size = (800, 600)
# launch app
app.Application(backend_name='PyQt5')
# define texture
tex = np.c_[(np.ones(shape=(1, x_size, 1)),np.zeros(shape=(1, x_size, 1)),np.zeros(shape=(1, x_size, 1)),np.random.uniform(size=(1, x_size, 1)))]
class Canvas(app.Canvas):
def __init__(self):
# housekeeping
app.Canvas.__init__(self, title='Use your wheel to zoom!', keys='interactive', vsync=True, autoswap=True)
gloo.set_viewport(0, 0, *self.physical_size)
# translate and scale 1d texture to full screen
self.heatmap = visuals.ImageVisual(data=tex, method='subdivide',interpolation='nearest')
s = (1 / (self.size[0]*self.heatmap.size[0] / (self.size[0]*2)), 100)
self.heatmap.transform = STTransform(scale=s, translate=(-1,-1))
self.translate = 0.
self.scale = 1.
# track time
self._timer = app.Timer('auto', connect=self.on_timer, start=True)
# housekeeping
gloo.set_state(clear_color='black', blend=True, blend_func=('src_alpha', 'one_minus_src_alpha'))
self.show()
def scr2obj(self, x):
res = (x - self.translate) / self.scale
return res
def obj2scr(self, x):
res = self.translate + (x * self.scale)
return res
def on_mouse_wheel(self, event):
#get new mouse pos
mx = self._normalize(event.pos)[0]
# translation of new mouse pos to world
mx0 = self.scr2obj(mx)
#apply zoom
dx = np.sign(event.delta[1]) * 0.05
self.scale = self.scale * math.exp(1.0 * dx)
#now compute new screen based on already translated position and new zoom
mx0 = self.obj2scr(mx0)
#update
self.translate = self.translate + (mx-mx0)
def on_resize(self, event):
vp = (0, 0, event.physical_size[0], event.physical_size[1])
self.context.set_viewport(*vp)
def on_timer(self, event):
#reset trnasform
self.heatmap.transform._scale = np.array([1 / (self.size[0]*self.heatmap.size[0] / (self.size[0]*2)),2.,1.,1.])#np.ones(4, dtype=np.float32)
self.heatmap.transform._translate = np.array([-1., -1. , 0., 0.])
#scale and translate to mouse pos
self.heatmap.transform.zoom(zoom=self.scale, center=self.translate)
#send to the shader
self.update()
def on_draw(self, event):
gloo.clear(color='black', depth=True)
self.heatmap.draw()
def _normalize(self, x):
w = float(self.size[0])
return x / (w / 2.) - 1
if __name__ == '__main__':
c = Canvas()
app.run()