Replace loading spinner with a completely new CSS driven spinner - is it doable?

Hi everyone

I want my users to see this spinner while waiting for the main server function to complete:

Having never set up a loading animation before, I’m firmly in the evaulation stage on this at the moment, looking for a yes or no - is it possible in Anvil and not too difficult?

Questions on my mind at the moment:

  • It looks like the CSS would go in the theme file and the html in the html file?
  • Or would they be in files of their own?
  • How would the CSS and HTML for the new spinner be called instead of the normal spinner?
  • Any involvement of native libraries?

Just looking to avoid going on a 2 hour rampage only to discover that ‘Anvil doesn’t do that’!

Richard

Yes, it’s doable. Have a look at:

Thanks, but that method only works if I have a ready made .gif file I want to use, as far as I can tell. Your answer did address my question as I wrote it in the subject originally, I’ve now re-worded it.

The new spinner needs its own CSS. I tried just pasting the CSS they provide into the theme.css file in Anvil, CSS novice that I am, that was a long shot admittedly - the editor didn’t even recognise it as valid CSS.

Edit: Turns out that’s because it’s SCSS. Tried converting it to CSS using an online converter, no luck though, threw an error that requires good CSS understanding to fix.

Here’s the css you should paste into your theme.css which is just the compiled SCSS from your link.
Plus the first part to disable the default loading spinner gif.


#loadingSpinner {
  background-image: none;
}

div.spinner {
  -moz-animation: rotate 10s infinite linear;
  -webkit-animation: rotate 10s infinite linear;
  animation: rotate 10s infinite linear;
  position: relative;
  display: block;
  margin: auto;
  width: 142px;
  height: 142px;
}
div.spinner i {
  -moz-animation: rotate 3s infinite cubic-bezier(0.09, 0.6, 0.8, 0.03);
  -webkit-animation: rotate 3s infinite cubic-bezier(0.09, 0.6, 0.8, 0.03);
  animation: rotate 3s infinite cubic-bezier(0.09, 0.6, 0.8, 0.03);
  -moz-transform-origin: 50% 100% 0;
  -webkit-transform-origin: 50% 100% 0;
  transform-origin: 50% 100% 0;
  position: absolute;
  display: inline-block;
  top: 50%;
  left: 50%;
  border: solid 6px transparent;
  border-bottom: none;
}
div.spinner i:nth-child(1) {
  -moz-animation-timing-function: cubic-bezier(0.09, 0.3, 0.12, 0.03);
  -webkit-animation-timing-function: cubic-bezier(0.09, 0.3, 0.12, 0.03);
  animation-timing-function: cubic-bezier(0.09, 0.3, 0.12, 0.03);
  width: 44px;
  height: 22px;
  margin-top: -22px;
  margin-left: -22px;
  border-color: #2172b8;
  border-top-left-radius: 36px;
  border-top-right-radius: 36px;
}
div.spinner i:nth-child(2) {
  -moz-animation-timing-function: cubic-bezier(0.09, 0.6, 0.24, 0.03);
  -webkit-animation-timing-function: cubic-bezier(0.09, 0.6, 0.24, 0.03);
  animation-timing-function: cubic-bezier(0.09, 0.6, 0.24, 0.03);
  width: 58px;
  height: 29px;
  margin-top: -29px;
  margin-left: -29px;
  border-color: #18a39b;
  border-top-left-radius: 42px;
  border-top-right-radius: 42px;
}
div.spinner i:nth-child(3) {
  -moz-animation-timing-function: cubic-bezier(0.09, 0.9, 0.36, 0.03);
  -webkit-animation-timing-function: cubic-bezier(0.09, 0.9, 0.36, 0.03);
  animation-timing-function: cubic-bezier(0.09, 0.9, 0.36, 0.03);
  width: 72px;
  height: 36px;
  margin-top: -36px;
  margin-left: -36px;
  border-color: #82c545;
  border-top-left-radius: 48px;
  border-top-right-radius: 48px;
}
div.spinner i:nth-child(4) {
  -moz-animation-timing-function: cubic-bezier(0.09, 1.2, 0.48, 0.03);
  -webkit-animation-timing-function: cubic-bezier(0.09, 1.2, 0.48, 0.03);
  animation-timing-function: cubic-bezier(0.09, 1.2, 0.48, 0.03);
  width: 86px;
  height: 43px;
  margin-top: -43px;
  margin-left: -43px;
  border-color: #f8b739;
  border-top-left-radius: 54px;
  border-top-right-radius: 54px;
}
div.spinner i:nth-child(5) {
  -moz-animation-timing-function: cubic-bezier(0.09, 1.5, 0.6, 0.03);
  -webkit-animation-timing-function: cubic-bezier(0.09, 1.5, 0.6, 0.03);
  animation-timing-function: cubic-bezier(0.09, 1.5, 0.6, 0.03);
  width: 100px;
  height: 50px;
  margin-top: -50px;
  margin-left: -50px;
  border-color: #f06045;
  border-top-left-radius: 60px;
  border-top-right-radius: 60px;
}
div.spinner i:nth-child(6) {
  -moz-animation-timing-function: cubic-bezier(0.09, 1.8, 0.72, 0.03);
  -webkit-animation-timing-function: cubic-bezier(0.09, 1.8, 0.72, 0.03);
  animation-timing-function: cubic-bezier(0.09, 1.8, 0.72, 0.03);
  width: 114px;
  height: 57px;
  margin-top: -57px;
  margin-left: -57px;
  border-color: #ed2861;
  border-top-left-radius: 66px;
  border-top-right-radius: 66px;
}
div.spinner i:nth-child(7) {
  -moz-animation-timing-function: cubic-bezier(0.09, 2.1, 0.84, 0.03);
  -webkit-animation-timing-function: cubic-bezier(0.09, 2.1, 0.84, 0.03);
  animation-timing-function: cubic-bezier(0.09, 2.1, 0.84, 0.03);
  width: 128px;
  height: 64px;
  margin-top: -64px;
  margin-left: -64px;
  border-color: #c12680;
  border-top-left-radius: 72px;
  border-top-right-radius: 72px;
}
div.spinner i:nth-child(8) {
  -moz-animation-timing-function: cubic-bezier(0.09, 2.4, 0.96, 0.03);
  -webkit-animation-timing-function: cubic-bezier(0.09, 2.4, 0.96, 0.03);
  animation-timing-function: cubic-bezier(0.09, 2.4, 0.96, 0.03);
  width: 142px;
  height: 71px;
  margin-top: -71px;
  margin-left: -71px;
  border-color: #5d3191;
  border-top-left-radius: 78px;
  border-top-right-radius: 78px;
}

@-moz-keyframes rotate {
  to {
    -moz-transform: rotate(360deg);
    transform: rotate(360deg);
  }
}
@-webkit-keyframes rotate {
  to {
    -webkit-transform: rotate(360deg);
    transform: rotate(360deg);
  }
}
@keyframes rotate {
  to {
    -moz-transform: rotate(360deg);
    -ms-transform: rotate(360deg);
    -webkit-transform: rotate(360deg);
    transform: rotate(360deg);
  }
}

Then in NativeLibraries (Native Libraries is best because this loads before the app)

<script>
$(document).ready(() => {
    $('#loadingSpinner')
    .addClass('spinner')
    .append($('<i/><i/><i/><i/><i/><i/><i/>'));
})
</script>

4 Likes

Thank you @stucork, it works and looks phenomenal!

Would be great to know how you compiled the SCSS (all of the SCSS to CSS converters I found on Google threw an error)

it was closer to home:
Screenshot 2021-05-18 at 18.13.03

There’s a view compiled button already there.

1 Like

@stucork That’s awesome, thank you!

This has spurred me to start learning more about the way you have injected HTML into the app using jquery (I think?) via native libraries, to be able to add even better loading animations.

Working from the code snippet you provided in Native Libraries, do you know how you would insert a more deeply nested set of divs?

The HTML I am trying to insert via native libraries (in the same capacity as in your original example i.e. tied to the #loadingSpinner) is this, which is the same set of nested divs, repeated 6 times:

<div class="loader">

  <div class="group">
    <div class="dot"></div>
    <div class="dot"></div>
    <div class="dot"></div>
    <div class="dot"></div>
  </div>

  <div class="group">
    <div class="dot"></div>
    <div class="dot"></div>
    <div class="dot"></div>
    <div class="dot"></div>
  </div>

  <div class="group">
    <div class="dot"></div>
    <div class="dot"></div>
    <div class="dot"></div>
    <div class="dot"></div>
  </div>

  <div class="group">
    <div class="dot"></div>
    <div class="dot"></div>
    <div class="dot"></div>
    <div class="dot"></div>
  </div>

  <div class="group">
    <div class="dot"></div>
    <div class="dot"></div>
    <div class="dot"></div>
    <div class="dot"></div>
  </div>

  <div class="group">
    <div class="dot"></div>
    <div class="dot"></div>
    <div class="dot"></div>
    <div class="dot"></div>
  </div>

</div>