IA patterns

09 September 2018
  • Hierarchy - broad to narrow tree relationship
  • Database - similar things - get to know the things in different ways. Pieces are the same and there’s lots of different ways to get to them - metadata / attributes.
  • Hypertext - pieces related by relationships in content
  • Linear - not on the web much. book, walking
  • Catalogue = database sitting on top of hierarchy
  • Hub and spoke - search results

JavaScript functions example

06 June 2018

While working on a project, I asked Paul why Airbnb’s coding standards recommend using named function expressions instead of function declarations?

He made this example, which I am posting with permission, along with his note:

I’ve never actually had a problem caused by function name hoisting (i.e. being able to call a function before it’s defined) before, but maybe it’s an issue in larger codebases.

console.log("=============================================================");
console.log("1. Running a function before it’s defined, using its own name\n");

foo_bad1();

console.log("\n");
console.log("That works. Airbnb think that’s bad. I’m sure there are reasons, but I don’t know what they are.");


console.log("\n");
console.log("\n");
console.log("=============================================================");
console.log("2. Running a function before it’s defined, using a variable that will later be assigned that function\n");

try {
	foo_bad2();
}
catch (e) {
	console.log(e);

	console.log("\n");
	console.log("We got an error! Good!");
}


// bad
function foo_bad1() {
  console.log(" -- foo_bad1 ran! -- ");
}

// bad
var foo_bad2 = function () {
  console.log(" -- foo_bad2 ran! --");
  thisFunctionDoesNotExist();
};

// good
// lexical name distinguished from the variable-referenced invocation(s)
var foo_good = function longUniqueMoreDescriptiveLexicalFoo() {
  console.log(" -- foo_good ran! --");
  thisFunctionDoesNotExist();
};


console.log("\n\n====================================================");
console.log("3. Running a function after it’s defined, and it throws an error, but the function is anonymous\n");

try {
	foo_bad2();
}
catch (e) {
	console.log(e);

	console.log("\n");
	console.log("We got an error! Good!");
	console.log("But we only get the short name in the call stack. And that’s bad, for some reason?");
}



console.log("\n\n====================================================");
console.log("4. Running a function after it’s defined, and it throws an error, and the function has its own name\n");

try {
	foo_good();
}
catch (e) {
	console.log(e);

	console.log("\n");
	console.log("We got an error! Good!");
	console.log("And it’s got the long name in the call stack. So that’s good too.");
}


console.log("\n");
console.log("\n");

JavaScript 30 - #1 - JavaScript Drum Kit

22 May 2018

Diving in to this course on JavaScript, we’re making a drum kit: the user presses a key and it plays a sound. It’s all nicely set up in the starter file:

<div data-key="65" class="key">
<kbd>A</kbd><span class="sound">clap</span></div>
<audio data-key="65" src="sounds/clap.wav"></audio>

The key is linked to the sound using the data key value. http://keycode.info is a good way to get these key values.

So we need to listen for these key events:

window.addEventListener('keydown', function(e) {
  console.log (e);
});

This logs out lots of info to the console including the keyCode.

At this point, I started wondering about functions and the different ways to declare functions.

Function declarations

These need a name, a list of parameters to the function, enclosed in parentheses and separated by commas and the JavaScript statements that define the function, enclosed in curly brackets, { }.

function square(number) {
  return number * number;
}

It creates a variable in the current scope which holds the function object. This function variable is hoisted up to the top of the current scope, so the function can be invoked before the declaration.

Function expressions

The function declaration in a statement always starts with the keyword “function” else it’s a function expression. Function expressions are convenient when passing a function as an argument to another function.

var square = function(number) { return number * number; };
var x = square(4); // x gets the value 16

A “method” is a function that is a property of an object.

Notes from here and here

The Airbnb style says to use function expressions instead of function declarations.

Why? Function declarations are hoisted, which means that it’s easy - too easy - to reference the function before it is defined in the file. This harms readability and maintainability. If you find that a function’s definition is large or complex enough that it is interfering with understanding the rest of the file, then perhaps it’s time to extract it to its own module! Don’t forget to explicitly name the expression, regardless of whether or not the name is inferred from the containing variable (which is often the case in modern browsers or when using compilers such as Babel). This eliminates any assumptions made about the Error’s call stack.

Back from the rabbit hole. The next step involved matching up the keyCode value with the audio. Rather than using IDs or classes, there’s a data attribute which can be accessed in a similar way. Also some funky stuff going on with ES6 template literals. Enclose it in a back-tick (` `) and then use the $ sign and curly brackets to denote a placeholder - in this case the keyCode value from the event listener. The next bit is to return the function if there’s no audio which will stop the function from running altogether. The last bit takes what we’ve pulled in and plays the audio. Setting the currentTime to 0 allows for repeated presses on the same key in quick succession.

window.addEventListener('keydown', function(e) {
  const audio = document.querySelector(audio[data-key="${e.keyCode}"]);
  console.log (audio);
if (!audio) return;
  audio.currentTime = 0;
  audio.play();
});

The animation on the buttons can be done by adding and removing a class. To remove the class at the right point and reset the button, use the transitionEnd event. The if statement in the removeTransition function means we only get the transform event. Then a bit of tidying up to put the logic in a separate function playSound and then take in the event.

 function removeTransition(e) {
    if (e.propertyName !== 'transform') return;
    e.target.classList.remove('playing');
  }

  function playSound(e) {
    const audio = document.querySelector(`audio[data-key="${e.keyCode}"]`);
    const key = document.querySelector(`div[data-key="${e.keyCode}"]`);
    if (!audio) return;

    key.classList.add('playing');
    audio.currentTime = 0;
    audio.play();
  }

  const keys = Array.from(document.querySelectorAll('.key'));
  keys.forEach(key => key.addEventListener('transitionend', removeTransition));
  window.addEventListener('keydown', playSound);

Notes from "Intro to D3"

18 May 2018

Having built a few things in D3, I’m going back to the basics to learn it from the ground up. First up is Intro to D3 by Square.

SVG

I need to learn more about SVG.

Where HTML has the <div> and tags, SVG has the tag for an arbitrary group. You’ll see a lot in D3 examples. The tag is powerful but complex, it can be used for either lines or arbitrary filled-in shapes depending on the styling.

D3 provides “helpers” for:

  • Scales
  • Axes
  • Data

Selections

Data binding or “the join” is the heart of D3. Create a selection and use .data() to bind data to the selection.

  • Add elements with selection.enter()
  • Remove elements selection.exit()
  • Transition between things with selection.transition()

Responsive typography

25 April 2016

Responsive typography boils down to:

  1. Relative font size
  2. Active white space
  3. Screen friendly line height
  4. Clear colour contrast
  5. Discern text and images

So many people have written great things on this subject, but I found these points in my notes and wanted to get them down.

Older ↬