Powerful and easy-to-use vector graphics Swift library with SVG support

Overview

Macaw

Powerful and easy-to-use vector graphics Swift library with SVG support


We are a development agency building phenomenal apps.




CI Status Version Carthage Compatible License Platform

What is Macaw?

Macaw is a powerful and easy-to-use vector graphics library written in Swift.

It's simple

Get started with Macaw in several lines of code:

class MyView: MacawView {

	required init?(coder aDecoder: NSCoder) {
		let text = Text(text: "Hello, World!", place: .move(dx: 145, dy: 100))
		super.init(node: text, coder: aDecoder)
	}

}

It has SVG support

Include Scalable Vector Graphics right into your iOS application:

It's powerful

Affine transformations, user events, animation and various effects to build beautiful apps with Macaw:

Motivation

Modern designs contain tons of illustrations and complex animations. Mobile developers have to spend a lot of time on converting designs into native views that will be resizable for different screens. With Macaw you can reduce development time to a minimum and describe all graphics in high level scene elements. Or even render SVG graphics right from your design tool with Macaw events and animation support.

Resources

Docs

We're working hard to provide full documentation. Currently you can take a look at the following docs:

Posts

Examples

Macaw-Examples is a repository where you can find various usages of the Macaw library from simple charts to the complex periodic table.

Requirements

  • iOS 9.0+
  • Mac OS X 10.11+
  • Xcode 7.3+

Installation

CocoaPods

To install it, simply add the following line to your Podfile:

pod "Macaw", "0.9.7"

Carthage

github "Exyte/Macaw" ~> 0.9.7

Building from sources

To build Macaw from sources:

  • clone the repo [email protected]:exyte/Macaw.git
  • open terminal and run cd <MacawRepo>/Example/
  • run pod install to install all dependencies
  • run open Example.xcworkspace/ to open project in the Xcode

Change Log

You can find list of all changes by version in the Change Log

License

Macaw is available under the MIT license. See the LICENSE file for more info.

Comments
  • crash xcode 10.2

    crash xcode 10.2

    Update xcode to latest one. now app crash on using svgcolor view. it was working on previous one before update.

    crash log: When added to a view, the constraint's items must be descendants of that view (or the view itself). This will crash if the constraint needs to be resolved before the view hierarchy is assembled. Break on -[UIView(UIConstraintBasedLayout) _viewHierarchyUnpreparedForConstraint:] to debug. 2019-03-26 16:07:18.180525+0500 TheQuranApp[18096:632046] *** Terminating app due to uncaught exception 'NSGenericException', reason: 'This coder requires that replaced objects be returned from initWithCoder:' *** First throw call stack: ( 0 CoreFoundation 0x0000000110a7b6fb __exceptionPreprocess + 331 1 libobjc.A.dylib 0x000000010f9a1ac5 objc_exception_throw + 48 2 CoreFoundation 0x0000000110a7b555 +[NSException raise:format:] + 197 3 UIFoundation 0x0000000115c5b89c UINibDecoderDecodeObjectForValue + 827 4 UIFoundation 0x0000000115c5baf9 UINibDecoderDecodeObjectForValue + 1432 5 UIFoundation 0x0000000115c5b554 -[UINibDecoder decodeObjectForKey:] + 251 6 UIKitCore 0x000000011a5a2705 -[UIView initWithCoder:] + 802 7 UIFoundation 0x0000000115c5b852 UINibDecoderDecodeObjectForValue + 753 8 UIFoundation 0x0000000115c5baf9 UINibDecoderDecodeObjectForValue + 1432 9 UIFoundation 0x0000000115c5b554 -[UINibDecoder decodeObjectForKey:] + 251 10 UIKitCore 0x000000011a5a2705 -[UIView initWithCoder:] + 802 11 UIFoundation 0x0000000115c5b852 UINibDecoderDecodeObjectForValue + 753 12 UIFoundation 0x0000000115c5b554 -[UINibDecoder decodeObjectForKey:] + 251 13 UIKitCore 0x0000000119d87b41 -[UIRuntimeConnection initWithCoder:] + 178 14 UIFoundation 0x0000000115c5b852 UINibDecoderDecodeObjectForValue + 753 15 UIFoundation 0x0000000115c5baf9 UINibDecoderDecodeObjectForValue + 1432 16 UIFoundation 0x0000000115c5b554 -[UINibDecoder decodeObjectForKey:] + 251 17 UIKitCore 0x0000000119d853f1 -[UINib instantiateWithOwner:options:] + 1216 18 UIKitCore 0x0000000119b023af -[UIViewController _loadViewFromNibNamed:bundle:] + 382 19 UIKitCore 0x0000000119b02d39 -[UIViewController loadView] + 177 20 UIKitCore 0x0000000119b03048 -[UIViewController loadViewIfRequired] + 172 21 UIKitCore 0x0000000119a67004 -[UINavigationController _updateScrollViewFromViewController:toViewController:] + 68 22 UIKitCore 0x0000000119a672f7 -[UINavigationController _startTransition:fromViewController:toViewController:] + 146 23 UIKitCore 0x0000000119a683b5 -[UINavigationController _startDeferredTransitionIfNeeded:] + 896 24 UIKitCore 0x0000000119a696a7 -[UINavigationController __viewWillLayoutSubviews] + 150 25 UIKitCore 0x0000000119a4a38d -[UILayoutContainerView layoutSubviews] + 217 26 UIKitCore 0x000000011a5d39c1 -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 1417 27 QuartzCore 0x000000010f04beae -[CALayer layoutSublayers] + 173 28 QuartzCore 0x000000010f050b88 _ZN2CA5Layer16layout_if_neededEPNS_11TransactionE + 396 29 QuartzCore 0x000000010f05cee4 _ZN2CA5Layer28layout_and_display_if_neededEPNS_11TransactionE + 72 30 QuartzCore 0x000000010efcc3aa _ZN2CA7Context18commit_transactionEPNS_11TransactionE + 328 31 QuartzCore 0x000000010f003584 _ZN2CA11Transaction6commitEv + 608 32 UIKitCore 0x000000011a11eccb __34-[UIApplication _firstCommitBlock]_block_invoke_2 + 128 33 CoreFoundation 0x00000001109e2aec CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK + 12 34 CoreFoundation 0x00000001109e22b0 __CFRunLoopDoBlocks + 336 35 CoreFoundation 0x00000001109dcb34 __CFRunLoopRun + 1252 36 CoreFoundation 0x00000001109dc302 CFRunLoopRunSpecific + 626 37 GraphicsServices 0x0000000115ecb2fe GSEventRunModal + 65 38 UIKitCore 0x000000011a105ba2 UIApplicationMain + 140 39 TheQuranApp 0x000000010de6128b main + 75 40 libdyld.dylib 0x000000011402a541 start + 1 ) libc++abi.dylib: terminating with uncaught exception of type NSException

    opened by usman-whizpool 14
  • Sharing Node instance across different SVGViews causes infinite loop

    Sharing Node instance across different SVGViews causes infinite loop

    Hi, I use Macaw (great library) in such a way that I download SVG files from the internet to memory cache, turn them into Macaw Nodes, manipulate them to alter their colors and then use them as icons in a table view.

    The issue

    I noticed that when one Node instance appears in more than one SVGView the main thread enters an infinite loop (somewhere in drawRect).

    Discussion

    It looks like Macaw doesn't really like using Nodes directly. For instance, once a node is set on MacawView, there's no way to nil it out, so I had to use an awkward construction like this:

    if let icon = model.icon {
        titleCell.iconSvgView.node = icon
    } else {
        titleCell.iconSvgView.fileName = nil
    }
    

    I can of course try to redesign my code so it saves images on the disk but isn't it worth discussing why a flow that would be typical for UIImage does not work for Macaw.Node?

    opened by lubiluk 12
  • SVG-rendering: change colors etc.

    SVG-rendering: change colors etc.

    What do you think about adding the possibility to make SVG-rendering more flexible? It would be perfect to load one svg-file but replace maybe some of the fill colors. I'm actually checking the code, but I would suggest sth. like this (and I will post my results as soon, as I could solve the problem):

    You're loading the SVG via SVGParser.parse(...). I would suggest to add one more parameter, so that you can call like this:

    let myParsingOptions = [ParsingOption(id: "someId", attribute: .fill, newAttribute: NSColor.red), ...]
    
    SVGParser.parse("myFile", myParsingOptions)
    

    I will search in the SVGParser.swift file, where I have to make the changes.

    opened by JoachimM7 12
  • Getting Path

    Getting Path

    Is there any way to get CGPath object (or UIBezierPath) from any .SVG file? I think, there should be such way, because Macaw uses CGContext to draw paths. I'd like to put CGPath to CAShapeLayer then. Thanks for response.

    question 
    opened by lukaszkrystek 11
  • Use SVG stored in Firebase Storage

    Use SVG stored in Firebase Storage

    Let me start by saying that I love Macaw. I have been using this library in my project for the past 2 months and this is a perfect match for what I want in the project. Now the requirements have slightly changed and I need to use SVGs that have been uploaded to the Firebase storage directory. Is there anyway I can use the SVG directly in my project after perhaps downloading it? Or by using it's URL?

    opened by ajilo297 11
  • Move To Specific position on svg

    Move To Specific position on svg

    Hello, Now my svg is working fine on svgscrollview. I am getting one issue when I try to move to specific position with cgpoint in scrollview. Actually I got points like this - shape.bounds?.center().toCG() and then move my scrollview to particular points. Please help me how can I move to particular points. Thank you.

    question 
    opened by tarunsachdeva001 10
  • Rotate animation doesn't work when Node has translation

    Rotate animation doesn't work when Node has translation

    How do I animate an explicit Transform in Macaw? My app involves a compass, which is a Node on a MacawView. I only want to animate rotation, so what I really wanted was to do this:

    myNode.placeVar.animate(transform: Transform.rotate(...))
    

    Therefore retaining (but not modifying) my scaling set to myNode.place.

    I do understand that there is animate(to: Transform), but I loose my scaling. If I use animate(to: myNode.place.rotate(...)), I get rather weird issues with the node resizing almost seemingly randomly.

    Is this possible in Macaw?

    Thanks

    opened by galexite 10
  • Decouple graph structure from views

    Decouple graph structure from views

    Hi guys!

    Firstly, thank you for the library — it's definitely something that is needed!

    My immediate needs are for parsing and rendering SVG images as static images. I know that this is possible using a MacawView (or SVGView), but this seems unnecessarily heavy for rendering images, if we are not actually using views (views are expensive).

    How would you feel about enabling rendering without the view dependencies?

    • we could start by decoupling the scene models from view concerns (basically the touch methods);
    • NodeRenderer should have its AnimationCache as optional (since it is only ever used optionally anyway), which would allow us to create renderers which do not depend on views;
    • we could abstract out some of the rendering logic from MacawView into a protocol with default implementations, allowing us to make MacawView conform to the protocol so that we can use the same logic, while also being able to make a different, non-view class which can render without a view.

    Incidentally, I think we ought to be able to use some dependency injection in the view / animation methods to get rid of the nodesMap and parentsMap singletons.

    Let me know what you think. I would be happy to try to create some PRs for it, if you think this is a direction you might like to take. Otherwise I would probably try creating my own library, with this as a good starting point.

    opened by Rupert-RR 10
  • Macaw.image.srcVar do not change image on change src

    Macaw.image.srcVar do not change image on change src

    Need help urgent! :( On xcode 9 our code was worked well, but after start working with xcode 10 Macaw.image.srcVar do not change image if we change srcVar on the fly.

    Maybe I misunderstood something, but I expecting that if I we change scrVar it will rerender image in the node....

    here is code example:

    substrate.onTap { _ in
           if !self.pickedSeats.contains(index) {
                    self.pickedSeats.insert(index)
                    seatView.sView.srcVar.value = SeatType.picked.getSrc()
                    seatView.sView.opacityVar.animate(to: 0.9)
                    seatView.text.font = Font(name: "MullerExtraBold", size: 13)
                    self.delegate?.seatPicked(id: seat.id, unselect: false, publicPid: seat.publicPid)
            } else {
                    self.pickedSeats.remove(index)
                    seatView.sView.srcVar.value = seat.type.getSrc()
                    seatView.text.font = Font(name: "MullerMedium", size: 12)
                    self.delegate?.seatPicked(id: seat.id, unselect: true, publicPid: seat.publicPid)
               }
       }
    

    > seatView.sView.srcVar.value = SeatType.picked.getSrc() > seatView.sView.srcVar.value = seat.type.getSrc()

    This lines worked, but now no.

    opened by mkdk 9
  • Text fixes

    Text fixes

    • Using bottom as default baseline. I also think the current calculation for the baseline might be a little off, will look a little more in detail when I have the time.
    • font-size attributes can end with "px", this change allows that.
    opened by rFlex 9
  • Couldn't use sequence for morphing animations

    Couldn't use sequence for morphing animations

    Hey All,

    I am trying to use Macaw and it is awesome but I am thinking that I am missing something in the documentation and wonder if I could get some help?

    I am training to chain around 8 animations together then repeat them all from 1-8 continuously.

      let animationOne = trianglegroup.contentsVar.animation(from: squaregroup, to: square, during: 1.0, delay: 0.0)
               animationOne.onComplete {
                   print("animationOne complete")
                   let animationTwo = crossgroup.contentsVar.animation(from: squaregroup, to: triangle, during: 1.0, delay: 0.0)
                   animationTwo.onComplete {
                       print("animationTwo complete")
                       let animationThree = circlegroup.contentsVar.animation(from: squaregroup, to: circleClosedState, during: 1.0, delay: 0.0)
                       animationThree.onComplete {
                           print("animationThree complete")
                           let animationFour = circlegroup.contentsVar.animation(from: squaregroup, to: circle, during: 1.0, delay: 0.0)
                           animationFour.onComplete {
                               print("animationFour complete")
                               let animationFive = squaregroup.contentsVar.animation(from: squaregroup, to: crossClosedState, during: 1.0, delay: 0.0)
                               animationFive.onComplete {
                                   print("animationFive complete")
                                   let animationSix = squaregroup.contentsVar.animation(from: squaregroup, to: cross, during: 1.0, delay: 0.0)
                                   animationSix.onComplete {
                                       print("animationSix complete")
                                       let animationSeven = squaregroup.contentsVar.animation(from: squaregroup, to: squareClosedState, during: 1.0, delay: 0.0)
                                       animationSeven.onComplete {
                                           print("animationSeven complete")
                                           let animationOne = trianglegroup.contentsVar.animation(from: squaregroup, to: square, during: 1.0, delay: 0.0)
                                           animationOne.onComplete {
                                               print("animationOne complete")
                                           }
                                       }
                                       animationSeven.play()
                                   }
                                   animationSix.play()
                               }
                               animationFive.play()
                           }
                           animationFour.play()
                       }
                       animationThree.play()
                   }
                   animationTwo.play()
               }
               animationOne.play()
    

    The problem with this is obvious plus It isn't continuous as I have to include another set of animations to repeat an extra time so I am wondering if there is a better way to do it?

    Thanks in advance for any help!

    opened by pbmayne 9
  • Animate start point bezier path. #2

    Animate start point bezier path. #2

    hi its possible animate bezier path lines. Like a CAShapeLayer strokenEnd property. I put example image and video what I mean.

    I have bezier path Screenshot 2022-11-20 at 12 37 26

    Next I have animation with duration 1.0 seconds, when animation started I need calculate bezier points relative animation progress each frame. Below video example.

    https://user-images.githubusercontent.com/29518174/202891971-e5fe05d6-04e9-4ede-8534-a56b0fdbde77.mp4

    opened by alyfreym 0
  • Unnecessary black color has been fixed.

    Unnecessary black color has been fixed.

    There is a problem on iOS when we have Shape with Stroke and NO Fill tag in XML. Color by Default is black but I think that clear color is more useful and standard (cause I compare SVG with online viewer and there is no black color by default).

    opened by TheHmmka 1
  • There are some performance issues when use mask/effect...

    There are some performance issues when use mask/effect...

    we should not handle mask/effect by this way:

    func renderToImage(bounds: Rect, inset: Double = 0, coloringMode: ColoringMode = .rgb) -> MImage? {
            let screenScale: CGFloat = MMainScreen()?.mScale ?? 1.0
            MGraphicsBeginImageContextWithOptions(CGSize(width: bounds.w + inset, height: bounds.h + inset), false, screenScale)
            let tempContext = MGraphicsGetCurrentContext()!
    
            // flip y-axis and leave space for the blur
            tempContext.translateBy(x: CGFloat(inset / 2 - bounds.x), y: CGFloat(bounds.h + inset / 2 + bounds.y))
            tempContext.scaleBy(x: 1, y: -1)
            directRender(in: tempContext, force: false, opacity: 1.0, coloringMode: coloringMode)
    
            let img = MGraphicsGetImageFromCurrentImageContext()
            MGraphicsEndImageContext()
            return img
        }
    

    when we have many effects,mask, us operations would get stuck... Image processing is very consumptive performance.

    opened by wanqingrongruo 0
Owner
Exyte
Exyte
A Powerful , Extensible CSS Parser written in pure Swift.

A Powerful , Extensible CSS Parser written in pure Swift. Basic Usage From CSS: #View { "width" : 118; "height" : 120.5; "color1" : "#888888"; "co

null 273 Sep 9, 2022
An easy to use FAQ view for iOS written in Swift

FAQView An easy to use FAQ view for iOS written in Swift. This view is a subclass of UIView. Setup with CocoaPods If you are using CocoaPods add this

Mukesh Thawani 467 Dec 5, 2022
An easy to use FAQ view for iOS written in Swift

FAQView An easy to use FAQ view for iOS written in Swift. This view is a subclass of UIView. Setup with CocoaPods If you are using CocoaPods add this

Mukesh Thawani 466 Nov 9, 2021
React.js like Mixin. More powerful Protocol-Oriented Programming.

Mixin ?? Why? Swift is Protocol-Oriented Programming, and it's more powerful by default implementations of extensions of protocols. You can mixin meth

Wan-Huang Yang 45 Dec 28, 2021
An easy to use UI component to help display a signal bar with an added customizable fill animation

TZSignalStrengthView for iOS Introduction TZSignalStrengthView is an easy to use UI component to help display a signal bar with an added customizable

TrianglZ LLC 22 May 14, 2022
Easy-to-use HStack that snaps to elements on scroll.

SnapToScroll Drop-in SwiftUI-based container view for horizontal snapping. example-video.mp4 Getting Started Using SnapToScroll is straightforward. Th

null 206 Jan 7, 2023
Easy to use, highly customizable gauge view

GDGauge - Customizable Gauge View Requirements Xcode 11+ Swift 5 iOS 9+ Installation Swift Package Manager .package(url: "https://github.com/saeid/GDG

Saeid 74 Dec 5, 2022
A custom stretchable header view for UIScrollView or any its subclasses with UIActivityIndicatorView and iPhone X safe area support for content reloading. Built for iOS 10 and later.

Arale A custom stretchable header view for UIScrollView or any its subclasses with UIActivityIndicatorView support for reloading your content. Built f

Putra Z. 43 Feb 4, 2022
MZFormSheetPresentationController provides an alternative to the native iOS UIModalPresentationFormSheet, adding support for iPhone and additional opportunities to setup UIPresentationController size and feel form sheet.

MZFormSheetPresentationController MZFormSheetPresentationController provides an alternative to the native iOS UIModalPresentationFormSheet, adding sup

Michał Zaborowski 979 Nov 17, 2022
An UITextView in Swift. Support auto growing, placeholder and length limit.

GrowingTextView Requirements iOS 8.0 or above Installation CocoaPods GrowingTextView is available through CocoaPods. To install it, simply add the fol

Kenneth Tsang 941 Jan 5, 2023
A UITextView subclass that adds support for multiline placeholder written in Swift.

KMPlaceholderTextView A UITextView subclass that adds support for multiline placeholder written in Swift. Usage You can set the value of the placehold

Zhouqi Mo 794 Jan 7, 2023
🔍 Awesome fully customize search view like Pinterest written in Swift 5.0 + Realm support!

YNSearch + Realm Support Updates See CHANGELOG for details Intoduction ?? Awesome search view, written in Swift 5.0, appears search view like Pinteres

Kyle Yi 1.2k Dec 17, 2022
A UINavigationController subclass that support pop interactive UINavigationbar with hidden or show.

KDInteractiveNavigationController Features ✨ UINavigationController interactive with UINavigationBar hidden or show Hide all UINavigationController ba

Kingiol 154 Dec 3, 2022
SAHistoryNavigationViewController realizes iOS task manager like UI in UINavigationContoller. Support 3D Touch!

SAHistoryNavigationViewController Support 3D Touch for iOS9!! SAHistoryNavigationViewController realizes iOS task manager like UI in UINavigationConto

Taiki Suzuki 1.6k Dec 29, 2022
SheetPresentation for SwiftUI. Multiple devices support: iOS, watchOS, tvOS, macOS, macCatalyst.

SheetPresentation for SwiftUI. Multiple devices support: iOS, watchOS, tvOS, macOS, macCatalyst.

Aben 13 Nov 17, 2021
An iOS Library that makes shadows management easy on UIView.

ShadowView is an iOS Shadow library that makes view's shadow implementation easy and sweet ?? ?? . Add simple shadows to add a gaussian blurred projec

Pierre 404 Dec 8, 2022
UIPheonix is a super easy, flexible, dynamic and highly scalable UI framework + concept for building reusable component/control-driven apps for macOS, iOS and tvOS

UIPheonix is a super easy, flexible, dynamic and highly scalable UI framework + concept for building reusable component/control-driven apps for macOS, iOS and tvOS

Mohsan Khan 29 Sep 9, 2022
Twinkle is a Swift and easy way to make any UIView in your iOS or tvOS app twinkle.

Twinkle ✨ Twinkle is a Swift and easy way to make any UIView in your iOS or tvOS app twinkle. This library creates several CAEmitterLayers and animate

patrick piemonte 600 Nov 24, 2022
CITreeView created to implement and maintain that wanted TreeView structures for IOS platforms easy way

CITreeView CITreeView created to implement and maintain that wanted TreeView structures for IOS platforms easy way. CITreeView provides endless treevi

Cenk Işık 126 May 28, 2022