Skip to content
This repository was archived by the owner on Dec 2, 2020. It is now read-only.

Commit 17fe25f

Browse files
author
Sam Spencer
committed
Fixes bezier curve boundary issues
Fixes #135 by keeping bezier curve lines inside the view bounds. Removed old imports in favor of modules.
1 parent 0bb60c9 commit 17fe25f

File tree

5 files changed

+86
-83
lines changed

5 files changed

+86
-83
lines changed

Classes/BEMAverageLine.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
// Copyright (c) 2015 Boris Emorine. All rights reserved.
77
//
88

9+
@import Foundation;
910
@import UIKit;
1011

1112

Classes/BEMCircle.h

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,9 @@
77
// Copyright (c) 2014 Sam Spencer.
88
//
99

10-
11-
#if __has_feature(objc_modules)
12-
// We recommend enabling Objective-C Modules in your project Build Settings for numerous benefits over regular #imports
13-
@import Foundation;
14-
@import UIKit;
15-
@import CoreGraphics;
16-
#else
17-
#import <Foundation/Foundation.h>
18-
#import <UIKit/UIKit.h>
19-
#import <CoreGraphics/CoreGraphics.h>
20-
#endif
10+
@import Foundation;
11+
@import UIKit;
12+
@import CoreGraphics;
2113

2214

2315
/// Class to draw the circle for the points.

Classes/BEMLine.h

Lines changed: 23 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,9 @@
77
// Copyright (c) 2014 Sam Spencer.
88
//
99

10-
11-
#if __has_feature(objc_modules)
12-
// We recommend enabling Objective-C Modules in your project Build Settings for numerous benefits over regular #imports
13-
@import Foundation;
14-
@import UIKit;
15-
@import CoreGraphics;
16-
#else
17-
#import <Foundation/Foundation.h>
18-
#import <UIKit/UIKit.h>
19-
#import <CoreGraphics/CoreGraphics.h>
20-
#endif
10+
@import Foundation;
11+
@import UIKit;
12+
@import CoreGraphics;
2113

2214
#import "BEMAverageLine.h"
2315

@@ -50,51 +42,39 @@ typedef NS_ENUM(NSUInteger, BEMLineGradientDirection) {
5042

5143
//----- POINTS -----//
5244

53-
/// The previous point. Necessary for Bezier curve
54-
@property (assign, nonatomic) CGPoint P0;
55-
56-
/// The starting point of the line
57-
@property (assign, nonatomic) CGPoint P1;
58-
59-
/// The ending point of the line
60-
@property (assign, nonatomic) CGPoint P2;
61-
62-
/// The next point. Necessary for Bezier curve
63-
@property (assign, nonatomic) CGPoint P3;
64-
6545
/// All of the Y-axis values for the points
66-
@property (nonatomic) NSArray *arrayOfPoints;
46+
@property (strong, nonatomic) NSArray *arrayOfPoints;
6747

6848
/// All of the X-Axis coordinates used to draw vertical lines through
69-
@property (nonatomic) NSArray *arrayOfVerticalRefrenceLinePoints;
49+
@property (strong, nonatomic) NSArray *arrayOfVerticalRefrenceLinePoints;
7050

7151
/// The value used to offset the fringe vertical reference lines when the x-axis labels are on the edge
7252
@property (assign, nonatomic) CGFloat verticalReferenceHorizontalFringeNegation;
7353

7454
/// All of the Y-Axis coordinates used to draw horizontal lines through
75-
@property (nonatomic) NSArray *arrayOfHorizontalRefrenceLinePoints;
55+
@property (strong, nonatomic) NSArray *arrayOfHorizontalRefrenceLinePoints;
7656

7757
/// All of the point values
78-
@property (nonatomic) NSArray *arrayOfValues;
58+
@property (strong, nonatomic) NSArray *arrayOfValues;
7959

8060
/** Draw thin, translucent, reference lines using the provided X-Axis and Y-Axis coordinates.
8161
@see Use \p arrayOfVerticalRefrenceLinePoints to specify vertical reference lines' positions. Use \p arrayOfHorizontalRefrenceLinePoints to specify horizontal reference lines' positions. */
82-
@property (nonatomic) BOOL enableRefrenceLines;
62+
@property (assign, nonatomic) BOOL enableRefrenceLines;
8363

8464
/** Draw a thin, translucent, frame on the edge of the graph to separate it from the labels on the X-Axis and the Y-Axis. */
85-
@property (nonatomic) BOOL enableRefrenceFrame;
65+
@property (assign, nonatomic) BOOL enableRefrenceFrame;
8666

8767
/** If reference frames are enabled, this will enable/disable specific borders. Default: YES */
88-
@property (nonatomic) BOOL enableLeftReferenceFrameLine;
68+
@property (assign, nonatomic) BOOL enableLeftReferenceFrameLine;
8969

9070
/** If reference frames are enabled, this will enable/disable specific borders. Default: YES */
91-
@property (nonatomic) BOOL enableBottomReferenceFrameLine;
71+
@property (assign, nonatomic) BOOL enableBottomReferenceFrameLine;
9272

9373
/** If reference frames are enabled, this will enable/disable specific borders. Default: NO */
94-
@property (nonatomic) BOOL enableRightReferenceFrameLine;
74+
@property (assign, nonatomic) BOOL enableRightReferenceFrameLine;
9575

9676
/** If reference frames are enabled, this will enable/disable specific borders. Default: NO */
97-
@property (nonatomic) BOOL enableTopReferenceFrameLine;
77+
@property (assign, nonatomic) BOOL enableTopReferenceFrameLine;
9878

9979
/** Dash pattern for the references line on the X axis */
10080
@property (nonatomic, strong) NSArray *lineDashPatternForReferenceXAxisLines;
@@ -103,10 +83,10 @@ typedef NS_ENUM(NSUInteger, BEMLineGradientDirection) {
10383
@property (nonatomic, strong) NSArray *lineDashPatternForReferenceYAxisLines;
10484

10585
/** If a null value is present, interpolation would draw a best fit line through the null point bound by its surrounding points. Default: YES */
106-
@property (nonatomic) BOOL interpolateNullValues;
86+
@property (assign, nonatomic) BOOL interpolateNullValues;
10787

10888
/** Draws everything but the main line on the graph; correlates to the \p displayDotsOnly property. Default: NO */
109-
@property (nonatomic) BOOL disableMainLine;
89+
@property (assign, nonatomic) BOOL disableMainLine;
11090

11191

11292

@@ -141,20 +121,20 @@ typedef NS_ENUM(NSUInteger, BEMLineGradientDirection) {
141121
//----- ALPHA -----//
142122

143123
/// The line alpha
144-
@property (nonatomic) float lineAlpha;
124+
@property (assign, nonatomic) float lineAlpha;
145125

146126
/// The alpha value of the area above the line, inside of its superview
147-
@property (nonatomic) float topAlpha;
127+
@property (assign, nonatomic) float topAlpha;
148128

149129
/// The alpha value of the area below the line, inside of its superview
150-
@property (nonatomic) float bottomAlpha;
130+
@property (assign, nonatomic) float bottomAlpha;
151131

152132

153133

154134
//----- SIZE -----//
155135

156136
/// The width of the line
157-
@property (nonatomic) float lineWidth;
137+
@property (assign, nonatomic) float lineWidth;
158138

159139
/// The width of a reference line
160140
@property (nonatomic) float referenceLineWidth;
@@ -164,17 +144,17 @@ typedef NS_ENUM(NSUInteger, BEMLineGradientDirection) {
164144
//----- BEZIER CURVE -----//
165145

166146
/// The line is drawn with smooth curves rather than straight lines when set to YES.
167-
@property (nonatomic) BOOL bezierCurveIsEnabled;
147+
@property (assign, nonatomic) BOOL bezierCurveIsEnabled;
168148

169149

170150

171151
//----- ANIMATION -----//
172152

173153
/// The entrance animation period in seconds.
174-
@property (nonatomic) CGFloat animationTime;
154+
@property (assign, nonatomic) CGFloat animationTime;
175155

176156
/// The type of entrance animation.
177-
@property (nonatomic) BEMLineAnimation animationType;
157+
@property (assign, nonatomic) BEMLineAnimation animationType;
178158

179159

180160

@@ -184,7 +164,7 @@ typedef NS_ENUM(NSUInteger, BEMLineGradientDirection) {
184164
@property (strong, nonatomic) BEMAverageLine *averageLine;
185165

186166
/// The average line's y-value translated into the coordinate system
187-
@property (nonatomic) CGFloat averageLineYCoordinate;
167+
@property (assign, nonatomic) CGFloat averageLineYCoordinate;
188168

189169

190170

Classes/BEMLine.m

Lines changed: 57 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,22 @@
1616
#define CGFloatValue floatValue
1717
#endif
1818

19+
@interface BEMLine ()
20+
21+
/// The previous point. Necessary for Bezier curve
22+
@property (assign, nonatomic) CGPoint P0;
23+
24+
/// The starting point of the line
25+
@property (assign, nonatomic) CGPoint P1;
26+
27+
/// The ending point of the line
28+
@property (assign, nonatomic) CGPoint P2;
29+
30+
/// The next point. Necessary for Bezier curve
31+
@property (assign, nonatomic) CGPoint P3;
32+
33+
@end
34+
1935
@implementation BEMLine
2036

2137
- (instancetype)initWithFrame:(CGRect)frame {
@@ -151,10 +167,10 @@ - (void)drawRect:(CGRect)rect {
151167
UIBezierPath *fillTop = [UIBezierPath bezierPath];
152168
UIBezierPath *fillBottom = [UIBezierPath bezierPath];
153169

154-
CGPoint p0;
155-
CGPoint p1;
156-
CGPoint p2;
157-
CGPoint p3;
170+
CGPoint point0;
171+
CGPoint point1;
172+
CGPoint point2;
173+
CGPoint point3;
158174
CGFloat tensionBezier1 = 0.3;
159175
CGFloat tensionBezier2 = 0.3;
160176
CGFloat xIndexScale = self.frame.size.width/([self.arrayOfPoints count] - 1);
@@ -176,33 +192,38 @@ - (void)drawRect:(CGRect)rect {
176192
CGPoint previousPoint2 = CGPointMake(0,0);
177193

178194
for (int i = 0; i < points.count - 1; i++) {
179-
p1 = [[points objectAtIndex:i] CGPointValue];
180-
p2 = [[points objectAtIndex:i + 1] CGPointValue];
195+
point1 = [[points objectAtIndex:i] CGPointValue];
196+
point2 = [[points objectAtIndex:i + 1] CGPointValue];
181197

182-
if (!self.interpolateNullValues && (p1.y == BEMNullGraphValue || p2.y == BEMNullGraphValue)) continue;
198+
if (!self.interpolateNullValues && (point1.y == BEMNullGraphValue || point2.y == BEMNullGraphValue)) continue;
183199

184-
if (self.disableMainLine == NO) [line moveToPoint:p1];
185-
[fillBottom addLineToPoint:p1];
186-
[fillTop addLineToPoint:p1];
200+
if (self.disableMainLine == NO) [line moveToPoint:point1];
201+
[fillBottom addLineToPoint:point1];
202+
[fillTop addLineToPoint:point1];
187203

204+
// Check if bézier curves are enabled
188205
if (self.bezierCurveIsEnabled == YES) {
206+
// Bézier curves are enabled, proceed to draw line with curve
207+
// Determine the maximum amount of bézier tension
189208
const CGFloat maxTension = 1.0f / 3.0f;
190209
tensionBezier1 = maxTension;
191210
tensionBezier2 = maxTension;
192211

212+
// Set tension and points
193213
if (i > 0) { // Exception for first line because there is no previous point
194-
p0 = previousPoint1;
195-
if (p2.y - p1.y == p1.y - p0.y) tensionBezier1 = 0;
214+
point0 = previousPoint1;
215+
if (point2.y - point1.y == point1.y - point0.y) tensionBezier1 = 0;
196216
} else {
197217
tensionBezier1 = 0;
198-
p0 = p1;
218+
point0 = point1;
199219
}
200220

221+
// Set tension and points
201222
if (i < points.count - 2) { // Exception for last line because there is no next point
202-
p3 = [[points objectAtIndex:i + 2] CGPointValue];
203-
if (p3.y - p2.y == p2.y - p1.y) tensionBezier2 = 0;
223+
point3 = [[points objectAtIndex:i + 2] CGPointValue];
224+
if (point3.y - point2.y == point2.y - point1.y) tensionBezier2 = 0;
204225
} else {
205-
p3 = p2;
226+
point3 = point2;
206227
tensionBezier2 = 0;
207228
}
208229

@@ -211,24 +232,32 @@ - (void)drawRect:(CGRect)rect {
211232
if (tensionBezier2 > maxTension) tensionBezier2 = maxTension;
212233

213234
// First control point
214-
CP1 = CGPointMake(p1.x + (p2.x - p1.x)/3,
215-
p1.y - (p1.y - p2.y)/3 - (p0.y - p1.y)*tensionBezier1);
235+
CGFloat CP1x = point1.x + (point2.x - point1.x)/3;
236+
CGFloat CP1y = point1.y - (point1.y - point2.y)/3 - (point0.y - point1.y)*tensionBezier1;
237+
if (CP1x > self.frame.size.width) CP1x = self.frame.size.width - 1;
238+
if (CP1y > self.frame.size.height) CP1y = self.frame.size.height - 1;
239+
else if (CP1y < 0) CP1y = 0;
240+
CP1 = CGPointMake(CP1x, CP1y);
216241

217242
// Second control point
218-
CP2 = CGPointMake(p1.x + 2*(p2.x - p1.x)/3,
219-
(p1.y - 2*(p1.y - p2.y)/3) + (p2.y - p3.y)*tensionBezier2);
243+
CGFloat CP2x = point1.x + 2*(point2.x - point1.x)/3;
244+
CGFloat CP2y = (point1.y - 2*(point1.y - point2.y)/3) + (point2.y - point3.y)*tensionBezier2;
245+
if (CP2x > self.frame.size.width) CP2x = self.frame.size.width - 1;
246+
if (CP2y > self.frame.size.height) CP2y = self.frame.size.height - 1;
247+
else if (CP2y < 0) CP2y = 0; // Control points that go out of bounds will cause the graph curve to draw outside of its bounds, so we must implement a safety check to ensure that the graph does not leave its bounds
248+
CP2 = CGPointMake(CP2x, CP2y);
220249

221-
if (self.disableMainLine == NO) [line addCurveToPoint:p2 controlPoint1:CP1 controlPoint2:CP2];
222-
[fillBottom addCurveToPoint:p2 controlPoint1:CP1 controlPoint2:CP2];
223-
[fillTop addCurveToPoint:p2 controlPoint1:CP1 controlPoint2:CP2];
250+
if (self.disableMainLine == NO) [line addCurveToPoint:point2 controlPoint1:CP1 controlPoint2:CP2];
251+
[fillBottom addCurveToPoint:point2 controlPoint1:CP1 controlPoint2:CP2];
252+
[fillTop addCurveToPoint:point2 controlPoint1:CP1 controlPoint2:CP2];
224253
} else {
225-
if (self.disableMainLine == NO) [line addLineToPoint:p2];
226-
[fillBottom addLineToPoint:p2];
227-
[fillTop addLineToPoint:p2];
254+
if (self.disableMainLine == NO) [line addLineToPoint:point2];
255+
[fillBottom addLineToPoint:point2];
256+
[fillTop addLineToPoint:point2];
228257
}
229258

230-
previousPoint1 = p1;
231-
previousPoint2 = p2;
259+
previousPoint1 = point1;
260+
previousPoint2 = point2;
232261
}
233262

234263

Classes/BEMPermanentPopupView.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66
// Copyright (c) 2015 Boris Emorine. All rights reserved.
77
//
88

9-
#import <UIKit/UIKit.h>
9+
@import UIKit;
10+
1011

1112
@interface BEMPermanentPopupView : UIView
1213

0 commit comments

Comments
 (0)