<commit_before>//
//  ChartViewPortHandler.swift
//  Charts
//
//  Created by <NAME> on 27/2/15.
//
//  Copyright 2015 <NAME> & <NAME>
//  A port of MPAndroidChart for iOS
//  Licensed under Apache License 2.0
//
//  https://github.com/danielgindi/ios-charts
//

import Foundation
import CoreGraphics

public class ChartViewPortHandler: NSObject
{
    /// matrix used for touch events
    private var _touchMatrix = CGAffineTransformIdentity;
    
    /// this rectangle defines the area in which graph values can be drawn
    private var _contentRect = CGRect();
    
    private var _chartWidth = CGFloat(0.0);
    private var _chartHeight = CGFloat(0.0);
    
    /// minimum scale value on the y-axis
    private var _minScaleY = CGFloat(1.0);
    
    /// minimum scale value on the x-axis
    private var _minScaleX = CGFloat(1.0);
    
    /// maximum scale value on the x-axis
    private var _maxScaleX = CGFloat.max;
    
    /// contains the current scale factor of the x-axis
    private var _scaleX = CGFloat(1.0);
    
    /// contains the current scale factor of the y-axis
    private var _scaleY = CGFloat(1.0);
    
    /// offset that allows the chart to be dragged over its bounds on the x-axis
    private var _transOffsetX = CGFloat(0.0);
    
    /// offset that allows the chart to be dragged over its bounds on the x-axis
    private var _transOffsetY = CGFloat(0.0);
    
    public override init()
    {
    }
    
    public init(width: CGFloat, height: CGFloat)
    {
        super.init();
        
        setChartDimens(width: width, height: height);
    }
    
    public func setChartDimens(#width: CGFloat, height: CGFloat)
    {
        var offsetLeft = self.offsetLeft;
        var offsetTop = self.offsetTop;
        var offsetRight = self.offsetRight;
        var offsetBottom = self.offsetBottom;
        
        _chartHeight = height;
        _chartWidth = width;
        
        restrainViewPort(offsetLeft: offsetLeft, offsetTop: offsetTop, offsetRight: offsetRight, offsetBottom: offsetBottom);
    }
    
    public var hasChartDimens: Bool
    {
        if (_chartHeight > 0.0 && _chartWidth > 0.0)
        {
            return true;
        }
        else
        {
            return false;
        }
    }

    public func restrainViewPort(#offsetLeft: CGFloat, offsetTop: CGFloat, offsetRight: CGFloat, offsetBottom: CGFloat)
    {
        _contentRect.origin.x = offsetLeft;
        _contentRect.origin.y = offsetTop;
        _contentRect.size.width = _chartWidth - offsetLeft - offsetRight;
        _contentRect.size.height = _chartHeight - offsetBottom - offsetTop;
    }
    
    public var offsetLeft: CGFloat
    {
        return _contentRect.origin.x;
    }
    
    public var offsetRight: CGFloat
    {
        return _chartWidth - _contentRect.size.width - _contentRect.origin.x;
    }
    
    public var offsetTop: CGFloat
    {
        return _contentRect.origin.y;
    }
    
    public var offsetBottom: CGFloat
    {
        return _chartHeight - _contentRect.size.height - _contentRect.origin.y;
    }
    
    public var contentTop: CGFloat
    {
        return _contentRect.origin.y;
    }
    
    public var contentLeft: CGFloat
    {
        return _contentRect.origin.x;
    }
    
    public var contentRight: CGFloat
    {
        return _contentRect.origin.x + _contentRect.size.width;
    }
    
    public var contentBottom: CGFloat
    {
        return _contentRect.origin.y + _contentRect.size.height;
    }
    
    public var contentWidth: CGFloat
    {
        return _contentRect.size.width;
    }
    
    public var contentHeight: CGFloat
    {
        return _contentRect.size.height;
    }
    
    public var contentRect: CGRect { return _contentRect; }
    
    public var contentCenter: CGPoint
    {
        return CGPoint(x: _contentRect.origin.x + _contentRect.size.width / 2.0, y: _contentRect.origin.y + _contentRect.size.height / 2.0);
    }
    
    public var chartHeight: CGFloat { return _chartHeight; }
    
    public var chartWidth: CGFloat { return _chartWidth; }

    // MARK: - Scaling/Panning etc.
    
    /// Zooms around the specified center
    public func zoom(#scaleX: CGFloat, scaleY: CGFloat, x: CGFloat, y: CGFloat) -> CGAffineTransform
    {
        var matrix = CGAffineTransformTranslate(_touchMatrix, x, y);
        matrix = CGAffineTransformScale(matrix, scaleX, scaleY);
        matrix = CGAffineTransformTranslate(matrix, -x, -y);
        return matrix;
    }
    
    /// Zooms in by 1.4, x and y are the coordinates (in pixels) of the zoom center.
    public func zoomIn(#x: CGFloat, y: CGFloat) -> CGAffineTransform
    {
        return zoom(scaleX: 1.4, scaleY: 1.4, x: x, y: y);
    }
    
    /// Zooms out by 0.7, x and y are the coordinates (in pixels) of the zoom center.
    public func zoomOut(#x: CGFloat, y: CGFloat) -> CGAffineTransform
    {
        return zoom(scaleX: 0.7, scaleY: 0.7, x: x, y: y);
    }
    
    /// Resets all zooming and dragging and makes the chart fit exactly it's bounds.
    public func fitScreen() -> CGAffineTransform
    {
        _minScaleX = 1.0;
        _minScaleY = 1.0;

        return CGAffineTransformIdentity;
    }
    
    /// Centers the viewport around the specified position (x-index and y-value) in the chart.
    public func centerViewPort(#pt: CGPoint, chart: ChartViewBase)
    {
        let translateX = pt.x - offsetLeft;
        let translateY = pt.y - offsetTop;
        
        var matrix = CGAffineTransformConcat(_touchMatrix, CGAffineTransformMakeTranslation(-translateX, -translateY));
        
        refresh(newMatrix: matrix, chart: chart, invalidate: false);
    }
    
    /// call this method to refresh the graph with a given matrix
    public func refresh(#newMatrix: CGAffineTransform, chart: ChartViewBase, invalidate: Bool) -> CGAffineTransform
    {
        _touchMatrix = newMatrix;
        
        // make sure scale and translation are within their bounds
        limitTransAndScale(matrix: &_touchMatrix, content: _contentRect);
        
        chart.setNeedsDisplay();
        
        return _touchMatrix;
    }
    
    /// limits the maximum scale and X translation of the given matrix
    private func limitTransAndScale(inout #matrix: CGAffineTransform, content: CGRect?)<commit_msg>Fixed an issue where invalidate was not called after centre<commit_after>//
//  ChartViewPortHandler.swift
//  Charts
//
//  Created by <NAME> on 27/2/15.
//
//  Copyright 2015 <NAME> & <NAME>
//  A port of MPAndroidChart for iOS
//  Licensed under Apache License 2.0
//
//  https://github.com/danielgindi/ios-charts
//

import Foundation
import CoreGraphics

public class ChartViewPortHandler: NSObject
{
    /// matrix used for touch events
    private var _touchMatrix = CGAffineTransformIdentity;
    
    /// this rectangle defines the area in which graph values can be drawn
    private var _contentRect = CGRect();
    
    private var _chartWidth = CGFloat(0.0);
    private var _chartHeight = CGFloat(0.0);
    
    /// minimum scale value on the y-axis
    private var _minScaleY = CGFloat(1.0);
    
    /// minimum scale value on the x-axis
    private var _minScaleX = CGFloat(1.0);
    
    /// maximum scale value on the x-axis
    private var _maxScaleX = CGFloat.max;
    
    /// contains the current scale factor of the x-axis
    private var _scaleX = CGFloat(1.0);
    
    /// contains the current scale factor of the y-axis
    private var _scaleY = CGFloat(1.0);
    
    /// offset that allows the chart to be dragged over its bounds on the x-axis
    private var _transOffsetX = CGFloat(0.0);
    
    /// offset that allows the chart to be dragged over its bounds on the x-axis
    private var _transOffsetY = CGFloat(0.0);
    
    public override init()
    {
    }
    
    public init(width: CGFloat, height: CGFloat)
    {
        super.init();
        
        setChartDimens(width: width, height: height);
    }
    
    public func setChartDimens(#width: CGFloat, height: CGFloat)
    {
        var offsetLeft = self.offsetLeft;
        var offsetTop = self.offsetTop;
        var offsetRight = self.offsetRight;
        var offsetBottom = self.offsetBottom;
        
        _chartHeight = height;
        _chartWidth = width;
        
        restrainViewPort(offsetLeft: offsetLeft, offsetTop: offsetTop, offsetRight: offsetRight, offsetBottom: offsetBottom);
    }
    
    public var hasChartDimens: Bool
    {
        if (_chartHeight > 0.0 && _chartWidth > 0.0)
        {
            return true;
        }
        else
        {
            return false;
        }
    }

    public func restrainViewPort(#offsetLeft: CGFloat, offsetTop: CGFloat, offsetRight: CGFloat, offsetBottom: CGFloat)
    {
        _contentRect.origin.x = offsetLeft;
        _contentRect.origin.y = offsetTop;
        _contentRect.size.width = _chartWidth - offsetLeft - offsetRight;
        _contentRect.size.height = _chartHeight - offsetBottom - offsetTop;
    }
    
    public var offsetLeft: CGFloat
    {
        return _contentRect.origin.x;
    }
    
    public var offsetRight: CGFloat
    {
        return _chartWidth - _contentRect.size.width - _contentRect.origin.x;
    }
    
    public var offsetTop: CGFloat
    {
        return _contentRect.origin.y;
    }
    
    public var offsetBottom: CGFloat
    {
        return _chartHeight - _contentRect.size.height - _contentRect.origin.y;
    }
    
    public var contentTop: CGFloat
    {
        return _contentRect.origin.y;
    }
    
    public var contentLeft: CGFloat
    {
        return _contentRect.origin.x;
    }
    
    public var contentRight: CGFloat
    {
        return _contentRect.origin.x + _contentRect.size.width;
    }
    
    public var contentBottom: CGFloat
    {
        return _contentRect.origin.y + _contentRect.size.height;
    }
    
    public var contentWidth: CGFloat
    {
        return _contentRect.size.width;
    }
    
    public var contentHeight: CGFloat
    {
        return _contentRect.size.height;
    }
    
    public var contentRect: CGRect { return _contentRect; }
    
    public var contentCenter: CGPoint
    {
        return CGPoint(x: _contentRect.origin.x + _contentRect.size.width / 2.0, y: _contentRect.origin.y + _contentRect.size.height / 2.0);
    }
    
    public var chartHeight: CGFloat { return _chartHeight; }
    
    public var chartWidth: CGFloat { return _chartWidth; }

    // MARK: - Scaling/Panning etc.
    
    /// Zooms around the specified center
    public func zoom(#scaleX: CGFloat, scaleY: CGFloat, x: CGFloat, y: CGFloat) -> CGAffineTransform
    {
        var matrix = CGAffineTransformTranslate(_touchMatrix, x, y);
        matrix = CGAffineTransformScale(matrix, scaleX, scaleY);
        matrix = CGAffineTransformTranslate(matrix, -x, -y);
        return matrix;
    }
    
    /// Zooms in by 1.4, x and y are the coordinates (in pixels) of the zoom center.
    public func zoomIn(#x: CGFloat, y: CGFloat) -> CGAffineTransform
    {
        return zoom(scaleX: 1.4, scaleY: 1.4, x: x, y: y);
    }
    
    /// Zooms out by 0.7, x and y are the coordinates (in pixels) of the zoom center.
    public func zoomOut(#x: CGFloat, y: CGFloat) -> CGAffineTransform
    {
        return zoom(scaleX: 0.7, scaleY: 0.7, x: x, y: y);
    }
    
    /// Resets all zooming and dragging and makes the chart fit exactly it's bounds.
    public func fitScreen() -> CGAffineTransform
    {
        _minScaleX = 1.0;
        _minScaleY = 1.0;

        return CGAffineTransformIdentity;
    }
    
    /// Centers the viewport around the specified position (x-index and y-value) in the chart.
    public func centerViewPort(#pt: CGPoint, chart: ChartViewBase)
    {
        let translateX = pt.x - offsetLeft;
        let translateY = pt.y - offsetTop;
        
        var matrix = CGAffineTransformConcat(_touchMatrix, CGAffineTransformMakeTranslation(-translateX, -translateY));
        
        refresh(newMatrix: matrix, chart: chart, invalidate: true);
    }
    
    /// call this method to refresh the graph with a given matrix
    public func refresh(#newMatrix: CGAffineTransform, chart: ChartViewBase, invalidate: Bool) -> CGAffineTransform
    {
        _touchMatrix = newMatrix;
        
        // make sure scale and translation are within their bounds
        limitTransAndScale(matrix: &_touchMatrix, content: _contentRect);
        
        chart.setNeedsDisplay();
        
        return _touchMatrix;
    }
    
    /// limits the maximum scale and X translation of the given matrix
    private func limitTransAndScale(inout #matrix: CGAffineTransform, content: CGRect?)
{'fraction_non_alphanumeric': 0.08677783924760926, 'fraction_numerical': 0.008061329329012882, 'mean_word_length': 2.2596599690880987, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 23, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5442990', 'n_tokens_mistral': 3911, 'n_tokens_neox': 3816, 'n_words': 1100}