exyte / Macaw

Powerful and easy-to-use vector graphics Swift library with SVG support
MIT License
6.01k stars 553 forks source link

Unable to change stroke color - wrong behaviour of `node.strokeVar` property #713

Closed devpolant closed 4 years ago

devpolant commented 4 years ago

Precondition

I have circle shape in my simple SVG file.

<svg width="100px" height="100px" viewBox="0 0 100 100" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
    <g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
        <circle id="circle" stroke="#2C2C2C" stroke-width="4" fill="#FF0000" fill-rule="nonzero" cx="40" cy="40" r="20"></circle>
    </g>
</svg>

That's all xml code that we need to reproduce the issue.

This circle is rendering like on this screenshot - circle with red fill color and black stroke color:

Screenshot 2020-07-08 at 23 17 35

Intention

I need to update stroke color, for instance from black to green. So I added the following code into my view controller:

import UIKit
import Macaw

final class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        let svgView = SVGView()
        svgView.contentMode = .scaleAspectFit
        svgView.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(svgView)

        NSLayoutConstraint.activate([
            view.topAnchor.constraint(equalTo: svgView.topAnchor),
            view.leadingAnchor.constraint(equalTo: svgView.leadingAnchor),
            view.trailingAnchor.constraint(equalTo: svgView.trailingAnchor),
            view.bottomAnchor.constraint(equalTo: svgView.bottomAnchor)
        ])
        svgView.fileName = "Circle"

        svgView.node.nodeBy(tag: "circle")?.onTap { event in
            guard let node = event.node as? Shape else {
                return
            }
            // `strokeVar` changes fill color, but not stroke color. So these 2 lines of code have the same effect.
            node.strokeVar.animate(to: Color.green, during: 0.3)
//            node.fillVar.animate(to: Color.green, during: 0.3)
        }
    }
}

Key line is:

node.strokeVar.animate(to: Color.green, during: 0.3)

Expected Result

We expect the following result when user taps on circle:

Screenshot 2020-07-08 at 23 15 44

But result is different:

Screenshot 2020-07-08 at 23 16 49

So, strokeVar's behaviour is the same like fillVar's which looks incorrect.

You could see the behaviour on this video:

Demo project

ystrot commented 4 years ago

It's definitely a bug that you can call this method on the Stroke and it will be fixed. However you can just call the correct one to animate stroke of the shape:

node.strokeVar.animate(to: Stroke(fill: Color.green, width: 4), during: 0.3)
devpolant commented 4 years ago

I tried and stroke color is changed, thanks! But is there any way to combine stroke and fill animation simultaneously? like:

node.fillVar.animate(to: Color.blue, during: 0.3)
node.strokeVar.animate(to: Stroke(fill: Color.green, width: 4), during: 0.3)

Current result has undefined behaviour:

Fill color is not applying correctly. Ideally fill and stroke animation looks independent, so they shouldn't affect each other.

ystrot commented 4 years ago

Yep, looks like a bug.