top of page

Fitness App Breakdown #1: Activity Rings

  • thim90
  • Jun 9
  • 3 min read

Soms komen de beste ideeën tijdens het bewegen. Na een kort (oké, heel kort) rondje hardlopen, keek ik naar de bekende Apple Fitness-ringen en dacht: "Waarom kan Power Apps er niet zó uitzien?"


Dat idee leidde tot een experiment in SVG, componenten en animaties in Canvas Apps. Wat begon als een simpel idee, groeide uit tot een volledig functioneel, herbruikbaar component dat geanimeerde activity rings weergeeft, net als de Fitness UI van Apple.


In deze blog neem ik je stap voor stap mee in hoe ik dit heb gebouwd, met codevoorbeelden en uitleg waarom bepaalde keuzes zijn gemaakt.


Stap 1: Maak het basiscomponent

We beginnen met een nieuw component in Power Apps. Daarin plaatsen we een Image control waarin straks de SVG wordt getoond.

Instellingen voor de Image control:

  • X = 0

  • Y = 0

  • Width = Parent.Width

  • Height = Parent.Height

  • Laat de Image property nog leeg — daar komen we zo op terug.


Step 1: New Component with Image Control

Stap 2: Voeg een basis-SVG toe

De Image control verwacht een string, dus we starten met een eenvoudige, geëncodeerde SVG-container. Zo ziet dat eruit:

"data:image/svg+xml;utf8, " & EncodeUrl(
  "<svg xmlns='http://www.w3.org/2000/svg' style='height: 100%; width: 100%' viewBox='0 0 28 28'></svg>"
)

Dit is onze canvas. Nog geen ringen, maar we zijn klaar om te bouwen.


Step 2: base svg

Stap 3: Voeg basistijlen en animatie toe

In de SVG voegen we een <style>-blok toe. Hier definiëren we de animatie en algemene ringopmaak.

<style>
@keyframes RingProgress {
  0% { stroke-dasharray: 0 100; }
}
.backgroundring {
  stroke: #000;
  fill: none;
  transform-origin: 50%;
}
.background { 
        opacity: 0.3;
}
.completed {
        stroke-linecap: round;  
        animation: RingProgress 1s ease-in-out forwards;
        repeatCount='indefinite';
    }
</style>

Dit is de basis: een klasse voor statische achtergrondcirkels en een simpele animatie. Deze stijl elementen gaan we later gebruiken bij het opbouwen van de ringen.


Stap 4: Bouw de eerste ring

Nu wordt het leuk. We maken de buitenste ring. Daarvoor gaan we eerst een bepalen hoe deze ring er uit moet zien.

Dit voegen we als stijl toe.

    .ring1{
        stroke: #c53f3d;
        fill: none;
        transform-origin: 50%;
    }

Nu we alle benodigde stijl elementen hebben gedefinieerd, gaan we de buitenste ring maken.


Dit doen we met een <g>-groep te maken voor ring1 class met daarin twee circels.

  • 1 hele ring die als achtergrond fungeert.

  • 1 ring voor de voortgang (voor nu hardcoded 60%)

<g class='ring1' style='transform: scale(0.68) rotate(-90deg);'>
  <circle class='background' stroke-width='4' r='15.915' cx='50%' cy='50%' />
  <circle class='completed' stroke-width='4' r='15.915' cx='50%' cy='50%'  
    stroke-dasharray='60, 100' />
</g>

Bovenstaande plaats je direct onder de </styles>


💡 Wat gebeurt hier:

  • rotate(-90deg) zorgt dat de ring om 12 uur start.

  • scale(0.68) verkleint de ring.

  • .background tekent een lichte achtergrond.

  • .completed tekent de voortgang.

  • stroke-dasharray='60, 100' --> 60% voortgang


Step 4: Ring 1

Stap 5: Voeg de binnenste ringen toe

We herhalen hetzelfde principe voor de twee binnenste ringen, met aangepaste scale() en stroke-width om het geheel in balans te houden.

<g class='ring2' style='transform: scale(0.49) rotate(-90deg);'>...</g>
<g class='ring3' style='transform: scale(0.3) rotate(-90deg);'>...</g>

Elke ring krijgt z'n eigen kleur en grootte. Hoe kleiner de scale(), hoe dichter bij het midden.


Step 5: 3 rings


Stap 6: Maak het dynamisch met parameters

Hardcoded waardes zijn leuk voor een demo, maar we willen dit echt bruikbaar maken.

Voeg inputparameters (type number) toe aan het component:

  • ProgressRing1 

  • ProgressRing2

  • ProgressRing3

Vervang vervolgens de vaste waardes in de SVG door:

stroke-dasharray='" & ActivityRings.ProgressRing1 & ", 100'

Zo reageert de component op data. De input parameter kan je binnen de context van je app vullen met een dynamische waarde die de procentuele voortgang vertegenwoordigd.

Herhaal de stappen voor alle drie de ringen.


In mijn voorbeeld implementeerde ik een procentuele vooruitgang. Het is ook mogelijk om ringen te gebruiken in absolute waarde. Hiervoor dien je "100" ter vervangen voor de maximale waarde.


Stap 7: Voeg gradients toe

Kleuren zijn prima, maar gradients maken het echt af. Definieer deze in <defs>:

<linearGradient id='gradient-ring1' y1='0' y2='1'>
  <stop stop-color='#FC3183' offset='0'/>
  <stop stop-color='#E6092A' offset='1'/>
</linearGradient>

Gebruik de gradient als stroke:

stroke='url(#gradient-ring1)'

Step 7: Add Gradient

Herhaal dit voor elke ring.

Step 7: Gradient result

Stap 8: Voeg de achtergrondring toe

Deze optionele ring voegt contrast en structuur toe.

<g class='backgroundring' style='transform: scale(0.2) rotate(-90deg);'>
  <circle stroke-width='93' r='15.915' cx='50%' cy='50%' />
</g>

Speel met scale en stroke-width voor het juiste effect.


Step 8: Background result


Het eindresultaat

Je hebt nu een herbruikbaar, geanimeerd activity ring-component — volledig gebouwd in Power Apps.

Dynamisch, visueel aantrekkelijk en klaar om in elke app te gebruiken!


Binnenkort volgen meer breakdowns van de op Apple geïnspireerde Fitness App. Spreken we in dat geval van PowerAbs?




Credits

Hoewel de implementatie in Power Apps volledig van mijzelf is, wil ik een shout-out geven aan Chilitime Design voor hun heldere uitleg over SVG-ringen. Hun blog hielp mij de basis van SVG te begrijpen.


Comments


Stay in touch! Sign up to my newsletter!

Thanks for submitting!

bottom of page