Coder Social home page Coder Social logo

svgview's Introduction

     

SVGView

SVG parser written in SwiftUI

SPM Compatible Cocoapods Compatible Carthage Compatible License: MIT

Overview

The goal of this project is to bring the full power of SVG to Apple platforms. Our framework can parse SVG files and represent their content in SwiftUI. It provides you with the ability to not only render SVG files, but also add interactivity to them, handle user input and use SwiftUI to put your art into motion.

Usage

Get started with SVGView in a few lines of code:

struct ContentView: View {
    var body: some View {
        SVGView(contentsOf: Bundle.main.url(forResource: "example", withExtension: "svg")!)
    }
}

Customization

You can change various parameters for the nodes like this:

let circle = SVGCircle(cx: 30, cy: 30, r: 30)
circle.fill = SVGColor.black
circle.stroke = SVGStroke(fill: SVGColor(hex: "ABCDEF"), width: 2)
circle.onTapGesture {
    print("tap")
}

Interact with vector elements

You may locate the desired part of your SVG file using standard identifiers to add gestures and change its properties in runtime:

struct ContentView: View {
    var body: some View {
        let view = SVGView(contentsOf: Bundle.main.url(forResource: "example", withExtension: "svg")!)
        if let part = view.getNode(byId: "part") {
            part.onTapGesture {
                part.opacity = 0.2
            }
        }
        return view
    }
}

Animation

You can use standard SwiftUI tools to animate your image:

if let part = view.getNode(byId: "part") {
    part.onTapGesture {
        withAnimation {
            part.opacity = 0.2
        }
    }
}

Complex effects

SVGView makes it easy to add custom effects to your app. For example, make this pikachu track finger movement:

var body: some View {
    let view = SVGView(contentsOf: Bundle.main.url(forResource: "pikachu", withExtension: "svg")!)
    let delta = CGAffineTransform(translationX: getEyeX(), y: 0)
    view.getNode(byId: "eye1")?.transform = delta
    view.getNode(byId: "eye2")?.transform = delta

    return view.gesture(DragGesture().onChanged { g in
        self.x = g.location.x
    })
}

SVG Tests Coverage

Our mission is to provide 100% support of all SVG standards: 1.1 (Second Edition), Tiny 1.2 and 2.0. However, this project is at its very beginning, so you can follow our progress on this page. You can also check out SVGViewTests project to see how well this framework handles every single SVG test case.

Installation

Swift Package Manager

dependencies: [
    .package(url: "https://github.com/exyte/SVGView.git")
]

CocoaPods

pod 'SVGView'

Carthage

github "Exyte/SVGView"

Requirements

  • iOS 14+ / watchOS 7+ / macOS 11+
  • Xcode 12+

Our other open source SwiftUI libraries

PopupView - Toasts and popups library
Grid - The most powerful Grid container
ScalingHeaderScrollView - A scroll view with a sticky header which shrinks as you scroll
AnimatedTabBar - A tabbar with number of preset animations
MediaPicker - Customizable media picker
Chat - Chat UI framework with fully customizable message cells, input view, and a built-in media picker
ConcentricOnboarding - Animated onboarding flow
FloatingButton - Floating button menu
ActivityIndicatorView - A number of animated loading indicators
ProgressIndicatorView - A number of animated progress indicators
LiquidSwipe - Liquid navigation animation

svgview's People

Contributors

ba01ei avatar bennie-atlassian avatar codycrossley avatar denis-obukhov avatar f3dm76 avatar jjaychen1e avatar magauran avatar nikita-afonasov avatar nnabeyang avatar philiptrauner avatar rstrahl avatar rushairer avatar sampettersson avatar wandersiemers avatar ystrot avatar zapletnev avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

svgview's Issues

How to Load svg from Assets Folder?

Hi, my file file.svg is found in the Assets folder and the code looks like this

SVGView(contentsOf: Bundle.main.url(forResource: "file", withExtension: "svg")!)

But says Unexpectedly found nil while unwrapping an Optional value. the file is there.
Also tried to clean everything, but same result. Am i missing something?

Text is not displayed on the SVGView

My Code here:

import SwiftUI
import SVGView

struct ContentView: View {
    @State private var data: Data?
    
    var body: some View {
        if let data {
            SVGView(data: data)
        } else {
            Color.black.opacity(0.001)
                .task {
                    if let (data, _) = try? await URLSession.shared.data(from: URL(string: "https://img.shields.io/cocoapods/l/SVGView.svg?style=flat")!) {
                        self.data = data
                    }
                }
        }
    }
}

I use the one in your README.md file, and this is( I guess ) a SVG, but SVGView can only show the background but no text on it.

截屏2022-10-16 16 50 49

transform with CGAffineTransform scale, or rotation also moves the position of the node

Hi. I am trying the package with a simple use very similar to your Pikachu example. Instead of translation, I am using scale. Basically, when the part of the image is tapped, it should scale up slightly. The scaling works, but the position also moves - the larger the scaling, the larger the movement. (making it smaller moves it in the opposite direction). I suspect it has to do with the svg having relative or absolute coordinates, but it is not clear what I need to do to fix this.

Value of type 'some View' has no member 'getNode'

    if let filePath = Bundle.main.url(forResource: "zones", withExtension: "svg") {
            ScrollView(.horizontal) {
                let zoneMap = SVGView(contentsOf: filePath).frame(width: 1100, height: 550)
                
                if let part = zoneMap.getNode(byId: "part") {
                            part.onTapGesture { // onTapGesture not available.
                                part.opacity = 0.2
                            }
                        }
            }
        }

Nor does the following from your "Getting Started" recognize a tap:


struct ZoneSelect: View {
    let fileURL = Bundle.main.url(forResource: "zones", withExtension: "svg")!
    var body: some View {
        let root = SVGView(contentsOf: fileURL)// 1
        let first = root.getNode(byId:"zone1")// 2
        first?.onTapGesture{ // 3
            (first as? SVGShape)?.fill = SVGColor.by(name: "red") // 4
            print("Tapped!")
        }
        return root
    }
    
}

What is the correct API to recognize a tap? Have you changed the API overall? If so, where's the documentation?

Font is always the same size.

When I render an svgs, the font is always the same size. I have a number of svgs images that have fonts of different size in them, but when rendered with SVGView, they are all the same size. Below are a couple of pictures from an example.

What the svgs should actually look like.
Screen Shot 2022-05-25 at 4 35 24 AM

What the svgs looks like with SVGView.
Screen Shot 2022-05-25 at 4 36 44 AM

Here is the actual svgs file that I used for this example.
FontExample

Support for Filling SVG Paths with Patterns

Hi!
I have an SVG file with a "path" element, and I'm attempting to use the "fill" attribute to apply a pattern to the path. However, it doesn't seem to be working as expected. Can you please clarify whether SVGView supports filling SVG paths with patterns?

Here is the example:

<?xml version="1.0" encoding="UTF-8"?>
<svg viewBox="0 0 500 500" >

<pattern id="pattern1"
           x="0" y="0" width="20" height="20"
           patternUnits="userSpaceOnUse">
           
           <rect x="0" y="0" width="10" height="10" style="stroke: none; fill: #0000ff" />
           
           </pattern>

 <path id="3" transform="translate(-25.438 -29.677)" d="m43.244 60.776c78.857 1.6957 278.12 33.917 354.43 229.79-26.286 5.088-90.727 67.834-100.9 102.6-194.17-99.206-249.29-256.07-253.53-332.38z" fill="url(#pattern1)" fill-rule="evenodd" stroke="#000" stroke-linejoin="round" stroke-width="10"/>

</svg>

Thanks in advance

SVGZ support

Tests: conform-viewers-01-t.svgz, conform-viewers-02-f.svg
Priority: Low
Comments:
SVGZ is just a gzip-compressed SVG file. It's pretty easy to implement, but it's not supported by Macaw and partly supported by WebKit (for example, doesn't work for local files). So it's a low priority task.

Carthage build failed: Task failed with exit code 75

We recently added SVGView library to try it out in our test apps. However, when building with Carthage it fails. Temporary solution:
/Carthage/Checkouts/SVGView/SVGView.xcodeproj
Edit the SVGView scheme and remove Build/Pre-actions

Task failed with exit code 75:
/usr/bin/xcrun xcodebuild -project /Carthage/Checkouts/SVGView/SVGView.xcodeproj -scheme SVGView -configuration Release -derivedDataPath /etcetera...

How do I add tint?

Hey, great package and works perfectly for me, but I can't seem to be able to tint the SVGs that I'm downloading from the CDN, is that something that's missing or do I just not know how to do ?

Are embeeded images supported?

I am rendering an svg with an embedded image and it does not render. I tried also adding the image with a remote url and it also does not render. I can see it render correctly in xcode preview though.

Thanks in advance.

JavaScript support

There are a lot of SVG tests using JS code. It's actually possible to integrate some JS engine into iOS app, but quite complicated and not sure it worths it. For now it's a low priority task, but I'll keep this issue open to track all tests blocked by JS support:

  • conform-viewers-03-f
  • coords-dom-01-f
  • coords-dom-02-f
  • coords-dom-03-f
  • coords-dom-04-f
  • paths-dom-01-f
  • paths-dom-02-f

stroke and fill with SVGNode

I want to fill and stroke these nodes, what should I do to achieve that?
let view = SVGView(contentsOf: Bundle.main.url(forResource: svgName, withExtension: "svg")!) let node = view.getNode(byId: "\(1)")

Resizing issue

Hi,

I'm having a resizing issue with the library. Depending on the svg file I use, I get an image correctly displayed, or I get an image taking way much space than it should (ie more space than the screen itself).

To display the svg file, I'm using this:

SVGView(fileURL: svgFilePath)
        .scaledToFit()
        .frame(width: 200, height: 200)

From what I've seen, the svg files that are defined with a large width and height are not displayed correctly, which maybe makes sense. But shouldn't svg images be stretched as we want?

Make view resizable

Right now in SVGDataImage and SVGURLImage I see modifier .frame(width: model.width, height: model.height), so image always this this size, I suggest replace it with resizable() modifier to let user to set image size

Animating color gradient changes

First of all, congrats on building this lib, it's really useful! One use case that I came across was animating a color change from a gradient to another from a single node. I tried using this piece of code provided from previous questions, but this would only apply animation changes to flat colors:

func tint(_ node: SVGNode, color: SVGColor) {
        if let group = node as? SVGGroup {
            for content in group.contents {
                tint(content, color: color)
            }
        } else if let shape = node as? SVGShape {
            shape.fill = color
        }
    }

Is there a way to achieve this with the current state in which the framework is in?

Dynamically set image as shape fill

Hi! I'm building a seat map for our office and I would like to dynamically add the pictures of people inside an SVGShape.

I tried getting the shape node and overriding it with an SVGDataImage, but it did not work. The shape's fill just became transparent.

for i in stride(from: 0, to: subgroup.contents.count, by: 1) {
    if let id = subgroup.contents[i].id {
        if id.contains("photo_") {
            subgroup.contents[i] = SVGDataImage(data: Data(imageAsBase64.utf8))
        }
    }
}

I hope this is possible to do. Any tips? Thanks in advance!

Masking

Hey folks!

Thanks for the nice library. I was testing the feasibility of using it in our production app, and noticed that it doesn't seem to support masking, unless I'm missing something.

Looking in SVGNode, I see that it includes a mask parameter is passed, but not actually used. I do see that clipping seems to be done in applyNodeAttributes(model:) What level of effort would be involved with getting masking working?

Uıkit

Can ı use this library in uikit, can you give an example usage?

Loading a Node without width/height/viewBox results in layer escaping view bounds

We're trying to separate an SVG's layers to be able to control each separately, so we implemented a method like this:

func node(for layer: MapLayers) -> SVGNode {
    return rootNode.getNode(byId: layer.rawValue) ?? .init()
}

The problem is loading layers like this results in the layer "escaping" the bounds of our view. Something told me it had to do with the viewBox part that now was "missing" (not included since we're not loading the entire SVG anymore).

So, to be clear, what works:

  • Loading an entire SVG, with either width/height OR viewBox in the svg tag.

What doesn't:

  • Loading a single layer gotten through the above method.
  • Loading an entire SVG that had width/height and viewBox removed in the svg tag.

To fix this, is there a way for me to specify width, height and viewBox for each Node (I tried .frame(), that didn't work) or maybe inject this svg tag into each layer?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.