Erik
Erik

Reputation: 519

How to scale Path in SwiftUI?

I have some problems to scale a Path accordingly to my purpose. I'm getting from an API some SVG data that I would like to draw in my view. In order to make it simple let's say this is what I get from the API:

extension UIBezierPath {
    static var rectangle: UIBezierPath {
        let path = UIBezierPath()
        path.move(to: CGPoint(x: 200, y: 100))
        path.addLine(to: CGPoint(x: 100, y: 300))
        path.addLine(to: CGPoint(x: 300, y: 300))
        path.addLine(to: CGPoint(x: 200, y: 100))
        return path
    }
}

When I display this path in my view everything works fine.

enter image description here

Since the SVG coordinates from the API have an offset and are sometimes bigger than the display screen of the iPhone, I need to scale them down/up to a specific size and center them in my view. In order to do that I tried this transformation:

struct ScaledShapeView: Shape {
    let bezier: UIBezierPath

    func path(in rect: CGRect) -> Path {
        let bounds = bezier.bounds
        let scaleX = rect.size.width/bounds.size.width
        let scaleY = rect.size.height/bounds.size.height
        let scale = max(scaleX, scaleY)
        return Path(bezier.cgPath).applying(CGAffineTransform(scaleX: scale, y: scale))
    }
}

and uses it in my view:

struct TestView: View {    
    var body: some View {
            ScaledShapeView(bezier: .rectangle)
                .frame(width: 100, height: 100)
    }
}

But this is my result:

enter image description here

I'm not sure what exactly the problem is. I would like to achieve that the shape is in the middle of the frame.

@SwiftPunk:

When I try

var body: some View {
    Path(UIBezierPath.logo1.cgPath)
            .frame(width: 100, height: 100)
            .scaleEffect(CGSize(width: 0.5, height: 0.5))
}

I get this result:

enter image description here

Upvotes: 0

Views: 2020

Answers (1)

Tushar Sharma
Tushar Sharma

Reputation: 2882

Normalized each X and Y position for drawing the points between 0 and 1, where 0 means the top edge or the leading edge, and 1 means the bottom edge or the trailing edge.

Also,we’re going to find the minimum of width and height so we can scale our Bezier path proportionally, so it stays the same shape as it grows.

import SwiftUI


extension UIBezierPath{
    static var rectangle: UIBezierPath {
        let path = UIBezierPath()
        path.move(to: CGPoint(x: 0.5, y: 0.2))
        path.addLine(to: CGPoint(x: 0.2, y: 0.8))
        path.addLine(to: CGPoint(x: 0.8, y: 0.8))
        path.addLine(to: CGPoint(x: 0.5, y: 0.2))
        return path
    }
}

struct ScaledShapeView:Shape{
    var bezier:UIBezierPath
    func path(in rect: CGRect) -> Path {
        let path = Path(bezier.cgPath)
        let multiplier = min(rect.width,rect.height)
       
        let transform = CGAffineTransform(scaleX:multiplier , y: multiplier)
        
        return path.applying(transform)
    }
}

struct TestView: View {
    @State private var endAmount: CGFloat = 0
    var body: some View {
        ScaledShapeView(bezier: UIBezierPath.rectangle)
            .frame(width: 300, height: 300)
        }
    }

Output-:

enter image description here

Upvotes: 1

Related Questions