Initial OpenECOMP policy/engine commit
[policy/engine.git] / ecomp-sdk-app / src / main / webapp / static / fusion / d3 / js / d3.layout.js
1 (function(){d3.layout = {};
2 d3.layout.chord = function() {
3   var chord = {},
4       chords,
5       groups,
6       matrix,
7       n,
8       padding = 0,
9       sortGroups,
10       sortSubgroups,
11       sortChords;
12
13   function relayout() {
14     var subgroups = {},
15         groupSums = [],
16         groupIndex = d3.range(n),
17         subgroupIndex = [],
18         k,
19         x,
20         x0,
21         i,
22         j;
23
24     chords = [];
25     groups = [];
26
27     // Compute the sum.
28     k = 0, i = -1; while (++i < n) {
29       x = 0, j = -1; while (++j < n) {
30         x += matrix[i][j];
31       }
32       groupSums.push(x);
33       subgroupIndex.push(d3.range(n));
34       k += x;
35     }
36
37     // Sort groups…
38     if (sortGroups) {
39       groupIndex.sort(function(a, b) {
40         return sortGroups(groupSums[a], groupSums[b]);
41       });
42     }
43
44     // Sort subgroups…
45     if (sortSubgroups) {
46       subgroupIndex.forEach(function(d, i) {
47         d.sort(function(a, b) {
48           return sortSubgroups(matrix[i][a], matrix[i][b]);
49         });
50       });
51     }
52
53     // Convert the sum to scaling factor for [0, 2pi].
54     // TODO Allow start and end angle to be specified.
55     // TODO Allow padding to be specified as percentage?
56     k = (2 * Math.PI - padding * n) / k;
57
58     // Compute the start and end angle for each group and subgroup.
59     x = 0, i = -1; while (++i < n) {
60       x0 = x, j = -1; while (++j < n) {
61         var di = groupIndex[i],
62             dj = subgroupIndex[i][j],
63             v = matrix[di][dj];
64         subgroups[di + "-" + dj] = {
65           index: di,
66           subindex: dj,
67           startAngle: x,
68           endAngle: x += v * k,
69           value: v
70         };
71       }
72       groups.push({
73         index: di,
74         startAngle: x0,
75         endAngle: x,
76         value: (x - x0) / k
77       });
78       x += padding;
79     }
80
81     // Generate chords for each (non-empty) subgroup-subgroup link.
82     i = -1; while (++i < n) {
83       j = i - 1; while (++j < n) {
84         var source = subgroups[i + "-" + j],
85             target = subgroups[j + "-" + i];
86         if (source.value || target.value) {
87           chords.push({
88             source: source,
89             target: target
90           })
91         }
92       }
93     }
94
95     if (sortChords) resort();
96   }
97
98   function resort() {
99     chords.sort(function(a, b) {
100       a = Math.min(a.source.value, a.target.value);
101       b = Math.min(b.source.value, b.target.value);
102       return sortChords(a, b);
103     });
104   }
105
106   chord.matrix = function(x) {
107     if (!arguments.length) return matrix;
108     n = (matrix = x) && matrix.length;
109     chords = groups = null;
110     return chord;
111   };
112
113   chord.padding = function(x) {
114     if (!arguments.length) return padding;
115     padding = x;
116     chords = groups = null;
117     return chord;
118   };
119
120   chord.sortGroups = function(x) {
121     if (!arguments.length) return sortGroups;
122     sortGroups = x;
123     chords = groups = null;
124     return chord;
125   };
126
127   chord.sortSubgroups = function(x) {
128     if (!arguments.length) return sortSubgroups;
129     sortSubgroups = x;
130     chords = null;
131     return chord;
132   };
133
134   chord.sortChords = function(x) {
135     if (!arguments.length) return sortChords;
136     sortChords = x;
137     if (chords) resort();
138     return chord;
139   };
140
141   chord.chords = function() {
142     if (!chords) relayout();
143     return chords;
144   };
145
146   chord.groups = function() {
147     if (!groups) relayout();
148     return groups;
149   };
150
151   return chord;
152 };
153 // A rudimentary force layout using Gauss-Seidel.
154 d3.layout.force = function() {
155   var force = {},
156       event = d3.dispatch("tick"),
157       size = [1, 1],
158       alpha = .5,
159       distance = 30,
160       interval,
161       nodes,
162       links,
163       distances;
164
165   function tick() {
166     var n = distances.length,
167         i, // current index
168         o, // current link
169         s, // current source
170         t, // current target
171         l, // current distance
172         x, // x-distance
173         y; // y-distance
174
175     // gauss-seidel relaxation
176     for (i = 0; i < n; ++i) {
177       o = distances[i];
178       s = o.source;
179       t = o.target;
180       x = t.x - s.x;
181       y = t.y - s.y;
182       if (l = Math.sqrt(x * x + y * y)) {
183         l = alpha / (o.distance * o.distance) * (l - distance * o.distance) / l;
184         x *= l;
185         y *= l;
186         if (!t.fixed) {
187           t.x -= x;
188           t.y -= y;
189         }
190         if (!s.fixed) {
191           s.x += x;
192           s.y += y;
193         }
194       }
195     }
196
197     event.tick.dispatch({type: "tick"});
198
199     // simulated annealing, basically
200     return (alpha *= .99) < .005;
201   }
202
203   force.on = function(type, listener) {
204     event[type].add(listener);
205     return force;
206   };
207
208   force.nodes = function(x) {
209     if (!arguments.length) return nodes;
210     nodes = x;
211     return force;
212   };
213
214   force.links = function(x) {
215     if (!arguments.length) return links;
216     links = x;
217     return force;
218   };
219
220   force.size = function(x) {
221     if (!arguments.length) return size;
222     size = x;
223     return force;
224   };
225
226   force.distance = function(d) {
227     if (!arguments.length) return distance;
228     distance = d;
229     return force;
230   };
231
232   force.start = function() {
233     var i,
234         j,
235         k,
236         n = nodes.length,
237         m = links.length,
238         w = size[0],
239         h = size[1],
240         o;
241
242     var paths = [];
243     for (i = 0; i < n; ++i) {
244       o = nodes[i];
245       o.x = o.x || Math.random() * w;
246       o.y = o.y || Math.random() * h;
247       o.fixed = 0;
248       paths[i] = [];
249       for (j = 0; j < n; ++j) {
250         paths[i][j] = Infinity;
251       }
252       paths[i][i] = 0;
253     }
254
255     for (i = 0; i < m; ++i) {
256       o = links[i];
257       paths[o.source][o.target] = 1;
258       paths[o.target][o.source] = 1;
259       o.source = nodes[o.source];
260       o.target = nodes[o.target];
261     }
262
263     // Floyd-Warshall
264     for (k = 0; k < n; ++k) {
265       for (i = 0; i < n; ++i) {
266         for (j = 0; j < n; ++j) {
267           paths[i][j] = Math.min(paths[i][j], paths[i][k] + paths[k][j]);
268         }
269       }
270     }
271
272     distances = [];
273     for (i = 0; i < n; ++i) {
274       for (j = i + 1; j < n; ++j) {
275         distances.push({
276           source: nodes[i],
277           target: nodes[j],
278           distance: paths[i][j] * paths[i][j]
279         });
280       }
281     }
282
283     distances.sort(function(a, b) {
284       return a.distance - b.distance;
285     });
286
287     d3.timer(tick);
288     return force;
289   };
290
291   force.resume = function() {
292     alpha = .1;
293     d3.timer(tick);
294     return force;
295   };
296
297   force.stop = function() {
298     alpha = 0;
299     return force;
300   };
301
302   // use `node.call(force.drag)` to make nodes draggable
303   force.drag = function() {
304     var node, element;
305
306     this
307       .on("mouseover", function(d) { d.fixed = true; })
308       .on("mouseout", function(d) { if (d != node) d.fixed = false; })
309       .on("mousedown", mousedown);
310
311     d3.select(window)
312       .on("mousemove", mousemove)
313       .on("mouseup", mouseup);
314
315     function mousedown(d) {
316       (node = d).fixed = true;
317       element = this;
318       d3.event.preventDefault();
319     }
320
321     function mousemove() {
322       if (!node) return;
323       var m = d3.svg.mouse(element);
324       node.x = m[0];
325       node.y = m[1];
326       force.resume(); // restart annealing
327     }
328
329     function mouseup() {
330       if (!node) return;
331       mousemove();
332       node.fixed = false;
333       node = element = null;
334     }
335
336     return force;
337   };
338
339   return force;
340 };
341 d3.layout.partition = function() {
342   var hierarchy = d3.layout.hierarchy(),
343       size = [1, 1]; // width, height
344
345   function position(node, x, dx, dy) {
346     var children = node.children;
347     node.x = x;
348     node.y = node.depth * dy;
349     node.dx = dx;
350     node.dy = dy;
351     if (children) {
352       var i = -1,
353           n = children.length,
354           c,
355           d;
356       dx /= node.value;
357       while (++i < n) {
358         position(c = children[i], x, d = c.value * dx, dy);
359         x += d;
360       }
361     }
362   }
363
364   function depth(node) {
365     var children = node.children,
366         d = 0;
367     if (children) {
368       var i = -1,
369           n = children.length;
370       while (++i < n) d = Math.max(d, depth(children[i]));
371     }
372     return 1 + d;
373   }
374
375   function partition(d, i) {
376     var nodes = hierarchy.call(this, d, i);
377     position(nodes[0], 0, size[0], size[1] / depth(nodes[0]));
378     return nodes;
379   }
380
381   partition.sort = d3.rebind(partition, hierarchy.sort);
382   partition.children = d3.rebind(partition, hierarchy.children);
383   partition.value = d3.rebind(partition, hierarchy.value);
384
385   partition.size = function(x) {
386     if (!arguments.length) return size;
387     size = x;
388     return partition;
389   };
390
391   return partition;
392 };
393 d3.layout.pie = function() {
394   var value = Number,
395       sort = null,
396       startAngle = 0,
397       endAngle = 2 * Math.PI;
398
399   function pie(data, i) {
400
401     // Compute the start angle.
402     var a = +(typeof startAngle == "function"
403         ? startAngle.apply(this, arguments)
404         : startAngle);
405
406     // Compute the angular range (end - start).
407     var k = (typeof endAngle == "function"
408         ? endAngle.apply(this, arguments)
409         : endAngle) - startAngle;
410
411     // Optionally sort the data.
412     var index = d3.range(data.length);
413     if (sort != null) index.sort(function(i, j) {
414       return sort(data[i], data[j]);
415     });
416
417     // Compute the numeric values for each data element.
418     var values = data.map(value);
419
420     // Convert k into a scale factor from value to angle, using the sum.
421     k /= values.reduce(function(p, d) { return p + d; }, 0);
422
423     // Compute the arcs!
424     var arcs = index.map(function(i) {
425       return {
426         value: d = values[i],
427         startAngle: a,
428         endAngle: a += d * k
429       };
430     });
431
432     // Return the arcs in the original data's order.
433     return data.map(function(d, i) {
434       return arcs[index[i]];
435     });
436   }
437
438   /**
439    * Specifies the value function *x*, which returns a nonnegative numeric value
440    * for each datum. The default value function is `Number`. The value function
441    * is passed two arguments: the current datum and the current index.
442    */
443   pie.value = function(x) {
444     if (!arguments.length) return value;
445     value = x;
446     return pie;
447   };
448
449   /**
450    * Specifies a sort comparison operator *x*. The comparator is passed two data
451    * elements from the data array, a and b; it returns a negative value if a is
452    * less than b, a positive value if a is greater than b, and zero if a equals
453    * b.
454    */
455   pie.sort = function(x) {
456     if (!arguments.length) return sort;
457     sort = x;
458     return pie;
459   };
460
461   /**
462    * Specifies the overall start angle of the pie chart. Defaults to 0. The
463    * start angle can be specified either as a constant or as a function; in the
464    * case of a function, it is evaluated once per array (as opposed to per
465    * element).
466    */
467   pie.startAngle = function(x) {
468     if (!arguments.length) return startAngle;
469     startAngle = x;
470     return pie;
471   };
472
473   /**
474    * Specifies the overall end angle of the pie chart. Defaults to 2Ď€. The
475    * end angle can be specified either as a constant or as a function; in the
476    * case of a function, it is evaluated once per array (as opposed to per
477    * element).
478    */
479   pie.endAngle = function(x) {
480     if (!arguments.length) return endAngle;
481     endAngle = x;
482     return pie;
483   };
484
485   return pie;
486 };
487 // data is two-dimensional array of x,y; we populate y0
488 // TODO perhaps make the `x`, `y` and `y0` structure customizable
489 d3.layout.stack = function() {
490   var order = "default",
491       offset = "zero";
492
493   function stack(data) {
494     var n = data.length,
495         m = data[0].length,
496         i,
497         j,
498         y0;
499
500     // compute the order of series
501     var index = d3_layout_stackOrders[order](data);
502
503     // set y0 on the baseline
504     d3_layout_stackOffsets[offset](data, index);
505
506     // propagate offset to other series
507     for (j = 0; j < m; ++j) {
508       for (i = 1, y0 = data[index[0]][j].y0; i < n; ++i) {
509         data[index[i]][j].y0 = y0 += data[index[i - 1]][j].y;
510       }
511     }
512
513     return data;
514   }
515
516   stack.order = function(x) {
517     if (!arguments.length) return order;
518     order = x;
519     return stack;
520   };
521
522   stack.offset = function(x) {
523     if (!arguments.length) return offset;
524     offset = x;
525     return stack;
526   };
527
528   return stack;
529 }
530
531 var d3_layout_stackOrders = {
532
533   "inside-out": function(data) {
534     var n = data.length,
535         i,
536         j,
537         max = data.map(d3_layout_stackMaxIndex),
538         sums = data.map(d3_layout_stackReduceSum),
539         index = d3.range(n).sort(function(a, b) { return max[a] - max[b]; }),
540         top = 0,
541         bottom = 0,
542         tops = [],
543         bottoms = [];
544     for (i = 0; i < n; i++) {
545       j = index[i];
546       if (top < bottom) {
547         top += sums[j];
548         tops.push(j);
549       } else {
550         bottom += sums[j];
551         bottoms.push(j);
552       }
553     }
554     return bottoms.reverse().concat(tops);
555   },
556
557   "reverse": function(data) {
558     return d3.range(data.length).reverse();
559   },
560
561   "default": function(data) {
562     return d3.range(data.length);
563   }
564
565 };
566
567 var d3_layout_stackOffsets = {
568
569   "silhouette": function(data, index) {
570     var n = data.length,
571         m = data[0].length,
572         sums = [],
573         max = 0,
574         i,
575         j,
576         o;
577     for (j = 0; j < m; ++j) {
578       for (i = 0, o = 0; i < n; i++) o += data[i][j].y;
579       if (o > max) max = o;
580       sums.push(o);
581     }
582     for (j = 0, i = index[0]; j < m; ++j) {
583       data[i][j].y0 = (max - sums[j]) / 2;
584     }
585   },
586
587   "wiggle": function(data, index) {
588     var n = data.length,
589         x = data[0],
590         m = x.length,
591         max = 0,
592         i,
593         j,
594         k,
595         ii,
596         ik,
597         i0 = index[0],
598         s1,
599         s2,
600         s3,
601         dx,
602         o,
603         o0;
604     data[i0][0].y0 = o = o0 = 0;
605     for (j = 1; j < m; ++j) {
606       for (i = 0, s1 = 0; i < n; ++i) s1 += data[i][j].y;
607       for (i = 0, s2 = 0, dx = x[j].x - x[j - 1].x; i < n; ++i) {
608         for (k = 0, ii = index[i], s3 = (data[ii][j].y - data[ii][j - 1].y) / (2 * dx); k < i; ++k) {
609           s3 += (data[ik = index[k]][j].y - data[ik][j - 1].y) / dx;
610         }
611         s2 += s3 * data[ii][j].y;
612       }
613       data[i0][j].y0 = o -= s1 ? s2 / s1 * dx : 0;
614       if (o < o0) o0 = o;
615     }
616     for (j = 0; j < m; ++j) data[i0][j].y0 -= o0;
617   },
618
619   "zero": function(data, index) {
620     var j = 0,
621         m = data[0].length,
622         i0 = index[0];
623     for (; j < m; ++j) data[i0][j].y0 = 0;
624   }
625
626 };
627
628 function d3_layout_stackReduceSum(d) {
629   return d.reduce(d3_layout_stackSum, 0);
630 }
631
632 function d3_layout_stackMaxIndex(array) {
633   var i = 1,
634       j = 0,
635       v = array[0].y,
636       k,
637       n = array.length;
638   for (; i < n; ++i) {
639     if ((k = array[i].y) > v) {
640       j = i;
641       v = k;
642     }
643   }
644   return j;
645 }
646
647 function d3_layout_stackSum(p, d) {
648   return p + d.y;
649 }
650 d3.layout.hierarchy = function() {
651   var sort = d3_layout_hierarchySort,
652       children = d3_layout_hierarchyChildren,
653       value = d3_layout_hierarchyValue;
654
655   // Recursively compute the node depth and value.
656   // Also converts the data representation into a standard hierarchy structure.
657   function recurse(data, depth, nodes) {
658     var datas = children.call(hierarchy, data, depth),
659         node = {depth: depth, data: data};
660     nodes.push(node);
661     if (datas) {
662       var i = -1,
663           n = datas.length,
664           c = node.children = [],
665           v = 0,
666           j = depth + 1;
667       while (++i < n) {
668         d = recurse(datas[i], j, nodes);
669         if (d.value > 0) { // ignore NaN, negative, etc.
670           c.push(d);
671           v += d.value;
672           d.parent = node;
673         }
674       }
675       if (sort) c.sort(sort);
676       node.value = v;
677     } else {
678       node.value = value.call(hierarchy, data, depth);
679     }
680     return node;
681   }
682
683   // Recursively re-evaluates the node value.
684   function revalue(node, depth) {
685     var children = node.children,
686         v = 0;
687     if (children) {
688       var i = -1,
689           n = children.length,
690           j = depth + 1;
691       while (++i < n) v += revalue(children[i], j);
692     } else {
693       v = value.call(hierarchy, node.data, depth);
694     }
695     return node.value = v;
696   }
697
698   function hierarchy(d) {
699     var nodes = [];
700     recurse(d, 0, nodes);
701     return nodes;
702   }
703
704   hierarchy.sort = function(x) {
705     if (!arguments.length) return sort;
706     sort = x;
707     return hierarchy;
708   };
709
710   hierarchy.children = function(x) {
711     if (!arguments.length) return children;
712     children = x;
713     return hierarchy;
714   };
715
716   hierarchy.value = function(x) {
717     if (!arguments.length) return value;
718     value = x;
719     return hierarchy;
720   };
721
722   // Re-evaluates the `value` property for the specified hierarchy.
723   hierarchy.revalue = function(root) {
724     revalue(root, 0);
725     return root;
726   };
727
728   return hierarchy;
729 }
730
731 function d3_layout_hierarchyChildren(d) {
732   return d.children;
733 }
734
735 function d3_layout_hierarchyValue(d) {
736   return d.value;
737 }
738
739 function d3_layout_hierarchySort(a, b) {
740   return b.value - a.value;
741 }
742 // Squarified Treemaps by Mark Bruls, Kees Huizing, and Jarke J. van Wijk
743 d3.layout.treemap = function() {
744   var hierarchy = d3.layout.hierarchy(),
745       round = Math.round,
746       size = [1, 1], // width, height
747       sticky = false,
748       stickies;
749
750   // Recursively compute the node area based on value & scale.
751   function scale(node, k) {
752     var children = node.children;
753     node.area = node.value * k;
754     if (children) {
755       var i = -1,
756           n = children.length;
757       while (++i < n) scale(children[i], k);
758     }
759   }
760
761   // Recursively arranges the specified node's children into squarified rows.
762   function squarify(node) {
763     if (!node.children) return;
764     var rect = {x: node.x, y: node.y, dx: node.dx, dy: node.dy},
765         row = [],
766         children = node.children.slice(), // copy-on-write
767         child,
768         best = Infinity, // the best row score so far
769         score, // the current row score
770         u = Math.min(rect.dx, rect.dy), // initial orientation
771         n;
772     row.area = 0;
773     while ((n = children.length) > 0) {
774       row.push(child = children[n - 1]);
775       row.area += child.area;
776       if ((score = worst(row, u)) <= best) { // continue with this orientation
777         children.pop();
778         best = score;
779       } else { // abort, and try a different orientation
780         row.area -= row.pop().area;
781         position(row, u, rect, false);
782         u = Math.min(rect.dx, rect.dy);
783         row.length = row.area = 0;
784         best = Infinity;
785       }
786     }
787     if (row.length) {
788       position(row, u, rect, true);
789       row.length = row.area = 0;
790     }
791     node.children.forEach(squarify);
792   }
793
794   // Recursively resizes the specified node's children into existing rows.
795   // Preserves the existing layout!
796   function stickify(node) {
797     if (!node.children) return;
798     var rect = {x: node.x, y: node.y, dx: node.dx, dy: node.dy},
799         children = node.children.slice(), // copy-on-write
800         child,
801         row = [];
802     row.area = 0;
803     while (child = children.pop()) {
804       row.push(child);
805       row.area += child.area;
806       if (child.z != null) {
807         position(row, child.z ? rect.dx : rect.dy, rect, !children.length);
808         row.length = row.area = 0;
809       }
810     }
811     node.children.forEach(stickify);
812   }
813
814   // Computes the score for the specified row, as the worst aspect ratio.
815   function worst(row, u) {
816     var s = row.area,
817         r,
818         rmax = 0,
819         rmin = Infinity,
820         i = -1,
821         n = row.length;
822     while (++i < n) {
823       r = row[i].area;
824       if (r < rmin) rmin = r;
825       if (r > rmax) rmax = r;
826     }
827     s *= s;
828     u *= u;
829     return Math.max((u * rmax) / s, s / (u * rmin));
830   }
831
832   // Positions the specified row of nodes. Modifies `rect`.
833   function position(row, u, rect, flush) {
834     var i = -1,
835         n = row.length,
836         x = rect.x,
837         y = rect.y,
838         v = u ? round(row.area / u) : 0,
839         o;
840     if (u == rect.dx) { // horizontal subdivision
841       if (flush || v > rect.dy) v = rect.dy; // over+underflow
842       while (++i < n) {
843         o = row[i];
844         o.x = x;
845         o.y = y;
846         o.dy = v;
847         x += o.dx = round(o.area / v);
848       }
849       o.z = true;
850       o.dx += rect.x + rect.dx - x; // rounding error
851       rect.y += v;
852       rect.dy -= v;
853     } else { // vertical subdivision
854       if (flush || v > rect.dx) v = rect.dx; // over+underflow
855       while (++i < n) {
856         o = row[i];
857         o.x = x;
858         o.y = y;
859         o.dx = v;
860         y += o.dy = round(o.area / v);
861       }
862       o.z = false;
863       o.dy += rect.y + rect.dy - y; // rounding error
864       rect.x += v;
865       rect.dx -= v;
866     }
867   }
868
869   function treemap(d) {
870     var nodes = stickies || hierarchy(d),
871         root = nodes[0];
872     root.x = 0;
873     root.y = 0;
874     root.dx = size[0];
875     root.dy = size[1];
876     if (stickies) hierarchy.revalue(root);
877     scale(root, size[0] * size[1] / root.value);
878     (stickies ? stickify : squarify)(root);
879     if (sticky) stickies = nodes;
880     return nodes;
881   }
882
883   treemap.sort = d3.rebind(treemap, hierarchy.sort);
884   treemap.children = d3.rebind(treemap, hierarchy.children);
885   treemap.value = d3.rebind(treemap, hierarchy.value);
886
887   treemap.size = function(x) {
888     if (!arguments.length) return size;
889     size = x;
890     return treemap;
891   };
892
893   treemap.round = function(x) {
894     if (!arguments.length) return round != Number;
895     round = x ? Math.round : Number;
896     return treemap;
897   };
898
899   treemap.sticky = function(x) {
900     if (!arguments.length) return sticky;
901     sticky = x;
902     stickies = null;
903     return treemap;
904   };
905
906   return treemap;
907 };
908 })()