Synlinks in Windows

Recently I had cause to create a symlink in Windows. I had a WordPress theme on one drive and an installation of Bitnami's WordPress stack on the system drive. I didn't want to copy the files over and have to copy them back so a symlink was the ideal solution.

In Powershell the syntax is:

New-Item -Path C:\Path\To\Symlink\<symlink-name> -ItemType SymbolicLink -Value "E:\Path\To\Target"

Communicate between sibling components in Vue

I had a situation where I had three instances of the same component, each mounted with a different value:

<Items type='new' />
<Items type='sold' />
<Items type='hidden' />

The Items component has a method that when called can affect sibling components. For example, if an item marked new is set to hidden, we need to update the current new Items component to remove it and also update the hidden Items component to show it.

Events are an ideal way to achieve this, but how do we dispatch an event to a sibling, rather than a parent-child relationship? Easy:

In the update method emit an event on the root component:

this.$root.$emit('updateItems');

And in the mounted() method of the Items component add the event handler:

mounted() {
  this.$root.$on('updateItems', (data) => {
    // reload contents
  });
}

Using a filter with v-html in Vue

The correct way to inject HTML formatted data into a Vue component is to use the v-html property on the element:

<p v-html="my_variable"></p>

However, this doesn't support the usual way to use a filter:

<p>\{\{ my_variable | my_filter\}\}</p>

In the above example, the filter would be applied and the HTML escaped. Not what we want. Logic would say put the pipe and the filter in the v-html property, but that fails.

The way to do it is to call the filter explictly as a method on the data:

<p v-html="$options.filters.my_filter(my_variable)"></p>

Javascript contextual clock

Another experiment I did way back to create a contextual clock in html/css/js, originally in jQuery but now updated to vanilla javascript. Source available on Github.

The clock itself is a table of cells containing a single character, each with its own ID. Rows have letters and columns numbers.

<table>
  <tr>
    <td id='a1'>I</td>
    <td id='a2'>T</td>
    ...

With this we can create the words and numbers as strings of IDs separated by commas. Because arrays are zero indexed I'm explicitly setting the hours so the array key matches the hour (eg. [1] = one):

var itis = "a1,a2,a4,a5";
var a = "a7";
var ten = "a9,a10,a11";
...

var hourwords = new Array();
hourwords[1] = "d1,d2,d3";
hourwords[2] = "d4,d5,d6";
...

Before we update the time it's important to clear the board. To do this we loop through all the <td> elements, ensure each has a numeric key and remove the CSS class 'alight':

function clearBoard(){
  var alltds = document.getElementsByTagName('td');
  for (var index in alltds) {
    if(!isNaN(parseInt(index, 10)) && alltds[index].classList.contains('alight')){
      alltds[index].classList.remove("alight");
    }
  }
}

To determine which words to light up we create an empty array to hold the words, then use an instance of the Date object to get numerical representations of the hour and the minutes:

var words = new Array();
var now = new Date();
var hour = now.getHours();
var mins = now.getMinutes();

The following is a little bit of a hacky approach but it avoids complicated if statements. Each case tests which five minute bracket the current minutes falls in and adds the relevant words to our array:

  switch(true){
    case (mins >= 55): words = [five, to]; hour++; break;
    case (mins >= 50): words = [ten, to]; hour++; break;
    case (mins >= 45): words = [quarter, to]; hour++; break;
    case (mins >= 40): words = [twenty, to]; hour++; break;
    case (mins >= 35): words = [twenty, five, to]; hour++; break;
    case (mins >= 30): words = [half, past]; break;
    case (mins >= 25): words = [twenty, five, past]; break;
    case (mins >= 20): words = [twenty, past]; break;
    case (mins >= 15): words = [a, quarter, past]; break;
    case (mins >= 10): words = [ten, past]; break;
    case (mins >= 5):  words = [five, past]; break;
    case (mins < 5):   words = [oclock]; break;
  }

Because Javascript's Date object returns hours in twenty-four hour format we have to do a little maths to change things to twelve hour format.

if(hour > 12){
  hour = hour - 12;
} else if(hour < 1){ 
  hour = 12; 
}

Now it's just a case of pushing the words 'it is' and the current hour to our words array. Looping through each word then splitting each word by the comma to get each cell ID. With this we can set the class to 'alight'.

words.push(itis, hourwords[hour]); 

words.forEach((word) => {
  word.split(',').forEach((letter) => {
 document.getElementById(letter).classList.add("alight");
  });
});

To get this all running we fire the showClock() function. To update it we run a function every five seconds to see if the current minutes is a multiple of five and if so, run the showClock() function again.

(function() {
  showClock();
  setInterval(() => {
    if(new Date().getMinutes() % 5 == 0){ 
      showClock();
    }
  }, 5000);
})();

To make the letters glow apply a text-shadow with a light colour against a dark background:

.alight { 
  text-shadow: 0px 0px 12px #ccc; 
  color:       #fff; 
}

Faces following the mouse

This is an old experiment I did where I had my face follow the mouse around the browser document. Originally I wrote it using jQuery, but I've updated it to vanilla js. Source available on Github. You can access it on its own here: Physiognomy - A JS experiment.

Step one is to create an image with the nine different head positions:

Head positions in a single image

Next create a function to take the mouse position and image position which will then be fed to another function which calculates which image to show. imagew and imageh are the size of the final element, in other words should be a third of the height and width

function changeFace(mousex, mousey, face_id){
    var face = document.querySelector(face_id)
    var imagew = 160;
    var imageh = 160;
    var facepos = { // image position
      top:  face.offsetTop,
      left: face.offsetLeft
    };
    face.style.backgroundPosition = calucateBp(imagew, imageh, mousex, mousey, facepos);
}

Next create a function to calculate which the CSS background-position and return it. This looks complicated but should be self explanatory. Each if statement tests where the mouse is relative to the element and sets the background-position accordingly.

function calucateBp(imagew, imageh, mousex, mousey, facepos){
    // TOP LEFT
    if(mousex < facepos.left && mousey < facepos.top){ 
      return '0px 0px'; 
    }
    // TOP
    if((facepos.left + imagew) > mousex && mousex > facepos.left && mousey < facepos.top){ 
      return '-'+ imagew +'px 0px'; 
    }
    // TOP RIGHT
    if(mousex > (facepos.left + imagew) && mousey < facepos.top){ 
      return '-'+ (2 * imagew) +'px 0px'; 
    }
    // LEFT
    if(mousex < facepos.left && mousey < (facepos.top + imageh) && mousey > facepos.top){ 
      return '0px -'+ imageh +'px'; 
    }
    // FRONT
    if((facepos.left + imagew) > mousex && mousex > facepos.left && mousey < (facepos.top + imageh) && mousey > facepos.top){
      return '-'+ imagew +'px -'+ imageh +'px' 
    }
    // RIGHT
    if(mousex > (facepos.left + imagew) && mousey < (facepos.top + imageh) && mousey > facepos.top){ 
      return '-'+ (2 * imagew) +'px -'+ imageh +'px'; 
    }
    // BOTTOM LEFT
    if(mousex < facepos.left && mousey > (facepos.top + imageh)){ 
      return '0px -'+ (2 * imageh) +'px'; 
    }
    // BOTTOM
    if((facepos.left + imagew) > mousex && mousex > facepos.left && mousey > (facepos.top + imageh)){ 
      return '-'+ imagew +'px -'+ (2 * imageh) +'px'; 
    }
    // BOTTOM RIGHT
    if(mousex > (facepos.left + imagew) && mousey > (facepos.top + imageh)){ 
      return '-'+ (2 * imagew) +'px -'+ (2 * imageh) +'px'; 
    }
}

To make it all work create an event listener for onmousemove passing in the x and y coordinates of the mouse and the ID of the element to apply.

  document.addEventListener('mousemove', (e) => {
    changeFace(e.pageX, e.pageY, '#jerry');
    changeFace(e.pageX, e.pageY, '#george');			
    changeFace(e.pageX, e.pageY, '#elaine');			
    changeFace(e.pageX, e.pageY, '#kramer');			
  });

Note .offsetTop and .offsetLeft return the offset relative to the parent element, not the document. Some extra maths are involved to allow for this if the element isn't at the root of the DOM.