d3-chord.js 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. // https://d3js.org/d3-chord/ v1.0.6 Copyright 2018 Mike Bostock
  2. (function (global, factory) {
  3. typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('d3-array'), require('d3-path')) :
  4. typeof define === 'function' && define.amd ? define(['exports', 'd3-array', 'd3-path'], factory) :
  5. (factory((global.d3 = global.d3 || {}),global.d3,global.d3));
  6. }(this, (function (exports,d3Array,d3Path) { 'use strict';
  7. var cos = Math.cos;
  8. var sin = Math.sin;
  9. var pi = Math.PI;
  10. var halfPi = pi / 2;
  11. var tau = pi * 2;
  12. var max = Math.max;
  13. function compareValue(compare) {
  14. return function(a, b) {
  15. return compare(
  16. a.source.value + a.target.value,
  17. b.source.value + b.target.value
  18. );
  19. };
  20. }
  21. function chord() {
  22. var padAngle = 0,
  23. sortGroups = null,
  24. sortSubgroups = null,
  25. sortChords = null;
  26. function chord(matrix) {
  27. var n = matrix.length,
  28. groupSums = [],
  29. groupIndex = d3Array.range(n),
  30. subgroupIndex = [],
  31. chords = [],
  32. groups = chords.groups = new Array(n),
  33. subgroups = new Array(n * n),
  34. k,
  35. x,
  36. x0,
  37. dx,
  38. i,
  39. j;
  40. // Compute the sum.
  41. k = 0, i = -1; while (++i < n) {
  42. x = 0, j = -1; while (++j < n) {
  43. x += matrix[i][j];
  44. }
  45. groupSums.push(x);
  46. subgroupIndex.push(d3Array.range(n));
  47. k += x;
  48. }
  49. // Sort groups…
  50. if (sortGroups) groupIndex.sort(function(a, b) {
  51. return sortGroups(groupSums[a], groupSums[b]);
  52. });
  53. // Sort subgroups…
  54. if (sortSubgroups) subgroupIndex.forEach(function(d, i) {
  55. d.sort(function(a, b) {
  56. return sortSubgroups(matrix[i][a], matrix[i][b]);
  57. });
  58. });
  59. // Convert the sum to scaling factor for [0, 2pi].
  60. // TODO Allow start and end angle to be specified?
  61. // TODO Allow padding to be specified as percentage?
  62. k = max(0, tau - padAngle * n) / k;
  63. dx = k ? padAngle : tau / n;
  64. // Compute the start and end angle for each group and subgroup.
  65. // Note: Opera has a bug reordering object literal properties!
  66. x = 0, i = -1; while (++i < n) {
  67. x0 = x, j = -1; while (++j < n) {
  68. var di = groupIndex[i],
  69. dj = subgroupIndex[di][j],
  70. v = matrix[di][dj],
  71. a0 = x,
  72. a1 = x += v * k;
  73. subgroups[dj * n + di] = {
  74. index: di,
  75. subindex: dj,
  76. startAngle: a0,
  77. endAngle: a1,
  78. value: v
  79. };
  80. }
  81. groups[di] = {
  82. index: di,
  83. startAngle: x0,
  84. endAngle: x,
  85. value: groupSums[di]
  86. };
  87. x += dx;
  88. }
  89. // Generate chords for each (non-empty) subgroup-subgroup link.
  90. i = -1; while (++i < n) {
  91. j = i - 1; while (++j < n) {
  92. var source = subgroups[j * n + i],
  93. target = subgroups[i * n + j];
  94. if (source.value || target.value) {
  95. chords.push(source.value < target.value
  96. ? {source: target, target: source}
  97. : {source: source, target: target});
  98. }
  99. }
  100. }
  101. return sortChords ? chords.sort(sortChords) : chords;
  102. }
  103. chord.padAngle = function(_) {
  104. return arguments.length ? (padAngle = max(0, _), chord) : padAngle;
  105. };
  106. chord.sortGroups = function(_) {
  107. return arguments.length ? (sortGroups = _, chord) : sortGroups;
  108. };
  109. chord.sortSubgroups = function(_) {
  110. return arguments.length ? (sortSubgroups = _, chord) : sortSubgroups;
  111. };
  112. chord.sortChords = function(_) {
  113. return arguments.length ? (_ == null ? sortChords = null : (sortChords = compareValue(_))._ = _, chord) : sortChords && sortChords._;
  114. };
  115. return chord;
  116. }
  117. var slice = Array.prototype.slice;
  118. function constant(x) {
  119. return function() {
  120. return x;
  121. };
  122. }
  123. function defaultSource(d) {
  124. return d.source;
  125. }
  126. function defaultTarget(d) {
  127. return d.target;
  128. }
  129. function defaultRadius(d) {
  130. return d.radius;
  131. }
  132. function defaultStartAngle(d) {
  133. return d.startAngle;
  134. }
  135. function defaultEndAngle(d) {
  136. return d.endAngle;
  137. }
  138. function ribbon() {
  139. var source = defaultSource,
  140. target = defaultTarget,
  141. radius = defaultRadius,
  142. startAngle = defaultStartAngle,
  143. endAngle = defaultEndAngle,
  144. context = null;
  145. function ribbon() {
  146. var buffer,
  147. argv = slice.call(arguments),
  148. s = source.apply(this, argv),
  149. t = target.apply(this, argv),
  150. sr = +radius.apply(this, (argv[0] = s, argv)),
  151. sa0 = startAngle.apply(this, argv) - halfPi,
  152. sa1 = endAngle.apply(this, argv) - halfPi,
  153. sx0 = sr * cos(sa0),
  154. sy0 = sr * sin(sa0),
  155. tr = +radius.apply(this, (argv[0] = t, argv)),
  156. ta0 = startAngle.apply(this, argv) - halfPi,
  157. ta1 = endAngle.apply(this, argv) - halfPi;
  158. if (!context) context = buffer = d3Path.path();
  159. context.moveTo(sx0, sy0);
  160. context.arc(0, 0, sr, sa0, sa1);
  161. if (sa0 !== ta0 || sa1 !== ta1) { // TODO sr !== tr?
  162. context.quadraticCurveTo(0, 0, tr * cos(ta0), tr * sin(ta0));
  163. context.arc(0, 0, tr, ta0, ta1);
  164. }
  165. context.quadraticCurveTo(0, 0, sx0, sy0);
  166. context.closePath();
  167. if (buffer) return context = null, buffer + "" || null;
  168. }
  169. ribbon.radius = function(_) {
  170. return arguments.length ? (radius = typeof _ === "function" ? _ : constant(+_), ribbon) : radius;
  171. };
  172. ribbon.startAngle = function(_) {
  173. return arguments.length ? (startAngle = typeof _ === "function" ? _ : constant(+_), ribbon) : startAngle;
  174. };
  175. ribbon.endAngle = function(_) {
  176. return arguments.length ? (endAngle = typeof _ === "function" ? _ : constant(+_), ribbon) : endAngle;
  177. };
  178. ribbon.source = function(_) {
  179. return arguments.length ? (source = _, ribbon) : source;
  180. };
  181. ribbon.target = function(_) {
  182. return arguments.length ? (target = _, ribbon) : target;
  183. };
  184. ribbon.context = function(_) {
  185. return arguments.length ? ((context = _ == null ? null : _), ribbon) : context;
  186. };
  187. return ribbon;
  188. }
  189. exports.chord = chord;
  190. exports.ribbon = ribbon;
  191. Object.defineProperty(exports, '__esModule', { value: true });
  192. })));