123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130 |
- // GNU Guix --- Functional package management for GNU
- // Copyright © 2016 Ricardo Wurmus <rekado@elephly.net>
- //
- // This file is part of GNU Guix.
- //
- // GNU Guix is free software; you can redistribute it and/or modify it
- // under the terms of the GNU General Public License as published by
- // the Free Software Foundation; either version 3 of the License, or (at
- // your option) any later version.
- //
- // GNU Guix is distributed in the hope that it will be useful, but
- // WITHOUT ANY WARRANTY; without even the implied warranty of
- // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- // GNU General Public License for more details.
- //
- // You should have received a copy of the GNU General Public License
- // along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
- var outerRadius = Math.max(nodeArray.length * 15, 500) / 2,
- innerRadius = outerRadius - Math.min(nodeArray.length * 5, 200),
- width = outerRadius * 2,
- height = outerRadius * 2,
- colors = d3.scale.category20c(),
- matrix = [];
- function neighborsOf (node) {
- return links.filter(function (e) {
- return e.source === node;
- }).map(function (e) {
- return e.target;
- });
- }
- function zoomed () {
- zoomer.attr("transform",
- "translate(" + d3.event.translate + ")" +
- "scale(" + d3.event.scale + ")");
- }
- function fade (opacity, root) {
- return function (g, i) {
- root.selectAll("g path.chord")
- .filter(function (d) {
- return d.source.index != i && d.target.index != i;
- })
- .transition()
- .style("opacity", opacity);
- };
- }
- // Now that we have all nodes in an object we can replace each reference
- // with the actual node object.
- links.forEach(function (link) {
- link.target = nodes[link.target];
- link.source = nodes[link.source];
- });
- // Construct a square matrix for package dependencies
- nodeArray.forEach(function (d, index, arr) {
- var source = index,
- row = matrix[source];
- if (!row) {
- row = matrix[source] = [];
- for (var i = -1; ++i < arr.length;) row[i] = 0;
- }
- neighborsOf(d).forEach(function (d) { row[d.index]++; });
- });
- // chord layout
- var chord = d3.layout.chord()
- .padding(0.01)
- .sortSubgroups(d3.descending)
- .sortChords(d3.descending)
- .matrix(matrix);
- var arc = d3.svg.arc()
- .innerRadius(innerRadius)
- .outerRadius(innerRadius + 20);
- var zoom = d3.behavior.zoom()
- .scaleExtent([0.1, 10])
- .on("zoom", zoomed);
- var svg = d3.select("body").append("svg")
- .attr("width", "100%")
- .attr("height", "100%")
- .attr('viewBox', '0 0 ' + Math.min(width, height) + ' ' + Math.min(width, height))
- .attr('preserveAspectRatio', 'xMinYMin')
- .call(zoom);
- var zoomer = svg.append("g");
- var container = zoomer.append("g")
- .attr("transform", "translate(" + outerRadius + "," + outerRadius + ")");
- // Group for arcs and labels
- var g = container.selectAll(".group")
- .data(chord.groups)
- .enter().append("g")
- .attr("class", "group")
- .on("mouseout", fade(1, container))
- .on("mouseover", fade(0.1, container));
- // Draw one segment per package
- g.append("path")
- .style("fill", function (d) { return colors(d.index); })
- .style("stroke", function (d) { return colors(d.index); })
- .attr("d", arc);
- // Add circular labels
- g.append("text")
- .each(function (d) { d.angle = (d.startAngle + d.endAngle) / 2; })
- .attr("dy", ".35em")
- .attr("transform", function (d) {
- return "rotate(" + (d.angle * 180 / Math.PI - 90) + ")"
- + "translate(" + (innerRadius + 26) + ")"
- + (d.angle > Math.PI ? "rotate(180)" : "");
- })
- .style("text-anchor", function (d) { return d.angle > Math.PI ? "end" : null; })
- .text(function (d) { return nodeArray[d.index].label; });
- // Draw chords from source to target; color by source.
- container.selectAll(".chord")
- .data(chord.chords)
- .enter().append("path")
- .attr("class", "chord")
- .style("stroke", function (d) { return d3.rgb(colors(d.source.index)).darker(); })
- .style("fill", function (d) { return colors(d.source.index); })
- .attr("d", d3.svg.chord().radius(innerRadius));
|