Mix.js
January 29, 2012
...Mah Nà Mah Nà
Have a Macbook? Spend a lot of time on boats? Use Chrome as your primary browser?* I’ve got you covered:
(function(w){
var body = document.body,
setOrigin = function(){
var height = body.scrollTop + ( w.innerHeight / 2 );
body.style.webkitTransformOrigin = '50% ' + height + 'px';
},
applyTransform = function(e){
body.style.webkitTransform = 'rotateZ(' + -e.gamma + 'deg)';
};
w.addEventListener('deviceorientation', applyTransform, false);
w.addEventListener('resize', setOrigin, false);
w.addEventListener('scroll', setOrigin, false);
setOrigin();
}(window));
Click the post title to try it out.
*Should probably (maybe?) also work with Safari and other Webkit browsers on devices that expose accelerometer data.
The entire JavaScript community (I know, this is already super nerdy) has been up in arms over the past couple days about semicolons — and I sort of felt compelled to write about it quickly.
I keep hearing people say that “semicolons aren’t required in JavaScript”. And technically, that’s true — the same way it’s true that you aren’t required to drive below the speed limit, and you aren’t required to pay your bill at the end of dinner.
I mean… it’s entirely possible to not do these things. For the most part, you can even learn how to do them with little or no chance of negative consequences.
But that’s not really the point, is it?
Automatic semicolon insertion means, by definition, that there’s supposed to be a semicolon. If that wasn’t the case, the parser wouldn’t have to automatically insert them. Amirite?
But ANYWAY, the point is this: Not wanting to write semicolons is fine, but actively campaigning against other people using them in their own code is ridiculous.
Here’s a cool bug:
<link rel=apple-touch-startup-image href=assets/ipad-landscape-retina.jpg media="screen and (orientation: landscape)" /> <link rel=apple-touch-startup-image href=assets/ipad-portrait-retina.jpg media="screen and (orientation: portrait)" />
These are the meta tags for including hi-res startup images when your web app is launched from the home screen (assuming you’ve also got the requisite ‘mobile-web-app-capable’ tag). No big d’s. I mean, the tags are long and ugly, but it’s not the end of the world — except for the tiny caveat that on subsequent loads from the home screen, the images are re-downloaded.
Okay, fine. That’s not so bad. Maybe you like the idea that users will always have the most up-to-date startup images possible. Whatever.
The real issue is that while both of these enormous 3 million pixel images are being downloaded, The entire UI thread is blocked.
That means none of your JavaScript will execute while those images are downloading (which, in my case, occurred immediately upon window.load and took roughly 8 seconds). No AJAX requests sent, no touch events propagated, no functions executed. Nothing.
Complete. Lack. Of responsiveness.
Anyway, this’ll fix it:
var p, l, r = window.devicePixelRatio, head = document.getElementsByTagName('head')[0], l1, l2;
if ( !window.navigator.standalone ) {
p = r === 2 ? "assets/css/layout/ipad3-portrait.jpg" : "assets/css/layout/ipad-portrait.jpg";
l = r === 2 ? "assets/css/layout/ipad3-landscape.jpg" : "assets/css/layout/ipad-landscape.jpg";
l1 = document.createElement('link');
l2 = document.createElement('link');
l1.setAttribute('rel', 'apple-touch-startup-image' );
l2.setAttribute('rel', 'apple-touch-startup-image' );
l1.setAttribute('media', 'screen and (orientation: landscape)');
l2.setAttribute('media', 'screen and (orientation: portrait)');
l1.setAttribute('href', l);
l2.setAttribute('href', p);
head.appendChild(l1);
head.appendChild(l2);
}
Basically, it’ll dynamically add the appropriate meta tags — but only when the app hasn’t been launched from the home screen. So, just throw that little snippet inside your <head>, swap out the file names, and you’ll be good to go.
Update: I’ve filed a bug report with Apple. We’ll see what happens.
A little utility function I wrote a couple months ago for setting and retrieving values in a deep object.
var cache = (function(){
'use strict';
var cache = {}, delim = '.';
return function(ns, val){
// No args? Return the full cache object
if (!ns) return cache;
var arr = ns.split(delim),
obj = cache,
prop,
i = 0,
l = arr.length - 1;
// Setter
if (typeof val !== 'undefined'){
for (; i < l; i++){
prop = arr[i];
obj[prop] = obj[prop] || {};
obj = obj[prop];
}
return obj[arr.pop()] = val;
// Getter
} else {
for (; i < l; i++){
prop = arr[i];
if (!( obj = obj[prop]))
return undefined;
}
return obj[arr.pop()];
}
};
}());
The idea is that instead of doing something like this:
if ( obj.people && obj.people.students && obj.people.students.john_doe ){
obj.people.students.john_doe.age = 15;
}
You can just do this:
cache('obj.people.students.john_doe.age', 15);
The cache function will automatically create any missing objects in the hierarchy.
Anyway, I have this written as a function expression here, but I usually use it as my getter/setter method for an object. For a slightly more detailed explanation, check out the project on Github.
switch(day){
case 'Sunday':
case 'Monday':
case 'Tuesday':
case 'Wednesday':
case 'Thursday':
case 'Friday':
HappyDay();
break;
case 'Saturday':
GroovingAllWeekWithYou();
break;
}
if ( you.hasOwnProperty('girlProblems') ){
this.feelBadForYouSon();
}
return this.problems.length == 99 && this.problems.indexOf(bitch) == -1;
Couldn’t help it.
Let d(n) be defined as the sum of proper divisors of n (numbers less than n which divide evenly into n). If d(a) = b and d(b) = a, where a is not equal to b, then a and b are an amicable pair and each of a and b are called amicable numbers. For example, the proper divisors of 220 are 1, 2, 4, 5, 10, 11, 20, 22, 44, 55 and 110; therefore d(220) = 284. The proper divisors of 284 are 1, 2, 4, 71 and 142; so d(284) = 220. Evaluate the sum of all the amicable numbers under 10000.Project Euler
Sometimes, instead of doing things like “going outside” or “interacting with other humans”, I like to solve problems on Project Euler. This particular one was sort of fun, so I thought I’d post my solution.
It’s not especially well-optimized, aside from a tiny bit of cacheing – but it still runs in ~190ms on my MacBook Pro in Node (which, I should mention, is faster than a lot of the guys on Project Euler who wrote algorithms in C/Python/Java. So, I mean… JavaScript for the win, right?).
Anyway, I basically broke the problem down into three parts:
getDivisors returns an array of factors of a given number.sumArray returns the sum of all the members in an array.var max = 10000,
result = [],
i = 0,
temp,
lookup = {};
function getDivisors ( num ){
if ( lookup[ num ] ) return lookup[ num ];
var arr = [], i = ( Math.floor( num / 2 ) );
for ( ; i > 0; i-- )
if ( !( num % i ) )
arr.push( i );
return lookup[ num ] = arr;
}
function sumArray ( arr ){
var i = arr.length, val = 0;
while ( i-- )
val += arr[ i ];
return val;
}
for ( ; i < max; i++ ){
if ( result.indexOf( i ) !== -1 ) continue;
temp = sumArray( getDivisors( i ) );
if ( temp != i && sumArray( getDivisors( temp ) ) == i )
result.push( temp, i );
}
console.log( sumArray( result ) );
TL;DR: Click here to check go straight to the Mix.js demo
Some background:
About two months ago, I put together a couple Web Audio API demos and never really showed them to anybody except for a few of my developer/nerd friends.
Since I already took a few hours today to overhaul the site, I thought I’d spend 5 more minutes and post them.
The first one is basically just a multiband spectral analyser with a volume control. Just a multiband spectral analyser with a volume control and convolution reverb. If you’re not familiar with convolution, just go here, because that’s really not the point of this post. Anyway, Chrome magically has a convolver built in, so we can add cool effects like reverb in real time. This particular example is using an impulse response from the venerable Lexicon PCM90.
The second demo is a bit more ambitious, and a lot more fun. It’s got 12 individual audio tracks which all have independent gain and pan controls, as well as a real-time meter with both Pre Fade Listen and After Fade Listen modes. Each track also has a Mute and Solo. I’m also storing the gain and pan values in localStorage, so if you leave and come back, your mix will be recalled. Just like an SSL (sort of).
Each of these demos only work in Chrome — so you should probably go ahead and download that if you (a) want to see the demos or (b) like awesome browsers.
For more cool Web Audio demos, check out this here internet webpagesite on The Google (code).
Hi Kevin,
I am currently working on a search for a front end web developer who has a flair for design.
You will be responsible for building high quality front end features for their Social Marketing Hub.
Strong working knowledge of Javascript,JSON,AJAX and JavaScript frameworks (jQuery)
I would like to speak with you about the positions that I am working on and find out more about your technical background.
Dear Name redacted,
You are the reason that companies complain about how hard it is to find good web developers. Why would anyone with a shred of talent and/or self-respect ever respond to a cut-and-paste message like this? You clearly didn’t bother to read my profile — nor did you provide any semblance of meaningful information about the “positions that [you] are working on”.
Good luck with your continued search for what I can only assume is anyone willing to turn PSD comps into semi-semantic HTML for $12/hour.
-Kevin Ennis