[ Launch: Higher-order fun ] 6532277 by davidmason
[ Launch: Tributary inlet ] 6026457 by codemiller
-
-
Save davidmason/6532277 to your computer and use it in GitHub Desktop.
Higher-order fun
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{"description":"Higher-order fun","endpoint":"","display":"svg","public":true,"require":[],"fileconfigs":{"inlet.js":{"default":true,"vim":false,"emacs":false,"fontSize":24},"_.md":{"default":true,"vim":false,"emacs":false,"fontSize":16},"config.json":{"default":true,"vim":false,"emacs":false,"fontSize":16},"style.css":{"default":true,"vim":false,"emacs":false,"fontSize":16},"visualise.js":{"default":true,"vim":false,"emacs":false,"fontSize":16},"func.js":{"default":true,"vim":false,"emacs":false,"fontSize":24},"data.js":{"default":true,"vim":false,"emacs":false,"fontSize":24},"map.js":{"default":true,"vim":false,"emacs":false,"fontSize":24},"filter.js":{"default":true,"vim":false,"emacs":false,"fontSize":24},"fold.js":{"default":true,"vim":false,"emacs":false,"fontSize":24},"glue.js":{"default":true,"vim":false,"emacs":false,"fontSize":24},"extras.js":{"default":true,"vim":false,"emacs":false,"fontSize":24}},"fullscreen":false,"play":false,"loop":false,"restart":false,"autoinit":true,"pause":true,"loop_type":"period","bv":false,"nclones":15,"clone_opacity":0.4,"duration":3000,"ease":"linear","dt":0.01,"thumbnail":"http://i.imgur.com/FY2NBW8.png"} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Data | |
imageDir = 'https://raw.github.com/codemiller/higher-order-fun/gh-pages/images'; | |
famousList = [{ 'name': 'Colonel Meow', 'kind': 'cat', 'image': [{'source': imageDir + '/cm.jpg'}], 'anagram': 'Welcome Loon', 'facebook': 198145, 'twitter': 4573}, | |
{ 'name': 'Guido van Rossum', 'kind': 'human', 'image': [{'source': imageDir + '/gv.jpg'}], 'anagram': 'Gun Sumo Advisor', 'facebook': 2693, 'twitter': 35528}, | |
{ 'name': 'Business Cat', 'kind': 'cat', 'image': [{'source': imageDir + '/bc.jpg'}], 'anagram': 'Bans Cuss Tie', 'facebook': 21767, 'twitter': 93}, | |
{ 'name': 'Brendan Eich', 'kind': 'human', 'image': [{'source': imageDir + '/be.jpg'}], 'anagram': 'Bare Chinned', 'facebook': 441, 'twitter': 24648}, | |
{ 'name': 'Rich Hickey', 'kind': 'human', 'image': [{'source': imageDir + '/rh.jpg'}], 'anagram': 'Heck I Cry Hi', 'facebook': 2332, 'twitter': 10927}, | |
{ 'name': 'Grumpy Cat', 'kind': 'cat', 'image': [{'source': imageDir + '/gc.jpg'}], 'anagram': 'My Crap Gut', 'facebook': 1309067, 'twitter': 110074}, | |
{ 'name': 'Yukihiro Matsumoto', 'kind': 'human', 'image': [{'source': imageDir + '/ym.jpg'}], 'anagram': 'Imitators You Hokum', 'facebook': 1564, 'twitter': 26501}, | |
{ 'name': 'Lil Bub', 'kind': 'cat', 'image': [{'source': imageDir + '/lb.jpg'}], 'anagram': 'Bub Ill', 'facebook': 198536, 'twitter': 20946}]; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Extra data | |
mo = {'source': imageDir + '/mo.png', 'height': 50, 'width': 100, 'xOffset': 37, 'yOffset': 110}; | |
mouth = {'source': imageDir + '/lips.png', 'height': 30, 'width': 80, 'xOffset': 45, 'yOffset': 132}; | |
beard = {'source': imageDir + '/beard.png', 'height': 105, 'width': 115, 'xOffset': 25, 'yOffset': 114}; | |
glasses = {'source': imageDir + '/glasses.png', 'height': 60, 'width': 150, 'xOffset': 10, 'yOffset': 70}; | |
hat = {'source': imageDir + '/fedora.png', 'height': 93, 'width': 200, 'xOffset': -8, 'yOffset': -17}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Filter names; consonants only | |
noVowels = function(name) { | |
return _.filter(name, function(l) { | |
return ! _.contains(['a','e','i','o','u'], l) | |
}).join(''); | |
} | |
nameConsonants = makeDisplayText(_.pluck(famousList, 'name'), | |
noVowels); | |
// Filter items | |
oneKind = function(kind) { | |
return function(item) { return item.kind === kind } | |
} | |
filtered = _.filter(famousList, oneKind('cat')); | |
filterDemo = function() { | |
newItems = extendObjects(famousList, pigLatinNames); | |
visualise(filtered); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Use fold to sum data for the list | |
twitFollowers = makeDisplayText(_.pluck(famousList, 'twitter'), | |
_.identity) | |
grabValue = function(item) { | |
return item.twitter | |
} | |
total = function(list, getValue) { | |
return _.foldl(list, function(acc, x) { | |
return acc + getValue(x); | |
}, 0); | |
} | |
catTotal = total(_.filter(famousList, oneKind('cat')), grabValue); | |
humanTotal = total(_.filter(famousList, oneKind('human')), grabValue); | |
/* | |
visualiseText("Cat popularity score: " + catTotal + | |
",</br> Human popularity score: " + humanTotal); | |
*/ | |
// Use fold to reverse a list | |
reverse = function(list) { | |
return _.foldl(list, function(acc, x) { | |
return cons(x, acc); | |
}, []); | |
} | |
costumeItems = [hat, glasses, mo, beard, mouth]; | |
applyDisguise = function(item) { | |
return {'image':deepCloneArray(item.image).concat(costumeItems)} | |
}; | |
disguises = _.map(famousList, applyDisguise); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Useful functions | |
// Takes an element and a list | |
// Returns a new list with that element on the head of the list | |
cons = function(element, list) { | |
return [element].concat(list); | |
} | |
// Takes a binary function and two arrays of arguments | |
// Returns the result of applying the function to each pair of zipped arguments | |
zipWith = function(func, arr0, arr1) { | |
return _.zip(arr0, arr1).map(function(params) { | |
return func(params[0], params[1]) | |
}); | |
} | |
// Takes a list of objects and a list of the same length containing objects to merge with those in the first list | |
// Returns a new list of objects, each of which contains the key/value pairs of both objects at corresponding indices in the input lists | |
// Key/value pairs of objects in the extension list will override those in the original list | |
extendObjects = function(objectList, extensionObjectList) { | |
return zipWith(function(obj, ext) { | |
return _.extend({}, obj, ext) | |
}, | |
objectList, extensionObjectList); | |
} | |
// To clone an object | |
deepClone = function(item) { | |
return _.extend({}, item); | |
} | |
// To clone an array | |
deepCloneArray = function(array) { | |
return _.map(array, function(item) { | |
if (_.isString(item) || _.isNumber(item)) { return item } | |
if (_.isArray(item)) { return deepCloneArray(item) } | |
if (_.isObject(item)) { return deepClone(item) } | |
return item; | |
}); | |
} | |
// Partial function from Underscore.js 1.4.4 and higher | |
// Reproduced here as Tributary is on Underscore 1.4.0 | |
_.partial = function(func) { | |
var args = Array.prototype.slice.call(arguments, 1); | |
return function() { | |
return func.apply(this, args.concat(Array.prototype.slice.call(arguments))); | |
}; | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Gluing it all together | |
displayScores = function(scorer, list) { | |
return extendObjects(list, makeDisplayText(list, scorer)); | |
} | |
rank = function(sortFunc, list) { | |
return reverse(_.sortBy(list, sortFunc)); | |
} | |
applyFilter = function(filterFunc, list) { | |
return _.filter(list, filterFunc) | |
} | |
transformFirst = function(transformFunc, list) { | |
var firstItem = _.head(list); | |
return cons(_.extend({}, firstItem, transformFunc(firstItem)), | |
_.tail(list)); | |
} | |
transformer = function(transformFunc, filterFunc, scoreFunc) { | |
return _.compose(_.partial(transformFirst, transformFunc), | |
_.partial(applyFilter, filterFunc), | |
_.partial(rank, scoreFunc), | |
_.partial(displayScores, scoreFunc)); | |
} | |
listTransformer = transformer(applyDisguise, | |
_.identity, | |
grabValue); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// mapDemo(); | |
filterDemo(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// To create display text | |
makeDisplayText = function(list, func) { | |
return _.map(list, function(n) { | |
return { 'displayText': func(n) } | |
}); | |
} | |
// Create anagram names | |
anagrams = _.pluck(famousList, 'anagram'); | |
anagramNames = makeDisplayText(anagrams, _.identity); | |
// Translate a string into Pig Latin | |
pigify = function(str) { | |
return _.map(str.split(' '), function(word) { | |
if (word.length < 2) return word | |
return word.charAt(1).toUpperCase() | |
+ word.slice(2) | |
+ word.charAt(0).toLowerCase() + 'ay'; | |
}).join(' ') | |
}; | |
// Create Pig Latin name for each list item | |
pigLatinNames = makeDisplayText(_.pluck(famousList, 'name'), | |
pigify); | |
// Create list with extra image for each item | |
mappedMo = _.map(famousList, function(item) { | |
return { 'image': deepCloneArray(item.image).concat([mo]) } | |
}); | |
mapDemo = function () { | |
newItems = extendObjects(famousList, pigLatinNames); | |
visualise(newItems); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
.cm-s-lesser-dark.CodeMirror { background: #1E2426; color: #696969; } | |
.cm-s-lesser-dark div.CodeMirror-selected {background: #064968 !important; } | |
.cm-s-lesser-dark span.cm-variable { color:#22EFFF; } | |
.cm-s-lesser-dark span.cm-variable-2 { color: #FFCCB4; } | |
.cm-s-lesser-dark span.cm-variable-3 { color: #FFF; } | |
.cm-s-lesser-dark span.cm-string { color: #76EE00; } | |
.cm-s-lesser-dark span.cm-string-2 {color: #76EE00; } | |
.cm-s-lesser-dark span.cm-def {color: #FFCCB4; opacity: 1.0 } | |
.cm-s-lesser-dark span.cm-bracket { color: #EBEFE7; } | |
.cm-s-lesser-dark pre { color:#FFF; } | |
.cm-s-lesser-dark span.cm-comment { color: #AFB4B4; } | |
.cm-s-lesser-dark span.cm-property {color: #FDA676; } | |
.cm-s-lesser-dark span.cm-number { color: #FF92EE; } | |
.cm-s-lesser-dark span.cm-keyword { color: #FFFF18; } | |
.cm-s-lesser-dark .CodeMirror-cursor { border-left: 1px solid white !important; } | |
body { background-color: rgb(200,185,235); } | |
.listEnd { color: black; font-family: serif; font-size: 440px; } | |
.listComma { color: black; font-family: serif; font-size: 250px; } | |
.itemText { color: black; font-size: 25px; text-align: center; min-height: 88px; padding: 3px; background-color: white; } | |
.textOutput { color: #330066; font-size: 40px; font-weight: bold; padding: 5px; line-height: 1em; } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Presentation logic | |
var listStart = {'char': '[', 'x': -10, 'y': 325}; | |
var listEnd = {'char': ']', 'x': 120, 'y': 325}; | |
var listPositions = [{'x': 100, 'y': 50}, {'x': 325, 'y': 50}, {'x': 550, 'y': 50}, {'x': 775, 'y': 50}, | |
{'x': 100, 'y': 440}, {'x': 325, 'y': 440}, {'x': 550, 'y': 440}, {'x': 775, 'y': 440}]; | |
var isLast = function(d, listPos, numItems) { | |
return d.x === _.last(_.take(listPos, numItems)).x && d.y === _.last(_.take(listPos, numItems)).y; | |
} | |
visualise = function(newListItems) { | |
var svg = d3.select('svg'); | |
var listDecoration = svg.append('g').classed('listEnd', true); | |
var listData = svg.append('g').classed('listData', true); | |
var textNode = listDecoration.selectAll('text'); | |
var listDecoData = newListItems.length > 0 ? textNode.data([listStart]) : textNode.data([listStart, listEnd]); | |
var listDeco = listDecoData.enter() | |
.append('text'); | |
var listDecoratorAttributes = listDeco.attr('x', function (d) { return d.x }) | |
.attr('y', function (d) { return d.y }) | |
.text(function (d) { return d.char }); | |
var listItems = extendObjects(newListItems, _.take(listPositions, newListItems.length)); | |
var itemImages = listData.selectAll('g').data(listItems).enter().append('g').classed('imageGroup', true); | |
var items = itemImages.append('image') | |
.classed('baseImage', true) | |
.attr('xlink:href', function(d) { return _.first(d.image).source } ) | |
.attr('x', function(d) { return d.x }) | |
.attr('y', function(d) { return d.y }) | |
.attr('height', 225) | |
.attr('width', 175); | |
var extraImages = itemImages.selectAll('g').data(function(d) { return extendObjects(_.rest(d.image), _.times(d.image.length-1, function() { return {'px': d.x, 'py': d.y} })) }) | |
.enter().append('g').classed('extraImageGroup', true); | |
var images = extraImages.append('image') | |
.classed('extraImage', true) | |
.attr('xlink:href', function(d) { return d.source }) | |
.attr('x', function(d) { return d.px + d.xOffset }) | |
.attr('y', function(d) { return d.py + d.yOffset }) | |
.attr('height', function(d) { return d.height}) | |
.attr('width', function(d) {return d.width}); | |
var namesText = listData.selectAll('.listData') | |
.data(listItems) | |
.enter() | |
.append('foreignObject'); | |
var textLabels = namesText.attr('x', function(d) { return d.x }) | |
.attr('y', function(d) { return d.y + 223 }) | |
.attr('width', 175) | |
.attr('height', 88) | |
.append('xhtml:body') | |
.html(function(d) { | |
return '<div class="itemText">' | |
+ (typeof d.displayText === 'undefined' ? d.name : d.displayText) | |
+ '</div>' | |
}); | |
var listDecoText = listData.selectAll('.listData') | |
.data(listItems) | |
.enter() | |
.append('text') | |
.classed('listComma', function(d) { return ! isLast(d, listPositions, newListItems.length) }) | |
.classed('listEnd', function(d) { return isLast(d, listPositions, newListItems.length) }); | |
var listDecos = listDecoText.attr('x', function(d) { if (isLast(d, listPositions, newListItems.length)) { return d.x + 135 } else { return d.x + 165 } }) | |
.attr('y', function(d) { if (isLast(d, listPositions, newListItems.length)) { return d.y + 275 } else { return d.y + 305 } }) | |
.text(function (d) { if (isLast(d, listPositions, newListItems.length)) { return listEnd.char } else { return ',' }}); | |
return listItems; | |
} | |
visualiseText = function(string) { | |
var svg = d3.select('svg'); | |
var textDisplay = svg.append('g').classed('textDisplay', true); | |
var textOutput = textDisplay.selectAll('text').data([string]).enter().append('foreignObject'); | |
var textDisplayAttr = textOutput.attr('x', 30).attr('y', 800).attr('width', 800).attr('height', 200) | |
.append('xhtml:body').html(function(d) { return '<div class="textOutput">' + d + '</div>' }); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment