I'm using SVGKit to display different SVG content in my app. One of required features is to detect tap happened within an area inside svg path and fill it with some color.
CGPathContainsPoint seems to be the proper solution here, but the problem is that my svg paths are set up with relative coordinates (while tap point is absolute within whole image area).
Below is some code I'm using:
class ViewController: UIViewController {
@IBOutlet weak var imageArea: UIView!
var iv : SVGKLayeredImageView!
let im = SVGKImage(named: "connections.svg")
override func viewDidLoad() {
super.viewDidLoad()
im.size = self.imageArea.frame.size
iv = SVGKLayeredImageView(SVGKImage: im)
let recognizer = UITapGestureRecognizer(target: self, action:#selector(ViewController.handleTap(_:)))
iv.addGestureRecognizer(recognizer)
self.imageArea.addSubview(iv)
}
func handleTap(recognizer: UITapGestureRecognizer) {
let point = recognizer.locationInView(iv)
changeFillColorRecursively(iv.layer.sublayers!, color: UIColor.redColor(), point: point)
}
func changeFillColorRecursively(sublayers: [AnyObject], color: UIColor, point: CGPoint) {
for layer in sublayers {
if let l = layer as? CAShapeLayer {
if CGPathContainsPoint(l.path, nil, point, false) {
l.fillColor = color.CGColor
}
}
if let l = layer as? CALayer, sub = l.sublayers {
changeFillColorRecursively(sub, color: color, point: point)
}
}
}
}
Filling code works, but points comparison is wrong, leading to no or multiple areas filled.
My thinking is that I should play with affineTransform parameter of CGPathContainsPoint func, however I'm not really sure how to set converting matrix properly.
SVGKit has the point-in-path feature built-in (there are subtleties about implementing it you may miss if you do it by hand - including this one about relative vs absolute paths).
Can you not use the built-in version?
(alternatively, use the source code and build your own - but off teh top of my head it's approximately 200 lines of source across 4 different files, to handle all the recursive transforms etc)