Skip to content

Instantly share code, notes, and snippets.

@harshvishu
Created September 1, 2016 06:04
Show Gist options
  • Save harshvishu/1d76bdf6ebe9498c45b84fdf33e20d18 to your computer and use it in GitHub Desktop.
Save harshvishu/1d76bdf6ebe9498c45b84fdf33e20d18 to your computer and use it in GitHub Desktop.
Scribblable modified class for drawing (Signature)
//
// Scribblable.swift
// Signature
//
// Created by harsh vishwakrama on 8/26/16.
//
import UIKit
// MARK: Scribblable protocol
protocol Scribblable{
func beginScribble(point: CGPoint)
func appendScribble(point: CGPoint)
func endScribble()
func clearScribble()
}
// MARK: Hermite interpolation implementation of line drawing from point to point
class HermiteScribbleView: UIImageView, Scribblable{
@IBInspectable var lineWidth: CGFloat = 2
@IBInspectable var borderColor: UIColor = UIColor.blueColor()
@IBInspectable var borderWidth: CGFloat = 1
let hermitePath = UIBezierPath()
var interpolationPoints = [CGPoint]()
let backgroundLayer = CAShapeLayer()
let drawingLayer = CAShapeLayer()
override func awakeFromNib() {
backgroundLayer.strokeColor = UIColor.darkGrayColor().CGColor
backgroundLayer.fillColor = nil
backgroundLayer.lineWidth = lineWidth
drawingLayer.strokeColor = UIColor.blackColor().CGColor
drawingLayer.fillColor = nil
drawingLayer.lineWidth = lineWidth
layer.addSublayer(backgroundLayer)
layer.addSublayer(drawingLayer)
//
// layer.borderColor = borderColor.CGColor
// layer.borderWidth = borderWidth
layer.masksToBounds = true
}
func beginScribble(point: CGPoint){
interpolationPoints = [point]
}
func appendScribble(point: CGPoint){
interpolationPoints.append(point)
hermitePath.removeAllPoints()
hermitePath.interpolatePointsWithHermite(interpolationPoints)
drawingLayer.path = hermitePath.CGPath
}
func endScribble(){
if let backgroundPath = backgroundLayer.path{
hermitePath.appendPath(UIBezierPath(CGPath: backgroundPath))
}
backgroundLayer.path = hermitePath.CGPath
hermitePath.removeAllPoints()
drawingLayer.path = hermitePath.CGPath
}
func clearScribble(){
backgroundLayer.path = nil
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
guard let location = touches.first?.locationInView(self) else{
return
}
guard frame.contains(location) else {return}
if let adjustedLocationInView = touches.first?.locationInView(self){
beginScribble(adjustedLocationInView)
}
}
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?){
guard let
touch = touches.first,
coalescedTouches = event?.coalescedTouchesForTouch(touch)else{return}
coalescedTouches.forEach{
appendScribble($0.locationInView(self))
}
}
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
endScribble()
}
}
// MARK: Extension to convert drawing to UIImage
extension HermiteScribbleView{
func toImage() -> UIImage{
UIGraphicsBeginImageContextWithOptions(self.bounds.size, true, 0.0)
self.drawViewHierarchyInRect(self.bounds, afterScreenUpdates: true)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image
}
}
extension UIBezierPath{
func interpolatePointsWithHermite(interpolationPoints:[CGPoint],alpha: CGFloat = 1.0/3.0){
// Return If points are empty
guard !interpolationPoints.isEmpty else {return}
self.moveToPoint(interpolationPoints.first!)
let n = interpolationPoints.count - 1
for index in 0..<n{
var currentPoint = interpolationPoints[index]
var nextIndex = (index + 1) % interpolationPoints.count
var prevIndex = index == 0 ? interpolationPoints.count - 1 : index - 1
var previousPoint = interpolationPoints[prevIndex]
var nextPoint = interpolationPoints[nextIndex]
let endPoint = nextPoint
var mx : CGFloat
var my : CGFloat
if index > 0
{
mx = (nextPoint.x - previousPoint.x) / 2.0
my = (nextPoint.y - previousPoint.y) / 2.0
}
else
{
mx = (nextPoint.x - currentPoint.x) / 2.0
my = (nextPoint.y - currentPoint.y) / 2.0
}
let controlPoint1 = CGPoint(x: currentPoint.x + mx * alpha, y: currentPoint.y + my * alpha)
currentPoint = interpolationPoints[nextIndex]
nextIndex = (nextIndex + 1) % interpolationPoints.count
prevIndex = index
previousPoint = interpolationPoints[prevIndex]
nextPoint = interpolationPoints[nextIndex]
if index < n - 1
{
mx = (nextPoint.x - previousPoint.x) / 2.0
my = (nextPoint.y - previousPoint.y) / 2.0
}
else
{
mx = (currentPoint.x - previousPoint.x) / 2.0
my = (currentPoint.y - previousPoint.y) / 2.0
}
let controlPoint2 = CGPoint(x: currentPoint.x - mx * alpha, y: currentPoint.y - my * alpha)
self.addCurveToPoint(endPoint, controlPoint1: controlPoint1, controlPoint2: controlPoint2)
}
}
}
@Harmonium
Copy link

Do you have an example of how to use it?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment