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
Create Live Graphics in SwiftUI (iOS, tvOS & macOS)

PixelUI import SwiftUI import PixelUI struct ContentView: View { var body: some View { GeometryReader { geo in

Anton Heestand 21 Dec 17, 2022
A simple, performant, and lightweight SVG parser

Key Features Parsing performance that meets or beats other popular SVG Frameworks A simple architecture, optimized for extension, flexibility and deve

Michael Choe 1.8k Dec 29, 2022
Display and interact with SVG Images on iOS / OS X, using native rendering (CoreAnimation)

SVGKit SVGKit is a Cocoa framework for rendering SVG files natively: it's fast and powerful. Some additional info and links are on the wiki Versions:

null 4.3k Jan 3, 2023
SVG parser and renderer written in SwiftUI

SVGView SVG parser written in SwiftUI We are a development agency building phenomenal apps. Overview The goal of this project is to bring the full pow

Exyte 269 Jan 4, 2023
❄️ SVG in Swift

Snowflake ❤️ Support my apps ❤️ Push Hero - pure Swift native macOS application to test push notifications PastePal - Pasteboard, note and shortcut ma

Khoa 949 Dec 14, 2022
🎞 Powerful gradient animations made simple for iOS.

AnimatedGradientView is a UIView subclass which makes it simple to add animated gradients to your iOS app. It is written purely in Swift. Further docu

Ross Butler 431 Dec 12, 2022
📰 Consistent & accessible visual styling on iOS with support for Dynamic Type.

TypographyKit makes it easy to define typography styles and colour palettes in your iOS app helping you achieve visual consistency in your design as w

Ross Butler 162 Dec 27, 2022
A super easy way to check if the installed app has an update available. It is built with simplicity and customisability in mind and comes with pre-written tests.

UpdateAvailableKit This is UpdateAvailableKit: a super easy way to check if the installed app has an update available. It is built with simplicity and

Swapnanil Dhol 22 Jan 5, 2023
Drawing and Geometry made easy on iOS - now in Swift 3.0

InkKit Swift Support Swift 4.0 InkKit is Swift 4.0 by default, so to use that just include InkKit in your podfile: pod 'InkKit' Swift 3.2 In order to

Shaps 373 Dec 27, 2022
NXDrawKit is a simple and easy but useful drawing kit for iPhone

⚠️ To use with Swift 5.0 please ensure you are using >= 0.8.0 ⚠️ ⚠️ To use with Swift 4.2 please ensure you are using >= 0.7.1 ⚠️ ⚠️ To use with Swift

Nicejinux 1.3k Dec 31, 2022
Crafter - Xcode project configuration CLI made easy.

How do you setup your Cocoa projects? Do you always set same warnings, clone configurations and do bunch of other stuff? Or maybe you work in a big co

Krzysztof Zabłocki 548 Nov 28, 2022
Visual designing library for iOS & OSX

ProcessingKit ProcessingKit is a Visual designing library for iOS & OSX. ProcessingKit written in Swift ?? and you can write like processing. Demo Dem

Atsuya Sato 333 Nov 12, 2022
An open source library that lets your users draw on things - mark up images with text, shapes, etc.

Drawsana 0.12.0 Drawsana is a generalized framework for making freehand drawing views on iOS. You can let users scribble over images, add shapes and t

Asana 569 Dec 23, 2022
A lightweight XMLParser for assembling and parsing XML values written for iOS 8+ in Swift 2.

Overview Description Requirements Installation Usage Author License Description XMLParser lets you convert a pure Swift dictionary into XML string and

Eugene Mozharovsky 75 Feb 2, 2022
iOS utility classes for asynchronous rendering and display.

YYAsyncLayer iOS utility classes for asynchronous rendering and display. (It was used by YYText) Simple Usage @interface YYLabel : UIView @property NS

null 672 Dec 27, 2022
An iOS framework for easily adding drawings and text to images.

jot is an easy way to add touch-controlled drawings and text to images in your iOS app. What's jot for? Annotating Images jot is the easiest way to ad

IFTTT 1.8k Oct 28, 2022
Create gradients and blur gradients without a single line of code

EZYGradientView is a different and unique take on creating gradients and gradients with blur on the iOS platform. The default CAGradientLayer implemen

Shashank Pali 380 Dec 6, 2022
The application is develop in Objective IOS. kids can draw whatever they want and also kids can save the drawing as well as undo erase the drawing.

IOSObjC_KidsBoard The application is develop in Objective IOS. kids can draw whatever they want and also kids can save the drawing as well as undo era

Haresh 0 Oct 28, 2021
When you scan the clothing tag, a 3D character appears and informs you of the clothing information.

1. Introduction When you scan the clothing tag, a 3D character appears and tells you the information on the clothes. You can select necessary informat

kimniki 0 Dec 23, 2021