A Pixel Story! (Part 1) — Journey of creating a pixel display component in MS Canvas app

András Fördős
6 min readOct 28, 2022

All this began with a simple question asked by Maria during BizzSummit 22 in Madrid: “Have you ever created a game”? Obviously, at first, this triggered a quick search through my brain: “Indeed, have I”? But with the answer, came more: memories, curiosity, motivation, doubt, inspiration, …

[A note here, in case you are not familiar with MS Canvas apps, I would suggest a short scroll through HERE so that you can also follow this post properly. Don’t worry, there won’t be any deep dives!]

I would assume, probably everyone has seen the Power Lemmings by the great Scott Durow (source here: LINK), but would it be possible to bring back other golden games too - such as The Settlers I — within a Canvas app? Or even just some great custom pixel art and animations to be used as app headers and background for fun? And all that with a neat simplicity and lightweightness? Game on!

To set myself some goals, my aim is to create a solution, which:

  • Is built within the no-code/low-code platform Microsoft Canvas app
  • Enables anyone to show visual data on custom pixels
  • Avoids anything hardcoded — like fixed amount of pixels
  • (Following up on above point) is fully responsive based on its available dimensions

It feels a bit hard to hold back at this moment, but before opening up the Maker portal and creating my fresh tablet-sized empty Canvas, let’s spend a small amount of time drafting up what actually I want to achieve, and how it would work on a high level. This will help to see the result up ahead whilst having an easy way to remember what calculations need to be done, how the various elements and their lengths cooperate with each other.

Enter the Matrix

And now, code! Or well… Almost… Reiterating my own goals: I don’t want something hardcoded, meaning I want to have just the right amount of pixels making up my display based on the actual needs, not more or less.

If you have ever worked with Canvas apps before, you may know that it is not possible to create objects on the fly during runtime: you can’t just say “add me 2 more square shapes” when needed based on the user clicking around. I could definitely put up already 2.073.600 colored squares (1920x1080), and based on the need hide most of them, however it would strongly go against my simplicity goal, not even mentioning the hardcoded part. Or the maintenance aspects if one of them behaves badly.

After a bit of time spent on thinking — and a great advice pointing in a direction from my colleague Meead — comes the revelation: galleries are actually doing something similar when showing a list of records such as products, and potentially I could have a perpendicular child gallery within a parent gallery to create my matrix.

This might just work! Still, a long way ahead.. But for now, focus on the present:

  • Open Maker portal and select Create, then “Blank canvas app”
  • Switch to Components view and add a new PixelDisplay component
  • Add first a vertical gallery galRows and inside of it a horizontal one galColumns. Be sure about their layout, as it drives the order how you have to push in visual data!
  • Empty out both galleries, removing all of their not needed children
  • Add a rectangle shape acting as pixel and a label for debugging purposes to the child gallery, without changing them for now: shpPixel and lblDebug
Don’t mind if it looks a bit different currently for you, Canvas generates it a bit randomly

Component Properties

Before we continue, time to add configurability to our component. This way we could already set up default values for the input properties and as we keep working on shaping the pixels, we have a direct visual feedback on what is happening and what might be wrong:

  • Add input inpData: containing the visual information to show on our display. Set its type to be Table
  • Add input inpScreenColor: rather just for fun, but the aim would be to control the basic color of the (physical) screen itself, potentially opening up a future Matrix mode opportunity with neon-green? Type is Color
  • Add input inpPixelPadding: we will be able to control padding in-between pixels, making custom visuals possible. Type is Number
  • And finally inputs inpScreenWidth and inpScreenHeight: two properties indicating the dimensions of the Data in number of pixels. Type is Number

Set the following default values:

As you might have noticed, I have already had to decide on a structure and format for the visual data. Based on the fact, that we are using galleries, it is given to work with some sort of arrays. The small “yay” moment is, that MS Canvas app knows “single dimensional” tables, making the data fairly generic, easy and reusable. But what does this actually mean?

Look at the following examples, they are equivalent expressions:

Make it scale!

So, finally, time to make it work! I would say, apart from doing the initial wiring of parameters, start our way from the outside — the containers — down to the pixels themselves, as this way we can leave the more complex calculations till the end.

I will be using in the following the Object.Property notation, like if I mean the text of the debugging label, then I will reference lblDebug.Text.

Probably you have noticed, that there came one complex function at the end for the TemplateSize properties — it is created based on the calculations from the draft drawing from above and it makes sure, that the galleries can display all the data they are supposed to, without any scrollbar at any moment.

And now, when all set, we have a reusable, scalable and responsive component at our hand, capable of visualizing the data we push into it.

Give it a try with some quick manual tests: navigate back to the Screens and add the new component. Change its inputs if needed, and try resizing in any direction you feel like, still in the editor.

During my tests, I encountered one issue: when scaling too wide, the last column of pixels got deformed. This reminded me, that I have forgotten to set the most important feature of a pixel — also shown on my initial draft plan: their width is the same as their height:

  • shpPixel.Width = Parent.TemplateWidth
  • shpPixel.Height = Self.Width

Final Thoughts

Naturally, the created display is far from perfect and cuts many corners, but at its heart it delivers what was set out as goal at the start.

As for the future, some possible next steps could be:

  • Many of the calculations lifted and moved into a custom “Pixel” component instead of the currently used simple rectangle shape, opening up the door for other complex future features...
  • The input properties inpScreenWidth and inpScreenHeight can feel a wee bit redundant in their form, they could be directly calculated based from the input data…
  • … which also leads to the possibility of including any input validation, mostly on the data itself, e.g.: “Does it have the expected amount of pixel data in all arrays?”, “Is the value an actual correct number value?”, …

If you are interested in what directions have I chosen in moving forward from here, or just looking for additional elaboration on why I have set things up as they are, come back a bit later to read the next post or follow me on LinkedIn!

--

--