[ Launch: Tributary inlet ] 6026457 by codemiller
-
-
Save katiejots/6026457 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":26},"_.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":26},"data.js":{"default":true,"vim":false,"emacs":false,"fontSize":26},"map.js":{"default":true,"vim":false,"emacs":false,"fontSize":26},"filter.js":{"default":true,"vim":false,"emacs":false,"fontSize":26},"fold.js":{"default":true,"vim":false,"emacs":false,"fontSize":26},"glue.js":{"default":true,"vim":false,"emacs":false,"fontSize":26},"extras.js":{"default":true,"vim":false,"emacs":false,"fontSize":26}},"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","ajax-caching":true} |
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
//imageDir = 'http://localhost/hof/images' | |
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': 'Grumpy Cat', 'kind': 'cat', 'image': [{'source': imageDir + '/gc.jpg'}], 'anagram': 'My Crap Gut', 'facebook': 1309067, 'twitter': 110074}, | |
{ 'name': 'Rich Hickey', 'kind': 'human', 'image': [{'source': imageDir + '/rh.jpg'}], 'anagram': 'Heck I Cry Hi', 'facebook': 2332, 'twitter': 10927}, | |
{ 'name': 'Lil Bub', 'kind': 'cat', 'image': [{'source': imageDir + '/lb.jpg'}], 'anagram': 'Bub Ill', 'facebook': 198536, 'twitter': 20946}, | |
{ 'name': 'Yukihiro Matsumoto', 'kind': 'human', 'image': [{'source': imageDir + '/ym.jpg'}], 'anagram': 'Imitators You Hokum', 'facebook': 1564, 'twitter': 26501}]; |
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
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}; | |
crown = {'source': imageDir + '/crown.png', 'height': 100, 'width': 135, 'xOffset': 13, 'yOffset': 0}; | |
prize = {'source': imageDir + '/winner.png', 'height': 133, 'width': 100, 'xOffset': 90, 'yOffset': 125}; |
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
filterVisualise = function() { | |
// Filter names; consonants only | |
var noVowels = function(name) { | |
return _.filter(name, function(l) { | |
return ! _.contains(['a','e','i','o','u'], l); | |
}).join(''); | |
}; | |
var nameCons = | |
makeDisplayText(_.pluck(famousList, 'name'), | |
noVowels); | |
// Filter items | |
var oneKind = function(kind) { | |
return function(item) { return item.kind === kind }; | |
}; | |
var filtered = _.filter(famousList, oneKind('cat')); | |
return [extendObjects(famousList, nameCons)]; | |
}; |
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
foldVisualise = function() { | |
// Code we are reusing (repeated here for ease of reference) | |
var oneKind = function(kind) { | |
return function(item) {return item.kind === kind}; | |
}; | |
// Use fold to sum data for the list | |
var total = function(list, getValue) { | |
return _.foldl(list, function(acc, x) { | |
return acc + getValue(x); | |
}, 0); | |
}; | |
var grabValue = function(item) { | |
return item.facebook; | |
}; | |
var catTotal = total(_.filter(famousList, | |
oneKind('cat')), grabValue); | |
var humanTotal = total(_.filter(famousList, | |
oneKind('human')), grabValue); | |
// Use fold to reverse a list | |
var reverse = function(list) { | |
return _.foldl(list, function(acc, x) { | |
return cons(x, acc); | |
}, []); | |
}; | |
var costumeItems = [hat, glasses, mo, beard, mouth]; | |
var applyCostume = function(item) { | |
return { | |
'image':deepCloneArr(item.image) | |
.concat(costumeItems) | |
}; | |
}; | |
var disguises = _.map(famousList, applyCostume); | |
var text = "Cat popularity score: " + catTotal | |
+ ",</br> Human popularity score: " + humanTotal; | |
var fbTotal = | |
makeDisplayText(_.pluck(famousList, 'facebook'), | |
_.identity); | |
return [extendObjects(famousList, fbTotal), text]; | |
}; |
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 | |
deepCloneArr = 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; | |
}); | |
}; | |
// Takes a list and a function, and transforms each item in the | |
// list with that function, returning a list of objects containing | |
// each result value as the property 'displayText'. Can be used with | |
// extendObjects() to add a displayText property to each object in a list. | |
makeDisplayText = function(list, func) { | |
return _.map(list, function(n) { | |
return { 'displayText': func(n) }; | |
}); | |
}; | |
// 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))); | |
}; | |
}; | |
// The Underscore times function is not working properly, so overriding for now | |
_.times = function(n, iterator) { | |
var accum = []; | |
for (var i = 0; i < n; i++) accum.push(iterator(i)); | |
return accum; | |
}; |
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
glueVisualise = function() { | |
// Code we are reusing (repeated here for ease of reference) | |
var oneKind = function(kind) { | |
return function(item) { return item.kind === kind }; | |
}; | |
var grabValue = function(item) { | |
return item.facebook; | |
}; | |
var total = function(list, getValue) { | |
return _.foldl(list, function(acc, x) { | |
return acc + getValue(x); | |
}, 0); | |
}; | |
var catTotal = total(_.filter(famousList, oneKind('cat')), grabValue); | |
var humanTotal = total(_.filter(famousList, oneKind('human')), grabValue); | |
var reverse = function(list) { | |
return _.foldl(list, function(acc, x) { | |
return cons(x, acc); | |
}, []); | |
}; | |
var costumeItems = [crown, prize]; | |
var applyCostume = function(item) { | |
return {'image':deepCloneArr(item.image).concat(costumeItems)}; | |
}; | |
// Four functions to transform list | |
var displayScores = function(scorer, list) { | |
return extendObjects(list, | |
makeDisplayText(list, scorer)); | |
}; | |
var rank = function(sortFunc, list) { | |
return reverse(_.sortBy(list, sortFunc)); | |
}; | |
var applyFilter = function(filterFunc, list) { | |
return _.filter(list, filterFunc); | |
}; | |
var transformNumOne = function(transformFunc, list) { | |
var firstItem = _.head(list); | |
return cons(_.extend({}, firstItem, | |
transformFunc(firstItem)), | |
_.tail(list)); | |
}; | |
var transformer = function(transformFunc, filterFunc, scoreFunc) { | |
return _.compose(_.partial(transformNumOne, transformFunc), | |
_.partial(applyFilter, filterFunc), | |
_.partial(rank, scoreFunc), | |
_.partial(displayScores, scoreFunc)); | |
}; | |
var revealPopularity = transformer(applyCostume, | |
_.identity, | |
grabValue); | |
var text = "Cat popularity score: " + catTotal | |
+ ",</br> Human popularity score: " + humanTotal; | |
return [revealPopularity(famousList), text]; | |
}; |
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
var initialVisualise = function() { | |
var anagrams = _.pluck(famousList, 'anagram'); | |
var anagramNames = makeDisplayText(anagrams, | |
_.identity); | |
var newItems = extendObjects(famousList, | |
anagramNames); | |
return [newItems]; | |
}; | |
visualise.apply(this, initialVisualise()); | |
//visualise.apply(this, mapVisualise()); | |
//visualise.apply(this, filterVisualise()); | |
//visualise.apply(this, foldVisualise()); | |
//visualise.apply(this, glueVisualise()); |
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
mapVisualise = function() { | |
// Translate a string into Pig Latin | |
var 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 | |
var latNames = | |
makeDisplayText(_.pluck(famousList, 'name'), | |
pigify); | |
// Create list with extra image for each item | |
var mappedMo = _.map(famousList, function(item) { | |
return { | |
'image':deepCloneArr(item.image).concat([mo]) | |
}; | |
}); | |
return [extendObjects(famousList, latNames)]; | |
}; |
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: 400px; } | |
.listComma { color: black; font-family: serif; font-size: 200px; } | |
.itemText { color: black; font-size: 25px; text-align: center; min-height: 88px; padding: 3px; background-color: white; } | |
.textOutput { color: #330066; font-size: 30px; font-weight: bold; padding: 5px; line-height: 1em; } | |
#panel { width:50%; } |
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': -20, 'y': 285}; | |
var listEnd = {'char': ']', 'x': 120, 'y': 285}; | |
var row1 = 23; | |
var row2 = 365; | |
var row3 = 707; | |
var col1 = 80; | |
var col2 = 300; | |
var col3 = 520; | |
var listPositions = [{'x': col1, 'y': row1}, {'x': col2, 'y': row1}, {'x': col3, 'y': row1}, | |
{'x': col1, 'y': row2}, {'x': col2, 'y': row2}, {'x': col3, 'y': row2}, | |
{'x': col1, 'y': row3}, {'x': col2, 'y': row3}]; | |
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 newText = arguments[1]; | |
var svg = d3.select('svg'); | |
if (newText) { | |
var textDisplay = svg.append('g').classed('textDisplay', true); | |
var textOutput = textDisplay.selectAll('text').data([newText]).enter().append('foreignObject'); | |
var textDisplayAttr = textOutput.attr('x', 80).attr('y', 1015).attr('width', 800).attr('height', 200) | |
.append('xhtml:body').html(function(d) { return '<div class="textOutput">' + d + '</div>' }); | |
} | |
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', 75) | |
.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 + 138 } else { return d.x + 170 } }) | |
.attr('y', function(d) { if (isLast(d, listPositions, newListItems.length)) { return d.y + 262 } else { return d.y + 288} }) | |
.text(function (d) { if (isLast(d, listPositions, newListItems.length)) { return listEnd.char } else { return ',' }}); | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment