Skip to content
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

Makes drawing more smoothly #14

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion Example/JotDemo/ExampleViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -172,4 +172,4 @@ - (void)jotViewController:(JotViewController *)jotViewController isEditingText:(
self.toggleDrawingButton.hidden = isEditing;
}

@end
@end
2 changes: 1 addition & 1 deletion Example/Podfile
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,4 @@ target 'JotDemoTests', :exclusive => true do
pod 'Expecta'
pod 'Expecta+Snapshots'
pod 'OCMockito'
end
end
2 changes: 1 addition & 1 deletion Example/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,4 @@ SPEC CHECKSUMS:
OCMockito: 4981140c9a9ec06c31af40f636e3c0f25f27e6b2
Specta: cf3e4188cf35375c3ee2cd03f8db8f1f4ef98234

COCOAPODS: 0.38.2
COCOAPODS: 0.38.2
27 changes: 23 additions & 4 deletions jot/JotDrawView.m
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,19 @@
CGFloat const kJotInitialVelocity = 220.f;
CGFloat const kJotRelativeMinStrokeWidth = 0.4f;

static inline CGRect calcRect(CGPoint p1,CGPoint p2, CGPoint p3, CGPoint p4){
CGFloat x1,y1,x2,y2,width,height;
x1 = MIN(MIN(p1.x, p2.x), MIN(p3.x, p4.x));
x2 = MAX(MAX(p1.x, p2.x), MAX(p3.x, p4.x));

y1 = MIN(MIN(p1.y, p2.y), MIN(p3.y, p4.y));
y2 = MAX(MAX(p1.y, p2.y), MAX(p3.y, p4.y));

width = x2 - x1 + 15;
height = y2 - y1 + 15;
return CGRectMake(MAX(x1 - 10, 0), MAX(y1 - 10, 0), width, height);
}

@interface JotDrawView ()

@property (nonatomic, strong) UIImage *cachedImage;
Expand Down Expand Up @@ -132,6 +145,7 @@ - (void)drawTouchMovedToPoint:(CGPoint)touchPoint
self.lastVelocity = velocity;
}


self.pointsArray[0] = self.pointsArray[3];
self.pointsArray[1] = self.pointsArray[4];

Expand All @@ -156,6 +170,8 @@ - (void)drawTouchEnded

- (void)drawBitmap
{
CGRect rect = calcRect(self.bezierPath.startPoint, self.bezierPath.controlPoint1, self.bezierPath.controlPoint2, self.bezierPath.endPoint);

UIGraphicsBeginImageContextWithOptions(self.bounds.size, NO, [UIScreen mainScreen].scale);

if (self.cachedImage) {
Expand All @@ -173,18 +189,21 @@ - (void)drawBitmap
[touchPoint.strokeColor setFill];
[JotTouchBezier jotDrawBezierPoint:[touchPoint CGPointValue]
withWidth:touchPoint.strokeWidth];

CGFloat pointWidth = touchPoint.strokeWidth;
CGPoint point = touchPoint.CGPointValue;
rect = CGRectMake(point.x - pointWidth, point.y - pointWidth, pointWidth * 2.f, pointWidth * 2.f);
}

self.cachedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
[self setNeedsDisplay];

[self setNeedsDisplayInRect:rect];
}

- (void)drawRect:(CGRect)rect
{
[self.cachedImage drawInRect:rect];

[self.bezierPath jotDrawBezier];
[self.cachedImage drawAtPoint:CGPointZero];
}

- (CGFloat)strokeWidthForVelocity:(CGFloat)velocity
Expand Down
43 changes: 41 additions & 2 deletions jot/JotTouchBezier.m
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@
#import "JotTouchBezier.h"

NSUInteger const kJotDrawStepsPerBezier = 300;
CGFloat const kJotBezierShadow = 0.65f;

static inline CGFloat pointLength(const CGPoint point1, const CGPoint point2){
return sqrt(pow(point1.x - point2.x, 2) + pow(point1.y - point2.y, 2));
}

@implementation JotTouchBezier

Expand All @@ -34,11 +39,26 @@ - (void)jotDrawBezier
} else {
[self.strokeColor setFill];

CGFloat minWidth = self.startWidth;
CGFloat widthDelta = self.endWidth - self.startWidth;

for (NSUInteger i = 0; i < kJotDrawStepsPerBezier; i++) {
CGFloat length = pointLength(self.startPoint, self.controlPoint1)
+ pointLength(self.controlPoint1, self.controlPoint2)
+ pointLength(self.controlPoint2, self.endPoint);

CGFloat drawSteps = MAX(MIN(length,kJotDrawStepsPerBezier),10);

CGContextRef context = UIGraphicsGetCurrentContext();
if (!context) {
return;
}

// Set shadow makes bezier path more smoothly
CGContextSetShadowWithColor(context, CGSizeMake(0, 0), kJotBezierShadow, self.strokeColor.CGColor);

for (NSUInteger i = 0; i < drawSteps; i++) {

CGFloat t = ((CGFloat)i) / (CGFloat)kJotDrawStepsPerBezier;
CGFloat t = ((CGFloat)i) / (CGFloat)drawSteps;
CGFloat tt = t * t;
CGFloat ttt = tt * t;
CGFloat u = 1.f - t;
Expand All @@ -56,8 +76,27 @@ - (void)jotDrawBezier
y += ttt * self.endPoint.y;

CGFloat pointWidth = self.startWidth + (ttt * widthDelta);
minWidth = MIN(pointWidth, minWidth);

[self.class jotDrawBezierPoint:CGPointMake(x, y) withWidth:pointWidth];
}

// Draw a min width bezier, in case of drawSteps is not enough
CGFloat span = 0.0f;
CGPoint startPoint = CGPointMake(self.startPoint.x, self.startPoint.y + span);
CGPoint controlPoint1 = CGPointMake(self.controlPoint1.x, self.controlPoint1.y + span);
CGPoint controlPoint2 = CGPointMake(self.controlPoint2.x, self.controlPoint2.y + span);
CGPoint endPoint = CGPointMake(self.endPoint.x, self.endPoint.y + span);

[self.strokeColor setStroke];
CGContextSetLineWidth(context, minWidth);
CGContextSetAllowsAntialiasing(context, true);
CGContextSetLineCap(context, kCGLineCapRound);
CGContextSetLineJoin(context, kCGLineJoinRound);
CGContextMoveToPoint(context, startPoint.x, startPoint.y);
CGContextAddCurveToPoint(context, controlPoint1.x, controlPoint1.y,
controlPoint2.x, controlPoint2.y, endPoint.x, endPoint.y);
CGContextStrokePath(context);
}
}

Expand Down