DEV Community

Cover image for Power Apps Tracks Santa
david wyatt
david wyatt

Posted on

Power Apps Tracks Santa

santa tracker

Ive had a couple of apps where positioning of mulitple images is dynamic, this can be painful. Think of a carpark map that you want to place an X on the space, there are a 100 spaces and you need to map the X,Y corodinates in the app, this could take forever. So I wanted to figure the best way, and as everyone knows I like to learn by doing, often with a crazy project.

Its almost Christmas so I was inspired by my childrens favourite Christmas site Norad Tracks Santa, could Power Apps Track Santa? Additionally not just any locations in the world, just the ones my children would love 😎

So in my mind I had 2 options, zoom in on the map, position Santa in the middle and move the map, or full screen the map and move Santa. The better way was the first, but due to time constraints and what I wanted to learn I went with the latter.

  • The plan was, plot all of the locations in a SharePoint list
  • On a timer move Santa from the current location to the next
  • Start the movement at midnight on internal dateline
  • Finsish the move after 24hours

After a little fun (and some pain, timezones suck), I learned a great technique for plotting coordinates, and just about understood dealing with timezones (who Im lying to, still no idea).

map

Plotting Multiple Coordinates

My old way was to position the component, read its X & Y values, then add that to a SharePoint list. What I wanted to do was to automatically record the X & Y values as I drag the icon around, but for security I dont approve custom components, so I have no drag and drop. Then I realised I do have drag and drop, in the maker studio.

So I created an Icon that on click patches the coordinates, in the studio I drag the icon to the position, and then hold the 'Alt' button (to activate test mode) and click it.

studio

To make it a little smarter I added 2 input boxes, one to record the location name that I needed, and second the row id. That way I couldnot just add (if Id input was empty) but also modify (if valid Id).

inputs

Icon onSelect

If(IsBlank(inID.Text),
    Patch('List-SantaTracker',{},
        {
            Title:inLocation.Text,
            X:Self.X+(Self.Width/2),
            Y:Self.Y+(Self.Height/2)
        }
    )
,
    Patch('List-SantaTracker',{ID:Value(inID.Text)},
        {
            Title:inLocation.Text,
            X:Self.X+(Self.Width/2),
            Y:Self.Y+(Self.Height/2)
        }
    )
)
Enter fullscreen mode Exit fullscreen mode

Incase you didnt know, you dont need to use Defaults() to create, just an empty object, and you dont need to use the LookUp() to modify, just the ID in an object

For a little extra functionality I also added a second Icon that had the current ID as its X & Y, so that I could check to see if the values were correct.

LookUp('List-SantaTracker',ID=Value(inID.Text)).X-(Self.Width/2)
Enter fullscreen mode Exit fullscreen mode
LookUp('List-SantaTracker',ID=Value(inID.Text)).Y-(Self.Height/2)
Enter fullscreen mode Exit fullscreen mode

As I now had a load of admin components that I didnt want to show in the live app I needed a way to hide them. I was orgionally going to have a hard coded boolean variable, but I knew I would forget one time. So I used a neat little trick, the SaveData function errors in the maker studio, so I could use that error handling to set the variable.

IfError(SaveData([],"makerStudio"),Set(vbAdmin,true),Set(vbAdmin,false));
Enter fullscreen mode Exit fullscreen mode

Time

There is not a single developer in the world that likes timezones, me included. I wanted the Santa to only move when it midnight on the international date line, but this was harder then you thought because Power Apps always reads your devices location and shows the time as local. Luckily you can force UTC time, its excatly 12 hours behind so I just had to move the date time to middday Xmas Eve. To do it you just use the Zulo time format "yyyy-MM-ddThh:mm:ss"

Set(vsStarttime,DateTimeValue("2023-12-24T12:00:00Z"));
Enter fullscreen mode Exit fullscreen mode

Now I need to compare my local time to the UTC time, I was going to use the Timezone function, but I found a quicker way, the Text function has timezone as a format. So I did the old stringfy/parse trick and converted to a string and back to a date.

DateTimeValue(Text(Now(), DateTimeFormat.UTC))
Enter fullscreen mode Exit fullscreen mode

I then would check to see if the local time was after midday UTC time.

The final thing I wanted was a countdown to when it started, this was a monster of an expression that hurts my head when I tried to describe so will just show you.

Set(voCountDown,
    {
        days: RoundDown(
                DateDiff(DateTimeValue(Text(Now(), DateTimeFormat.UTC))
                , 
                    vsStarttime
                , 
                    TimeUnit.Hours
                ) 
            / 24, 0
            ),
        hours: Mod(
                RoundDown(
                    DateDiff(DateTimeValue(Text(Now(),DateTimeFormat.UTC))
                    ,
                        vsStarttime
                    ,
                        TimeUnit.Minutes
                    )
                / 60, 0), 24
            ),
        minutes: Mod(
                DateDiff(DateTimeValue(Text(Now(), DateTimeFormat.UTC))
                ,
                    vsStarttime
                ,
                    TimeUnit.Minutes
                )
            , 
                60
            )
    }
);
Enter fullscreen mode Exit fullscreen mode

Position

X Positon
X was easy, as this is a simple linear movement. Santa would move from right to left at the same speed. I needed to convert a minute to horizontal pixels. This was calcualted by distance divided by time, so screen width / 1440 minutes in a day.

Set(viXstep,App.DesignWidth/1440);
Enter fullscreen mode Exit fullscreen mode

To get the current position based on time I mulitplied the minutes passed by the viXstep.

Set(viXposition,
    App.DesignWidth-
        (
            DateDiff(vsStarttime,
                DateTimeValue(Text(Now(), DateTimeFormat.UTC))
            ,
                TimeUnit.Minutes
            )
            *viXstep
        )
);
Enter fullscreen mode Exit fullscreen mode

Y Positon
Y was a little harder, as the end/target position was always moving. I calcualted the viYstep by getting the number of X steps between the current and target location, then dividing the difference between the current and target Y distance.

 Set(viYstep,(
        LookUp(colLocations,ID=voSanta.id).Y-voTarget.Y)
    /
        (
            (LookUp(colLocations,ID=voSanta.id).X-voTarget.X)
        *
            viXstep
        )
    );
Enter fullscreen mode Exit fullscreen mode

Whats nice about this is the steps works even when the Santa changes direction, as if it is moving down it will generate a negative step value, so Santa still moves in the right direction.

Other Stuff

There is lots more to the App but sure you have dealt with it before, but here are a few toplines:

To make the run now button work I cheated and changed the vsStarttime to Now(), then every loop deducted a minute from the vsStarttine, so increasing the time passed by making the start older, not the now in the future.

If(vbRunNow,Set(vsStarttime,DateAdd(vsStarttime,-1,TimeUnit.Minutes)));
Enter fullscreen mode Exit fullscreen mode

I used to 2 main objects, one for the current Santa position and one for the next/target, this relied on the SharePoint list ID being sequential (if you are deleting rows just add your own sequenced column and use that instead).

I cached the SharePoint list to a local collection then added a 0 ID record for the start location and an end record at X=0 to ensure the Santa started and finished in right places.


The solution is available here to download if you want to see more, you just need a sahrepoint list like this:

sahrepoint lsit

Top comments (9)

Collapse
 
balagmadhu profile image
Bala Madhusoodhanan

Going to steal your idea.. A series of for Games...

Collapse
 
jaloplo profile image
Jaime López

Great article!!! Funny apps to learn complex things!!!

Collapse
 
rasic-rudel profile image
Rasic-Rudel

Leider kann ich die Datei nicht importieren :-(
Es erscheint immer ein Fehler beim Import.

Collapse
 
wyattdave profile image
david wyatt

If you are getting below its because you need to create the SharePoint list first then import the solution.
Image description

Collapse
 
rasic-rudel profile image
Rasic-Rudel

Danke für die schnelle Antwort.
Leider habe ich nur die Möglichkeit die Zip-Datei zu importieren.
Ich kann vorab keine SPL erstellen und diese mit dem Import ZIP verknüpfen.
Gibt es vielleicht eine andere Möglichkeit?

Thread Thread
 
wyattdave profile image
david wyatt

I'm afraid not, the app requires SharePoint to hold the coordinates of the places Santa visits

Thread Thread
 
rasic-rudel profile image
Rasic-Rudel

Is it okay for if I text to u on LinkedIn?

Thread Thread
 
wyattdave profile image
david wyatt

Of course

Thread Thread
 
rasic-rudel profile image
Rasic-Rudel

I added u on LinkedIn u need to confirm pls✌️