Dynamic SVG graphics

Jonathon
Participant V

Recently I have been using Scalable Vector Graphics (SVG) in my applications, in place of typical raster images or even text in some cases. SVG graphics are defined through code, as per the examples here: https://www.w3schools.com/graphics/svg_examples.asp

As the images are defined with code, you can CONCATENATE() strings of code together while including application variables, to make the images dynamic. In this way, you could have animated images which react to user input.

Another thing to note, is SVG graphics scale/resize losslessly (unlike raster images). So everything will always look crisp! Also, when properly optimized, the file-sizes are often smaller than raster images.

There is a trade-off, in that the device must decode and render the graphics. Older devices/computers may have a hard time rendering poorly optimized or complex SVG code. Also, older browsers do not support some SVG functionality.


Some examples:

Richer looking detail headers, and small filesize gradient backgrounds:

SVG thumbnails, without having to rely on external services like Image Placeholder:

Dynamic progress bars:

@morgan
@praveen

28 156 22.3K
  • UX
156 REPLIES 156

Mike_A
Participant V

@Jonathon - love the idea - especially the โ€œDynamic progress barsโ€. As these are code, I am assuming you can use variables to change them dynamically, rather than needing a bunch of png files to simulate the changesโ€ฆ

Can you show how you created the progress bars inside appsheet? what went in which columns, and how do you call the SVG code? Where is the svg hosted?

I like the idea of not needing yet another service on top of appsheet+datasource. Not sure the drawbacks, but very interesting. Thanks for sharing.

Jonathon
Participant V

Iโ€™ll leave it up to the community to come up with their own graphics, but I will share some code for a simple square โ€˜progress barโ€™ that should explain the concept.

You can experiment / follow along with the example by putting your SVG code in this site: https://www.w3schools.com/graphics/tryit.asp?filename=trysvg_rect


This code will define a simple rectangle outline:

<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200">
  <rect width="100%" height="100%" style="fill:none;stroke-width:3;stroke:black"/> 
</svg>

To this, we want to add a second rectangle which grows to represent progress. This second rectangle does not need an outline, just a solid fill. You can control the progress with the width style property:

<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200">
  <rect width="20%" height="100%" style="fill:black;"/> 
  <rect width="100%" height="100%" style="fill:none;stroke-width:3;stroke:black"/> 
</svg>

If you preface the code string with data:image/svg+xml;utf8,, it will render in the browser. As a test, copy and paste the below into your browser address bar and it should load:

data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200">
  <rect width="20%" height="100%" style="fill:black;"/> 
  <rect width="100%" height="100%" style="fill:none;stroke-width:3;stroke:black"/> 
</svg>

Thus, we have all the necessary pieces of the puzzle. In AppSheet, input the above string or โ€˜codeโ€™ into the app formula of an image column, bounded by quotes:

2X_7_7eecfdd0da217a2d4d152cc0eb6b225ab3682c67.png

To make it dynamic, incorporate CONCATENATE() to alter the width value based on some progress metric. One thing to note here is, the CONCATENATE() formula will need to double quote all the SVG quotation marks. Something like this:

CONCATENATE("
    data:image/svg+xml;utf8,<svg xmlns=""http://www.w3.org/2000/svg"" width=""200"" height=""200"">
      <rect width=""",[YOUR LOGIC HERE],"%"" height=""100%"" style=""fill:black;""/> 
      <rect width=""100%"" height=""100%"" style=""fill:none;stroke-width:3;stroke:black""/> 
    </svg>
")

Note I didnโ€™t test the above, so I may have messed up a quotation somewhereโ€ฆ but it should run.

@Jonathon - thanks for sharing the knowledge! Really interesting approach!

WAY COOL!!!

Very neat @Jonathon. If this is appealing to our users, we could make this a lot easier by providing a suite of builtin SVG image functions. @morgan and @tony what do you think?

Hi @praveen!

Iโ€™m very interested in graphics that show progress so I think @Jonathonโ€™s idea is great and Iโ€™d love to see AppSheet add builtin SVG image functions, as you indicated. One concern I have, however, is that the data that is being displayed graphically needs to be up-to-date. On a flashcard app Iโ€™m continuing to refine, Iโ€™ve had difficulty getting accurate progress statistics without syncing:

I wish AppSheet would allow us to designate a particular calculation (say, the count of a slice, for example) as โ€œmust be currentโ€ or โ€œalways calculate immediately.โ€ I know that somewhere inside my AppSheet app there is always accurate information about what is in a particular slice and what is not, because the native navigation within the slice always works correctly and the number of records shown in the deck view is always correct. However, Iโ€™m not always able to access that information in realtime; the number of โ€œrecords remainingโ€ based on my count() expression is often inaccurate until the sync is complete.

One work around is to force the app to write the current count to my sheet before the โ€œprogressโ€ is displayed:

However, this adds to the โ€œsync queueโ€ in the app โ€“ another problem Iโ€™ve been trying to ameliorate.

So, if some kind of โ€œmust be real timeโ€ tool could be given to developers (with the understanding that overuse can cause problems), I think that would make graphics of this sort all the more attractive. Or, if by default counts of slices could be made to always be accurate, that would solve the problem.

Please do, sir!
Will be very appreciated

Is this possible yet?

Jonathon
Participant V

The โ€œhttps://www.w3.org/2000/svgโ€ is just the SVG namespace. Including the namespace lets the browser know how to decode the following xml code (i.e. that it is an SVG, and the version of SVG). There isnโ€™t any risk of this going down - itโ€™s not a host.

You can stick your SVG code in your database / google sheet if you want. For example:

2X_3_3c14e33f555ed0d130ccad60e5e2da2af66a11a2.png

In other words, there is no external dependencies beyond AppSheet / your existing database.

In a SQL database, there is no real limitation to how large the SVG can be. In Google Sheets, there is a 50,000 character limit in a cell, so your code would have to be less than that.

Love it even more. Will have to try that out. I am already using a lot of individual images to simulate dynamic graphics, while SVG would solve that. Thanks for sharing this approach.

If this would be better supported in Appsheet directly, that would be a powerful addition.

@Jonathon - I can see how easy it is to create dynamic images (like progress bars) this way. I created a nice and thin bar with a quick modification to your code example. Sweet. Did a bit of looking and could not find an easy example of the circular progress bars. All had html+css+JavaScript. Not clear to me how to create something like you showed above. Can you use CSS and javascript as well? Care to share a code snippet on how you did the circulate progress bars?

These links explain it pretty well:

https://codepen.io/xgad/post/svg-radial-progress-meters

Thanks @Jonathon!

thanks for this tips, very helpful !
a question : how do you integrate the css & js code beside the svg code ?

@jerome_houix - I am messing around with that as well (and failing!). Trying to get a single line SVG of a radial progress chart. Have a linear progress bar working. Canโ€™t seem to get the radial path working. Have example of in-line css with no script required, but keep getting syntax errors.

If anyone has an example radial path SVG with inline CSS that would be great. Otherwise, I will keep trying to track down the problem - but after a lot of reading - an html file with inline css looks possible (between the tags.

Jonathon
Participant V

No need to integrate CSS /JS.


<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 120 120">
<circle cx="60" cy="60" r="54" fill="none" stroke="grey" stroke-width="12" />
<circle cx="60" cy="60" r="54" fill="none" stroke="black" stroke-width="12" stroke-dasharray="339.292" stroke-dashoffset="-100" transform="rotate(-90 60 60)"/>
</svg>

In the above code, you want to replace the stroke-dasharray="โ€ฆ" variable with the INVERSE of your percentage metric, as a fraction of the 339.292.

As an example, if you want to represent 60%, your formula would calculate as:

(1-0.6)*339.292

Thanks @Jonathon! I now have a great starting point to play around with. Have not done and HTML/CSS work in many many years (and that was pretty crude), so itโ€™s like a new toy!

Your example was great. No JS or CSS (styles done in-line). Super simple.
Next up is to add in the variables like you did at the start of this conversation.

data:image/svg+xml;utf8, <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 120 120"> 
<circle cx="60" cy="60" r="54" fill="none" stroke="lightgrey" stroke-width="12" /> 
<circle cx="60" cy="60" r="54" fill="none" stroke="Navy" stroke-width="10" stroke-dasharray="339.292" stroke-dashoffset="-100" transform="rotate(-90 60 60)"/> 
<text fill="Navy" font-family="sans-serif" font-size="150%" x="40" y="60" >90%</text>
</svg>

learningโ€ฆlearningโ€ฆlearningโ€ฆ

Hey @Mike, it seems now we have a new toy to play with

Yes @LeventK! I want to explore this further. Still not succeeding so decided i will create a separate SVG app so I can do some testing. Might see if I can share that as a โ€œplaygroundโ€. I see potential here and want to figure out the performance implicationsโ€ฆ

Gotcha. May be we can work on that together @Mike. What do you think?

Sure! I might slow you down, but could be fun. I will throw something together later and add you as an admin.

Jonathon
Participant V

I would be interested in collaborating as well if you are interested!

@Jonathon - you started this โ€œmessโ€ so of course!!

I am likely the least capable in this area, but you really peaked my interest to explore. Just the ability to handle progress bars and radial charts with appsheet controlling the variables - great way to extend the capabilities without using third party solutions. Seems to require some real knowledgeโ€ฆ but thatโ€™s just learning.

I started a messy app to collect some things that donโ€™t all work yetโ€ฆ but happy to share โ€ฆ
Whatโ€™s the best approach? Add you as admins to the app, and also to the gsheet behind? Need your emails right? @LeventK

maybe if you both PM me your emails (via the community) I can add them.

@Mike
@Jonathon
You can always reach me at levent@able3ventures.com
Share the app as co-author and also the gSheet with edit access please.

done. added as co-author.

Thanks @Mike
Will check it tomorrow immediately Letโ€™s see what we can do with this new toy

need to make a change. moving the app from work acct to personal. will take a little bit. sorry for delayโ€ฆ

should be connected now. I just threw in some examples I had been playing with and have not messed with variables yet (as @Jonathon did). Was figuring I could test and build example use cases here to use in specific apps. Then I realized it might be a good way to create an SVG โ€œlibraryโ€ for easy testing and use. Got to run now, but will start playing around soon.

Feel free to add whatever you want - from views to other tables (just donโ€™t lose the code I currently have in the gsheet). Let the fun begin . And again, itโ€™s all Jonathanโ€™s fault!

Some further thoughts on the topic:

A current limitation of AppSheets formatting options, is they are initialized upon a form opening and from there remain static. There are workarounds which involve multiple columns and use of SHOW() to give the appearance of dynamic formatting rules within forms, but these are cumbersome to implement and add bloat to the app.

SVG graphics donโ€™t suffer from this limitation - using IF() statements to vary the SVG code works well.


Also, Mike has been messing around with animated SVG graphics. I was struggling to think of a tasteful way to use themโ€ฆ One use may be to draw attention to some important detail within a form, like a warning of sorts, or a โ€œNEW!โ€ indicator that has a rotating star or something.

You are rightโ€ฆ i am not likely to use animated SVG much (tasteless) but wanted to understand the capability. Only tasteful use case for me is if I need a visual indicator that uses motion (or even grow/shrink) animation to get attention. Otherwise itโ€™s just โ€œcuteโ€ - and flashing yellow new is so 1080โ€™s!

Most critical to me is the use of dynamic SVGโ€™s that change according to AppSheet column values - your example from the start of this thread. Thatโ€™s the sweet spot for me. I added a view in the example app just for that purposeโ€ฆ

A subtle twinkle effect on a star, or a glow may not be tasteless! Subtle being the key word.

@praveen

An โ€˜officialโ€™ SVG columntype built into appsheet may have the following features:

  • Include the data:image/svg+xml;utf8, preface, so we donโ€™t have to
  • have some clever way for users to insert appsheet variables into the svg code, rather than using CONCATENATE() - maybe something similar to how workflow rules use <<>>.
  • I would be cautious about trying to automate too much of the SVG code functionality. The beauty of this โ€˜featureโ€™ is that it is, by in large, unbounded.

The current issue with concatenate is the requirement to double-quote everything, or sometimes triple quote depending on the nature of the svg code. Things get messy quickly, to say the least.

Also, I am often using the SHOW columntype with IMAGE subtype, instead of straight up IMAGE column types. The benefit of using SHOW is the images arenโ€™t clickable; if I want an SVG image header, I donโ€™t want users to be able to click it and have a modal window of the header show over everything. In general, SVG graphics arenโ€™t something you want users clicking on to enlarge; the are more likely to be a UI/UX piece.

Finally, AppSheet does not like any svg code that includes a hashtag. This means hex color codes are out of the question - but converting them to rgb() works fine. However, other SVG functions which include hashtags and no obvious workaround arenโ€™t usable. One extreme solution to eliminate hashtags is to convert the entire svg code to BASE64. Unfortunately, including variables in BASE64 encoded strings gets pretty convoluted / becomes impossible.

Thanks for all the inputs here @Jonathon, and I agree with your comments. Having a column type for this that could handle a bit of formatting and an easy way to โ€œinjectโ€ Appsheet variables would be a huge help. The hashtag thing is a bummer and although BASE64 seems to work (creative of you), it is a pain to convert, and then cannot be edited again โ€œin-appโ€.

You can get around the hashtag problem by using the URLENCODE function in appsheet or google sheets. This substitutes the hashtag for %23 making it work in URLโ€™s

somes issues after few test

  • none display in the UI view detail when background is choosing,
  • same for the card view
  • Web browser not displaying too ( with complex code, i should missed something) but suceed in mobile device

    SVG rendering is good: filter, animation, importing various Data

Very good idea the SVG APP ! i will share my snippet too

Jonathon
Participant V

Hereโ€™s a question @Praveen:

If a parent record references an image from a child record as a virtual column, how does appsheet handle that image? Would the image be loaded twice, or just once and then referenced from cache?

This is particularly relevent when working when SVGโ€™s, as we can in theory add a simple icon to every record with a virtual image column and an SVG string as the app formula. I would assume in this case, AppSheet would handle that as a new image for each record, even if the SVG code was the same for all? In this case, it would be better to have a common_asset table and reference the image to all rows?

In a broader sense, if I have common asset images I would like to distribute through an application, such as icons, what is the best practice in terms of associating them with records? In terms of neatness, I would presume a common_asset table is best practice, but will this also have a positive impact on loading times?

Hi, I am very interested in this SVG solution, but i donโ€™t succeed actually make it work in my application (even if i try to copy/paste your examples)
actually i am generating on the fly png images
For this SVG example i am affraid that appsheet cache would cause some issues

With the help of @Jonathon , I have some pretty successful examples running. Still some tweaks and nuances to get this to work. My advice would be to post some details about your SVG code - or even an example app, and you might be able to get some more help. Itโ€™s not completely straight forward, so you need to be specific about what you are struggling with.

@Mike @Jonathon this is solidโ€ฆ I want in, can I check it out in your app?
grantstead@steadglobal.com

Hi Grant. I will add you when I get a second. Still some tweaking to do for it to work as I want, but convinced this has real potential.

Having an html/SVG column type might help so we can avoid having to add โ€œdata:image/svg+xml;utf8,โ€, deal with escaping quotes, and proper Appsheet handling of hashes and other special characters.

Top Labels in this Space