Fix 2.4.2 upgrade notes formatting refs #19330
[arvados.git] / apps / workbench / app / views / collections / graph.html.erb
1 <%# Copyright (C) The Arvados Authors. All rights reserved.
2
3 SPDX-License-Identifier: AGPL-3.0 %>
4
5 <%#= render :partial => 'nav' %>
6 <table class="table table-bordered">
7   <tbody>
8     <tr>
9       <td class="d3">
10       </td>
11     </tr>
12   </tbody>
13 </table>
14
15 <% content_for :head do %>
16 <%= javascript_include_tag '/d3.v3.min.js' %>
17
18     <style type="text/css">
19
20 path.link {
21   fill: none;
22   stroke: #666;
23   stroke-width: 1.5px;
24 }
25
26 path.link.derived_from {
27   stroke: green;
28   stroke-dasharray: 0,4 1;
29 }
30
31 path.link.can_write {
32   stroke: green;
33 }
34
35 path.link.member_of {
36   stroke: blue;
37   stroke-dasharray: 0,4 1;
38 }
39
40 path.link.created {
41   stroke: red;
42 }
43
44 circle.node {
45   fill: #ccc;
46   stroke: #333;
47   stroke-width: 1.5px;
48 }
49
50 edgetext {
51   font: 12px sans-serif;
52   pointer-events: none;
53     text-align: center;
54 }
55
56 text {
57   font: 12px sans-serif;
58   pointer-events: none;
59 }
60
61 text.shadow {
62   stroke: #fff;
63   stroke-width: 3px;
64   stroke-opacity: .8;
65 }
66
67     </style>
68 <% end %>
69
70 <% content_for :js do %>
71
72 jQuery(function($){
73
74     var links = <%= raw d3ify_links(@links).to_json %>;
75
76     var nodes = {};
77
78     // Compute the distinct nodes from the links.
79     links.forEach(function(link) {
80         link.source = nodes[link.source] || (nodes[link.source] = {name: link.source});
81         link.target = nodes[link.target] || (nodes[link.target] = {name: link.target});
82     });
83
84     var fill_for = {'ldvyl': 'green',
85                     'j58dm': 'red',
86                     '4zz18': 'blue'};
87     jQuery.each(nodes, function(i, node) {
88         var m = node.name.match(/-([a-z0-9]{5})-/)
89         if (m)
90             node.fill = fill_for[m[1]] || '#ccc';
91         else if (node.name.match(/^[0-9a-f]{32}/))
92             node.fill = fill_for['4zz18'];
93         else
94             node.fill = '#ccc';
95     });
96
97     var w = 960,
98     h = 600;
99
100     var force = d3.layout.force()
101         .nodes(d3.values(nodes))
102         .links(links)
103         .size([w, h])
104         .linkDistance(150)
105         .charge(-300)
106         .on("tick", tick)
107         .start();
108
109     var svg = d3.select("td.d3").append("svg:svg")
110         .attr("width", w)
111         .attr("height", h);
112
113     // Per-type markers, as they don't inherit styles.
114     svg.append("svg:defs").selectAll("marker")
115         .data(["member_of", "owner", "derived_from"])
116         .enter().append("svg:marker")
117         .attr("id", String)
118         .attr("viewBox", "0 -5 10 10")
119         .attr("refX", 15)
120         .attr("refY", -1.5)
121         .attr("markerWidth", 6)
122         .attr("markerHeight", 6)
123         .attr("orient", "auto")
124         .append("svg:path")
125         .attr("d", "M0,-5L10,0L0,5");
126
127     var path = svg.append("svg:g").selectAll("path")
128         .data(force.links())
129         .enter().append("svg:path")
130         .attr("class", function(d) { return "link " + d.type; })
131         .attr("marker-end", function(d) { return "url(#" + d.type + ")"; });
132
133     var circle = svg.append("svg:g").selectAll("circle")
134         .data(force.nodes())
135         .enter().append("svg:circle")
136         .attr("r", 6)
137         .style("fill", function(d) { return d.fill; })
138         .call(force.drag);
139
140     var text = svg.append("svg:g").selectAll("g")
141         .data(force.nodes())
142         .enter().append("svg:g");
143
144     // A copy of the text with a thick white stroke for legibility.
145     text.append("svg:text")
146         .attr("x", 8)
147         .attr("y", ".31em")
148         .attr("class", "shadow")
149         .text(function(d) { return d.name.replace(/^([0-9a-z]{5}-){2}/,''); });
150
151     text.append("svg:text")
152         .attr("x", 8)
153         .attr("y", ".31em")
154         .text(function(d) { return d.name.replace(/^([0-9a-z]{5}-){2}/,''); });
155
156     var edgetext = svg.append("svg:g").selectAll("g")
157         .data(force.links())
158         .enter().append("svg:g");
159
160     edgetext
161         .append("svg:text")
162         .attr("x","-5em")
163         .attr("y","-0.2em")
164         .text(function(d) { return d.type; });
165
166     // Use elliptical arc path segments to doubly-encode directionality.
167     function tick() {
168         path.attr("d", function(d) {
169             var dx = d.target.x - d.source.x,
170             dy = d.target.y - d.source.y,
171             // dr = Math.sqrt(dx * dx + dy * dy);
172             dr = 0;
173             return "M" + d.source.x + "," + d.source.y + "A" + dr + "," + dr + " 0 0,1 " + d.target.x + "," + d.target.y;
174         });
175
176         circle.attr("transform", function(d) {
177             return "translate(" + d.x + "," + d.y + ")";
178         });
179
180         text.attr("transform", function(d) {
181             return "translate(" + d.x + "," + d.y + ")";
182         });
183
184         edgetext.attr("transform", function(d) {
185             return "translate(" +
186                 (d.source.x + d.target.x)/2 + "," +
187                 (d.source.y + d.target.y)/2 +
188                 ")rotate(" +
189                 (Math.atan2(d.target.y - d.source.y, d.target.x - d.source.x) * 180 / Math.PI) +
190                 ")";
191         });
192     }
193
194 })(jQuery);
195 <% end %>