Dynamic SVG graphics

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

20 Likes

Jonathon:

Dynamic progress bars

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

1 Like

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:

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.

9 Likes

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?

23 Likes

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

WAY COOL!!!

1 Like

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:

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.

3 Likes

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.

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:

[New Bug Encountered: Fast syncs brought new delay in ref link to count(select result](https://community.appsheet.com/t/new-bug-encountered-fast-syncs-brought-new-delay-in-ref-link-to-count-select-result/11501) Questions

First of all, I haven’t seen an announcement or comment about this but AppSheet sync times seem to have improved substantially. Am I the only one who has noticed this? The speedy syncs are very, very welcome but I wonder if a change in app performance I’ve noticed may not be related to the AppSheet platform change that is giving us the quicker sync times. [02] On my app, I use a ref column to fetch the current count of records in a slice. The ref is to a tiny sheet (only a couple c…

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:

[Force immediate calculation](https://community.appsheet.com/t/force-immediate-calculation/10586/3) Tips & Tricks ?

Thanks for your interest. For quite a long time now, I’ve been working on a flashcard app for language learners. With this app, students following a review schedule that is divided into “sessions.” The “cards” (records) that a student is to study in each session are selected through a slice, according to the session number that each individual card was begun in comparison with the current session number. It its the “current session number,” stored in a separate small table, that completely c…

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.

1 Like

@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?

1 Like

These links explain it pretty well:

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

2 Likes

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.

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

2 Likes

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…

2 Likes

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

1 Like

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…

1 Like

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

1 Like

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

1 Like

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

2 Likes