block by tophtucker ca94dc9c971e35d1daa6

Bloomberg ex litera

Full Screen

Roll over the text.

S/o to http://stencilgram.com/.

Owes a huge debt to George Michael Brower’s FizzyText.

d3-jetpack.js

(function() {
        
    function jetpack(d3) {
        d3.selection.prototype.translate = function(xy) {
            return this.attr('transform', function(d,i) {
                return 'translate('+[typeof xy == 'function' ? xy(d,i) : xy]+')';
            });
        };

        d3.transition.prototype.translate = function(xy) {
            return this.attr('transform', function(d,i) {
                return 'translate('+[typeof xy == 'function' ? xy(d,i) : xy]+')';
            });
        };

        d3.selection.prototype.tspans = function(lines, lh) {
            return this.selectAll('tspan')
                .data(lines)
                .enter()
                .append('tspan')
                .text(function(d) { return d; })
                .attr('x', 0)
                .attr('dy', function(d,i) { return i ? lh || 15 : 0; });
        };

        d3.selection.prototype.append = 
        d3.selection.enter.prototype.append = function(name) {
            var n = d3_parse_attributes(name), s;
            //console.log(name, n);
            name = n.attr ? n.tag : name;
            name = d3_selection_creator(name);
            s = this.select(function() {
                return this.appendChild(name.apply(this, arguments));
            });
            return n.attr ? s.attr(n.attr) : s;
        };

        d3.selection.prototype.insert = 
        d3.selection.enter.prototype.insert = function(name, before) {
            var n = d3_parse_attributes(name), s;
            name = n.attr ? n.tag : name;
            name = d3_selection_creator(name);
            before = d3_selection_selector(before);
            s = this.select(function() {
                return this.insertBefore(name.apply(this, arguments), before.apply(this, arguments) || null);
            });
            return n.attr ? s.attr(n.attr) : s;
        };

        var d3_parse_attributes_regex = /([\.#])/g;

        function d3_parse_attributes(name) {
            if (typeof name === "string") {
                var attr = {},
                    parts = name.split(d3_parse_attributes_regex), p;
                    name = parts.shift();
                while ((p = parts.shift())) {
                    if (p == '.') attr['class'] = attr['class'] ? attr['class'] + ' ' + parts.shift() : parts.shift();
                    else if (p == '#') attr.id = parts.shift();
                }
                return attr.id || attr['class'] ? { tag: name, attr: attr } : name;
            }
            return name;
        }

        function d3_selection_creator(name) {
            return typeof name === "function" ? name : (name = d3.ns.qualify(name)).local ? function() {
                return this.ownerDocument.createElementNS(name.space, name.local);
            } : function() {
                return this.ownerDocument.createElementNS(this.namespaceURI, name);
            };
        }

        function d3_selection_selector(selector) {
            return typeof selector === "function" ? selector : function() {
                return this.querySelector(selector);
            };
        }

        d3.wordwrap = function(line, maxCharactersPerLine) {
            var w = line.split(' '),
                lines = [],
                words = [],
                maxChars = maxCharactersPerLine || 40,
                l = 0;
            w.forEach(function(d) {
                if (l+d.length > maxChars) {
                    lines.push(words.join(' '));
                    words.length = 0;
                    l = 0;
                }
                l += d.length;
                words.push(d);
            });
            if (words.length) {
                lines.push(words.join(' '));
            }
            return lines;
        };
        
        d3.ascendingKey = function(key) {
            return typeof key == 'function' ? function (a, b) {
                  return key(a) < key(b) ? -1 : key(a) > key(b) ? 1 : key(a) >= key(b) ? 0 : NaN;
            } : function (a, b) {
                  return a[key] < b[key] ? -1 : a[key] > b[key] ? 1 : a[key] >= b[key] ? 0 : NaN;
            };
        };

        d3.descendingKey = function(key) {
            return typeof key == 'function' ? function (a, b) {
                return key(b) < key(a) ? -1 : key(b) > key(a) ? 1 : key(b) >= key(a) ? 0 : NaN;
            } : function (a, b) {
                return b[key] < a[key] ? -1 : b[key] > a[key] ? 1 : b[key] >= a[key] ? 0 : NaN;
            };
        };
        
        d3.f = function(){
            var functions = arguments;
            //convert all string arguments into field accessors
            var i = 0, l = functions.length;
            while (i < l) {
                if (typeof(functions[i]) === 'string' || typeof(functions[i]) === 'number'){
                    functions[i] = (function(str){ return function(d){ return d[str] }; })(functions[i])
                }
                i++;
            }
             //return composition of functions
            return function(d) {
                var i=0, l = functions.length;
                while (i++ < l) d = functions[i-1].call(this, d);
                return d;
            };
        };
        // store d3.f as convenient unicode character function (alt-f on macs)
        if (!window.hasOwnProperty('ƒ')) window.ƒ = d3.f;
        
        // this tweak allows setting a listener for multiple events, jquery style
        var d3_selection_on = d3.selection.prototype.on;
        d3.selection.prototype.on = function(type, listener, capture) {
            if (typeof type == 'string' && type.indexOf(' ') > -1) {
                type = type.split(' ');
                for (var i = 0; i<type.length; i++) {
                    d3_selection_on.apply(this, [type[i], listener, capture]);
                }
            } else {
                d3_selection_on.apply(this, [type, listener, capture]);
            }
            return this;
        };
        
        // for heaven's sake, let's add prop as alias for property
        d3.selection.prototype.prop = d3.selection.prototype.property;
    }

    if (typeof d3 === 'object' && d3.version) jetpack(d3);
    else if (typeof define === 'function' && define.amd) {
        define(['d3'], jetpack);
    }

})();

fizzy.js

function CanvasText(container, message) {

  var width = container.offsetWidth;
  var height = container.offsetHeight;

  // This is the context we use to get a bitmap of text using
  // the getImageData function.
  var r = document.createElement('canvas');
  var s = r.getContext('2d');

  r.setAttribute('width', width);
  r.setAttribute('height', height);

  container.appendChild(r);

  // Stores bitmap image
  var pixels = [];

  s.font = "800 180px helvetica, arial, serif";
  s.textBaseline = 'middle';
  s.textAlign = "center";

  // This function creates a bitmap of pixels based on your message
  // It's called every time we change the message property.
  var createBitmap = function (msg) {

    s.fillStyle = "#fff";
    s.fillRect(0, 0, width, height);

    s.fillStyle = "#222";
    s.fillText(msg, width/2, height/2);

    // Pull reference
    var imageData = s.getImageData(0, 0, width, height);
    pixels = imageData.data;

  };

  // Returns x, y coordinates for a given index in the pixel array.
  var getPosition = function (i) {
    return {
      x: (i - (width * 4) * Math.floor(i / (width * 4))) / 4,
      y: Math.floor(i / (width * 4))
    };
  };

  // Returns a color for a given pixel in the pixel array.
  this.getColor = function (x, y) {
    var base = (Math.floor(y) * width + Math.floor(x)) * 4;
    var c = {
      r: pixels[base + 0],
      g: pixels[base + 1],
      b: pixels[base + 2],
      a: pixels[base + 3]
    };

    return "rgb(" + c.r + "," + c.g + "," + c.b + ")";
  };

  // createBitmap(message);

  var img = new Image();   // Create new img element
  img.addEventListener("load", function() {
    // execute drawImage statements here
    s.drawImage(img,0,0);
    var imageData = s.getImageData(0, 0, width, height);
    pixels = imageData.data;
  }, false);
  img.src = 'bloomberg.png'; // Set source path

}

improvedNoise.js

// http://mrl.nyu.edu/~perlin/noise/

var ImprovedNoise = function () {

    var p = [151,160,137,91,90,15,131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,
         23,190,6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33,88,237,149,56,87,
         174,20,125,136,171,168,68,175,74,165,71,134,139,48,27,166,77,146,158,231,83,111,229,122,60,211,
         133,230,220,105,92,41,55,46,245,40,244,102,143,54,65,25,63,161,1,216,80,73,209,76,132,187,208,
         89,18,169,200,196,135,130,116,188,159,86,164,100,109,198,173,186,3,64,52,217,226,250,124,123,5,
         202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42,223,183,170,213,119,
         248,152,2,44,154,163,70,221,153,101,155,167,43,172,9,129,22,39,253,19,98,108,110,79,113,224,232,
         178,185,112,104,218,246,97,228,251,34,242,193,238,210,144,12,191,179,162,241,81,51,145,235,249,
         14,239,107,49,192,214,31,181,199,106,157,184,84,204,176,115,121,50,45,127,4,150,254,138,236,205,
         93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180];

    for ( var i = 0; i < 256 ; i++ ) {

        p[ 256 + i ] = p[ i ];

    }

    function fade( t ) {

        return t * t * t * ( t * ( t * 6 - 15 ) + 10 );

    }

    function lerp( t, a, b ) {

        return a + t * ( b - a );

    }

    function grad( hash, x, y, z ) {

        var h = hash & 15;
        var u = h < 8 ? x : y, v = h < 4 ? y : h == 12 || h == 14 ? x : z;
        return ( ( h & 1 ) == 0 ? u : -u ) + ( ( h & 2 ) == 0 ? v : -v );

    }

    return {

        noise: function ( x, y, z ) {

            var floorX = Math.floor( x ), floorY = Math.floor( y ), floorZ = Math.floor( z );

            var X = floorX & 255, Y = floorY & 255, Z = floorZ & 255;

            x -= floorX;
            y -= floorY;
            z -= floorZ;

            var xMinus1 = x -1, yMinus1 = y - 1, zMinus1 = z - 1;

            var u = fade( x ), v = fade( y ), w = fade( z );

            var A = p[ X ] + Y, AA = p[ A ] + Z, AB = p[ A + 1 ] + Z, B = p[ X + 1 ] + Y, BA = p[ B ] + Z, BB = p[ B + 1 ] + Z;

            return lerp( w, lerp( v, lerp( u, grad( p[ AA ], x, y, z ),
                               grad( p[ BA ], xMinus1, y, z ) ),
                          lerp( u, grad( p[ AB ], x, yMinus1, z ),
                               grad( p[ BB ], xMinus1, yMinus1, z ) ) ),
                     lerp( v, lerp( u, grad( p[ AA + 1 ], x, y, zMinus1 ),
                               grad( p[ BA + 1 ], xMinus1, y, z - 1 ) ),
                          lerp( u, grad( p[ AB + 1 ], x, yMinus1, zMinus1 ),
                               grad( p[ BB + 1 ], xMinus1, yMinus1, zMinus1 ) ) ) );

        }
    }
}

var currentRandom = Math.random;

// Pseudo-random generator
function Marsaglia(i1, i2) {
  // from http://www.math.uni-bielefeld.de/~sillke/ALGORITHMS/random/marsaglia-c
  var z=i1 || 362436069, w= i2 || 521288629;
  var nextInt = function() {
    z=(36969*(z&65535)+(z>>>16)) & 0xFFFFFFFF;
    w=(18000*(w&65535)+(w>>>16)) & 0xFFFFFFFF;
    return (((z&0xFFFF)<<16) | (w&0xFFFF)) & 0xFFFFFFFF;
  };
 
  this.nextDouble = function() {
    var i = nextInt() / 4294967296;
    return i < 0 ? 1 + i : i;
  };
  this.nextInt = nextInt;
}
Marsaglia.createRandomized = function() {
  var now = new Date();
  return new Marsaglia((now / 60000) & 0xFFFFFFFF, now & 0xFFFFFFFF);
};      

// Noise functions and helpers
function PerlinNoise(seed) {
  var rnd = seed !== undefined ? new Marsaglia(seed) : Marsaglia.createRandomized();
  var i, j;
  // http://www.noisemachine.com/talk1/17b.html
  // http://mrl.nyu.edu/~perlin/noise/
  // generate permutation
  var p = new Array(512); 
  for(i=0;i<256;++i) { p[i] = i; }
  for(i=0;i<256;++i) { var t = p[j = rnd.nextInt() & 0xFF]; p[j] = p[i]; p[i] = t; }
  // copy to avoid taking mod in p[0];
  for(i=0;i<256;++i) { p[i + 256] = p[i]; } 
  
  function grad3d(i,x,y,z) {        
    var h = i & 15; // convert into 12 gradient directions
    var u = h<8 ? x : y,                 
        v = h<4 ? y : h===12||h===14 ? x : z;
    return ((h&1) === 0 ? u : -u) + ((h&2) === 0 ? v : -v);
  }

  function grad2d(i,x,y) { 
    var v = (i & 1) === 0 ? x : y;
    return (i&2) === 0 ? -v : v;
  }
  
  function grad1d(i,x) { 
    return (i&1) === 0 ? -x : x;
  }
  
  function lerp(t,a,b) { return a + t * (b - a); }
    
  this.noise3d = function(x, y, z) {
    var X = Math.floor(x)&255, Y = Math.floor(y)&255, Z = Math.floor(z)&255;
    x -= Math.floor(x); y -= Math.floor(y); z -= Math.floor(z);
    var fx = (3-2*x)*x*x, fy = (3-2*y)*y*y, fz = (3-2*z)*z*z;
    var p0 = p[X]+Y, p00 = p[p0] + Z, p01 = p[p0 + 1] + Z, p1  = p[X + 1] + Y, p10 = p[p1] + Z, p11 = p[p1 + 1] + Z;
    return lerp(fz, 
      lerp(fy, lerp(fx, grad3d(p[p00], x, y, z), grad3d(p[p10], x-1, y, z)),
               lerp(fx, grad3d(p[p01], x, y-1, z), grad3d(p[p11], x-1, y-1,z))),
      lerp(fy, lerp(fx, grad3d(p[p00 + 1], x, y, z-1), grad3d(p[p10 + 1], x-1, y, z-1)),
               lerp(fx, grad3d(p[p01 + 1], x, y-1, z-1), grad3d(p[p11 + 1], x-1, y-1,z-1))));
  };
  
  this.noise2d = function(x, y) {
    var X = Math.floor(x)&255, Y = Math.floor(y)&255;
    x -= Math.floor(x); y -= Math.floor(y);
    var fx = (3-2*x)*x*x, fy = (3-2*y)*y*y;
    var p0 = p[X]+Y, p1  = p[X + 1] + Y;
    return lerp(fy, 
      lerp(fx, grad2d(p[p0], x, y), grad2d(p[p1], x-1, y)),
      lerp(fx, grad2d(p[p0 + 1], x, y-1), grad2d(p[p1 + 1], x-1, y-1)));
  };

  this.noise1d = function(x) {
    var X = Math.floor(x)&255;
    x -= Math.floor(x);
    var fx = (3-2*x)*x*x;
    return lerp(fx, grad1d(p[X], x), grad1d(p[X+1], x-1));
  };
}

function noiser(oct, fall) {

  //  these are lifted from Processing.js
  // processing defaults
  var noiseProfile = { 
    generator: undefined, 
    octaves: oct || 4, 
    fallout: fall || .8, 
    seed: undefined
  };

  function noise(x, y, z) {
    if(noiseProfile.generator === undefined) {
      // caching
      noiseProfile.generator = new PerlinNoise(noiseProfile.seed);
    }
    var generator = noiseProfile.generator;
    var effect = 1, k = 1, sum = 0;
    for(var i=0; i<noiseProfile.octaves; ++i) {
      effect *= noiseProfile.fallout;        
      switch (arguments.length) {
      case 1:
        sum += effect * (1 + generator.noise1d(k*x))/2; break;
      case 2:
        sum += effect * (1 + generator.noise2d(k*x, k*y))/2; break;
      case 3:
        sum += effect * (1 + generator.noise3d(k*x, k*y, k*z))/2; break;
      }
      k *= 2;
    }
    return sum;
  };

  return noise;

}

main.js

function split(selection) {
  selection.each(function(d,i) {
    var text = this.innerText.split("");
    this.innerHTML = '';
    text.forEach(function(letter,j) {
      this.innerHTML += "<span>" + letter + "</span>";
    }, this);
    d3.select(this).selectAll("span")
      .each(function(dd,ii) {
        var data = {"bb": this.getBoundingClientRect()};
        data.x = data.bb.left - this.offsetParent.getBoundingClientRect().left;
        data.y = data.bb.top - this.offsetParent.getBoundingClientRect().top;
        d3.select(this).datum(data);
      });
  });
}

function positionAbsolutely(selection) {
  selection.each(function(d,i) {
    d3.select(this)
      .style('left', function(d) { return d.x + "px"; })
      .style('top', function(d) { return d.y + "px"; })
      .style('position', 'absolute');
  })
}

var container = d3.select(".container");
var text = container.select(".text");
var graf = text.selectAll("p")
  .call(split)
  .style('height', function(d,i) { return this.getBoundingClientRect().height + 'px'; });
var letters = text.selectAll("span").call(positionAbsolutely);

var canvasText = new CanvasText(container.node(), 'KUNDERA');

text.on("mousemove", function() {
  console.log(canvasText.getColor(d3.mouse(this)[0], d3.mouse(this)[1]));
})

var maxX = container.node().offsetWidth;
var maxY = container.node().offsetHeight;

text.on("mouseenter", function() {

  var targets = d3.range(letters.size()).map(function(d) {
    r = {};
    do {
      r.x = Math.floor(Math.random() * maxX);
      r.y = Math.floor(Math.random() * maxY);
      r.c = canvasText.getColor(r.x, r.y);
    } while (r.c == "rgb(255,255,255)");
    return r;
  });

  // semi-random sort by distance from top left corner
  targets = targets.sort(function(a,b) {
    return Math.random()*(Math.pow(a.x,2) + Math.pow(a.y,2)) - Math.random()*(Math.pow(b.x,2) + Math.pow(b.y,2));
  })

  letters
    .transition()
    .duration(2000)
    .delay(function(d,i) { return 2*i; })
    .style('left', function(d,i) { return targets[i].x + "px"; })
    .style('top', function(d,i) { return targets[i].y + "px"; });
});

text.on("mouseleave", function() { 
  letters
    .transition()
    .duration(1000)
    .delay(function(d,i) { return i; })
    .style('left', function(d) { return d.x + "px"; })
    .style('top', function(d) { return d.y + "px"; });
});