-
-
Notifications
You must be signed in to change notification settings - Fork 6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
lineChartView.zoom() - how to obtain center x/y coordinates #4434
Comments
Hello @lienbacher /// The lowest x-index (value on the x-axis) that is still visible on he chart.
open var lowestVisibleX: Double
{
var pt = CGPoint(
x: viewPortHandler.contentLeft,
y: viewPortHandler.contentBottom)
getTransformer(forAxis: .left).pixelToValues(&pt)
return max(xAxis._axisMinimum, Double(pt.x))
}
/// The highest x-index (value on the x-axis) that is still visible on the chart.
open var highestVisibleX: Double
{
var pt = CGPoint(
x: viewPortHandler.contentRight,
y: viewPortHandler.contentBottom)
getTransformer(forAxis: .left).pixelToValues(&pt)
return min(xAxis._axisMaximum, Double(pt.x))
} Why do not compute the values you need yourself? Seems like all the data is available. @objc open var viewPortHandler: ViewPortHandler!
open func getTransformer(forAxis axis: YAxis.AxisDependency) -> Transformer Also there is a let transformer = chartView.getTransformer(forAxis: .left)
...
func visibleCenter(of viewPortHandler: ViewPortHandler, transformer: Transformer) -> CGPoint
{
var pt = viewPortHandler.contentCenter
transformer.pixelToValues(&pt)
return pt //+ add checks for the min/max for the x/y if you need
} |
Thanks for your detailed reply @bivant!
Well I am trying, but I fail to find/understand the documentation. I understand from the documentation that the zoom() function expects x/y to be data values, but I have not found any documentation that would bring me anywhere close to how helpful your post was. edit: I have finally managed to understand what's going on with the snippets you provided. I was after all using the wrong overload of the zoom function without the axis dependency that would accept pixel values. Interestingly enough the function accepting pixel values would not yield the expected result when passing @objc func chartXZoomChanged(notification: Notification) {
let transformer = lineChartView.getTransformer(forAxis: .left)
var centerPt = lineChartView.viewPortHandler.contentCenter
transformer.pixelToValues(¢erPt)
lineChartView.zoom(scaleX: zoomValue, scaleY: lineChartView.scaleY, xValue: Double(centerPt.x), yValue: Double(centerPt.y), axis: .left)
} Thank you very much! I can finally sleep tight again 🙏 |
Hello @lienbacher
Seems like your assumption is wrong: /// Zooms in or out by the given scale factor. x and y are the coordinates
/// (in pixels) of the zoom center.
///
/// - Parameters:
/// - scaleX: if < 1 --> zoom out, if > 1 --> zoom in
/// - scaleY: if < 1 --> zoom out, if > 1 --> zoom in
/// - x:
/// - y:
@objc open func zoom(
scaleX: CGFloat,
scaleY: CGFloat,
x: CGFloat,
y: CGFloat)
{ Well, since pinch zoom works as you need maybe the best way is to check it's implementation: if canZoomMoreX || canZoomMoreY
{
var location = recognizer.location(in: self)
location.x = location.x - _viewPortHandler.offsetLeft
if isTouchInverted()
{
location.y = -(location.y - _viewPortHandler.offsetTop)
}
else
{
location.y = -(_viewPortHandler.chartHeight - location.y - _viewPortHandler.offsetBottom)
}
let scaleX = canZoomMoreX ? recognizer.nsuiScale : 1.0
let scaleY = canZoomMoreY ? recognizer.nsuiScale : 1.0
var matrix = CGAffineTransform(translationX: location.x, y: location.y)
matrix = matrix.scaledBy(x: scaleX, y: scaleY)
matrix = matrix.translatedBy(x: -location.x, y: -location.y)
matrix = _viewPortHandler.touchMatrix.concatenating(matrix)
_viewPortHandler.refresh(newMatrix: matrix, chart: self, invalidate: true)
if delegate !== nil
{
delegate?.chartScaled?(self, scaleX: scaleX, scaleY: scaleY)
}
} I hope that using the center of the viewPort you should achieve the result you need. The difference here, as I see, is the matrix logic. Glad you overcome this issue. Good luck :) |
Ahh this reply came way faster than I expected, I got it down shortly after I posted my reply and thought I would be fast enough with an edit. I was actually using the wrong overload of zoom. There is another one: /// Zooms in or out by the given scale factor.
/// x and y are the values (**not pixels**) of the zoom center.
///
/// - Parameters:
/// - scaleX: if < 1 --> zoom out, if > 1 --> zoom in
/// - scaleY: if < 1 --> zoom out, if > 1 --> zoom in
/// - xValue:
/// - yValue:
/// - axis:
@objc open func zoom(
scaleX: CGFloat,
scaleY: CGFloat,
xValue: Double,
yValue: Double,
axis: For future readers: the revision history has my old post still in there! And thanks for that additional snippet, that also helps a lot understanding! |
Hello!
I am trying to implement an x-axis zoom-slider on a mac os app. The zooming itself is no issue at all, it zooms just fine. I am however struggling to keep the current viewport centered during the zoom operation, especially when the scale of the viewpoint has already been altered by for instance a pinch zoom with the touchpad. I have managed to keep the x-axis centered on the viewport, by just calculating the center of highestVisibleX and lowestVisibleX and call moveViewToX(center), however there are no such functions for the y axis.
I am 100% sure there is a simple way to gather those x/y coordinates so I can just pass to the zoom() function and keep the view centered while I change the x-scale. I have read the documentation a few times and still fail to come up with a working solution. I'd be incredibly thankful if somebody would be able to help me along. 🙏
The text was updated successfully, but these errors were encountered: