collaborations

The visualization below shows how often the people collaborated.

Created by Nadieh Bremer | VisualCinnamon.com
Just professional collabobations
bootstrap.popover.js # /* ======================================================================== * Bootstrap: popover.js v3.1.1 * http://getbootstrap.com/javascript/#popovers * ======================================================================== * Copyright 2011-2014 Twitter, Inc. * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) * ======================================================================== */ +function ($) { 'use strict'; // POPOVER PUBLIC CLASS DEFINITION // =============================== var Popover = function (element, options) { this.init('popover', element, options) } if (!$.fn.tooltip) throw new Error('Popover requires tooltip.js') Popover.DEFAULTS = $.extend({}, $.fn.tooltip.Constructor.DEFAULTS, { placement: 'right', trigger: 'click', content: '', template: '

' }) // NOTE: POPOVER EXTENDS tooltip.js // ================================ Popover.prototype = $.extend({}, $.fn.tooltip.Constructor.prototype) Popover.prototype.constructor = Popover Popover.prototype.getDefaults = function () { return Popover.DEFAULTS } Popover.prototype.setContent = function () { var $tip = this.tip() var title = this.getTitle() var content = this.getContent() $tip.find('.popover-title')[this.options.html ? 'html' : 'text'](title) $tip.find('.popover-content')[ // we use append for html objects to maintain js events this.options.html ? (typeof content == 'string' ? 'html' : 'append') : 'text' ](content) $tip.removeClass('fade top bottom left right in') // IE8 doesn't accept hiding via the `:empty` pseudo selector, we have to do // this manually by checking the contents. if (!$tip.find('.popover-title').html()) $tip.find('.popover-title').hide() } Popover.prototype.hasContent = function () { return this.getTitle() || this.getContent() } Popover.prototype.getContent = function () { var $e = this.$element var o = this.options return $e.attr('data-content') || (typeof o.content == 'function' ? o.content.call($e[0]) : o.content) } Popover.prototype.arrow = function () { return this.$arrow = this.$arrow || this.tip().find('.arrow') } Popover.prototype.tip = function () { if (!this.$tip) this.$tip = $(this.options.template) return this.$tip } // POPOVER PLUGIN DEFINITION // ========================= var old = $.fn.popover $.fn.popover = function (option) { return this.each(function () { var $this = $(this) var data = $this.data('bs.popover') var options = typeof option == 'object' && option if (!data && option == 'destroy') return if (!data) $this.data('bs.popover', (data = new Popover(this, options))) if (typeof option == 'string') data[option]() }) } $.fn.popover.Constructor = Popover // POPOVER NO CONFLICT // =================== $.fn.popover.noConflict = function () { $.fn.popover = old return this } }(jQuery); bootstrap.tooltip.js # /* ======================================================================== * Bootstrap: tooltip.js v3.1.1 * http://getbootstrap.com/javascript/#tooltip * Inspired by the original jQuery.tipsy by Jason Frame * ======================================================================== * Copyright 2011-2014 Twitter, Inc. * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) * ======================================================================== */ +function ($) { 'use strict'; // TOOLTIP PUBLIC CLASS DEFINITION // =============================== var Tooltip = function (element, options) { this.type = this.options = this.enabled = this.timeout = this.hoverState = this.$measure = this.$element = null this.init('tooltip', element, options) } Tooltip.DEFAULTS = { animation: true, mouseOffset: 0, measure: false, followMouse: false, placement: 'top', selector: false, template: '
', trigger: 'hover focus', title: '', delay: 0, html: false, container: false } Tooltip.prototype.init = function (type, element, options) { this.enabled = true this.type = type this.$element = $(element) this.options = this.getOptions(options) if (this.options.measure) { this.$measure = $(this.options.measure) } var triggers = this.options.trigger.split(' ') for (var i = triggers.length; i--;) { var trigger = triggers[i] if (trigger == 'click') { this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this)) } else if (trigger != 'manual') { var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin' var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout' this.$element.on(eventIn + '.' + this.type, this.options.selector, $.proxy(this.enter, this)) this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this)) } } this.options.selector ? (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) : this.fixTitle() } Tooltip.prototype.getDefaults = function () { return Tooltip.DEFAULTS } Tooltip.prototype.getOptions = function (options) { options = $.extend({}, this.getDefaults(), this.$element.data(), options) if (options.delay && typeof options.delay == 'number') { options.delay = { show: options.delay, hide: options.delay } } return options } Tooltip.prototype.getDelegateOptions = function () { var options = {} var defaults = this.getDefaults() this._options && $.each(this._options, function (key, value) { if (defaults[key] != value) options[key] = value }) return options } Tooltip.prototype.enter = function (obj) { var self = obj instanceof this.constructor ? obj : $(obj.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type) clearTimeout(self.timeout) self.hoverState = 'in' if (!self.options.delay || !self.options.delay.show) return self.show() self.timeout = setTimeout(function () { if (self.hoverState == 'in') self.show() }, self.options.delay.show) } Tooltip.prototype.leave = function (obj) { var self = obj instanceof this.constructor ? obj : $(obj.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type) clearTimeout(self.timeout) self.hoverState = 'out' if (!self.options.delay || !self.options.delay.hide) return self.hide() self.timeout = setTimeout(function () { if (self.hoverState == 'out') self.hide() }, self.options.delay.hide) } Tooltip.prototype.show = function () { var e = $.Event('show.bs.' + this.type) if (this.hasContent() && this.enabled) { this.$element.trigger(e) if (e.isDefaultPrevented()) return var that = this; var $tip = this.tip() this.setContent() if (this.options.animation) $tip.addClass('fade') var placement = typeof this.options.placement == 'function' ? this.options.placement.call(this, $tip[0], this.$element[0]) : this.options.placement var autoToken = /\s?auto?\s?/i var autoPlace = autoToken.test(placement) if (autoPlace) placement = placement.replace(autoToken, '') || 'top' $tip .detach() .css({ top: 0, left: 0, display: 'block' }) .addClass(placement) this.options.container ? $tip.appendTo(this.options.container) : $tip.insertAfter(this.$element) var pos = this.getPosition() var actualWidth = $tip[0].offsetWidth var actualHeight = $tip[0].offsetHeight if (autoPlace) { placement = this.getAutoPlace($tip, placement, pos, actualWidth, actualHeight) } var calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight) this.applyPlacement(calculatedOffset, placement) this.hoverState = null var complete = function() { that.$element.trigger('shown.bs.' + that.type) } if (this.options.followMouse) { $(this.options.container).on('mousemove', $.proxy(this.follow, this)); } $.support.transition && this.$tip.hasClass('fade') ? $tip .one($.support.transition.end, complete) .emulateTransitionEnd(150) : complete() } } Tooltip.prototype.getAutoPlace = function($tip, placement, pos, actualWidth, actualHeight) { var $parent = this.$element.parent() var orgPlacement = placement var docScroll = document.documentElement.scrollTop || document.body.scrollTop var parentWidth = this.options.container == 'body' ? window.innerWidth : $parent.outerWidth() var parentHeight = this.options.container == 'body' ? window.innerHeight : $parent.outerHeight() var parentLeft = this.options.container == 'body' ? 0 : $parent.offset().left placement = placement == 'bottom' && pos.top + pos.height + actualHeight - docScroll > parentHeight ? 'top' : placement == 'top' && pos.top - docScroll - actualHeight < 0 ? 'bottom' : placement == 'right' && pos.left + actualWidth > parentWidth ? 'left' : placement == 'left' && pos.left - actualWidth < parentLeft ? 'right' : placement $tip .removeClass(orgPlacement) .addClass(placement) return placement } Tooltip.prototype.follow = function(e) { var $tip = this.tip() var pos = this.getPosition() var actualWidth = $tip[0].offsetWidth var actualHeight = $tip[0].offsetHeight var placement = typeof this.options.placement == 'function' ? this.options.placement.call(this, $tip[0], this.$element[0]) : this.options.placement var autoToken = /\s?auto?\s?/i var autoPlace = autoToken.test(placement) if (autoPlace) placement = placement.replace(autoToken, '') || 'top' pos.left = e.pageX + this.options.mouseOffset; pos.top = e.pageY + this.options.mouseOffset; var placement = this.getAutoPlace($tip, placement, pos, actualWidth, actualHeight) var calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight, e) this.applyPlacement(calculatedOffset, placement) } Tooltip.prototype.applyPlacement = function (offset, placement) { var replace var $tip = this.tip() var width = $tip[0].offsetWidth var height = $tip[0].offsetHeight // manually read margins because getBoundingClientRect includes difference var marginTop = parseInt($tip.css('margin-top'), 10) var marginLeft = parseInt($tip.css('margin-left'), 10) // we must check for NaN for ie 8/9 if (isNaN(marginTop)) marginTop = 0 if (isNaN(marginLeft)) marginLeft = 0 offset.top = offset.top + marginTop offset.left = offset.left + marginLeft // $.fn.offset doesn't round pixel values // so we use setOffset directly with our own function B-0 $.offset.setOffset($tip[0], $.extend({ using: function (props) { $tip.css({ top: Math.round(props.top), left: Math.round(props.left) }) } }, offset), 0) $tip.addClass('in') // check to see if placing tip in new offset caused the tip to resize itself var actualWidth = $tip[0].offsetWidth var actualHeight = $tip[0].offsetHeight if (placement == 'top' && actualHeight != height) { replace = true offset.top = offset.top + height - actualHeight } if (/bottom|top/.test(placement)) { var delta = 0 if (offset.left < 0) { delta = offset.left * -2 offset.left = 0 $tip.offset(offset) actualWidth = $tip[0].offsetWidth actualHeight = $tip[0].offsetHeight } this.replaceArrow(delta - width + actualWidth, actualWidth, 'left') } else { this.replaceArrow(actualHeight - height, actualHeight, 'top') } if (replace) $tip.offset(offset) } Tooltip.prototype.replaceArrow = function (delta, dimension, position) { if(this.options.mouseOffset > 0 && position === 'top') { this.arrow().css(position, this.options.mouseOffset + 10 + 'px') return; } this.arrow().css(position, delta ? (50 * (1 - delta / dimension) + '%') : '') } Tooltip.prototype.setContent = function () { var $tip = this.tip() var title = this.getTitle() $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title) $tip.removeClass('fade in top bottom left right') } Tooltip.prototype.hide = function () { var that = this var $tip = this.tip() var e = $.Event('hide.bs.' + this.type) function complete() { if (that.hoverState != 'in') $tip.detach() that.$element.trigger('hidden.bs.' + that.type) } $(this.options.container).off('mousemove'); this.$element.trigger(e) if (e.isDefaultPrevented()) return $tip.removeClass('in') $.support.transition && this.$tip.hasClass('fade') ? $tip .one($.support.transition.end, complete) .emulateTransitionEnd(150) : complete() this.hoverState = null return this } Tooltip.prototype.fixTitle = function () { var $e = this.$element if ($e.attr('title') || typeof($e.attr('data-original-title')) != 'string') { $e.attr('data-original-title', $e.attr('title') || '').attr('title', '') } } Tooltip.prototype.hasContent = function () { return this.getTitle() } Tooltip.prototype.getPosition = function () { var el = this.$element[0] if(this.$element.prop('tagName') == 'AREA') { var position = this.$element.attr('coords').split(','); var x = parseInt(position[0], 0) + parseInt(this.$measure.offset().left, 0); var y = parseInt(position[1], 0) + parseInt(this.$measure.offset().top, 0); return {bottom: 0, height: el.offsetWidth, left: x, right: 0, top: y, width: el.offsetWidth} } return $.extend({}, (typeof el.getBoundingClientRect == 'function') ? el.getBoundingClientRect() : { width: el.offsetWidth, height: el.offsetHeight }, this.$element.offset()) } Tooltip.prototype.getCalculatedOffset = function (placement, pos, actualWidth, actualHeight, follow) { if (typeof follow !== 'undefined') { return placement == 'bottom' ? { top: follow.pageY + this.options.mouseOffset, left: follow.pageX - (actualWidth / 2) } : placement == 'top' ? { top: follow.pageY - actualHeight - this.options.mouseOffset, left: follow.pageX - (actualWidth / 2) } : placement == 'left' ? { top: follow.pageY - this.options.mouseOffset, left: follow.pageX - (actualWidth + this.options.mouseOffset) } : { top: follow.pageY - this.options.mouseOffset, left: follow.pageX + this.options.mouseOffset } } return placement == 'bottom' ? { top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2 } : placement == 'top' ? { top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2 } : placement == 'left' ? { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth } : { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width } } Tooltip.prototype.getTitle = function () { var title var $e = this.$element var o = this.options title = $e.attr('data-original-title') || (typeof o.title == 'function' ? o.title.call($e[0]) : o.title) return title } Tooltip.prototype.tip = function () { return this.$tip = this.$tip || $(this.options.template) } Tooltip.prototype.arrow = function () { return this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow') } Tooltip.prototype.validate = function () { if (!this.$element[0].parentNode) { this.hide() this.$element = null this.options = null } } Tooltip.prototype.enable = function () { this.enabled = true } Tooltip.prototype.disable = function () { this.enabled = false } Tooltip.prototype.toggleEnabled = function () { this.enabled = !this.enabled } Tooltip.prototype.toggle = function (e) { var self = e ? $(e.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type) : this self.tip().hasClass('in') ? self.leave(self) : self.enter(self) } Tooltip.prototype.destroy = function () { clearTimeout(this.timeout) this.hide().$element.off('.' + this.type).removeData('bs.' + this.type) } // TOOLTIP PLUGIN DEFINITION // ========================= var old = $.fn.tooltip $.fn.tooltip = function (option) { return this.each(function () { var $this = $(this) var data = $this.data('bs.tooltip') var options = typeof option == 'object' && option if (!data && option == 'destroy') return if (!data) $this.data('bs.tooltip', (data = new Tooltip(this, options))) if (typeof option == 'string') data[option]() }) } $.fn.tooltip.Constructor = Tooltip // TOOLTIP NO CONFLICT // =================== $.fn.tooltip.noConflict = function () { $.fn.tooltip = old return this } }(jQuery); d3.layout.chord.sort.js # //////////////////////////////////////////////////////////// //////////// Custom Chord Layout Function ////////////////// /////// Places the Chords in the visually best order /////// ///////////////// to reduce overlap //////////////////////// //////////////////////////////////////////////////////////// //////// Slightly adjusted by Nadieh Bremer //////////////// //////////////// VisualCinnamon.com //////////////////////// //////////////////////////////////////////////////////////// ////// Original from the d3.layout.chord() function //////// ///////////////// from the d3.js library /////////////////// //////////////// Created by Mike Bostock /////////////////// //////////////////////////////////////////////////////////// customChordLayout = function() { var ε = 1e-6, ε2 = ε * ε, π = Math.PI, τ = 2 * π, τε = τ - ε, halfπ = π / 2, d3_radians = π / 180, d3_degrees = 180 / π; var chord = {}, chords, groups, matrix, n, padding = 0, sortGroups, sortSubgroups, sortChords; function relayout() { var subgroups = {}, groupSums = [], groupIndex = d3.range(n), subgroupIndex = [], k, x, x0, i, j; var numSeq; chords = []; groups = []; k = 0, i = -1; while (++i < n) { x = 0, j = -1, numSeq = []; while (++j < n) { x += matrix[i][j]; } groupSums.push(x); ////////////////////////////////////// ////////////// New part ////////////// ////////////////////////////////////// for(var m = 0; m < n; m++) { numSeq[m] = (n+(i-1)-m)%n; } subgroupIndex.push(numSeq); ////////////////////////////////////// ////////// End new part ///////////// ////////////////////////////////////// k += x; }//while k = (τ - padding * n) / k; x = 0, i = -1; while (++i < n) { x0 = x, j = -1; while (++j < n) { var di = groupIndex[i], dj = subgroupIndex[di][j], v = matrix[di][dj], a0 = x, a1 = x += v * k; subgroups[di + "-" + dj] = { index: di, subindex: dj, startAngle: a0, endAngle: a1, value: v }; }//while groups[di] = { index: di, startAngle: x0, endAngle: x, value: (x - x0) / k }; x += padding; }//while i = -1; while (++i < n) { j = i - 1; while (++j < n) { var source = subgroups[i + "-" + j], target = subgroups[j + "-" + i]; if (source.value || target.value) { chords.push(source.value < target.value ? { source: target, target: source } : { source: source, target: target }); }//if }//while }//while if (sortChords) resort(); }//function relayout function resort() { chords.sort(function(a, b) { return sortChords((a.source.value + a.target.value) / 2, (b.source.value + b.target.value) / 2); }); } chord.matrix = function(x) { if (!arguments.length) return matrix; n = (matrix = x) && matrix.length; chords = groups = null; return chord; }; chord.padding = function(x) { if (!arguments.length) return padding; padding = x; chords = groups = null; return chord; }; chord.sortGroups = function(x) { if (!arguments.length) return sortGroups; sortGroups = x; chords = groups = null; return chord; }; chord.sortSubgroups = function(x) { if (!arguments.length) return sortSubgroups; sortSubgroups = x; chords = null; return chord; }; chord.sortChords = function(x) { if (!arguments.length) return sortChords; sortChords = x; if (chords) resort(); return chord; }; chord.chords = function() { if (!chords) relayout(); return chords; }; chord.groups = function() { if (!groups) relayout(); return groups; }; return chord; }; script.js # //////////////////////////////////////////////////////////// //////////////////////// Set-Up //////////////////////////// //////////////////////////////////////////////////////////// var margin = {left:20, top:20, right:20, bottom:20}, width = Math.min(window.innerWidth, 700) - margin.left - margin.right, height = Math.min(window.innerWidth, 700) - margin.top - margin.bottom, innerRadius = Math.min(width, height) * .39, outerRadius = innerRadius * 1.1; var Names = ["Black Widow","Captain America","Hawkeye","the Hulk","Iron Man","Thor"], colors = ["#301E1E", "#083E77", "#342350", "#567235", "#8B161C", "#DF7C00"], opacityDefault = 0.8; var matrix = [ [0,4,3,2,5,2], //Black Widow [4,0,3,2,4,3], //Captain America [3,3,0,2,3,3], //Hawkeye [2,2,2,0,3,3], //The Hulk [5,4,3,3,0,2], //Iron Man [2,3,3,3,2,0], //Thor ]; //////////////////////////////////////////////////////////// /////////// Create scale and layout functions ////////////// //////////////////////////////////////////////////////////// var colors = d3.scale.ordinal() .domain(d3.range(Names.length)) .range(colors); //A "custom" d3 chord function that automatically sorts the order of the chords in such a manner to reduce overlap var chord = customChordLayout() .padding(.15) .sortChords(d3.descending) //which chord should be shown on top when chords cross. Now the biggest chord is at the bottom .matrix(matrix); var arc = d3.svg.arc() .innerRadius(innerRadius*1.01) .outerRadius(outerRadius); var path = d3.svg.chord() .radius(innerRadius); //////////////////////////////////////////////////////////// ////////////////////// Create SVG ////////////////////////// //////////////////////////////////////////////////////////// var svg = d3.select("#chart").append("svg") .attr("width", width + margin.left + margin.right) .attr("height", height + margin.top + margin.bottom) .append("g") .attr("transform", "translate(" + (width/2 + margin.left) + "," + (height/2 + margin.top) + ")"); //////////////////////////////////////////////////////////// /////////////// Create the gradient fills ////////////////// //////////////////////////////////////////////////////////// //Function to create the id for each chord gradient function getGradID(d){ return "linkGrad-" + d.source.index + "-" + d.target.index; } //Create the gradients definitions for each chord var grads = svg.append("defs").selectAll("linearGradient") .data(chord.chords()) .enter().append("linearGradient") .attr("id", getGradID) .attr("gradientUnits", "userSpaceOnUse") .attr("x1", function(d,i) { return innerRadius * Math.cos((d.source.endAngle-d.source.startAngle)/2 + d.source.startAngle - Math.PI/2); }) .attr("y1", function(d,i) { return innerRadius * Math.sin((d.source.endAngle-d.source.startAngle)/2 + d.source.startAngle - Math.PI/2); }) .attr("x2", function(d,i) { return innerRadius * Math.cos((d.target.endAngle-d.target.startAngle)/2 + d.target.startAngle - Math.PI/2); }) .attr("y2", function(d,i) { return innerRadius * Math.sin((d.target.endAngle-d.target.startAngle)/2 + d.target.startAngle - Math.PI/2); }) //Set the starting color (at 0%) grads.append("stop") .attr("offset", "0%") .attr("stop-color", function(d){ return colors(d.source.index); }); //Set the ending color (at 100%) grads.append("stop") .attr("offset", "100%") .attr("stop-color", function(d){ return colors(d.target.index); }); //////////////////////////////////////////////////////////// ////////////////// Draw outer Arcs ///////////////////////// //////////////////////////////////////////////////////////// var outerArcs = svg.selectAll("g.group") .data(chord.groups) .enter().append("g") .attr("class", "group") .on("mouseover", fade(.1)) .on("mouseout", fade(opacityDefault)); outerArcs.append("path") .style("fill", function(d) { return colors(d.index); }) .attr("d", arc) .each(function(d,i) { //Search pattern for everything between the start and the first capital L var firstArcSection = /(^.+?)L/; //Grab everything up to the first Line statement var newArc = firstArcSection.exec( d3.select(this).attr("d") )[1]; //Replace all the comma's so that IE can handle it newArc = newArc.replace(/,/g , " "); //If the end angle lies beyond a quarter of a circle (90 degrees or pi/2) //flip the end and start position if (d.endAngle > 90*Math.PI/180 & d.startAngle < 270*Math.PI/180) { var startLoc = /M(.*?)A/, //Everything between the first capital M and first capital A middleLoc = /A(.*?)0 0 1/, //Everything between the first capital A and 0 0 1 endLoc = /0 0 1 (.*?)$/; //Everything between the first 0 0 1 and the end of the string (denoted by $) //Flip the direction of the arc by switching the start en end point (and sweep flag) //of those elements that are below the horizontal line var newStart = endLoc.exec( newArc )[1]; var newEnd = startLoc.exec( newArc )[1]; var middleSec = middleLoc.exec( newArc )[1]; //Build up the new arc notation, set the sweep-flag to 0 newArc = "M" + newStart + "A" + middleSec + "0 0 0 " + newEnd; }//if //Create a new invisible arc that the text can flow along svg.append("path") .attr("class", "hiddenArcs") .attr("id", "arc"+i) .attr("d", newArc) .style("fill", "none"); }); //////////////////////////////////////////////////////////// ////////////////// Append Names //////////////////////////// //////////////////////////////////////////////////////////// //Append the label names on the outside outerArcs.append("text") .attr("class", "titles") .attr("dy", function(d,i) { return (d.endAngle > 90*Math.PI/180 & d.startAngle < 270*Math.PI/180 ? 25 : -16); }) .append("textPath") .attr("startOffset","50%") .style("text-anchor","middle") .attr("xlink:href",function(d,i){return "#arc"+i;}) .text(function(d,i){ return Names[i]; }); //////////////////////////////////////////////////////////// ////////////////// Draw inner chords /////////////////////// //////////////////////////////////////////////////////////// svg.selectAll("path.chord") .data(chord.chords) .enter().append("path") .attr("class", "chord") .style("fill", function(d){ return "url(#" + getGradID(d) + ")"; }) .style("opacity", opacityDefault) .attr("d", path) .on("mouseover", mouseoverChord) .on("mouseout", mouseoutChord); //////////////////////////////////////////////////////////// ////////////////// Extra Functions ///////////////////////// //////////////////////////////////////////////////////////// //Returns an event handler for fading a given chord group. function fade(opacity) { return function(d,i) { svg.selectAll("path.chord") .filter(function(d) { return d.source.index !== i && d.target.index !== i; }) .transition() .style("opacity", opacity); }; }//fade //Highlight hovered over chord function mouseoverChord(d,i) { //Decrease opacity to all svg.selectAll("path.chord") .transition() .style("opacity", 0.1); //Show hovered over chord with full opacity d3.select(this) .transition() .style("opacity", 1); //Define and show the tooltip over the mouse location $(this).popover({ placement: 'auto top', container: 'body', mouseOffset: 10, followMouse: true, trigger: 'hover', html : true, content: function() { return "

" + Names[d.source.index] + " and " + Names[d.target.index] + " appeared together in " + d.source.value + " projects

"; } }); $(this).popover('show'); }//mouseoverChord //Bring all chords back to default opacity function mouseoutChord(d) { //Hide the tooltip $('.popover').each(function() { $(this).remove(); }); //Set opacity back to default for all svg.selectAll("path.chord") .transition() .style("opacity", opacityDefault); }//function mouseoutChord LICENSE # This block appears to have no license. Please contact the author to request a license.