1 [[!meta script="assets/relays"]]
2 [[!meta script="assets/d3/d3.v3.min"]]
4 <style type="text/css">
12 <div style="float: left; width: 45%">
13 <h2 style="text-align: center;">Consensus weight</h2>
14 <div id="consensus-pie"></div>
16 <div style="float: left; width: 45%; margin-left: 3%">
17 <h2 style="text-align: center;">Exit probability</h2>
18 <div id="exit-pie"></div>
20 <div style="clear: left;"></div>
22 <script type="text/javascript">
26 radius = Math.min(width, height) / 2,
27 formatPercent = d3.format(".2%");
29 var color_nos_oignons = "#ffa430";
30 var color_others = "#57075f";
32 var arc = d3.svg.arc()
33 .outerRadius(radius - 30)
34 .innerRadius(radius - 80);
36 var labelRadius = radius - 15;
38 var pie = d3.layout.pie()
40 .value(function(d) { return d.frac; });
42 var onionoo_url = "https://onionoo.torproject.org/details?type=relay&contact=adminsys@nos-oignons.net";
44 var search_terms = "";
45 nos_oignons_relays.forEach(function(r) {
46 search_terms += " $" + r.fingerprint
49 function PieDrawer() { };
50 PieDrawer.prototype.getSelector = undefined;
51 PieDrawer.prototype.getFieldName = undefined;
52 PieDrawer.prototype.getField = undefined;
53 PieDrawer.prototype.draw = function() {
54 var svg = d3.select(this.getSelector()).append("svg")
55 .style("margin", "auto")
57 .attr("height", height)
59 .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
61 var text = svg.append("text")
62 .attr("text-anchor", "middle")
66 var field_getter = this.getField;
67 d3.json(onionoo_url + "&fields=fingerprint," + this.getFieldName(), function(error, raw_data) {
68 var frac_nos_oignons = 0;
69 raw_data['relays'].forEach(function(d) {
70 nos_oignons_relays.forEach(function(r) {
71 if (r.fingerprint == d.fingerprint) {
72 var value = field_getter(d);
74 frac_nos_oignons += value;
79 var frac_others = 1 - frac_nos_oignons;
81 data = [ { name: 'Nos oignons', frac: frac_nos_oignons, color: color_nos_oignons, },
82 { name: 'Others', frac: frac_others, color: color_others }, ];
84 text.text(formatPercent(data[0].frac));
86 var g = svg.selectAll(".arc")
89 .attr("class", "arc");
93 .style("fill", function(d) { return d.data.color; });
98 function ConsensusPieDrawer() { };
99 ConsensusPieDrawer.prototype = new PieDrawer();
100 ConsensusPieDrawer.prototype.getSelector = function() {
101 return "#consensus-pie";
103 ConsensusPieDrawer.prototype.getFieldName = function() {
104 return "consensus_weight_fraction";
106 ConsensusPieDrawer.prototype.getField = function(r) {
107 return r.consensus_weight_fraction;
110 function ExitPieDrawer() { };
111 ExitPieDrawer.prototype = new PieDrawer();
112 ExitPieDrawer.prototype.getSelector = function() {
115 ExitPieDrawer.prototype.getFieldName = function() {
116 return "exit_probability";
118 ExitPieDrawer.prototype.getField = function(r) {
119 return r.exit_probability;
122 new ConsensusPieDrawer().draw();
123 new ExitPieDrawer().draw();
129 <h3>3 days / read</h3>
130 <div id="bandwidth-3d-read"></div>
131 <h3>3 days / write</h3>
132 <div id="bandwidth-3d-write"></div>
133 <h3>1 week / read</h3>
134 <div id="bandwidth-1w-read"></div>
135 <h3>1 week / write</h3>
136 <div id="bandwidth-1w-write"></div>
137 <h3>1 month / read</h3>
138 <div id="bandwidth-1m-read"></div>
139 <h3>1 month / write</h3>
140 <div id="bandwidth-1m-write"></div>
141 <h3>3 months / read</h3>
142 <div id="bandwidth-3m-read"></div>
143 <h3>3 months / write</h3>
144 <div id="bandwidth-3m-write"></div>
145 <h3>1 year / read</h3>
146 <div id="bandwidth-1y-read"></div>
147 <h3>1 year / write</h3>
148 <div id="bandwidth-1y-write"></div>
150 <style type="text/css">
156 shape-rendering: crispEdges;
165 <script type="text/javascript">
167 var margin = {top: 50, right: 90, bottom: 90, left: 90},
168 width = 600 - margin.left - margin.right,
169 height = 300 - margin.top - margin.bottom;
171 var parseTime = d3.time.format("%Y-%m-%d %H:%M:%S").parse,
172 bwFormatter = d3.format(".2r");
174 var x = d3.time.scale()
177 var y = d3.scale.linear()
180 var color = d3.scale.category20();
182 var xAxis = d3.svg.axis()
186 var yAxis = d3.svg.axis()
189 .tickFormat(function(d) { return bwFormatter(d * 8 / (1000 * 1000)) + "Mbit/s"; });
191 var area = d3.svg.area()
192 .x(function(d) { return x(d.date); })
193 .y0(function(d) { return y(d.y0); })
194 .y1(function(d) { return y(d.y0 + d.y); });
196 var stack = d3.layout.stack()
197 .values(function(d) { return d.values; });
199 var onionoo_url = "https://onionoo.torproject.org/bandwidth?type=relay&contact=adminsys@nos-oignons.net";
201 function draw_bandwidth_graph(raw_data, selector, direction, period) {
202 var svg = d3.select(selector).append("svg")
203 .attr("width", width + margin.left + margin.right)
204 .attr("height", height + margin.top + margin.bottom)
206 .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
208 var valid_fingerprints = [];
209 nos_oignons_relays.forEach(function(r) {
210 var relay_data = raw_data["relays"].filter(function(d) { return d.fingerprint == r.fingerprint; })[0];
211 if (relay_data && relay_data[direction][period]) {
212 valid_fingerprints.push(r.fingerprint);
215 color.domain(valid_fingerprints);
217 var minTime = d3.max(raw_data.relays.map(function(d) { return d[direction][period] && parseTime(d[direction][period].first); }));
218 var maxTime = d3.min(raw_data.relays.map(function(d) { return d[direction][period] && parseTime(d[direction][period].last); }));
219 var maxTotalBandwidth = 0;
221 var data = stack(color.domain().map(function(fingerprint) {
222 var relay_data = raw_data["relays"].filter(function(d) { return d.fingerprint == fingerprint; })[0];
223 var history = relay_data[direction][period];
226 var first = parseTime(history.first);
227 var last = parseTime(history.last);
229 for (var current = minTime; current <= maxTime; current = d3.time.second.offset(current, history.interval)) {
230 if (first <= current && current <= last) {
231 values.push({ date: current, y: history.factor * history.values[i++] });
235 maxTotalBandwidth = maxTotalBandwidth + history.factor * d3.max(history.values);
238 fingerprint: fingerprint,
242 x.domain([minTime, maxTime]);
243 y.domain([0, maxTotalBandwidth]);
245 var relay = svg.selectAll(".relay")
248 .attr("class", "relay");
251 .attr("class", "area")
252 .attr("d", function(d) { return area(d.values); })
253 .style("fill", function(d) { return color(d.fingerprint); });
256 .attr("class", "x axis")
257 .attr("transform", "translate(0," + height + ")")
260 .style("text-anchor", "end")
261 .attr("transform", "rotate(-90) translate(-10, 0)");
264 .attr("class", "y axis")
267 var legend = svg.selectAll(".legend")
268 .data(color.domain().slice().reverse())
270 .attr("class", "legend")
271 .attr("transform", function(d, i) { return "translate(0," + ((i * 20) - margin.top) + ")"; });
273 legend.append("rect")
274 .attr("x", width - 18)
277 .style("fill", color);
279 legend.append("text")
280 .attr("x", width - 24)
283 .style("text-anchor", "end")
285 return nos_oignons_relays.filter(function(r) { return r.fingerprint == d; })[0].name;
289 d3.json(onionoo_url, function(error, raw_data) {
290 draw_bandwidth_graph(raw_data, "#bandwidth-3d-read", "read_history", "3_days");
291 draw_bandwidth_graph(raw_data, "#bandwidth-3d-write", "write_history", "3_days");
292 draw_bandwidth_graph(raw_data, "#bandwidth-1w-read", "read_history", "1_week");
293 draw_bandwidth_graph(raw_data, "#bandwidth-1w-write", "write_history", "1_week");
294 draw_bandwidth_graph(raw_data, "#bandwidth-1m-read", "read_history", "1_month");
295 draw_bandwidth_graph(raw_data, "#bandwidth-1m-write", "write_history", "1_month");
296 draw_bandwidth_graph(raw_data, "#bandwidth-3m-read", "read_history", "3_months");
297 draw_bandwidth_graph(raw_data, "#bandwidth-3m-write", "write_history", "3_months");
298 draw_bandwidth_graph(raw_data, "#bandwidth-1y-read", "read_history", "1_year");
299 draw_bandwidth_graph(raw_data, "#bandwidth-1y-write", "write_history", "1_year");