Skip to content

Instantly share code, notes, and snippets.

@mojowen
Forked from enjalot/index.html
Last active August 29, 2015 14:04

Revisions

  1. mojowen revised this gist Jul 23, 2014. 1 changed file with 2 additions and 3 deletions.
    5 changes: 2 additions & 3 deletions index.html
    Original file line number Diff line number Diff line change
    @@ -116,7 +116,7 @@
    .each(lineEnter);



    var pause = false;
    var sm = .39
    function update_spacing()
    {
    @@ -146,8 +146,7 @@
    .range([1, .4])


    var pause = false,
    b = 1;
    b = 1;

    d3.timer(function() {
    if( pause ) return false;
  2. mojowen revised this gist Jul 23, 2014. 1 changed file with 4 additions and 2 deletions.
    6 changes: 4 additions & 2 deletions index.html
    Original file line number Diff line number Diff line change
    @@ -146,9 +146,11 @@
    .range([1, .4])


    b = 1;
    var pause = false,
    b = 1;

    d3.timer(function() {
    if(pause) return false;
    if( pause ) return false;
    var elapsed = Date.now() - start
    var damp = .3

  3. mojowen revised this gist Jul 23, 2014. 2 changed files with 0 additions and 498 deletions.
    33 changes: 0 additions & 33 deletions index.html
    Original file line number Diff line number Diff line change
    @@ -22,7 +22,6 @@
    <body>
    <svg></svg>
    <script type="text/javascript" src="http://mbostock.github.com/d3/d3.js?2.6.0"></script>
    <script type="text/javascript" src="jwerty.js"></script>
    <script type="text/javascript">

    var w = 960,
    @@ -117,20 +116,6 @@
    .each(lineEnter);


    jwerty.key('a', function () {
    omega -= .01;
    console.log("omega", omega)
    });
    jwerty.key('d', function () {
    omega += .01;
    console.log("omega", omega)
    });

    var pause = false;
    jwerty.key('p', function () {
    pause = !pause;
    });


    var sm = .39
    function update_spacing()
    @@ -149,24 +134,6 @@
    return "translate(" + [0, h/2 + th / 2 - spacing * d.index] + ")";
    })
    }
    jwerty.key('↑', function () {
    spacing += 1;
    update_spacing();
    });
    jwerty.key('↓', function () {
    spacing -= 1;
    update_spacing();
    });
    //jwerty.key('↑', function () {
    jwerty.key('←', function () {
    sm -= .01;
    console.log("speed multiplier", sm);
    });
    //jwerty.key('↓', function () {
    jwerty.key('→', function () {
    sm += .01;
    console.log("speed multiplier", sm);
    });


    var color = d3.scale.linear()
    465 changes: 0 additions & 465 deletions jwerty.js
    Original file line number Diff line number Diff line change
    @@ -1,465 +0,0 @@
    /*
    * jwerty - Awesome handling of keyboard events
    *
    * jwerty is a JS lib which allows you to bind, fire and assert key combination
    * strings against elements and events. It normalises the poor std api into
    * something easy to use and clear.
    *
    * This code is licensed under the MIT
    * For the full license see: http://keithamus.mit-license.org/
    * For more information see: http://keithamus.github.com/jwerty
    *
    * @author Keith Cirkel ('keithamus') <jwerty@keithcirkel.co.uk>
    * @license http://keithamus.mit-license.org/
    * @copyright Copyright © 2011, Keith Cirkel
    *
    */
    (function (global, exports) {

    // Helper methods & vars:
    var $d = global.document
    , $ = (global.jQuery || global.Zepto || global.ender || $d)
    , $$
    , $b
    , ke = 'keydown';

    function realTypeOf(v, s) {
    return (v === null) ? s === 'null'
    : (v === undefined) ? s === 'undefined'
    : (v.is && v instanceof $) ? s === 'element'
    : Object.prototype.toString.call(v).toLowerCase().indexOf(s) > 7;
    }

    if ($ === $d) {
    $$ = function (selector, context) {
    return selector ? $.querySelector(selector, context || $) : $;
    };

    $b = function (e, fn) { e.addEventListener(ke, fn, false); };
    $f = function (e, jwertyEv) {
    var ret = document.createEvent('Event')
    , i;

    ret.initEvent(ke, true, true);

    for (i in jwertyEv) ret[i] = jwertyEv[i];

    return (e || $).dispatchEvent(ret);
    }
    } else {
    $$ = function (selector, context, fn) { return $(selector || $d, context); };
    $b = function (e, fn) { $(e).bind(ke + '.jwerty', fn); };
    $f = function (e, ob) { $(e || $d).trigger($.Event(ke, ob)); };
    }

    // Private
    var _modProps = { 16: 'shiftKey', 17: 'ctrlKey', 18: 'altKey', 91: 'metaKey' };

    // Generate key mappings for common keys that are not printable.
    var _keys = {

    // MOD aka toggleable keys
    mods: {
    // Shift key, ⇧
    '⇧': 16, shift: 16,
    // CTRL key, on Mac: ⌃
    '⌃': 17, ctrl: 17,
    // ALT key, on Mac: ⌥ (Alt)
    '⌥': 18, alt: 18, option: 18,
    // META, on Mac: ⌘ (CMD), on Windows (Win), on Linux (Super)
    '⌘': 91, meta: 91, cmd: 91, 'super': 91, win: 91
    },

    // Normal keys
    keys: {
    // Backspace key, on Mac: ⌫ (Backspace)
    '⌫': 8, backspace: 8,
    // Tab Key, on Mac: ⇥ (Tab), on Windows ⇥⇥
    '⇥': 9, '⇆': 9, tab: 9,
    // Return key, ↩
    '↩': 13, 'return': 13, enter: 13, '⌅': 13,
    // Pause/Break key
    'pause': 19, 'pause-break': 19,
    // Caps Lock key, ⇪
    '⇪': 20, caps: 20, 'caps-lock': 20,
    // Escape key, on Mac: ⎋, on Windows: Esc
    '⎋': 27, escape: 27, esc: 27,
    // Space key
    space: 32,
    // Page-Up key, or pgup, on Mac: ↖
    '↖': 33, pgup: 33, 'page-up': 33,
    // Page-Down key, or pgdown, on Mac: ↘
    '↘': 34, pgdown: 34, 'page-down': 34,
    // END key, on Mac: ⇟
    '⇟': 35, end: 35,
    // HOME key, on Mac: ⇞
    '⇞': 36, home: 36,
    // Insert key, or ins
    ins: 45, insert: 45,
    // Delete key, on Mac: ⌫ (Delete)
    del: 45, 'delete': 45,

    // Left Arrow Key, or ←
    '←': 37, left: 37, 'arrow-left': 37,
    // Up Arrow Key, or ↑
    '↑': 38, up: 38, 'arrow-up': 38,
    // Right Arrow Key, or →
    '→': 39, right: 39, 'arrow-right': 39,
    // Up Arrow Key, or ↓
    '↓': 40, down: 40, 'arrow-down': 40,

    // odities, printing characters that come out wrong:
    // Num-Multiply, or *
    '*': 106, star: 106, asterisk: 106, multiply: 106,
    // Num-Plus or +
    '+': 107, 'plus': 107,
    // Num-Subtract, or -
    '-': 109, subtract: 109,
    //';': 186, //???
    // = or equals
    '=': 187, 'equals': 187,
    // Comma, or ,
    ',': 188, comma: 188,
    //'-': 189, //???
    // Period, or ., or full-stop
    '.': 190, period: 190, 'full-stop': 190,
    // Slash, or /, or forward-slash
    '/': 191, slash: 191, 'forward-slash': 191,
    // Tick, or `, or back-quote
    '`': 192, tick: 192, 'back-quote': 192,
    // Open bracket, or [
    '[': 219, 'open-bracket': 219,
    // Back slash, or \
    '\\': 220, 'back-slash': 220,
    // Close backet, or ]
    ']': 221, 'close-bracket': 221,
    // Apostraphe, or Quote, or '
    '\'': 222, quote: 222, apostraphe: 222
    }

    };

    // To minimise code bloat, add all of the NUMPAD 0-9 keys in a loop
    i = 95, n = 0;
    while(++i < 106) {
    _keys.keys['num-' + n] = i;
    ++n;
    }

    // To minimise code bloat, add all of the top row 0-9 keys in a loop
    i = 47, n = 0;
    while(++i < 58) {
    _keys.keys[n] = i;
    ++n;
    }

    // To minimise code bloat, add all of the F1-F25 keys in a loop
    i = 111, n = 1;
    while(++i < 136) {
    _keys.keys['f' + n] = i;
    ++n;
    }

    // To minimise code bloat, add all of the letters of the alphabet in a loop
    var i = 64;
    while(++i < 91) {
    _keys.keys[String.fromCharCode(i).toLowerCase()] = i;
    }

    function JwertyCode(jwertyCode) {
    var i
    , c
    , n
    , z
    , keyCombo
    , optionals
    , jwertyCodeFragment
    , rangeMatches
    , rangeI;

    // In-case we get called with an instance of ourselves, just return that.
    if (jwertyCode instanceof JwertyCode) return jwertyCode;

    // If jwertyCode isn't an array, cast it as a string and split into array.
    if (!realTypeOf(jwertyCode, 'array')) {
    jwertyCode = (String(jwertyCode)).replace(/\s/g, '').toLowerCase().
    match(/(?:\+,|[^,])+/g);
    }

    // Loop through each key sequence in jwertyCode
    for (i = 0, c = jwertyCode.length; i < c; ++i) {

    // If the key combo at this part of the sequence isn't an array,
    // cast as a string and split into an array.
    if (!realTypeOf(jwertyCode[i], 'array')) {
    jwertyCode[i] = String(jwertyCode[i])
    .match(/(?:\+\/|[^\/])+/g);
    }

    // Parse the key optionals in this sequence
    optionals = [], n = jwertyCode[i].length;
    while (n--) {

    // Begin creating the object for this key combo
    var jwertyCodeFragment = jwertyCode[i][n];

    keyCombo = {
    jwertyCombo: String(jwertyCodeFragment),
    shiftKey: false,
    ctrlKey: false,
    altKey: false,
    metaKey: false
    }

    // If jwertyCodeFragment isn't an array then cast as a string
    // and split it into one.
    if (!realTypeOf(jwertyCodeFragment, 'array')) {
    jwertyCodeFragment = String(jwertyCodeFragment).toLowerCase()
    .match(/(?:(?:[^\+])+|\+\+|^\+$)/g);
    }

    z = jwertyCodeFragment.length;
    while (z--) {

    // Normalise matching errors
    if (jwertyCodeFragment[z] === '++') jwertyCodeFragment[z] = '+';

    // Inject either keyCode or ctrl/meta/shift/altKey into keyCombo
    if (jwertyCodeFragment[z] in _keys.mods) {
    keyCombo[_modProps[_keys.mods[jwertyCodeFragment[z]]]] = true;
    } else if(jwertyCodeFragment[z] in _keys.keys) {
    keyCombo.keyCode = _keys.keys[jwertyCodeFragment[z]];
    } else {
    rangeMatches = jwertyCodeFragment[z].match(/^\[([^-]+\-?[^-]*)-([^-]+\-?[^-]*)\]$/);
    }
    }
    if (realTypeOf(keyCombo.keyCode, 'undefined')) {
    // If we picked up a range match earlier...
    if (rangeMatches && (rangeMatches[1] in _keys.keys) && (rangeMatches[2] in _keys.keys)) {
    rangeMatches[2] = _keys.keys[rangeMatches[2]];
    rangeMatches[1] = _keys.keys[rangeMatches[1]];

    // Go from match 1 and capture all key-comobs up to match 2
    for (rangeI = rangeMatches[1]; rangeI < rangeMatches[2]; ++rangeI) {
    optionals.push({
    altKey: keyCombo.altKey,
    shiftKey: keyCombo.shiftKey,
    metaKey: keyCombo.metaKey,
    ctrlKey: keyCombo.ctrlKey,
    keyCode: rangeI,
    jwertyCombo: String(jwertyCodeFragment)
    });

    }
    keyCombo.keyCode = rangeI;
    // Inject either keyCode or ctrl/meta/shift/altKey into keyCombo
    } else {
    keyCombo.keyCode = 0;
    }
    }
    optionals.push(keyCombo);

    }
    this[i] = optionals;
    }
    this.length = i;
    return this;
    }

    var jwerty = exports.jwerty = {
    /**
    * jwerty.event
    *
    * `jwerty.event` will return a function, which expects the first
    * argument to be a key event. When the key event matches `jwertyCode`,
    * `callbackFunction` is fired. `jwerty.event` is used by `jwerty.key`
    * to bind the function it returns. `jwerty.event` is useful for
    * attaching to your own event listeners. It can be used as a decorator
    * method to encapsulate functionality that you only want to fire after
    * a specific key combo. If `callbackContext` is specified then it will
    * be supplied as `callbackFunction`'s context - in other words, the
    * keyword `this` will be set to `callbackContext` inside the
    * `callbackFunction` function.
    *
    * @param {Mixed} jwertyCode can be an array, or string of key
    * combinations, which includes optinals and or sequences
    * @param {Function} callbackFucntion is a function (or boolean) which
    * is fired when jwertyCode is matched. Return false to
    * preventDefault()
    * @param {Object} callbackContext (Optional) The context to call
    * `callback` with (i.e this)
    *
    */
    event: function (jwertyCode, callbackFunction, callbackContext /*? this */) {

    // Construct a function out of callbackFunction, if it is a boolean.
    if (realTypeOf(callbackFunction, 'boolean')) {
    var bool = callbackFunction;
    callbackFunction = function () { return bool; }
    }

    jwertyCode = new JwertyCode(jwertyCode);

    // Initialise in-scope vars.
    var i = 0
    , c = jwertyCode.length - 1
    , returnValue
    , jwertyCodeIs;

    // This is the event listener function that gets returned...
    return function (event) {

    // if jwertyCodeIs returns truthy (string)...
    if ((jwertyCodeIs = jwerty.is(jwertyCode, event, i))) {
    // ... and this isn't the last key in the sequence,
    // incriment the key in sequence to check.
    if (i < c) {
    ++i;
    return;
    // ... and this is the last in the sequence (or the only
    // one in sequence), then fire the callback
    } else {
    returnValue = callbackFunction.call(
    callbackContext || this, event, jwertyCodeIs);

    // If the callback returned false, then we should run
    // preventDefault();
    if (returnValue === false) event.preventDefault();

    // Reset i for the next sequence to fire.
    i = 0;
    return;
    }
    }

    // If the event didn't hit this time, we should reset i to 0,
    // that is, unless this combo was the first in the sequence,
    // in which case we should reset i to 1.
    i = jwerty.is(jwertyCode, event) ? 1 : 0;
    }
    },

    /**
    * jwerty.is
    *
    * `jwerty.is` will return a boolean value, based on if `event` matches
    * `jwertyCode`. `jwerty.is` is called by `jwerty.event` to check
    * whether or not to fire the callback. `event` can be a DOM event, or
    * a jQuery/Zepto/Ender manufactured event. The properties of
    * `jwertyCode` (speficially ctrlKey, altKey, metaKey, shiftKey and
    * keyCode) should match `jwertyCode`'s properties - if they do, then
    * `jwerty.is` will return `true`. If they don't, `jwerty.is` will
    * return `false`.
    *
    * @param {Mixed} jwertyCode can be an array, or string of key
    * combinations, which includes optinals and or sequences
    * @param {KeyboardEvent} event is the KeyboardEvent to assert against
    * @param {Integer} i (Optional) checks the `i` key in jwertyCode
    * sequence
    *
    */
    is: function (jwertyCode, event, i /*? 0*/) {
    jwertyCode = new JwertyCode(jwertyCode);
    // Default `i` to 0
    i = i || 0;
    // We are only interesting in `i` of jwertyCode;
    jwertyCode = jwertyCode[i];
    // jQuery stores the *real* event in `originalEvent`, which we use
    // because it does annoything stuff to `metaKey`
    event = event.originalEvent || event;

    // We'll look at each optional in this jwertyCode sequence...
    var key
    , n = jwertyCode.length
    , returnValue = false;

    // Loop through each fragment of jwertyCode
    while (n--) {
    returnValue = jwertyCode[n].jwertyCombo;
    // For each property in the jwertyCode object, compare to `event`
    for (var p in jwertyCode[n]) {
    // ...except for jwertyCode.jwertyCombo...
    if (p !== 'jwertyCombo' && event[p] != jwertyCode[n][p]) returnValue = false;
    }
    // If this jwertyCode optional wasn't falsey, then we can return early.
    if (returnValue !== false) return returnValue;
    }
    return returnValue;
    },

    /**
    * jwerty.key
    *
    * `jwerty.key` will attach an event listener and fire
    * `callbackFunction` when `jwertyCode` matches. The event listener is
    * attached to `document`, meaning it will listen for any key events
    * on the page (a global shortcut listener). If `callbackContext` is
    * specified then it will be supplied as `callbackFunction`'s context
    * - in other words, the keyword `this` will be set to
    * `callbackContext` inside the `callbackFunction` function.
    *
    * @param {Mixed} jwertyCode can be an array, or string of key
    * combinations, which includes optinals and or sequences
    * @param {Function} callbackFunction is a function (or boolean) which
    * is fired when jwertyCode is matched. Return false to
    * preventDefault()
    * @param {Object} callbackContext (Optional) The context to call
    * `callback` with (i.e this)
    * @param {Mixed} selector can be a string, jQuery/Zepto/Ender object,
    * or an HTML*Element on which to bind the eventListener
    * @param {Mixed} selectorContext can be a string, jQuery/Zepto/Ender
    * object, or an HTML*Element on which to scope the selector
    *
    */
    key: function (jwertyCode, callbackFunction, callbackContext /*? this */, selector /*? document */, selectorContext /*? body */) {
    // Because callbackContext is optional, we should check if the
    // `callbackContext` is a string or element, and if it is, then the
    // function was called without a context, and `callbackContext` is
    // actually `selector`
    var realSelector = realTypeOf(callbackContext, 'element') || realTypeOf(callbackContext, 'string') ? callbackContext : selector
    // If `callbackContext` is undefined, or if we skipped it (and
    // therefore it is `realSelector`), set context to `global`.
    , realcallbackContext = realSelector === callbackContext ? global : callbackContext
    // Finally if we did skip `callbackContext`, then shift
    // `selectorContext` to the left (take it from `selector`)
    , realSelectorContext = realSelector === callbackContext ? selector : selectorContext;

    // If `realSelector` is already a jQuery/Zepto/Ender/DOM element,
    // then just use it neat, otherwise find it in DOM using $$()
    $b(realTypeOf(realSelector, 'element') ?
    realSelector : $$(realSelector, realSelectorContext)
    , jwerty.event(jwertyCode, callbackFunction, realcallbackContext));
    },

    /**
    * jwerty.fire
    *
    * `jwerty.fire` will construct a keyup event to fire, based on
    * `jwertyCode`. The event will be fired against `selector`.
    * `selectorContext` is used to search for `selector` within
    * `selectorContext`, similar to jQuery's
    * `$('selector', 'context')`.
    *
    * @param {Mixed} jwertyCode can be an array, or string of key
    * combinations, which includes optinals and or sequences
    * @param {Mixed} selector can be a string, jQuery/Zepto/Ender object,
    * or an HTML*Element on which to bind the eventListener
    * @param {Mixed} selectorContext can be a string, jQuery/Zepto/Ender
    * object, or an HTML*Element on which to scope the selector
    *
    */
    fire: function (jwertyCode, selector /*? document */, selectorContext /*? body */, i) {
    jwertyCode = new JwertyCode(jwertyCode);
    var realI = realTypeOf(selectorContext, 'number') ? selectorContext : i;

    // If `realSelector` is already a jQuery/Zepto/Ender/DOM element,
    // then just use it neat, otherwise find it in DOM using $$()
    $f(realTypeOf(selector, 'element') ?
    selector : $$(selector, selectorContext)
    , jwertyCode[realI || 0][0]);
    },

    KEYS: _keys
    };

    }(this, (typeof module !== 'undefined' && module.exports ? module.exports : this)));
  4. @enjalot enjalot revised this gist Dec 13, 2011. 1 changed file with 66 additions and 35 deletions.
    101 changes: 66 additions & 35 deletions index.html
    Original file line number Diff line number Diff line change
    @@ -32,8 +32,8 @@
    var rings = [ ];
    var lines = [ ];

    var n = 20;
    var m = 100;
    var n = 25;
    var m = 70;

    for (i in d3.range(n))
    {
    @@ -42,15 +42,17 @@
    else
    var speed = (i-2) * 1e-2;
    //var speed = 50e-2 / (i + 1)
    var speed = .001 * m / (.5*i+1)
    //var speed = .001 * n / (.5*i+1)
    var speed = .001 * i * 4;

    var data = d3.range(m)
    lines.push({
    //radius: 65*i,
    width: 5,
    height: 15,
    speed: speed,
    phase: +i,
    index: +i,
    //speed: speed_scale(i),
    index: i,
    data: data
    })

    @@ -59,51 +61,47 @@
    var xscale = d3.scale.linear()
    .domain([0,m])
    .range([0, w])
    var yscale = d3.scale.linear()
    .domain([-1,1])
    //.interpolate("cubic")
    .range([-10,10])


    var phase = d3.scale.linear()
    .domain( [0 , m] )
    .range( [ 1, 100 ])

    var omega = -.22
    function line_maker( data, speed )
    {
    var freq = Math.PI*.4 + 3 * omega * data.index // * 3000
    var svgline = d3.svg.line()
    .x(function(d,i)
    {
    return xscale(d);
    })
    .y(function(d,i)
    {
    var theta = phase(data.phase) * d/m * Math.PI * 4;
    var theta = freq * d/m * Math.PI * 4
    //console.log("sin", Math.sin(theta), d)
    var y = 15 * (Math.sin(theta + speed * .1 ));
    var y = data.height * (Math.sin(theta + (n-data.index) * .1 * speed * .18 ));
    //console.log ("y", y)
    return y
    })
    .interpolate("basis")
    return svgline(data.data);
    }

    var spacing = 26;
    function lineEnter(d, i) {

    //console.log("line enter", d)
    d3.select(this).selectAll("g.line")
    d3.select(this).selectAll("path.path")
    .data([d])
    .enter().append("svg:path")
    .enter()
    .append("svg:path")
    .attr("class", "path")
    .attr("transform", function(_, i) { return "translate(" + [0, h - 30 * d.index] + ")"; })
    .attr("d", function(d,i) {
    //.attr("transform", function(_, i) { return "translate(" + [0, h - spacing * d.index] + ")"; })
    .attr("d", function(d,i) {
    return line_maker( d, 0 )
    }
    )
    .attr("stroke-width", function(e,i) { return e.width;})
    .attr("stroke", "#fff")
    .attr("fill", "none")

    update_spacing()
    }

    var svg = d3.select("svg")
    @@ -119,16 +117,55 @@
    .each(lineEnter);


    jwerty.key('a', function () {
    omega -= .01;
    console.log("omega", omega)
    });
    jwerty.key('d', function () {
    omega += .01;
    console.log("omega", omega)
    });

    var pause = false;
    jwerty.key('p', function () {
    pause = !pause;
    });

    var a = 1.

    var sm = .39
    function update_spacing()
    {
    var th = spacing * n;
    var hscale = d3.scale.linear()
    .domain([0, n])
    .range([0, h])

    //console.log("th", th, hscale(99))
    console.log("spacing", spacing)
    d3.selectAll("g.line path")
    .attr("transform", function(d, i) {
    //console.log("h",h, spacing, d.index);
    //return "translate(" + [0, th - spacing * d.index] + ")";
    return "translate(" + [0, h/2 + th / 2 - spacing * d.index] + ")";
    })
    }
    jwerty.key('↑', function () {
    spacing += 1;
    update_spacing();
    });
    jwerty.key('↓', function () {
    spacing -= 1;
    update_spacing();
    });
    //jwerty.key('↑', function () {
    jwerty.key(',←', function () {
    a -= .1;
    jwerty.key('←', function () {
    sm -= .01;
    console.log("speed multiplier", sm);
    });
    //jwerty.key('↓', function () {
    jwerty.key('→', function () {
    a += .1;
    sm += .01;
    console.log("speed multiplier", sm);
    });


    @@ -141,28 +178,22 @@
    .domain([0, n])
    .range([1, .4])

    var velocity = function(speed)
    {
    sin = Math.sin(speed)
    sc = d3.scale.linear()
    .domain([-1, 1])
    .range([0, 100])
    return sc(sin);
    }

    b = 1;
    d3.timer(function() {
    if(pause) return false;
    var elapsed = Date.now() - start
    var damp = .3

    rotate = function(d,i) {
    var speed = a * d.speed * elapsed * .1
    var speed = sm * d.speed * elapsed * .1
    return "rotate(" + speed + ")";
    };


    line = d3.selectAll("g.line path")
    .attr("d", function(d,i) {
    var speed = a * d.speed * elapsed
    //var speed = a * d.speed * elapsed + .01 * d.index
    var speed = sm * .08 * elapsed + d.index * 4
    return line_maker( d, speed )
    })
    .attr("stroke-opacity", function(d,i) { return opacity(d.index);})
  5. @enjalot enjalot revised this gist Dec 11, 2011. 1 changed file with 5 additions and 62 deletions.
    67 changes: 5 additions & 62 deletions index.html
    Original file line number Diff line number Diff line change
    @@ -5,7 +5,7 @@
    <style type="text/css">

    body {
    background: #888;
    background: #333;
    }

    rect {
    @@ -43,19 +43,11 @@
    var speed = (i-2) * 1e-2;
    //var speed = 50e-2 / (i + 1)
    var speed = .001 * m / (.5*i+1)
    /*
    rings.push({
    radius: 65*i,
    width: 16,
    speed: speed,
    phase: i
    })
    */

    var data = d3.range(m)
    lines.push({
    //radius: 65*i,
    width: 4,
    width: 5,
    speed: speed,
    phase: +i,
    index: +i,
    @@ -120,12 +112,6 @@
    .append("svg:g")
    //.attr("transform", "translate(" + w / 2 + "," + h / 2 + ")scale(.6)");

    var ring = svg.selectAll("g.ring")
    .data(rings)
    .enter().append("svg:g")
    .attr("class", "ring")
    .each(ringEnter);

    var line = svg.selectAll("g.line")
    .data(lines)
    .enter().append("svg:g")
    @@ -152,8 +138,8 @@
    .range(['#fff', '#000'])

    var opacity = d3.scale.linear()
    .domain([-1, 1])
    .range([.3, 1])
    .domain([0, n])
    .range([1, .4])

    var velocity = function(speed)
    {
    @@ -179,53 +165,10 @@
    var speed = a * d.speed * elapsed
    return line_maker( d, speed )
    })
    .attr("stroke-opacity", function(d,i) { return opacity(d.index);})


    /*
    ring
    .attr("transform", rotate)
    .selectAll("rect")
    .attr("transform", rotate)
    .attr("fill", function(d,i) {
    var eo = -1
    if(i % 2 == 0) eo = 1;
    var theta = damp * a * d.speed * elapsed * eo;
    var sin = Math.sin(theta)
    return color( sin );
    })
    .attr("fill-opacity", function(d) {
    var eo = -1
    if(i % 2 == 0) eo = 1;
    var theta = Math.sin(damp * a * d.speed * elapsed * eo)
    return opacity( theta );
    })
    .attr("stroke", function(d) {
    var eo = -1
    if(i % 2 == 0) eo = 1;
    var theta = Math.cos(damp * a * d.speed * elapsed * eo)
    return color( theta );
    })
    */


    });

    function ringEnter(d, i) {
    var n = Math.floor(2 * Math.PI * d.radius / d.width * Math.SQRT1_2),
    k = 360 / n;

    d3.select(this).selectAll("g")
    .data(d3.range(n).map(function() { return d; }))
    .enter().append("svg:g")
    .attr("class", "square")
    .attr("transform", function(_, i) { return "rotate(" + i * k + ")translate(" + d.radius + ")"; })
    .append("svg:rect")
    .attr("x", -d.width / 2)
    .attr("y", -d.width / 2)
    .attr("width", d.width)
    .attr("height", d.width);
    }

    </script>
    </body>
    </html>
  6. @enjalot enjalot revised this gist Dec 11, 2011. 1 changed file with 23 additions and 9 deletions.
    32 changes: 23 additions & 9 deletions index.html
    Original file line number Diff line number Diff line change
    @@ -32,7 +32,7 @@
    var rings = [ ];
    var lines = [ ];

    var n = 14;
    var n = 20;
    var m = 100;

    for (i in d3.range(n))
    @@ -41,6 +41,8 @@
    var speed = (i-3) * 1e-2;
    else
    var speed = (i-2) * 1e-2;
    //var speed = 50e-2 / (i + 1)
    var speed = .001 * m / (.5*i+1)
    /*
    rings.push({
    radius: 65*i,
    @@ -67,6 +69,7 @@
    .range([0, w])
    var yscale = d3.scale.linear()
    .domain([-1,1])
    //.interpolate("cubic")
    .range([-10,10])


    @@ -83,10 +86,13 @@
    })
    .y(function(d,i)
    {
    var theta = phase(data.phase) * d/m * Math.PI * 2 * speed;
    var theta = phase(data.phase) * d/m * Math.PI * 4;
    //console.log("sin", Math.sin(theta), d)
    return 10 * (Math.sin(theta));
    var y = 15 * (Math.sin(theta + speed * .1 ));
    //console.log ("y", y)
    return y
    })
    .interpolate("basis")
    return svgline(data.data);
    }

    @@ -97,9 +103,9 @@
    .data([d])
    .enter().append("svg:path")
    .attr("class", "path")
    .attr("transform", function(_, i) { return "translate(" + [0, 40 * d.index] + ")"; })
    .attr("transform", function(_, i) { return "translate(" + [0, h - 30 * d.index] + ")"; })
    .attr("d", function(d,i) {
    return line_maker( d, 1 )
    return line_maker( d, 0 )
    }
    )
    .attr("stroke-width", function(e,i) { return e.width;})
    @@ -149,21 +155,29 @@
    .domain([-1, 1])
    .range([.3, 1])

    var velocity = function(speed)
    {
    sin = Math.sin(speed)
    sc = d3.scale.linear()
    .domain([-1, 1])
    .range([0, 100])
    return sc(sin);
    }
    b = 1;
    d3.timer(function() {
    var elapsed = Date.now() - start
    var damp = .3

    rotate = function(d,i) {
    var speed = a * d.speed * elapsed
    var speed = a * d.speed * elapsed * .1
    return "rotate(" + speed + ")";
    };


    line
    line = d3.selectAll("g.line path")
    .attr("d", function(d,i) {
    //var speed = a * d.speed * elapsed
    //return line_maker( d, speed )
    var speed = a * d.speed * elapsed
    return line_maker( d, speed )
    })


  7. @enjalot enjalot revised this gist Dec 11, 2011. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion index.html
    Original file line number Diff line number Diff line change
    @@ -32,7 +32,7 @@
    var rings = [ ];
    var lines = [ ];

    var n = 12;
    var n = 14;
    var m = 100;

    for (i in d3.range(n))
  8. @enjalot enjalot revised this gist Dec 11, 2011. 2 changed files with 620 additions and 18 deletions.
    173 changes: 155 additions & 18 deletions index.html
    Original file line number Diff line number Diff line change
    @@ -9,54 +9,191 @@
    }

    rect {
    fill: none;
    stroke: #000;
    stroke-width: 2.5px;
    }

    /*
    .square:nth-child(2n + 1) rect {
    stroke: #fff;
    }
    */

    </style>
    </head>
    <body>
    <script type="text/javascript" src="http://mbostock.github.com/d3/d3.js?2.5.1"></script>
    <svg></svg>
    <script type="text/javascript" src="http://mbostock.github.com/d3/d3.js?2.6.0"></script>
    <script type="text/javascript" src="jwerty.js"></script>
    <script type="text/javascript">

    var w = 960,
    h = 500,
    start = Date.now();

    var rings = [
    {radius: 65 * 1, width: 16, speed: -3e-2},
    {radius: 65 * 2, width: 16, speed: -2e-2},
    {radius: 65 * 3, width: 16, speed: -1e-2},
    {radius: 65 * 4, width: 16, speed: 1e-2},
    {radius: 65 * 5, width: 16, speed: 2e-2},
    {radius: 65 * 6, width: 16, speed: 3e-2}
    ];
    var rings = [ ];
    var lines = [ ];

    var svg = d3.select("body").append("svg:svg")
    var n = 12;
    var m = 100;

    for (i in d3.range(n))
    {
    if(i < 3)
    var speed = (i-3) * 1e-2;
    else
    var speed = (i-2) * 1e-2;
    /*
    rings.push({
    radius: 65*i,
    width: 16,
    speed: speed,
    phase: i
    })
    */

    var data = d3.range(m)
    lines.push({
    //radius: 65*i,
    width: 4,
    speed: speed,
    phase: +i,
    index: +i,
    data: data
    })

    }

    var xscale = d3.scale.linear()
    .domain([0,m])
    .range([0, w])
    var yscale = d3.scale.linear()
    .domain([-1,1])
    .range([-10,10])


    var phase = d3.scale.linear()
    .domain( [0 , m] )
    .range( [ 1, 100 ])

    function line_maker( data, speed )
    {
    var svgline = d3.svg.line()
    .x(function(d,i)
    {
    return xscale(d);
    })
    .y(function(d,i)
    {
    var theta = phase(data.phase) * d/m * Math.PI * 2 * speed;
    //console.log("sin", Math.sin(theta), d)
    return 10 * (Math.sin(theta));
    })
    return svgline(data.data);
    }

    function lineEnter(d, i) {

    //console.log("line enter", d)
    d3.select(this).selectAll("g.line")
    .data([d])
    .enter().append("svg:path")
    .attr("class", "path")
    .attr("transform", function(_, i) { return "translate(" + [0, 40 * d.index] + ")"; })
    .attr("d", function(d,i) {
    return line_maker( d, 1 )
    }
    )
    .attr("stroke-width", function(e,i) { return e.width;})
    .attr("stroke", "#fff")
    .attr("fill", "none")

    }

    var svg = d3.select("svg")
    .attr("width", w)
    .attr("height", h)
    .append("svg:g")
    .attr("transform", "translate(" + w / 2 + "," + h / 2 + ")scale(.6)");
    //.attr("transform", "translate(" + w / 2 + "," + h / 2 + ")scale(.6)");

    var ring = svg.selectAll("g")
    var ring = svg.selectAll("g.ring")
    .data(rings)
    .enter().append("svg:g")
    .attr("class", "ring")
    .each(ringEnter);

    var line = svg.selectAll("g.line")
    .data(lines)
    .enter().append("svg:g")
    .attr("class", "line")
    .each(lineEnter);



    var a = 1.

    //jwerty.key('↑', function () {
    jwerty.key(',←', function () {
    a -= .1;
    });
    //jwerty.key('↓', function () {
    jwerty.key('→', function () {
    a += .1;
    });


    var color = d3.scale.linear()
    .domain([-1, 1])
    .interpolate(d3.interpolateRgb)
    .range(['#fff', '#000'])

    var opacity = d3.scale.linear()
    .domain([-1, 1])
    .range([.3, 1])

    b = 1;
    d3.timer(function() {
    var elapsed = Date.now() - start,
    rotate = function(d) { return "rotate(" + d.speed * elapsed + ")"; };
    var elapsed = Date.now() - start
    var damp = .3

    rotate = function(d,i) {
    var speed = a * d.speed * elapsed
    return "rotate(" + speed + ")";
    };


    line
    .attr("d", function(d,i) {
    //var speed = a * d.speed * elapsed
    //return line_maker( d, speed )
    })


    /*
    ring
    .attr("transform", rotate)
    .selectAll("rect")
    .attr("transform", rotate);
    .attr("transform", rotate)
    .attr("fill", function(d,i) {
    var eo = -1
    if(i % 2 == 0) eo = 1;
    var theta = damp * a * d.speed * elapsed * eo;
    var sin = Math.sin(theta)
    return color( sin );
    })
    .attr("fill-opacity", function(d) {
    var eo = -1
    if(i % 2 == 0) eo = 1;
    var theta = Math.sin(damp * a * d.speed * elapsed * eo)
    return opacity( theta );
    })
    .attr("stroke", function(d) {
    var eo = -1
    if(i % 2 == 0) eo = 1;
    var theta = Math.cos(damp * a * d.speed * elapsed * eo)
    return color( theta );
    })
    */


    });

    function ringEnter(d, i) {
    465 changes: 465 additions & 0 deletions jwerty.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,465 @@
    /*
    * jwerty - Awesome handling of keyboard events
    *
    * jwerty is a JS lib which allows you to bind, fire and assert key combination
    * strings against elements and events. It normalises the poor std api into
    * something easy to use and clear.
    *
    * This code is licensed under the MIT
    * For the full license see: http://keithamus.mit-license.org/
    * For more information see: http://keithamus.github.com/jwerty
    *
    * @author Keith Cirkel ('keithamus') <jwerty@keithcirkel.co.uk>
    * @license http://keithamus.mit-license.org/
    * @copyright Copyright © 2011, Keith Cirkel
    *
    */
    (function (global, exports) {

    // Helper methods & vars:
    var $d = global.document
    , $ = (global.jQuery || global.Zepto || global.ender || $d)
    , $$
    , $b
    , ke = 'keydown';

    function realTypeOf(v, s) {
    return (v === null) ? s === 'null'
    : (v === undefined) ? s === 'undefined'
    : (v.is && v instanceof $) ? s === 'element'
    : Object.prototype.toString.call(v).toLowerCase().indexOf(s) > 7;
    }

    if ($ === $d) {
    $$ = function (selector, context) {
    return selector ? $.querySelector(selector, context || $) : $;
    };

    $b = function (e, fn) { e.addEventListener(ke, fn, false); };
    $f = function (e, jwertyEv) {
    var ret = document.createEvent('Event')
    , i;

    ret.initEvent(ke, true, true);

    for (i in jwertyEv) ret[i] = jwertyEv[i];

    return (e || $).dispatchEvent(ret);
    }
    } else {
    $$ = function (selector, context, fn) { return $(selector || $d, context); };
    $b = function (e, fn) { $(e).bind(ke + '.jwerty', fn); };
    $f = function (e, ob) { $(e || $d).trigger($.Event(ke, ob)); };
    }

    // Private
    var _modProps = { 16: 'shiftKey', 17: 'ctrlKey', 18: 'altKey', 91: 'metaKey' };

    // Generate key mappings for common keys that are not printable.
    var _keys = {

    // MOD aka toggleable keys
    mods: {
    // Shift key, ⇧
    '⇧': 16, shift: 16,
    // CTRL key, on Mac: ⌃
    '⌃': 17, ctrl: 17,
    // ALT key, on Mac: ⌥ (Alt)
    '⌥': 18, alt: 18, option: 18,
    // META, on Mac: ⌘ (CMD), on Windows (Win), on Linux (Super)
    '⌘': 91, meta: 91, cmd: 91, 'super': 91, win: 91
    },

    // Normal keys
    keys: {
    // Backspace key, on Mac: ⌫ (Backspace)
    '⌫': 8, backspace: 8,
    // Tab Key, on Mac: ⇥ (Tab), on Windows ⇥⇥
    '⇥': 9, '⇆': 9, tab: 9,
    // Return key, ↩
    '↩': 13, 'return': 13, enter: 13, '⌅': 13,
    // Pause/Break key
    'pause': 19, 'pause-break': 19,
    // Caps Lock key, ⇪
    '⇪': 20, caps: 20, 'caps-lock': 20,
    // Escape key, on Mac: ⎋, on Windows: Esc
    '⎋': 27, escape: 27, esc: 27,
    // Space key
    space: 32,
    // Page-Up key, or pgup, on Mac: ↖
    '↖': 33, pgup: 33, 'page-up': 33,
    // Page-Down key, or pgdown, on Mac: ↘
    '↘': 34, pgdown: 34, 'page-down': 34,
    // END key, on Mac: ⇟
    '⇟': 35, end: 35,
    // HOME key, on Mac: ⇞
    '⇞': 36, home: 36,
    // Insert key, or ins
    ins: 45, insert: 45,
    // Delete key, on Mac: ⌫ (Delete)
    del: 45, 'delete': 45,

    // Left Arrow Key, or ←
    '←': 37, left: 37, 'arrow-left': 37,
    // Up Arrow Key, or ↑
    '↑': 38, up: 38, 'arrow-up': 38,
    // Right Arrow Key, or →
    '→': 39, right: 39, 'arrow-right': 39,
    // Up Arrow Key, or ↓
    '↓': 40, down: 40, 'arrow-down': 40,

    // odities, printing characters that come out wrong:
    // Num-Multiply, or *
    '*': 106, star: 106, asterisk: 106, multiply: 106,
    // Num-Plus or +
    '+': 107, 'plus': 107,
    // Num-Subtract, or -
    '-': 109, subtract: 109,
    //';': 186, //???
    // = or equals
    '=': 187, 'equals': 187,
    // Comma, or ,
    ',': 188, comma: 188,
    //'-': 189, //???
    // Period, or ., or full-stop
    '.': 190, period: 190, 'full-stop': 190,
    // Slash, or /, or forward-slash
    '/': 191, slash: 191, 'forward-slash': 191,
    // Tick, or `, or back-quote
    '`': 192, tick: 192, 'back-quote': 192,
    // Open bracket, or [
    '[': 219, 'open-bracket': 219,
    // Back slash, or \
    '\\': 220, 'back-slash': 220,
    // Close backet, or ]
    ']': 221, 'close-bracket': 221,
    // Apostraphe, or Quote, or '
    '\'': 222, quote: 222, apostraphe: 222
    }

    };

    // To minimise code bloat, add all of the NUMPAD 0-9 keys in a loop
    i = 95, n = 0;
    while(++i < 106) {
    _keys.keys['num-' + n] = i;
    ++n;
    }

    // To minimise code bloat, add all of the top row 0-9 keys in a loop
    i = 47, n = 0;
    while(++i < 58) {
    _keys.keys[n] = i;
    ++n;
    }

    // To minimise code bloat, add all of the F1-F25 keys in a loop
    i = 111, n = 1;
    while(++i < 136) {
    _keys.keys['f' + n] = i;
    ++n;
    }

    // To minimise code bloat, add all of the letters of the alphabet in a loop
    var i = 64;
    while(++i < 91) {
    _keys.keys[String.fromCharCode(i).toLowerCase()] = i;
    }

    function JwertyCode(jwertyCode) {
    var i
    , c
    , n
    , z
    , keyCombo
    , optionals
    , jwertyCodeFragment
    , rangeMatches
    , rangeI;

    // In-case we get called with an instance of ourselves, just return that.
    if (jwertyCode instanceof JwertyCode) return jwertyCode;

    // If jwertyCode isn't an array, cast it as a string and split into array.
    if (!realTypeOf(jwertyCode, 'array')) {
    jwertyCode = (String(jwertyCode)).replace(/\s/g, '').toLowerCase().
    match(/(?:\+,|[^,])+/g);
    }

    // Loop through each key sequence in jwertyCode
    for (i = 0, c = jwertyCode.length; i < c; ++i) {

    // If the key combo at this part of the sequence isn't an array,
    // cast as a string and split into an array.
    if (!realTypeOf(jwertyCode[i], 'array')) {
    jwertyCode[i] = String(jwertyCode[i])
    .match(/(?:\+\/|[^\/])+/g);
    }

    // Parse the key optionals in this sequence
    optionals = [], n = jwertyCode[i].length;
    while (n--) {

    // Begin creating the object for this key combo
    var jwertyCodeFragment = jwertyCode[i][n];

    keyCombo = {
    jwertyCombo: String(jwertyCodeFragment),
    shiftKey: false,
    ctrlKey: false,
    altKey: false,
    metaKey: false
    }

    // If jwertyCodeFragment isn't an array then cast as a string
    // and split it into one.
    if (!realTypeOf(jwertyCodeFragment, 'array')) {
    jwertyCodeFragment = String(jwertyCodeFragment).toLowerCase()
    .match(/(?:(?:[^\+])+|\+\+|^\+$)/g);
    }

    z = jwertyCodeFragment.length;
    while (z--) {

    // Normalise matching errors
    if (jwertyCodeFragment[z] === '++') jwertyCodeFragment[z] = '+';

    // Inject either keyCode or ctrl/meta/shift/altKey into keyCombo
    if (jwertyCodeFragment[z] in _keys.mods) {
    keyCombo[_modProps[_keys.mods[jwertyCodeFragment[z]]]] = true;
    } else if(jwertyCodeFragment[z] in _keys.keys) {
    keyCombo.keyCode = _keys.keys[jwertyCodeFragment[z]];
    } else {
    rangeMatches = jwertyCodeFragment[z].match(/^\[([^-]+\-?[^-]*)-([^-]+\-?[^-]*)\]$/);
    }
    }
    if (realTypeOf(keyCombo.keyCode, 'undefined')) {
    // If we picked up a range match earlier...
    if (rangeMatches && (rangeMatches[1] in _keys.keys) && (rangeMatches[2] in _keys.keys)) {
    rangeMatches[2] = _keys.keys[rangeMatches[2]];
    rangeMatches[1] = _keys.keys[rangeMatches[1]];

    // Go from match 1 and capture all key-comobs up to match 2
    for (rangeI = rangeMatches[1]; rangeI < rangeMatches[2]; ++rangeI) {
    optionals.push({
    altKey: keyCombo.altKey,
    shiftKey: keyCombo.shiftKey,
    metaKey: keyCombo.metaKey,
    ctrlKey: keyCombo.ctrlKey,
    keyCode: rangeI,
    jwertyCombo: String(jwertyCodeFragment)
    });

    }
    keyCombo.keyCode = rangeI;
    // Inject either keyCode or ctrl/meta/shift/altKey into keyCombo
    } else {
    keyCombo.keyCode = 0;
    }
    }
    optionals.push(keyCombo);

    }
    this[i] = optionals;
    }
    this.length = i;
    return this;
    }

    var jwerty = exports.jwerty = {
    /**
    * jwerty.event
    *
    * `jwerty.event` will return a function, which expects the first
    * argument to be a key event. When the key event matches `jwertyCode`,
    * `callbackFunction` is fired. `jwerty.event` is used by `jwerty.key`
    * to bind the function it returns. `jwerty.event` is useful for
    * attaching to your own event listeners. It can be used as a decorator
    * method to encapsulate functionality that you only want to fire after
    * a specific key combo. If `callbackContext` is specified then it will
    * be supplied as `callbackFunction`'s context - in other words, the
    * keyword `this` will be set to `callbackContext` inside the
    * `callbackFunction` function.
    *
    * @param {Mixed} jwertyCode can be an array, or string of key
    * combinations, which includes optinals and or sequences
    * @param {Function} callbackFucntion is a function (or boolean) which
    * is fired when jwertyCode is matched. Return false to
    * preventDefault()
    * @param {Object} callbackContext (Optional) The context to call
    * `callback` with (i.e this)
    *
    */
    event: function (jwertyCode, callbackFunction, callbackContext /*? this */) {

    // Construct a function out of callbackFunction, if it is a boolean.
    if (realTypeOf(callbackFunction, 'boolean')) {
    var bool = callbackFunction;
    callbackFunction = function () { return bool; }
    }

    jwertyCode = new JwertyCode(jwertyCode);

    // Initialise in-scope vars.
    var i = 0
    , c = jwertyCode.length - 1
    , returnValue
    , jwertyCodeIs;

    // This is the event listener function that gets returned...
    return function (event) {

    // if jwertyCodeIs returns truthy (string)...
    if ((jwertyCodeIs = jwerty.is(jwertyCode, event, i))) {
    // ... and this isn't the last key in the sequence,
    // incriment the key in sequence to check.
    if (i < c) {
    ++i;
    return;
    // ... and this is the last in the sequence (or the only
    // one in sequence), then fire the callback
    } else {
    returnValue = callbackFunction.call(
    callbackContext || this, event, jwertyCodeIs);

    // If the callback returned false, then we should run
    // preventDefault();
    if (returnValue === false) event.preventDefault();

    // Reset i for the next sequence to fire.
    i = 0;
    return;
    }
    }

    // If the event didn't hit this time, we should reset i to 0,
    // that is, unless this combo was the first in the sequence,
    // in which case we should reset i to 1.
    i = jwerty.is(jwertyCode, event) ? 1 : 0;
    }
    },

    /**
    * jwerty.is
    *
    * `jwerty.is` will return a boolean value, based on if `event` matches
    * `jwertyCode`. `jwerty.is` is called by `jwerty.event` to check
    * whether or not to fire the callback. `event` can be a DOM event, or
    * a jQuery/Zepto/Ender manufactured event. The properties of
    * `jwertyCode` (speficially ctrlKey, altKey, metaKey, shiftKey and
    * keyCode) should match `jwertyCode`'s properties - if they do, then
    * `jwerty.is` will return `true`. If they don't, `jwerty.is` will
    * return `false`.
    *
    * @param {Mixed} jwertyCode can be an array, or string of key
    * combinations, which includes optinals and or sequences
    * @param {KeyboardEvent} event is the KeyboardEvent to assert against
    * @param {Integer} i (Optional) checks the `i` key in jwertyCode
    * sequence
    *
    */
    is: function (jwertyCode, event, i /*? 0*/) {
    jwertyCode = new JwertyCode(jwertyCode);
    // Default `i` to 0
    i = i || 0;
    // We are only interesting in `i` of jwertyCode;
    jwertyCode = jwertyCode[i];
    // jQuery stores the *real* event in `originalEvent`, which we use
    // because it does annoything stuff to `metaKey`
    event = event.originalEvent || event;

    // We'll look at each optional in this jwertyCode sequence...
    var key
    , n = jwertyCode.length
    , returnValue = false;

    // Loop through each fragment of jwertyCode
    while (n--) {
    returnValue = jwertyCode[n].jwertyCombo;
    // For each property in the jwertyCode object, compare to `event`
    for (var p in jwertyCode[n]) {
    // ...except for jwertyCode.jwertyCombo...
    if (p !== 'jwertyCombo' && event[p] != jwertyCode[n][p]) returnValue = false;
    }
    // If this jwertyCode optional wasn't falsey, then we can return early.
    if (returnValue !== false) return returnValue;
    }
    return returnValue;
    },

    /**
    * jwerty.key
    *
    * `jwerty.key` will attach an event listener and fire
    * `callbackFunction` when `jwertyCode` matches. The event listener is
    * attached to `document`, meaning it will listen for any key events
    * on the page (a global shortcut listener). If `callbackContext` is
    * specified then it will be supplied as `callbackFunction`'s context
    * - in other words, the keyword `this` will be set to
    * `callbackContext` inside the `callbackFunction` function.
    *
    * @param {Mixed} jwertyCode can be an array, or string of key
    * combinations, which includes optinals and or sequences
    * @param {Function} callbackFunction is a function (or boolean) which
    * is fired when jwertyCode is matched. Return false to
    * preventDefault()
    * @param {Object} callbackContext (Optional) The context to call
    * `callback` with (i.e this)
    * @param {Mixed} selector can be a string, jQuery/Zepto/Ender object,
    * or an HTML*Element on which to bind the eventListener
    * @param {Mixed} selectorContext can be a string, jQuery/Zepto/Ender
    * object, or an HTML*Element on which to scope the selector
    *
    */
    key: function (jwertyCode, callbackFunction, callbackContext /*? this */, selector /*? document */, selectorContext /*? body */) {
    // Because callbackContext is optional, we should check if the
    // `callbackContext` is a string or element, and if it is, then the
    // function was called without a context, and `callbackContext` is
    // actually `selector`
    var realSelector = realTypeOf(callbackContext, 'element') || realTypeOf(callbackContext, 'string') ? callbackContext : selector
    // If `callbackContext` is undefined, or if we skipped it (and
    // therefore it is `realSelector`), set context to `global`.
    , realcallbackContext = realSelector === callbackContext ? global : callbackContext
    // Finally if we did skip `callbackContext`, then shift
    // `selectorContext` to the left (take it from `selector`)
    , realSelectorContext = realSelector === callbackContext ? selector : selectorContext;

    // If `realSelector` is already a jQuery/Zepto/Ender/DOM element,
    // then just use it neat, otherwise find it in DOM using $$()
    $b(realTypeOf(realSelector, 'element') ?
    realSelector : $$(realSelector, realSelectorContext)
    , jwerty.event(jwertyCode, callbackFunction, realcallbackContext));
    },

    /**
    * jwerty.fire
    *
    * `jwerty.fire` will construct a keyup event to fire, based on
    * `jwertyCode`. The event will be fired against `selector`.
    * `selectorContext` is used to search for `selector` within
    * `selectorContext`, similar to jQuery's
    * `$('selector', 'context')`.
    *
    * @param {Mixed} jwertyCode can be an array, or string of key
    * combinations, which includes optinals and or sequences
    * @param {Mixed} selector can be a string, jQuery/Zepto/Ender object,
    * or an HTML*Element on which to bind the eventListener
    * @param {Mixed} selectorContext can be a string, jQuery/Zepto/Ender
    * object, or an HTML*Element on which to scope the selector
    *
    */
    fire: function (jwertyCode, selector /*? document */, selectorContext /*? body */, i) {
    jwertyCode = new JwertyCode(jwertyCode);
    var realI = realTypeOf(selectorContext, 'number') ? selectorContext : i;

    // If `realSelector` is already a jQuery/Zepto/Ender/DOM element,
    // then just use it neat, otherwise find it in DOM using $$()
    $f(realTypeOf(selector, 'element') ?
    selector : $$(selector, selectorContext)
    , jwertyCode[realI || 0][0]);
    },

    KEYS: _keys
    };

    }(this, (typeof module !== 'undefined' && module.exports ? module.exports : this)));
  9. @mbostock mbostock revised this gist Nov 22, 2011. 1 changed file with 70 additions and 163 deletions.
    233 changes: 70 additions & 163 deletions index.html
    Original file line number Diff line number Diff line change
    @@ -1,173 +1,80 @@
    <!DOCTYPE html>
    <html>
    <head>
    <title>Spiral</title>
    <script type="text/javascript" src="http://mbostock.github.com/d3/d3.js"></script>
    <style type="text/css">
    <head>
    <meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
    <style type="text/css">

    body {
    font: 10px sans-serif;
    background: #888;
    }

    </style>
    </head>
    <body>
    <p>Click the spiral to pause</p>
    <script type="text/javascript">

    var w = 500;
    var h = 500;

    var r1 = 90;
    var r2 = 150;
    var r3 = 220;
    var r4 = 280;
    var r5 = 340;
    var r6 = 410;


    var size = 20

    var click = function()
    {
    running = !running
    if(running)
    setTimeout(update_circles, 80);

    }

    //setup svg canvas
    svg = d3.select("body")
    .append("svg:svg")
    .attr("width", w)
    .attr("height", h)
    //.attr("transform", "scale(.5 .5)")
    .attr("id", "spiral")
    .on("click", click)
    svg.append("svg:rect")
    .attr("class", "background_rect")
    .attr("width", "100%")
    .attr("height", "100%")
    .attr("stroke", "#000")
    .attr("stroke-width", 1)
    .attr("fill", "#888")

    chart = svg.append("svg:g")
    .attr("class", "base_group")
    .attr("transform", "translate(" + [w/2,h/2] + ")scale(.5 .5)");

    var make_circle = function(r,n,offset, step)
    {
    data = []
    for(i = 0; i < n; i++)
    {
    theta = offset + i * 2 * Math.PI / n
    sz = Math.abs(size/4 * Math.sin(i*Math.PI)) + size
    //sz = Math.abs(size/2 * Math.sin(theta)) + size
    data.push({x: r * Math.cos(theta), y: r * Math.sin(theta), angle: theta, index: i, size: sz })
    }
    return data
    }

    var circle_factory = function(name, data, offset)
    {

    var boxes = chart.selectAll("g." + name)
    .data(data, function(d) { return d.index })

    boxes.enter().append("svg:g")
    .attr("class", name)
    .append("svg:rect")
    /*
    .attr("width", function(d,i) { return d.size})
    .attr("height", function(d,i) { return d.size})
    .attr("stroke", function(d,i){
    if(d.index % 2 == 1) {
    return "#fff"
    }
    return "#000"
    })
    .attr("stroke-width", 2)
    .attr("fill", "none")
    .attr("transform", function(d,i) {
    a = offset + step * d.index;
    return "translate(" + [d.x ,d.y] + ")rotate(" + [a, d.size/2, d.size/2] + ")"
    })
    */

    boxes.selectAll("rect")
    .data(data, function(d) { return d.index })
    .attr("width", function(d,i) { return d.size})
    .attr("height", function(d,i) { return d.size})
    .attr("stroke", function(d,i){
    if(d.index % 2 == 1) {
    return "#fff"
    }
    return "#000"
    })
    .attr("stroke-width", 3)
    .attr("fill", "none")
    .attr("transform", function(d,i) {
    a = offset + step * d.index;
    //console.log("a,d",a,d);
    return "translate(" + [d.x ,d.y] + ")rotate(" + [a, d.size/2, d.size/2] + ")"
    })

    }

    rot = 0

    var update_circles = function() {
    rot += Math.PI / 24
    //console.log(rot)
    n = 18
    data1 = make_circle(r1, n, rot)
    step = 20
    offset = 15;
    circle_factory("one", data1, offset, step)
    //console.log(data)

    n = 30
    data2 = make_circle(r2, n, rot)
    step = 12
    offset = -15
    circle_factory("two", data2, offset, step)

    n = 44
    data3 = make_circle(r3, n, rot)
    step = 8
    offset = 15;
    circle_factory("three", data3, offset, step)

    n = 60
    data4 = make_circle(r4, n, rot)
    step = 6
    offset = -15;
    circle_factory("four", data4, offset, step)

    n = 80
    data5 = make_circle(r5, n, rot)
    step = 4
    offset = 15;
    circle_factory("five", data5, offset, step)

    n = 90
    data6 = make_circle(r6, n, rot)
    step = 4
    offset = -15;
    circle_factory("six", data6, offset, step)

    if(running)
    setTimeout(update_circles, 100);
    }

    rect {
    fill: none;
    stroke: #000;
    stroke-width: 2.5px;
    }

    running = true
    update_circles();
    .square:nth-child(2n + 1) rect {
    stroke: #fff;
    }

    //setTimeout(update_circles, 100);
    </style>
    </head>
    <body>
    <script type="text/javascript" src="http://mbostock.github.com/d3/d3.js?2.5.1"></script>
    <script type="text/javascript">

    var w = 960,
    h = 500,
    start = Date.now();

    var rings = [
    {radius: 65 * 1, width: 16, speed: -3e-2},
    {radius: 65 * 2, width: 16, speed: -2e-2},
    {radius: 65 * 3, width: 16, speed: -1e-2},
    {radius: 65 * 4, width: 16, speed: 1e-2},
    {radius: 65 * 5, width: 16, speed: 2e-2},
    {radius: 65 * 6, width: 16, speed: 3e-2}
    ];

    var svg = d3.select("body").append("svg:svg")
    .attr("width", w)
    .attr("height", h)
    .append("svg:g")
    .attr("transform", "translate(" + w / 2 + "," + h / 2 + ")scale(.6)");

    var ring = svg.selectAll("g")
    .data(rings)
    .enter().append("svg:g")
    .attr("class", "ring")
    .each(ringEnter);

    d3.timer(function() {
    var elapsed = Date.now() - start,
    rotate = function(d) { return "rotate(" + d.speed * elapsed + ")"; };

    ring
    .attr("transform", rotate)
    .selectAll("rect")
    .attr("transform", rotate);
    });

    function ringEnter(d, i) {
    var n = Math.floor(2 * Math.PI * d.radius / d.width * Math.SQRT1_2),
    k = 360 / n;

    d3.select(this).selectAll("g")
    .data(d3.range(n).map(function() { return d; }))
    .enter().append("svg:g")
    .attr("class", "square")
    .attr("transform", function(_, i) { return "rotate(" + i * k + ")translate(" + d.radius + ")"; })
    .append("svg:rect")
    .attr("x", -d.width / 2)
    .attr("y", -d.width / 2)
    .attr("width", d.width)
    .attr("height", d.width);
    }


    </script>
    </body>
    </script>
    </body>
    </html>
  10. @enjalot enjalot created this gist Nov 20, 2011.
    173 changes: 173 additions & 0 deletions index.html
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,173 @@
    <!DOCTYPE html>
    <html>
    <head>
    <title>Spiral</title>
    <script type="text/javascript" src="http://mbostock.github.com/d3/d3.js"></script>
    <style type="text/css">

    body {
    font: 10px sans-serif;
    }

    </style>
    </head>
    <body>
    <p>Click the spiral to pause</p>
    <script type="text/javascript">

    var w = 500;
    var h = 500;

    var r1 = 90;
    var r2 = 150;
    var r3 = 220;
    var r4 = 280;
    var r5 = 340;
    var r6 = 410;


    var size = 20

    var click = function()
    {
    running = !running
    if(running)
    setTimeout(update_circles, 80);

    }

    //setup svg canvas
    svg = d3.select("body")
    .append("svg:svg")
    .attr("width", w)
    .attr("height", h)
    //.attr("transform", "scale(.5 .5)")
    .attr("id", "spiral")
    .on("click", click)
    svg.append("svg:rect")
    .attr("class", "background_rect")
    .attr("width", "100%")
    .attr("height", "100%")
    .attr("stroke", "#000")
    .attr("stroke-width", 1)
    .attr("fill", "#888")

    chart = svg.append("svg:g")
    .attr("class", "base_group")
    .attr("transform", "translate(" + [w/2,h/2] + ")scale(.5 .5)");

    var make_circle = function(r,n,offset, step)
    {
    data = []
    for(i = 0; i < n; i++)
    {
    theta = offset + i * 2 * Math.PI / n
    sz = Math.abs(size/4 * Math.sin(i*Math.PI)) + size
    //sz = Math.abs(size/2 * Math.sin(theta)) + size
    data.push({x: r * Math.cos(theta), y: r * Math.sin(theta), angle: theta, index: i, size: sz })
    }
    return data
    }

    var circle_factory = function(name, data, offset)
    {

    var boxes = chart.selectAll("g." + name)
    .data(data, function(d) { return d.index })

    boxes.enter().append("svg:g")
    .attr("class", name)
    .append("svg:rect")
    /*
    .attr("width", function(d,i) { return d.size})
    .attr("height", function(d,i) { return d.size})
    .attr("stroke", function(d,i){
    if(d.index % 2 == 1) {
    return "#fff"
    }
    return "#000"
    })
    .attr("stroke-width", 2)
    .attr("fill", "none")
    .attr("transform", function(d,i) {
    a = offset + step * d.index;
    return "translate(" + [d.x ,d.y] + ")rotate(" + [a, d.size/2, d.size/2] + ")"
    })
    */

    boxes.selectAll("rect")
    .data(data, function(d) { return d.index })
    .attr("width", function(d,i) { return d.size})
    .attr("height", function(d,i) { return d.size})
    .attr("stroke", function(d,i){
    if(d.index % 2 == 1) {
    return "#fff"
    }
    return "#000"
    })
    .attr("stroke-width", 3)
    .attr("fill", "none")
    .attr("transform", function(d,i) {
    a = offset + step * d.index;
    //console.log("a,d",a,d);
    return "translate(" + [d.x ,d.y] + ")rotate(" + [a, d.size/2, d.size/2] + ")"
    })

    }

    rot = 0

    var update_circles = function() {
    rot += Math.PI / 24
    //console.log(rot)
    n = 18
    data1 = make_circle(r1, n, rot)
    step = 20
    offset = 15;
    circle_factory("one", data1, offset, step)
    //console.log(data)

    n = 30
    data2 = make_circle(r2, n, rot)
    step = 12
    offset = -15
    circle_factory("two", data2, offset, step)

    n = 44
    data3 = make_circle(r3, n, rot)
    step = 8
    offset = 15;
    circle_factory("three", data3, offset, step)

    n = 60
    data4 = make_circle(r4, n, rot)
    step = 6
    offset = -15;
    circle_factory("four", data4, offset, step)

    n = 80
    data5 = make_circle(r5, n, rot)
    step = 4
    offset = 15;
    circle_factory("five", data5, offset, step)

    n = 90
    data6 = make_circle(r6, n, rot)
    step = 4
    offset = -15;
    circle_factory("six", data6, offset, step)

    if(running)
    setTimeout(update_circles, 100);
    }


    running = true
    update_circles();

    //setTimeout(update_circles, 100);


    </script>
    </body>
    </html>