Skip to content

Commit

Permalink
A two finger rotation recogniser for Pie/Radar (Good for scrollviews)…
Browse files Browse the repository at this point in the history
… (issue #65)

This will play nice with other gesture recognizers, especially good for when inside a scrollview.
It is disabled by default.
  • Loading branch information
danielgindi committed May 7, 2015
1 parent 89fed6f commit e056480
Show file tree
Hide file tree
Showing 2 changed files with 118 additions and 33 deletions.
7 changes: 0 additions & 7 deletions Charts/Classes/Charts/ChartViewBase.swift
Original file line number Diff line number Diff line change
Expand Up @@ -317,13 +317,6 @@ public class ChartViewBase: UIView, ChartAnimatorDelegate
ChartUtils.drawText(context: context, text: descriptionText, point: CGPoint(x: frame.width - _viewPortHandler.offsetRight - 10.0, y: frame.height - _viewPortHandler.offsetBottom - 10.0 - font!.lineHeight), align: .Right, attributes: attrs);
}

/// enables/disables defauilt touch events to be handled. When disable, touches are not passed to parent views so scrolling inside a UIScrollView won't work.
public var defaultTouchEventsEnabled: Bool
{
get { return _interceptTouchEvents; }
set { _interceptTouchEvents = true; }
}

// MARK: - Highlighting

/// Returns the array of currently highlighted values. This might be null or empty if nothing is highlighted.
Expand Down
144 changes: 118 additions & 26 deletions Charts/Classes/Charts/PieRadarChartViewBase.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,18 @@ import UIKit.UIGestureRecognizer
public class PieRadarChartViewBase: ChartViewBase
{
/// holds the normalized version of the current rotation angle of the chart
private var _rotationAngle = CGFloat(270.0);
private var _rotationAngle = CGFloat(270.0)

/// holds the raw version of the current rotation angle of the chart
private var _rawRotationAngle = CGFloat(270.0);
private var _rawRotationAngle = CGFloat(270.0)

/// flag that indicates if rotation is enabled or not
public var rotationEnabled = true

private var _rotationWithTwoFingers = false

private var _tapGestureRecognizer: UITapGestureRecognizer!
private var _rotationGestureRecognizer: UIRotationGestureRecognizer!

public override init(frame: CGRect)
{
Expand All @@ -49,7 +52,14 @@ public class PieRadarChartViewBase: ChartViewBase
super.initialize();

_tapGestureRecognizer = UITapGestureRecognizer(target: self, action: Selector("tapGestureRecognized:"));
_rotationGestureRecognizer = UIRotationGestureRecognizer(target: self, action: Selector("rotationGestureRecognized:"));

self.addGestureRecognizer(_tapGestureRecognizer);

if (rotationWithTwoFingers)
{
self.addGestureRecognizer(_rotationGestureRecognizer);
}
}

internal override func calcMinMax()
Expand Down Expand Up @@ -348,6 +358,41 @@ public class PieRadarChartViewBase: ChartViewBase

public var isRotationEnabled: Bool { return rotationEnabled; }

/// flag that indicates if rotation is done with two fingers or one.
/// when the chart is inside a scrollview, you need a two-finger rotation because a one-finger rotation eats up all touch events.
/// :default: false
public var rotationWithTwoFingers: Bool
{
get
{
return _rotationWithTwoFingers;
}
set
{
if (newValue != _rotationWithTwoFingers)
{
_rotationWithTwoFingers = newValue;

if (_rotationWithTwoFingers)
{
self.addGestureRecognizer(_rotationGestureRecognizer);
}
else
{
self.removeGestureRecognizer(_rotationGestureRecognizer);
}
}
}
}

/// flag that indicates if rotation is done with two fingers or one.
/// when the chart is inside a scrollview, you need a two-finger rotation because a one-finger rotation eats up all touch events.
/// :default: false
public var isRotationWithTwoFingers: Bool
{
return _rotationWithTwoFingers;
}

// MARK: - Animation

private var _spinAnimator: ChartAnimator!;
Expand Down Expand Up @@ -408,35 +453,39 @@ public class PieRadarChartViewBase: ChartViewBase

public override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent)
{
super.touchesBegan(touches, withEvent: event);

// if rotation by touch is enabled
if (rotationEnabled)
{
var touch = touches.first as! UITouch!;

stopDeceleration();

var touchLocation = touch.locationInView(self);

self.resetVelocity();

if (rotationEnabled)
if (!rotationWithTwoFingers)
{
self.sampleVelocity(touchLocation: touchLocation);
var touch = touches.first as! UITouch!;

var touchLocation = touch.locationInView(self);

self.resetVelocity();

if (rotationEnabled)
{
self.sampleVelocity(touchLocation: touchLocation);
}

self.setGestureStartAngle(x: touchLocation.x, y: touchLocation.y);

_touchStartPoint = touchLocation;
}

self.setGestureStartAngle(x: touchLocation.x, y: touchLocation.y);

_touchStartPoint = touchLocation;
}

if (!_isRotating)
{
super.touchesBegan(touches, withEvent: event);
}
}

public override func touchesMoved(touches: Set<NSObject>, withEvent event: UIEvent)
{
super.touchesMoved(touches, withEvent: event);

if (rotationEnabled)
if (rotationEnabled && !rotationWithTwoFingers)
{
var touch = touches.first as! UITouch!;

Expand All @@ -450,23 +499,28 @@ public class PieRadarChartViewBase: ChartViewBase
if (!_isRotating && distance(eventX: touchLocation.x, startX: _touchStartPoint.x, eventY: touchLocation.y, startY: _touchStartPoint.y) > CGFloat(8.0))
{
_isRotating = true;

_defaultTouchEventsWereEnabled = self.defaultTouchEventsEnabled;
self.defaultTouchEventsEnabled = false;
}
else
{
self.updateGestureRotation(x: touchLocation.x, y: touchLocation.y);
setNeedsDisplay();
}
}

if (!_isRotating)
{
super.touchesMoved(touches, withEvent: event);
}
}

public override func touchesEnded(touches: Set<NSObject>, withEvent event: UIEvent)
{
super.touchesEnded(touches, withEvent: event);
if (!_isRotating)
{
super.touchesEnded(touches, withEvent: event);
}

if (rotationEnabled)
if (rotationEnabled && !rotationWithTwoFingers)
{
var touch = touches.first as! UITouch!;

Expand All @@ -488,9 +542,9 @@ public class PieRadarChartViewBase: ChartViewBase
}
}
}

if (_isRotating)
{
self.defaultTouchEventsEnabled = _defaultTouchEventsWereEnabled;
_isRotating = false;
}
}
Expand All @@ -501,7 +555,6 @@ public class PieRadarChartViewBase: ChartViewBase

if (_isRotating)
{
self.defaultTouchEventsEnabled = _defaultTouchEventsWereEnabled;
_isRotating = false;
}
}
Expand Down Expand Up @@ -712,4 +765,43 @@ public class PieRadarChartViewBase: ChartViewBase
}
}
}

@objc private func rotationGestureRecognized(recognizer: UIRotationGestureRecognizer)
{
if (recognizer.state == UIGestureRecognizerState.Began)
{
stopDeceleration();

_startAngle = self.rawRotationAngle;
}

if (recognizer.state == UIGestureRecognizerState.Began || recognizer.state == UIGestureRecognizerState.Changed)
{
var angle = ChartUtils.Math.FRAD2DEG * recognizer.rotation;

self.rotationAngle = _startAngle + angle;
setNeedsDisplay();
}
else if (recognizer.state == UIGestureRecognizerState.Ended)
{
var angle = ChartUtils.Math.FRAD2DEG * recognizer.rotation;

self.rotationAngle = _startAngle + angle;
setNeedsDisplay();

if (isDragDecelerationEnabled)
{
stopDeceleration();

_decelerationAngularVelocity = ChartUtils.Math.FRAD2DEG * recognizer.velocity;

if (_decelerationAngularVelocity != 0.0)
{
_decelerationLastTime = CACurrentMediaTime();
_decelerationDisplayLink = CADisplayLink(target: self, selector: Selector("decelerationLoop"));
_decelerationDisplayLink.addToRunLoop(NSRunLoop.mainRunLoop(), forMode: NSRunLoopCommonModes);
}
}
}
}
}

0 comments on commit e056480

Please sign in to comment.