Christian Heilmann

You are currently browsing the archives for the General category.

Archive for the ‘General’ Category

That was Halfstack Online’s first edition (musings, and slides)

Monday, May 25th, 2020

Halfstack is a series of events that are very close to my heart. They are predominantly about connections and sharing some nerdy fun. The locations are pubs and cinemas and there is a lot less pressure on presenters and audience. They aren’t a “cool crowd” event where you need to deliver “the killer talk”. Instead they are a social gathering of, well, nerds. They also end in a ridiculously hard and geeky pub quiz and some musical performance.

There’s a beautiful irreverence about them and yet they are well organised and you learn a lot. Especially letting go and playing with technology rather than trying to “be awesome”. The main organiser, Dylan Schiemann spends a lot of time and effort to make these events easy to attend and present at.

I’ve been a supporter from day one of the events as they were easy to attend when I lived in London. I already signed up for the London, Tel Aviv and others when Covid-19 hit. I am now proud owner of flight vouchers and was sad that they won’t happen. When Dylan announced the online edition of Halfstack I wondered if the cozy vibe can survive.

Dylan Schiemann introducing Halfstack online

It did. Halfstack Online was a highly affordable, $19 conference with an excellent line-up. Most of the talks were pre-recorded, 30 minute presentations. This made sure that connectivity issues couldn’t ruin the party and it doesn’t get boring. After each talk there was a Skype interview with the presenter. Dylan, Jo and Tony asked prepared questions and those that people submitted in the chat during the presentations.

Dylan put a lot of effort into interspersing the presentations with breaks. There were also quite a few irreverent videos like out-takes of HalfStack conferences. All in all it gave a lovely vibe to the event and took the seriousness out of it.

Facial Mapping and transposing onto a puppet in JavaScript

The range of talks reflected the “hey, tell us about something cool people can play with” attitude. We had talks about detecting body movement with TensorFlow and use it as a control for web products. We had in-browser face mapping to control a puppet’s movements. We had a “how to build your own weather station” talk which bravely showed the UK weather. All in all it felt more like a variety show than an event. But one where you learn a lot.

I’ve been to a lot of conferences and many do a great job of skirting the line between inspirational and educational. In Halfstack, this came naturally, as the group running it picked a wild mix. There were no ego talks, no thinly veiled product advertising, just a lot of “here is why I found this interesting, what do you think?”. The divide between presenter and attendee was very low, and I enjoyed this a lot.

It was great to see presenters I’ve seen before on stage relaxing more in a recorded talk. It was funny to be on the Skype backchannel where all the presenters hung out to see them worry about how the video might go down with the audience. There were too many to mention, but the line-up had some immensely creative and inspiring people as well as some who clearly were there to talk about something that they had fun doing. All in all it felt very accessible. There were no “heroes” there, just a bunch of people showing some work – warts and all.

The conference also acts as a fundraiser for Covid-19 related charities. With a ticket price of $19 and first-time expenses on a streaming system there won’t be a six figure donation at the end. But it still is a great thing to support.

There will be another edition of this in August and I am looking forward to see what comes next. I have a few ideas what to do, and for once I feel utterly free to choose something that is not what people expect. And that’s one of the fun bits of Halfstack.

Imagine the creativity of, the creative/educational mix of Beyond Tellerrand and then give it a “jam session/MTV unplugged” kind of feel and you have Halfstack.

My recording setup - as it were

My submission this time was a talk that was a walk through the developer tools of Chromium. I showed some of the bits you may not use or never have seen but are in there. I did this more or less for myself, as I caught myself using only a small amount of what I could. I did that because of familiarity and “always having it done that way” which is not a good place to be in as a developer. And I learned a few bits along the way which hopefully inspired some people.

The slides are available on with the resources I talked about.

View All tooled up and nowhere to go? on Notist.

The video should be available soon. Make sure to check HalfStack’s social media channels the next few weeks to see more videos cropping up. I saw most of them but also had to work, and will make sure to check some of them I missed out on.

Progressively enhancing radio buttons with SVG whilst staying accessible

Tuesday, May 5th, 2020

Sometimes it is fun to re-visit very basic HTML things and look what we can do with them nowadays. This is what I will do now with a radio button group. I will progressively enhance it to look great and still work with keyboard and screen readers.

As part of my Logo-O-Matic upgrade, I added text alignment to the generator. At first I used a select element to have a dropdown asking you to select left, centre or right. After using it for a while I was annoyed with it and wanted a simpler way. That’s when I looked at radio groups again.

The final product is three graphical buttons depicting the alignment. You can try the example out here.

Animation showing the final effect

In the following video you can see and hear how Voiceover for Mac deals with this construct.

Taking a step back: Radio what?

Radio buttons are a form element group that go back to the old days of radios where you had a preset amount of buttons to choose from. You could only select one of them at a time and when you selected a new one, the formerly chosen one popped out. In most cases this was to select the wave band to choose, others also had preset stations to pick from.

Old car stereo with radio buttons

In any case, radio buttons mean that you have a preset amount of options to choose from and you can only have one selected at a time. This is different to checkbox groups where you can select several. Even select menus allow more than one choice when you press shift whilst selecting them and the multiple attribute is present.

When there are not many choices to choose from, a radio group can be a very simple and obvious way to make the user choose one and only one option from them.

Radio group basics

In HTML, radio is a type of input element. You define a group of them by using the same name attribute amongst them. In the case of my alignment example, all I needed to do was to define three input element with a type of radio and a shared name:

<input type="radio" name="aligned" value="left" checked>
Aligned Left
<input type="radio" name="aligned" value="center">
Aligned Center
<input type="radio" name="aligned" value="right">
Aligned Right

Unstyled Radio Group

The checked attribute defines the preset. Every time another radio button is activated it moves to that one and its value is what the form will submit as the value of the “aligned” parameter. This is pretty useful and means we don’t have to program that functionality.

Radio group problems

There are of course a few issues with radio groups. One issue is that they are not the prettiest things to look at and they are tough to style. A bigger issue is that they are tiny and hard to access with a mouse. Scaling them makes them even uglier. And, like any form field, screenreaders wouldn’t know what an element is unless you also provide a label.

I’ve set up my Visual Studio Code with the Webhint extension. This is great as it uses Axe-Core to tell you about accessibility issues while you code. So in the case of the earlier example, it rightfully complains about a lack of labels (click to see full screen picture):

Webhint extension for Visual Studio Code showing in-line accessibility errors.

You can add labels in two ways. You can either wrap the element itself in a label:

  <input type="radio" name="aligned" value="left" checked>
  Aligned Left

Or you can have the label as a sibling in the DOM tree and use the “for” attribute and an ID on the element to connect them:

<input type="radio" id="r1" name="aligned" value="left" checked> 
<label for="r1">Aligned Left</label>

The latter way is more complex, but also more flexible, as you can put the label anywhere in the document. In case you need to put something else there that shouldn’t be in the label.

Once you added the label you can select the radio button by clicking or tabbing to the text label. That way you made it much easier to access as the hit area is much bigger.

Selecting a radio button without labels is hard

Selecting radio buttons without labels is frustrating

By adding labels you make it easier
By adding labels you make it much easier to interact with radio buttons

Radio group benefits

Despite all its drawbacks, I like radio groups as they give you all the functionality you want out of the box. You don’t need to set focus to a new element by hand and you don’t need to remove the selected state from the former one. Radio buttons are keyboard and mouse accessible. If you use a keyboard to tab into a radio group you can navigate it using arrow left and right. By using labels you don’t only help improving the accessibility and usability. You also get an easier style-able element that changes the state of the input for you.

Getting the value of a radio button group

On the backend, this is a non-issue. The form only sends the value of the selected element in the group. In JavaScript on the front-end, it was somehow tougher, but much better these days.

Back in the days when I started with web development, this was a horrible task. You had to traverse the elements collection of the form and compare the type, name and check if the element is checked. When you did the right thing and added labels and IDs, you could loop through the IDs you chose. That was a maintenance nightmare.

Nowadays, we have three ways:

If you want to check the value on form submission, you can use FormData.

const form = document.querySelector('form');
const log = document.querySelector('output');
form.addEventListener('submit',(event) => {
  var data = new FormData(form);
  var output = '';
  for (const entry of data) {
    output = output + `${entry[0]} = ${entry[1]}`;
  log.innerText = output;

If you want to get the value when you clicked on the element , you can use event delegation and a complex selector. This is also good if you plan on using more click reactions in your form.

form.addEventListener('click', (event) => {
  let t =;
  if (t.nodeName.toLowerCase()=== 'input') {
  // if the user clicked on an input element
  // (labels forward that click)
    let state = document.querySelector(
      // Find the input element with a type of radio
      // the name aligned and that is currently 
      // checked
    // and get its value.
    log.innerText = state;

Or you can listen to the change event, which gives you the element interacted with as the event target.

const form = document.querySelector('form');
const log = document.querySelector('output')
form.addEventListener('change', (event) => {
  let t =;
  log.innerText = t.value;

Replacing the radio buttons

OK, now let’s take a stab at making radio buttons nicer to look at. For this, we could use CSS to change the look of the buttons itself, but there is a lot of cross-browser pain in that one. So the best plan is to replace them with something else. Replacing also means though that we need to replicate the different states of a radio button.

Hiding the radio buttons and styling the label

Hiding things on the web isn’t easy. You want to make them not show up but you also don’t want to make them inaccessible. Non-sighted users and search engines should find content we want to replace with prettier alternatives. Scott O’Hara collected a lot of excellent information on the subject. Applying this knowledge, we can use the following CSS to hide the radio buttons themselves across all kind of browsers and devices. The label will still change the state of the radio button when we click it, so that’s good.

input[type=radio] {
  border: 0;
  clip: rect(0, 0, 0, 0);
  height: 1px;
  overflow: hidden;
  padding: 0;
  position: absolute !important;
  white-space: nowrap;
  width: 1px;

Defining the different states

Having hidden the radio buttons, we now need to simulate the different states of the radio button. We can do that in CSS, no JavaScript needed. You can see the result here

labels styled to show different states

Style each label that is following a input
of the type radio as light grey on mid grey
input[type=radio] + label {
  background: #444444;
  color: #ccc;

/* Radio buttons that are currently checked should be green... */        
input[type=radio]:checked + label {
  background: #9AD284;
  color: #000;

Reacting to interaction

Having the two states isn’t enough, we also need to react to user actions like hovering with a mouse or focusing the element with the keyboard. This invites interaction and is an important usability feature. Luckily, CSS has both :hover and :focus pseudo selectors to create those.

/* When the user hovers over the label... */
input[type=radio]:hover + label {
  background: #666;
  color: #000;
/* When the user focuses the label via keyboard... */
input[type=radio]:focus + label {
  background: #666;
  color: #000;
/* Radio buttons that are checked hovered over */
input[type=radio]:checked:hover + label {
  background: #fff;
  color: #000;
/* Radio buttons that are checked and have focus */
input[type=radio]:checked:focus + label {
  background: #fff;
  color: #000;

Adding the SVG buttons

Traditionally we replaced things that aren’t pretty with images. However, this is annoying both in terms of performance and zoom quality. Instead of using bitmap images to replace the button which get blurry when zoomed, let’s use SVG, which scales better. We also can inline SVG which means we can edit it in the document if needed. The last excellent part of SVG is that you can change the colours of SVG paths in CSS instead of creating a new image.

You can see what this looks like in this SVG example.

The code might look daunting at first, but there are lots of excellent SVG resources available these days to get started.

<input type="radio" id="r1" name="aligned" value="left" checked> 
<label for="r1">
  <svg xmlns="" 
       fill="#ffffff" height="3em" width="3em" 
       viewBox="0 0 100 100" x="0px" y="0px">
    <rect x="17.04" y="25.36" width="65.91" height="6"></rect>
    <rect x="17.04" y="39.79" width="43.87" height="6"></rect>
    <rect x="17.04" y="54.21" width="65.91" height="6"></rect>
    <rect x="17.04" y="68.64" width="43.87" height="6"></rect>

This looks great, and if you click the different icons you can see that it also works. But you have no idea which one is currently active. To fix this, we need to add the changes to the fill state of the SVG to our CSS.

Making the SVG icons accessible

The first thing to do is to style the SVG to allow for colour to be changed. We can do this by setting the fill to currentColor which means the colour of the SVG fill will now be the text colour (thanks to Arnout ‘3rdEden’ for the reminder).

svg {
  fill: currentColor;
  height: 2em;
  width: 2em;

This fixes the “I have no clue where I am” issue. However, there is also another problem. We replaced the text inside the label, and thus the radio button is hidden and has no description. Something once again flagged up by Webhint in my editor:

SVG icons with no title are like images without alternative text.

To remedy that we need to add a title to each of the SVG elements. This should act like an alternative text to the image when it can’t be seen and you can actually see it when you hover over the element:

SVG title on hover

However, for screenreaders this isn’t enough. We also need to give the SVG element a role of “img” and announce the title of the SVG using “aria-labelledby” pointing to an ID on the title element:

<input type="radio" id="r1" name="aligned" value="left" checked> 
<label for="r1">
  <svg xmlns="" 
       fill="#ffffff" height="3em" width="3em" 
       viewBox="0 0 100 100" x="0px" y="0px" 
       aria-labelledby="title-r1" role="img">
    <title id="title-r1">Aligned Left</title>
    <rect x="17.04" y="25.36" width="65.91" height="6"></rect>
    <rect x="17.04" y="39.79" width="43.87" height="6"></rect>
    <rect x="17.04" y="54.21" width="65.91" height="6"></rect>
    <rect x="17.04" y="68.64" width="43.87" height="6"></rect>

This announces our images correctly as label text to assistive technology like screenreaders and also gets rid of the errors in Webhint.

Adding some fanciness

And that’s it, using these steps we were able to create pretty, styled and accessible radio buttons that have all the benefits of radio groups and are screenreader and keyboard accessible. Without any fancy JavaScript or frameworks.

A small extra I added to the final example is a transition between the states and an inner shadow to make it really obvious which state is currently chosen.

label {
  text-align: center;
  height: 2em;
  width: 2em;
  color: #fff;
  float: left;
  transition: 200ms;
input[type=radio]:checked + label {
  background: #9AD284;
  fill: #000;
  color: #000;
  box-shadow: 2px 2px 3px inset #333;


This was fun and it is amazing how far you can come without having to write any logic in your code. Instead you let HTML do what it does best and CSS to react to user input and show different visual outcome. However, I think there would be a lot to gain by cleaning up the mess that is form element styling and I wished it would be easier and more predictable cross-browser to style these elements.

Another thing I am not too happy about is the need to define relationships with IDs and “for” and “aria-labelledby” attributes respectively. IDs have to be unique and generating them is annoying. Sure, you can re-use them in CSS and it makes for easier query selectors, but I never feel good adding one to a document that should be easily extensible.

There is a proposal to get a has: selector into CSS, which would allow at least to get rid of the for-ID relationship and nest the SVG inside the label using a label:has(>input[type=radio]) selector instead, but the browser support so far is non-existent.

An alternative proposal fixing the above issues

Big thanks to Andrea Giammarchi who proposed an alternative on Twitter and created a CodePen to show it in action. In essence, he turned the approach around and instead of hiding the radio button and its label text, he positions the SVG above it.

You can see his solution in this example.

The first thing I liked about his approach is that there is no need for IDs, as everything is contained in the label itself:

  Aligned Left
  <input type="radio" name="aligned" value="left" checked>
  <svg xmls="" viewBox="0 0 100 100" x="0px" y="0px">
    <rect x="17.04" y="25.36" width="65.91" height="6"></rect>
    <rect x="17.04" y="39.79" width="43.87" height="6"></rect>
    <rect x="17.04" y="54.21" width="65.91" height="6"></rect>
    <rect x="17.04" y="68.64" width="43.87" height="6"></rect>

In his CSS, he positions the label relative, sets the text colour to transparent to hide it, and set to overflow to hidden to not expand the label to the full width of the text.

label {
  position: relative;
  display: inline-block;
  overflow: hidden;
  color: transparent;
  width: 2em;
  height: 2em;
  padding: 0;

He then positions SVG and input as absolute to make the SVG cover all the rest of the elements in the label.

label > input, label > svg {
  position: absolute;
  top: 0;
  left: 0;

He then sets the width and height of the SVG to 100%, and applies all the other styles to the SVG itself.

label > svg {
  width: 100%;
  height: 100%;
  transition: 200ms;
  fill: currentColor;
input[type=radio] + svg {
  background: #444444;
  color: #ccc;

You can see all the examples here on GitHub and you can fork and play with them.

Limiting input type=”color” to a certain palette (from an image)

Wednesday, April 22nd, 2020

The colour input type is pretty amazing, if you think about it. You can pick a colour from it and there are lots of great presets available. The colour picker is provided by the OS for the browser, so it differs from machine to machine. I, for example, totally missed that on a Mac, you can pick a colour from an image with it. The “spectrum” option is in fact an image and you can replace it.

Picking a colour from the colour spectrum

Simply drag and drop any image into it or use any of the other options available from the cog menu.

Picking a colour from an image

Get an image into the colour picker

But what if you want to do limit the colours available to the colours used in an image? That’s what I needed and here begins our journey.

The input type colour supports the list attribute, which allows you to define a preset list of options. For example, the following code limits the colour picker to grey, white and blue.

<input type="color" list="presets"></label>
<datalist id="presets">
  <option value="#cccccc">Grey</option>
  <option value="#ffffff">White</option>
  <option value="#6699cc">Blue</option>

The colours need to be defined as hexadecimal colours. They can be defined as values or text inside the option tags, but the values take precedence.

On Chromium browsers like Edge and Chrome this renders as a group of colour swatches and a “more” button to turn on all the features of the colour picker.

Colour Picker with limited palette on Chromium

On Safari, it looks a bit different.

Colour Picker with limited palette on Safari

On Windows, it looks a bit different, but has the same functionality. In the current Edge it looks like this:

Colour Picker on Chromium Based Edge on Windows

And on older Edge versions like this:

Colour Picker on Old Edge on Windows

In Firefox, it doesn’t limit the colour picker, sadly enough, and there is a six year old bug reported on it.

Firefox not limiting the colour picker to a preset

So, how can we get all the colours from an image and make it the palette of the colour picker? We use HTML5 canvas and populate the list dynamically.

You can see all of this working in this demo on GitHub. The code is heavily documented, but let’s go through the steps now.

First, we need to get the image. This could be done by loading it with a file picker, drag and drop or paste. I just wrote about that here, and re-used the code for this.

Once we have the image we create a new Image object and send it to our analysis method when it is loaded:

const loadImage = (file) => {
  var img = new Image();
  img.src = file;
    img.onload = function() { analyseColours(img); }

As the image could be big and have a lot of colours, it is prudent not to analyse the colours on the main thread but use a Worker instead.

let worker = new Worker('imagecolouranalyser.js');
worker.addEventListener('message', (e) => {
}, false);
worker.addEventListener('error', (e) => {
    console.log('worker error', e);
}, false);

The analyseColours method creates a new canvas element, resizes it to the dimensions of the image (so we get all the pixels) and draws the image onto it. We then get the image data of the canvas and send it to the worker file.

const analyseColours = (img) => {
    let c = document.createElement('canvas');
    let cx = c.getContext('2d');
    let w = img.naturalWidth;
    let h = img.naturalHeight;
    c.width = w;
    c.height = h;
    cx.drawImage(img, 0,0);
    let pixels = cx.getImageData(0, 0, w, h).data;

Inside the worker we listen to an incoming message and analyse the pixels by looping through the data array:

const process = (e) => {
    var data =;
    let all = data.length;
    let coloursused = new Set();
    for (i = 0; i < all; i += 4) {
        let hex = ''+
            rgbToHex(data[i]) +
            rgbToHex(data[i+1]) +
const rgbToHex = (col) => {
    return parseInt(col,10).toString(16);
addEventListener('message', process, false);

We create a new Set to hold the values of the unique colours we find. A Set is perfect there as it automatically removes duplicates added to it. Another option would have been to use an Object and the colours as keys.

The image data of a canvas is an array of all the pixel colour values as their RGBa values. Thus we need to loop through it in steps of 4. We assemble a string by converting the Red, Green and Blue values into hexadecimals. Once the loop is done we send the Set back to the main thread and thus to the addColourPicker() method, which is the Worker listener defined earlier.

const addToColourPicker = (colours) => {
    let out = '';
    colours.forEach(c => {
      out += `<option value="#${c}"></option>`
    datalist.innerHTML = out;;

We create a new string called out, loop over all the colour values and add an option element for each. We set the innerHTML of the datalist to this string and fire a click event on the colour picker. This last thing is mostly for the demo, it isn’t needed for the functionality. Weirdly enough Safari doesn’t do anything with that.

So that’s it, limiting a colour picker to a certain palette can pretty much save you from having to write a complex UI yourself, and I bet the colour picker will be more accessible than anything we create ourselves.

The joy of pixeling and building pixel tools with HTML5 canvas and JavaScript

Friday, April 17th, 2020

Some people knit, others do puzzles, and yet others find calm by colouring. Me, I love pixeling. My computer career started with a super basic computer. It didn’t even have a way to store what I programmed. So, every day, I would write myself a small program that allows me to paint on the screen using the cursor (there was no mouse). I’d paint something, turn off the machine and all was gone.

I love working within constraints, it fuels my imagination. I love trying to push the boundaries but also found a lot of happiness in making the best with what is possible.

Pixel logo saying Diversidty

The big computer of my youth was the Commodore 64. On this machine I did a lot of pixeling for the demo scene. A huge part of my professional network came from that sub-culture and it is fun to keep in contact with people you were in competition with in the 90s. The main input was keyboard and joystick. Painting swoops and natural shapes was tough. It meant knowing how to set pixels of the correct colours next to one another and let the human brain do the rest. Our eyes are lazy and our brain craves harmony. We’re happy to fill a gap between two points and make the design appear smoother to us than it is.

So, when I want to pretend I am artistically gifted, I go back to pixeling logos and fonts. Lacking space for a real Commodore 64, I use an emulator and some special tools. These have the same constraints as the real machine:

  • 16 pre-defined colours
  • 320ˣ200 pixels resolution
  • Two colours per each 8×8 square in hi-res mode
  • One background colour for the whole screen and 3 colours per each 8ˣ8 square in multicolour mode. In this code pixels are 1ˣ2 pixels and not 1ˣ1.

Tooling is fun these days, and Multipaint does an OK job to convert non-compliant graphics. My old Photoshop isn’t running on my current version of MacOS. So I started using PhotoPea in the browser for some of the conversions.

I soon discovered though that there are some things that are hard to do, so I wrote some tools to help myself. And for this, of course, I used JavaScript and canvas in the browser.

Canvas is awesome. Its paint API is odd and rudimentary, but I love that it turns any image into an array of pixels. And that you can manipulate things and then save them as a PNG.

So, to help myself paint some things for upcoming demos, I wrote a few tools in the browser. These are all open source and on GitHub. Have a peek and maybe there is something in there of interest for you.

C64 Colour Changer

C64 Colour Changer

I lost a lot of my old floppy disks and some of my old work only exists as screenshots. And depending who did those the colours are off and I can’t remix or use them. Using a “select colour range” in PhotoPea is a pain, so I wrote a small tool to re-colour images.

You can check the Colour Changer here
and the source is on GitHub


Tile Edit Multicolour Mode

TileEdit is a small pixel editor that allows you to paint seamless tiles. I needed that for some 3D ball texture animation and no tool allowed me to to do what I wanted.

Tile Edit Hires Mode

Now I can use this to paint C64 textures, and I also added a feature to paint general pixel textures. You can choose any colour with a colour picker and you are not limited to the C64 limitations.

The Tile Edit Source is also on GitHub.


Logo-O-Matic in the browser

I’ve written this in PHP using imageMagick ages ago and changed it to a canvas solution a few years ago. Now, Logo-O-Matic features 64 charsets (a lot by me). You can pick one, type your logo text, switch colours around, fix kerning and word spacing, add a character offset and save your cool retro logo.

jenkins in an old 8 bit font

linkedin in an old 8 bit font

github in an old 8 bit font

The Logo-O-Matic source is also on GitHub.

Ongoing work

I love the simplicity of pixeling and its repetitive nature. I especially the way you can create a whole charset from the “8” character and changing a few pixels around. And I love that I can use plain vanilla JavaScript to create myself tools that I don’t get otherwise. Maybe you can also find some joy in this.

But now back to work on the lovely Edge browser and compatibility

Edge Logo in C64 Mode

Firefox Logo in Multicolour

Quick solution: getting the mouse position on an element regardless of positioning

Thursday, April 2nd, 2020

As I was upgrading an older codebase of mine that used layerX and layerY I looked into a very succinct way of finding the current mouse position on any element regardless of its position, scrolling, padding, margin and such and I found this to work for me, so maybe it is good for you, too.

const getposition = ev => {
  let x = ev.clientX;
  let y = ev.clientY;
  let pos =;
  // the bitwise shift |0 rounds non-integer values down.
  // if you want to round up, use 1.
  return {
    x: x - pos.x|0,
    y: y - pos.y|0

Here’s a codepen of it in action, and you can play with it and give it more annoying things to deal with.

See the Pen
Get mouse position on element.
by Christian Heilmann (@codepo8)
on CodePen.