78 lines
2.2 KiB
Python
78 lines
2.2 KiB
Python
"""
|
|
UX interaction customs.
|
|
"""
|
|
import pyqtgraph as pg
|
|
from pyqtgraph import functions as fn
|
|
|
|
from ..log import get_logger
|
|
from ._style import _min_points_to_show
|
|
|
|
|
|
log = get_logger(__name__)
|
|
|
|
|
|
class ChartView(pg.ViewBox):
|
|
"""Price chart view box with interaction behaviors you'd expect from
|
|
any interactive platform:
|
|
|
|
- zoom on mouse scroll that auto fits y-axis
|
|
- no vertical scrolling
|
|
- zoom to a "fixed point" on the y-axis
|
|
"""
|
|
def __init__(
|
|
self,
|
|
parent=None,
|
|
**kwargs,
|
|
):
|
|
super().__init__(parent=parent, **kwargs)
|
|
# disable vertical scrolling
|
|
self.setMouseEnabled(x=True, y=False)
|
|
self.linked_charts = None
|
|
|
|
def wheelEvent(self, ev, axis=None):
|
|
"""Override "center-point" location for scrolling.
|
|
|
|
This is an override of the ``ViewBox`` method simply changing
|
|
the center of the zoom to be the y-axis.
|
|
|
|
TODO: PR a method into ``pyqtgraph`` to make this configurable
|
|
"""
|
|
|
|
if axis in (0, 1):
|
|
mask = [False, False]
|
|
mask[axis] = self.state['mouseEnabled'][axis]
|
|
else:
|
|
mask = self.state['mouseEnabled'][:]
|
|
|
|
# don't zoom more then the min points setting
|
|
l, lbar, rbar, r = self.linked_charts.chart.bars_range()
|
|
vl = r - l
|
|
|
|
if ev.delta() > 0 and vl <= _min_points_to_show:
|
|
log.trace("Max zoom bruh...")
|
|
return
|
|
if ev.delta() < 0 and vl >= len(self.linked_charts._array):
|
|
log.trace("Min zoom bruh...")
|
|
return
|
|
|
|
# actual scaling factor
|
|
s = 1.015 ** (ev.delta() * -1 / 20) # self.state['wheelScaleFactor'])
|
|
s = [(None if m is False else s) for m in mask]
|
|
|
|
# center = pg.Point(
|
|
# fn.invertQTransform(self.childGroup.transform()).map(ev.pos())
|
|
# )
|
|
|
|
# XXX: scroll "around" the right most element in the view
|
|
furthest_right_coord = self.boundingRect().topRight()
|
|
center = pg.Point(
|
|
fn.invertQTransform(
|
|
self.childGroup.transform()
|
|
).map(furthest_right_coord)
|
|
)
|
|
|
|
self._resetTarget()
|
|
self.scaleBy(s, center)
|
|
ev.accept()
|
|
self.sigRangeChangedManually.emit(mask)
|