Fix s/about/~/ substitution on dashboard.
[arvados.git] / apps / workbench / public / graph-example.html
1 <!DOCTYPE html>
2 <!-- from http://bl.ocks.org/1153292 -->
3 <html>
4   <head>
5     <meta http-equiv="Content-type" content="text/html; charset=utf-8">
6     <title>Object graph example</title>
7     <script src="d3.v3.min.js"></script>
8     <style type="text/css">
9
10 path.link {
11   fill: none;
12   stroke: #666;
13   stroke-width: 1.5px;
14 }
15
16 marker#can_read {
17   fill: green;
18 }
19
20 path.link.can_read {
21   stroke: green;
22   stroke-dasharray: 0,4 1;
23 }
24
25 path.link.can_write {
26   stroke: green;
27 }
28
29 path.link.member_of {
30   stroke: blue;
31   stroke-dasharray: 0,4 1;
32 }
33
34 path.link.created {
35   stroke: red;
36 }
37
38 circle {
39   fill: #ccc;
40   stroke: #333;
41   stroke-width: 1.5px;
42 }
43
44 edgetext {
45   font: 12px sans-serif;
46   pointer-events: none;
47     text-align: center;
48 }
49
50 text {
51   font: 12px sans-serif;
52   pointer-events: none;
53 }
54
55 text.shadow {
56   stroke: #fff;
57   stroke-width: 3px;
58   stroke-opacity: .8;
59 }
60
61     </style>
62   </head>
63   <body>
64     <script type="text/javascript">
65
66 var links = [
67   {source: "user: customer", target: "project: customer_project", type: "can_read"},
68   {source: "user: import robot", target: "project: customer_project", type: "can_read"},
69   {source: "user: pipeline robot", target: "project: customer_project", type: "can_read"},
70   {source: "user: uploader", target: "collection: w3anr2hk2wgfpuo", type: "created"},
71   {source: "user: uploader", target: "project: customer_project", type: "created"},
72   {source: "collection: w3anr2hk2wgfpuo", target: "project: customer_project", type: "member_of"}
73 ];
74
75 var nodes = {};
76
77 // Compute the distinct nodes from the links.
78 links.forEach(function(link) {
79   link.source = nodes[link.source] || (nodes[link.source] = {name: link.source});
80   link.target = nodes[link.target] || (nodes[link.target] = {name: link.target});
81 });
82
83 var w = 960,
84     h = 500;
85
86 var force = d3.layout.force()
87     .nodes(d3.values(nodes))
88     .links(links)
89     .size([w, h])
90     .linkDistance(250)
91     .charge(-300)
92     .on("tick", tick)
93     .start();
94
95 var svg = d3.select("body").append("svg:svg")
96     .attr("width", w)
97     .attr("height", h);
98
99 // Per-type markers, as they don't inherit styles.
100 svg.append("svg:defs").selectAll("marker")
101     .data(["created", "member_of", "can_read", "can_write"])
102   .enter().append("svg:marker")
103     .attr("id", String)
104     .attr("viewBox", "0 -5 10 10")
105     .attr("refX", 15)
106     .attr("refY", -1.5)
107     .attr("markerWidth", 6)
108     .attr("markerHeight", 6)
109     .attr("orient", "auto")
110   .append("svg:path")
111     .attr("d", "M0,-5L10,0L0,5");
112
113 var path = svg.append("svg:g").selectAll("path")
114     .data(force.links())
115   .enter().append("svg:path")
116     .attr("class", function(d) { return "link " + d.type; })
117     .attr("marker-end", function(d) { return "url(#" + d.type + ")"; });
118
119 var circle = svg.append("svg:g").selectAll("circle")
120     .data(force.nodes())
121   .enter().append("svg:circle")
122     .attr("r", 6)
123     .call(force.drag);
124
125 var text = svg.append("svg:g").selectAll("g")
126     .data(force.nodes())
127   .enter().append("svg:g");
128
129 // A copy of the text with a thick white stroke for legibility.
130 text.append("svg:text")
131     .attr("x", 8)
132     .attr("y", ".31em")
133     .attr("class", "shadow")
134     .text(function(d) { return d.name; });
135
136 text.append("svg:text")
137     .attr("x", 8)
138     .attr("y", ".31em")
139     .text(function(d) { return d.name; });
140
141 var edgetext = svg.append("svg:g").selectAll("g")
142     .data(force.links())
143     .enter().append("svg:g");
144
145 edgetext
146     .append("svg:text")
147     .attr("x",0)
148     .attr("y","-0.2em")
149     .text(function(d) { return d.type; });
150
151 // Use elliptical arc path segments to doubly-encode directionality.
152 function tick() {
153   path.attr("d", function(d) {
154     var dx = d.target.x - d.source.x,
155         dy = d.target.y - d.source.y,
156         // dr = Math.sqrt(dx * dx + dy * dy);
157         dr = 0;
158     return "M" + d.source.x + "," + d.source.y + "A" + dr + "," + dr + " 0 0,1 " + d.target.x + "," + d.target.y;
159   });
160
161   circle.attr("transform", function(d) {
162     return "translate(" + d.x + "," + d.y + ")";
163   });
164
165   text.attr("transform", function(d) {
166     return "translate(" + d.x + "," + d.y + ")";
167   });
168
169   edgetext.attr("transform", function(d) {
170       return "translate(" +
171           (d.source.x + d.target.x)/2 + "," +
172           (d.source.y + d.target.y)/2 +
173           ")rotate(" +
174           (Math.atan2(d.target.y - d.source.y, d.target.x - d.source.x) * 180 / Math.PI) +
175           ")";
176   });
177 }
178
179     </script>
180   </body>
181 </html>