Difference between revisions of "Template:Genspace"
Line 144: | Line 144: | ||
<script> | <script> | ||
+ | (function() { | ||
+ | |||
+ | function jetpack(d3) { | ||
+ | d3.selection.prototype.translate = function(xy) { | ||
+ | return this.attr('transform', function(d,i) { | ||
+ | return 'translate('+[typeof xy == 'function' ? xy(d,i) : xy]+')'; | ||
+ | }); | ||
+ | }; | ||
+ | |||
+ | d3.transition.prototype.translate = function(xy) { | ||
+ | return this.attr('transform', function(d,i) { | ||
+ | return 'translate('+[typeof xy == 'function' ? xy(d,i) : xy]+')'; | ||
+ | }); | ||
+ | }; | ||
+ | |||
+ | d3.selection.prototype.tspans = function(lines, lh) { | ||
+ | return this.selectAll('tspan') | ||
+ | .data(lines) | ||
+ | .enter() | ||
+ | .append('tspan') | ||
+ | .text(function(d) { return d; }) | ||
+ | .attr('x', 0) | ||
+ | .attr('dy', function(d,i) { return i ? lh || 15 : 0; }); | ||
+ | }; | ||
+ | |||
+ | d3.selection.prototype.append = | ||
+ | d3.selection.enter.prototype.append = function(name) { | ||
+ | var n = d3_parse_attributes(name), s; | ||
+ | //console.log(name, n); | ||
+ | name = n.attr ? n.tag : name; | ||
+ | name = d3_selection_creator(name); | ||
+ | s = this.select(function() { | ||
+ | return this.appendChild(name.apply(this, arguments)); | ||
+ | }); | ||
+ | return n.attr ? s.attr(n.attr) : s; | ||
+ | }; | ||
+ | |||
+ | d3.selection.prototype.insert = | ||
+ | d3.selection.enter.prototype.insert = function(name, before) { | ||
+ | var n = d3_parse_attributes(name), s; | ||
+ | name = n.attr ? n.tag : name; | ||
+ | name = d3_selection_creator(name); | ||
+ | before = d3_selection_selector(before); | ||
+ | s = this.select(function() { | ||
+ | return this.insertBefore(name.apply(this, arguments), before.apply(this, arguments) || null); | ||
+ | }); | ||
+ | return n.attr ? s.attr(n.attr) : s; | ||
+ | }; | ||
+ | |||
+ | var d3_parse_attributes_regex = /([\.#])/g; | ||
+ | |||
+ | function d3_parse_attributes(name) { | ||
+ | if (typeof name === "string") { | ||
+ | var attr = {}, | ||
+ | parts = name.split(d3_parse_attributes_regex), p; | ||
+ | name = parts.shift(); | ||
+ | while ((p = parts.shift())) { | ||
+ | if (p == '.') attr['class'] = attr['class'] ? attr['class'] + ' ' + parts.shift() : parts.shift(); | ||
+ | else if (p == '#') attr.id = parts.shift(); | ||
+ | } | ||
+ | return attr.id || attr['class'] ? { tag: name, attr: attr } : name; | ||
+ | } | ||
+ | return name; | ||
+ | } | ||
+ | |||
+ | function d3_selection_creator(name) { | ||
+ | return typeof name === "function" ? name : (name = d3.ns.qualify(name)).local ? function() { | ||
+ | return this.ownerDocument.createElementNS(name.space, name.local); | ||
+ | } : function() { | ||
+ | return this.ownerDocument.createElementNS(this.namespaceURI, name); | ||
+ | }; | ||
+ | } | ||
+ | |||
+ | function d3_selection_selector(selector) { | ||
+ | return typeof selector === "function" ? selector : function() { | ||
+ | return this.querySelector(selector); | ||
+ | }; | ||
+ | } | ||
+ | |||
+ | d3.wordwrap = function(line, maxCharactersPerLine) { | ||
+ | var w = line.split(' '), | ||
+ | lines = [], | ||
+ | words = [], | ||
+ | maxChars = maxCharactersPerLine || 40, | ||
+ | l = 0; | ||
+ | w.forEach(function(d) { | ||
+ | if (l+d.length > maxChars) { | ||
+ | lines.push(words.join(' ')); | ||
+ | words.length = 0; | ||
+ | l = 0; | ||
+ | } | ||
+ | l += d.length; | ||
+ | words.push(d); | ||
+ | }); | ||
+ | if (words.length) { | ||
+ | lines.push(words.join(' ')); | ||
+ | } | ||
+ | return lines; | ||
+ | }; | ||
+ | |||
+ | d3.ascendingKey = function(key) { | ||
+ | return typeof key == 'function' ? function (a, b) { | ||
+ | return key(a) < key(b) ? -1 : key(a) > key(b) ? 1 : key(a) >= key(b) ? 0 : NaN; | ||
+ | } : function (a, b) { | ||
+ | return a[key] < b[key] ? -1 : a[key] > b[key] ? 1 : a[key] >= b[key] ? 0 : NaN; | ||
+ | }; | ||
+ | }; | ||
+ | |||
+ | d3.descendingKey = function(key) { | ||
+ | return typeof key == 'function' ? function (a, b) { | ||
+ | return key(b) < key(a) ? -1 : key(b) > key(a) ? 1 : key(b) >= key(a) ? 0 : NaN; | ||
+ | } : function (a, b) { | ||
+ | return b[key] < a[key] ? -1 : b[key] > a[key] ? 1 : b[key] >= a[key] ? 0 : NaN; | ||
+ | }; | ||
+ | }; | ||
+ | |||
+ | d3.f = function(){ | ||
+ | var functions = arguments; | ||
+ | //convert all string arguments into field accessors | ||
+ | var i = 0, l = functions.length; | ||
+ | while (i < l) { | ||
+ | if (typeof(functions[i]) === 'string' || typeof(functions[i]) === 'number'){ | ||
+ | functions[i] = (function(str){ return function(d){ return d[str] }; })(functions[i]) | ||
+ | } | ||
+ | i++; | ||
+ | } | ||
+ | //return composition of functions | ||
+ | return function(d) { | ||
+ | var i=0, l = functions.length; | ||
+ | while (i++ < l) d = functions[i-1].call(this, d); | ||
+ | return d; | ||
+ | }; | ||
+ | }; | ||
+ | // store d3.f as convenient unicode character function (alt-f on macs) | ||
+ | if (!window.hasOwnProperty('ƒ')) window.ƒ = d3.f; | ||
+ | |||
+ | // this tweak allows setting a listener for multiple events, jquery style | ||
+ | var d3_selection_on = d3.selection.prototype.on; | ||
+ | d3.selection.prototype.on = function(type, listener, capture) { | ||
+ | if (typeof type == 'string' && type.indexOf(' ') > -1) { | ||
+ | type = type.split(' '); | ||
+ | for (var i = 0; i<type.length; i++) { | ||
+ | d3_selection_on.apply(this, [type[i], listener, capture]); | ||
+ | } | ||
+ | } else { | ||
+ | d3_selection_on.apply(this, [type, listener, capture]); | ||
+ | } | ||
+ | return this; | ||
+ | }; | ||
+ | |||
+ | // for heaven's sake, let's add prop as alias for property | ||
+ | d3.selection.prototype.prop = d3.selection.prototype.property; | ||
+ | } | ||
+ | |||
+ | if (typeof d3 === 'object' && d3.version) jetpack(d3); | ||
+ | else if (typeof define === 'function' && define.amd) { | ||
+ | define(['d3'], jetpack); | ||
+ | } | ||
+ | |||
+ | })(); | ||
+ | |||
+ | function graphScroll() { | ||
+ | var windowHeight, | ||
+ | dispatch = d3.dispatch("scroll", "active", "fixed", "above", "below"), | ||
+ | sections = d3.select('null'), | ||
+ | i = -1, | ||
+ | sectionPos = [], | ||
+ | n, | ||
+ | graph = d3.select('null'), | ||
+ | isFixed = null, | ||
+ | isBelow = null, | ||
+ | isAbove = null, | ||
+ | container = d3.select('body'), | ||
+ | containerStart = 0, | ||
+ | belowStart, | ||
+ | eventId = Math.random(), | ||
+ | stickyTop | ||
+ | |||
+ | function reposition(){ | ||
+ | var i1 = 0 | ||
+ | sectionPos.forEach(function(d, i){ | ||
+ | if (d < pageYOffset - containerStart + 180) i1 = i | ||
+ | }) | ||
+ | i1 = Math.min(n - 1, i1) | ||
+ | if (i != i1){ | ||
+ | sections.classed('graph-scroll-active', function(d, i){ return i === i1 }) | ||
+ | |||
+ | dispatch.active(i1, i) | ||
+ | |||
+ | i = i1 | ||
+ | } | ||
+ | |||
+ | var isAbove1 = pageYOffset < containerStart | ||
+ | if (isAbove != isAbove1){ | ||
+ | isAbove = isAbove1 | ||
+ | graph.classed('graph-scroll-above', isAbove) | ||
+ | if(isAbove) dispatch.above(i1) | ||
+ | } | ||
+ | var isBelow1 = pageYOffset > belowStart | ||
+ | if (isBelow != isBelow1){ | ||
+ | isBelow = isBelow1 | ||
+ | graph.classed('graph-scroll-below', isBelow) | ||
+ | if(isBelow) dispatch.below(i1) | ||
+ | } | ||
+ | var isFixed1 = !isBelow && pageYOffset > containerStart+stickyTop | ||
+ | if (isFixed != isFixed1){ | ||
+ | isFixed = isFixed1 | ||
+ | graph.classed('graph-scroll-fixed', isFixed) | ||
+ | if(isFixed) dispatch.fixed(i1) | ||
+ | } | ||
+ | |||
+ | if (stickyTop){ | ||
+ | graph.style('padding-top', (isBelow || isFixed ? stickyTop : 0)+ 'px') | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function resize(){ | ||
+ | sectionPos = [] | ||
+ | var startPos | ||
+ | sections.each(function(d, i){ | ||
+ | if (!i) startPos = this.getBoundingClientRect().top | ||
+ | sectionPos.push(this.getBoundingClientRect().top - startPos) }) | ||
+ | |||
+ | var containerBB = container.node().getBoundingClientRect() | ||
+ | var graphBB = graph.node().getBoundingClientRect() | ||
+ | |||
+ | containerStart = containerBB.top + pageYOffset | ||
+ | belowStart = containerBB.bottom - graphBB.height + pageYOffset | ||
+ | } | ||
+ | |||
+ | function keydown() { | ||
+ | if (!isFixed) return | ||
+ | var delta | ||
+ | switch (d3.event.keyCode) { | ||
+ | case 39: // right arrow | ||
+ | if (d3.event.metaKey) return | ||
+ | case 40: // down arrow | ||
+ | case 34: // page down | ||
+ | delta = d3.event.metaKey ? Infinity : 1 ;break | ||
+ | case 37: // left arrow | ||
+ | if (d3.event.metaKey) return | ||
+ | case 38: // up arrow | ||
+ | case 33: // page up | ||
+ | delta = d3.event.metaKey ? -Infinity : -1 ;break | ||
+ | case 32: // space | ||
+ | delta = d3.event.shiftKey ? -1 : 1 | ||
+ | ;break | ||
+ | default: return | ||
+ | } | ||
+ | |||
+ | var i1 = Math.max(0, Math.min(i + delta, n - 1)) | ||
+ | rv.scrollTo(i1) | ||
+ | |||
+ | d3.event.preventDefault() | ||
+ | } | ||
+ | |||
+ | |||
+ | var rv ={} | ||
+ | |||
+ | rv.scrollTo = function(_x){ | ||
+ | if (isNaN(_x)) return rv | ||
+ | |||
+ | d3.select(document.documentElement) | ||
+ | .interrupt() | ||
+ | .transition() | ||
+ | .duration(500) | ||
+ | .tween("scroll", function() { | ||
+ | var i = d3.interpolateNumber(pageYOffset, sectionPos[_x] + containerStart+(stickyTop?-stickyTop:0)) | ||
+ | return function(t) { scrollTo(0, i(t)) } | ||
+ | }) | ||
+ | return rv | ||
+ | } | ||
+ | |||
+ | |||
+ | rv.container = function(_x){ | ||
+ | if (!_x) return container | ||
+ | |||
+ | container = _x | ||
+ | return rv | ||
+ | } | ||
+ | |||
+ | rv.graph = function(_x){ | ||
+ | if (!_x) return graph | ||
+ | |||
+ | graph = _x | ||
+ | return rv | ||
+ | } | ||
+ | |||
+ | rv.eventId = function(_x){ | ||
+ | if (!_x) return eventId | ||
+ | |||
+ | eventId = _x | ||
+ | return rv | ||
+ | } | ||
+ | |||
+ | rv.stickyTop = function(_x){ | ||
+ | if (!_x) return stickyTop | ||
+ | |||
+ | stickyTop = _x | ||
+ | return rv | ||
+ | } | ||
+ | |||
+ | rv.sections = function (_x){ | ||
+ | if (!_x) return sections | ||
+ | |||
+ | sections = _x | ||
+ | n = sections.size() | ||
+ | |||
+ | d3.select(window) | ||
+ | .on('scroll.gscroll' + eventId, reposition) | ||
+ | .on('resize.gscroll' + eventId, resize) | ||
+ | .on('keydown.gscroll' + eventId, keydown) | ||
+ | |||
+ | resize() | ||
+ | d3.timer(function() { | ||
+ | reposition() | ||
+ | return true | ||
+ | }) | ||
+ | |||
+ | return rv | ||
+ | } | ||
+ | |||
+ | d3.rebind(rv, dispatch, "on") | ||
+ | |||
+ | return rv | ||
+ | } | ||
+ | |||
+ | d3.selectAll('.dropdown') | ||
+ | .on('mouseover',function(){ this.classList.add('expand') }) | ||
+ | .on('mouseout',function(){ this.classList.remove('expand') }) | ||
+ | |||
+ | var map = d3.select('#map') | ||
+ | var img = d3.select('#mapimg') | ||
+ | var content = d3.select('#content') | ||
+ | size() | ||
+ | function size () { | ||
+ | img.style({ | ||
+ | width:window.innerWidth+'px', | ||
+ | }) | ||
+ | // content.style({ | ||
+ | // height:img.node().getBoundingClientRect().height, | ||
+ | // }) | ||
+ | } | ||
+ | |||
+ | d3.select(window).on('resize.index',size) | ||
+ | |||
+ | d3.selectAll('video') | ||
+ | .on('click',function(){ | ||
+ | console.log(this) | ||
+ | this.play() | ||
+ | }) | ||
</script> | </script> | ||
Revision as of 15:37, 18 September 2015
<!DOCTYPE html>
SuperFUNd Gowanus!
The Gowanus Canal is a heavily polluted waterway that runs through Brooklyn NY. A designated superfund site, it is slated for cleanup but nearby residents are concerned about the results. Our team is developing a biosensor for waste pollution, giving the community real time access to data on the health of the canal. Additionally we have mined the canal for extremophiles with interesting properties.