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:
@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.
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.
@Jonathon - thanks for sharing the knowledge! Really interesting approach!
WAY COOL!!!
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?
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.
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:
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
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.
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.
An โofficialโ SVG columntype built into appsheet may have the following features:
data:image/svg+xml;utf8,
preface, so we donโt have toThe 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
Very good idea the SVG APP ! i will share my snippet too
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.