I draw a notch stroke on macOS with NSBezierPath.
How is it possible to make a "hand-drawing" animation for this path?
Thank you
//
// NotchOutlineView.swift
// DynamicLake Pro
//
// Created by Avior Rokach on 12/13/23.
//
import Foundation
import Cocoa
class NotchOutlineView: NSView {
private var shapeLayer: CAShapeLayer!
var thePath:CGPath?
var isAnimated = false
open var outlineColor: NSColor = .clear {
didSet {
// Redraw the view when the notch radius changes
self.needsDisplay = true
}
}
open var notchRadius: CGFloat = 19.0 {
didSet {
// Redraw the view when the notch radius changes
self.needsDisplay = true
}
}
override func draw(_ dirtyRect: NSRect) {
//super.draw(dirtyRect)
drawOutline()
}
private func drawOutline() {
let size = self.frame.size
let gap: CGFloat = 0.8
let notch = NSBezierPath()
notch.move(to: NSPoint(x: 0.0, y: size.height + 1.0))
notch.curve(to: NSPoint(x: notchRadius, y: size.height - notchRadius),
controlPoint1: NSPoint(x: notchRadius - gap, y: size.height),
controlPoint2: NSPoint(x: notchRadius, y: size.height - gap))
notch.line(to: NSPoint(x: notchRadius , y: notchRadius))
notch.curve(to: NSPoint(x: notchRadius * 2.0, y: 1.0),
controlPoint1: NSPoint(x: notchRadius, y: gap),
controlPoint2: NSPoint(x: notchRadius + gap, y: 1.0))
notch.line(to: NSPoint(x: size.width - 2 * notchRadius, y: 1.0))
notch.curve(to: NSPoint(x: size.width - notchRadius, y: notchRadius),
controlPoint1: NSPoint(x: size.width - notchRadius - gap, y: 1.0),
controlPoint2: NSPoint(x: size.width - notchRadius, y: gap))
notch.line(to: NSPoint(x: size.width - notchRadius, y: size.height - notchRadius))
notch.curve(to: NSPoint(x: size.width, y: size.height + 1.0),
controlPoint1: NSPoint(x: size.width - notchRadius, y: size.height - gap),
controlPoint2: NSPoint(x: size.width - notchRadius + gap, y: size.height))
notch.close()
/*Fill the notch in gradeint
let gradient = NSGradient(starting: NSColor.red, ending: NSColor.blue)
gradient?.draw(in: notch, angle: 90.0) */
// Create a gradient with two colors for the stroke
notch.lineWidth = 1.6
outlineColor.setStroke()
notch.stroke()
thePath = notch.cgPath
// Create a CAShapeLayer for animation
if shapeLayer == nil {
shapeLayer = CAShapeLayer()
shapeLayer.path = notch.cgPath
shapeLayer.lineWidth = notch.lineWidth
shapeLayer.strokeColor = NSColor.notchPurple.cgColor
shapeLayer.fillColor = NSColor.clear.cgColor
// Set shadow properties for outer glow
shapeLayer.shadowColor = NSColor.white.cgColor // Color of the outer glow
shapeLayer.shadowOffset = CGSize(width: 0, height: 0) // No offset for a centered glow
shapeLayer.shadowRadius = 6.0 // Adjust the radius to control the size of the outer glow
shapeLayer.shadowOpacity = 0.0 // CURRENTLY I DISBALED THE OUTHER GLOW
self.layer?.addSublayer(shapeLayer)
}
animatePathDrawing()
}
func animatePathDrawing() {
self.alphaValue = 1.0
// Set initial state
shapeLayer.strokeEnd = 0.0
// Create a CABasicAnimation for strokeEnd
let animation = CABasicAnimation(keyPath: "strokeEnd")
animation.fromValue = 0.0
animation.toValue = 1.0
animation.duration = 2.0 // Animation duration in seconds
animation.timingFunction = CAMediaTimingFunction(name: .linear)
animation.repeatCount = .infinity
animation.autoreverses = true
// Add the animation to the shape layer
shapeLayer.add(animation, forKey: "strokeEndAnimation")
isAnimated = true
}
func stopPathDrawing () {
shapeLayer?.removeAllAnimations()
self.isAnimated = false
}
}