How We Built Our Calendar Color Feature
Author: Garry Shutler
17th August 2017
These are the latest features hitting our alpha channel.
This lets you brand your events within your users’ calendars, highlighting where your real-time calendar integration provides value.
Adding color support was an interesting example where providing a single API over multiple calendar services can prove a challenge so lets deep dive into it.
Sticking with the familiar
We decided to expose the color attribute as an RGB hex value.
This is very familiar to developers as it’s the common format for providing colors in CSS.
The problem, from our side, comes when using that value with the multiple APIs we support.
Some providers, such as Exchange, don’t support color (at least not that we could find out despite scouring documentation and experimentation), so that’s quite black-and-white – the color you provide can’t be used.
Some providers for some operations support RGB hex values so that’s easy peasy too, but in a much more satisfying way as it works.
The tricky parts come when an operation supports a well-defined palette of colors which is the case for Google events.
Google events allow you to specify one of 11 color IDs. Those colors look like this:
However, we’re accepting 16,777,216 colors, which look like this:
So the problem is how do we map from 16,777,216 colors to 11?
The most obvious solution is that from RGB you can derive a 3D co-ordinate so you can then map your known palette into a set of points in 3D space, then similarly map a given RGB value and check for the closest color from the known palette.
It’s all about perception
This will work ok, but the problem comes from the fact that the eye does not interpret colors in such a linear fashion – it’s much fuzzier than that.
Fortunately, the science of color is a field of academic research and so we can leverage that (we’ll still be here once you’ve read the Wikipedia article!).
Specifically, there are algorithms for calculating the color difference between two colors. These take into account how colors are perceived, not just their numeric values.
In our case we’re using a library that implements CIE94. Leaning on this algorithm gets us 80% of the way there.
From there we created a set of tests from another, larger well-known palette, the set of CSS3 named colors. This gives us 280 tests which we can first verify visually, via a generated HTML file (example), and then codify in tests.
With such a limited target palette there are times where even this method cannot decide correctlywhat the nearest color is and some colors are conceptually “larger” than other color.
For example, orange is a comparative sliver between red and yellow. To get around this we added some additional colors that would map to the canonical Google colors to fill out the definition of what a given color looks like.
Conceptually, this works like this:
By expanding the definition of red by adding more candidates, more colors end up being categorized as red when looking for the closest match.
This gets us about 95% of the way there.
In general, we were then left looking at extremely light and dark colors.
Gray is reasonably “close” to every color and so is a candidate for matching all of them.
Instead of adding more colors to combat this, we removed gray from the candidates at the search stage and looked at the darkness of the color before performing a search, classifying it as gray if it is above or below a given threshold.
Let’s agree to disagree
That gets us 99% of the way there. Unfortunately that’s as far as we can go, particularly with such a limited target palette.
There’s always going to be some cases where people will disagree because people’s eyes perceive color differently and different displays can present them differently as well.
Try it out today
Let us know what you think or get in touch if you need some help at email@example.com.