GithubHelp home page GithubHelp 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  avatar

svgview's Issues

Change text

Hello guys, thanks for such a great library! : )

I am testing to load an SVG that has curved text, and be able to allow the user :

  • change text
  • change font type and size

Is that possible?

Screenshot 2023-10-30 at 11 37 14 Screenshot 2023-10-30 at 11 36 15

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...

Question: How to apply tint to SVGView?

Hi. I just started to use SVGView. I need to apply a tint to the svg image. How can I?

I tried unseccessfully:

SVGView(data: data)
                .foregroundColor(.blue)

SVGView(data: data)
                .tint(.blue)

SVGView(data: data)
                .background(Color.blue)

Thanks for any advice.

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?

.help(_:) modifier does not work with SVGView

I tried adding a .help(_:) modifier to an SVGView to get a tooltip on macOS. However, it does not seem to work (works OK on other image views in the same app).

SVGView(contentsOf: svgURL)
    .help("Test Tooltip")
    .frame(width: 15, height: 15)

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!

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?

Uıkit

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

Animatable SVG Support?

I am trying to add SVG animation to my watchOS app, but when I load it using the SVGView only the first frame is shown and no animations are playing.

Am I doing something wrong or there is no support for SVG animations?

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.

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

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?

Bugs when circle and rect need rotate

When the svg code need convert to SVGCircle and SVGRect, and need to add rotate attribute, it can't display correctly.

I found this issue is caused by below code, ".applyShapeAttributes(model: model)" should below the frame, position and offset.
Circle()
.applySVGStroke(stroke: model.stroke)
.applyShapeAttributes(model: model)
.frame(width: 2 * model.r, height: 2 * model.r)
.position(x: model.cx, y: model.cy)

both with SVGRect
RoundedRectangle(cornerSize: CGSize(width: model.rx, height: model.ry))
.applySVGStroke(stroke: model.stroke)
.applyShapeAttributes(model: model)
.frame(width: model.width, height: model.height)
.position(x: model.x, y: model.y)
.offset(x: model.width/2, y: model.height/2)

I want to raise a pull request to fix it, but can't push my branch successful, hope your team can fix it.

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?

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?

View updates changes

After letting my app run for a while I get this message in the console: Publishing changes from within view updates is not allowed, this will cause undefined behavior. Further investigation might be necessary as I tested in a new project just with SVGView confirming that this lib is the cause of the issue.

SVGView(contentsOf: url) asynchronous question

Looks like SVGView(contentsOf: url) downloads an image synchronously on the main thread 😳 Is there a way to make it download asynchronously on background thread? Like KingFisher library does it: KFImage(url).
Also I can't find any documentation. It would be very helpful.

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

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

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

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 ?

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?

DOMParser working on Main thread

Hi exyte,

I love your svg library! It is the best lib could find and I really appreciate that you guys made it open source.

I noticed that in the DOMParser is working on the Main thread. This is not a problem for svg files loaded from the asset catalog. However, given that one can specify any URL for a svg , this will cause the embedding app to freeze permanently in the case that the url is pointing to a web resource and the app does not have a network connection.

Keep up the great work!

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

Setting specific frame glitches with onTapGesture

I'm having some issues with getting a big schematic in SVG resized and keeping the onTapGestures unaffected. I created a scrollView around the SVGView and I'm adding the typical gestures (drag, zoom, pinch etc.) I also want to have certain parts of the schematic selectable but that seems to break partially when I use the .frame modifier to scale out the SVG to fit the screen. I can zoom in perfectly but the selection just works on the top left part of the SVGView.
I tried the .scaleEffect modifier which retains the tab gestures perfectly but as that only affects the view layer the content size of the scrollview is way too big and not adjusted to the scaled schematic.

Does anyone have any idea what is going on?

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.

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.

Font weight support

Please add support for font-weight css and svg properties.
The attribute supports "normal | bold | bolder | lighter | [<number>]".
Right now, in file Source/Model/Primitives/SVGFont.swift:16 there is an attempt of working out some font weight logic (might be necessary to bridge perhaps).

Code samples do not work in Xcode 15

Trying to use SVGView to create simple shape according to sample code.

   HStack {
    let circle = SVGCircle(cx: 30, cy: 30, r: 30)
    circle.fill = SVGColor.black  // Type '()' cannot conform to 'View'

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)")

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.