]> nos-oignons.net Git - website.git/commitdiff
Services : Ajout d'un graphe avec l'historique du poid dasn le consensus et de la...
authorLunar <lunar@anargeek.net>
Fri, 3 Jun 2016 14:14:25 +0000 (16:14 +0200)
committerLunar <lunar@anargeek.net>
Fri, 3 Jun 2016 14:14:25 +0000 (16:14 +0200)
Services.mdwn
assets/bw_graphs.css
assets/l10n.en.js
assets/l10n.fr.js
assets/weights_graphs.css [new file with mode: 0644]
assets/weights_graphs.js [new file with mode: 0644]
local.css

index f80c4f48b6dff18e22dc66e7d890ff4022e1be69..75ea52a34fd6694d9f4756e86fd204e4bfa48545 100644 (file)
@@ -3,6 +3,8 @@
 [[!meta script="assets/d3/d3.v3.min"]]
 [[!meta script="assets/bw_graphs"]]
 [[!meta stylesheet="assets/bw_graphs" rel="stylesheet"]]
+[[!meta script="assets/weights_graphs"]]
+[[!meta stylesheet="assets/weights_graphs" rel="stylesheet"]]
 [[!meta script="assets/pie_graphs"]]
 [[!meta title="Services"]]
 
@@ -111,4 +113,12 @@ d3.select("#content").append("div")
   .text(L10n.loading);
 
 new BwDrawer("#bandwidth").draw();
+
+d3.select("#content").append("h1")
+  .text(L10n.weights);
+d3.select("#content").append("div")
+  .attr("id", "weights")
+  .text(L10n.loading);
+
+new WeightsDrawer("#weights").draw();
 </script>
index a455147192aeca913ba46fcb6b8e3c3fedb88043..7fd6abeca1f8eb5d4fe4847557360e2d2c80f55f 100644 (file)
@@ -1,5 +1,5 @@
-.axis path,
-.axis line {
+#bandwidth .axis path,
+#bandwidth .axis line {
   fill: none;
   stroke: #000;
   shape-rendering: crispEdges;
index 6360646a268afbed7480e33ec7bb40ba51da03ca..a03d9bea8eb4995231c201fc67f2664dbe60fa04 100644 (file)
@@ -3,6 +3,7 @@ L10n.loading = "Loading…";
 L10n.consensus_weight = "Nos oignons' weight in the Tor network";
 L10n.exit_probability = "Probability to use one of our exit nodes";
 L10n.bandwidth = "Bandwidth";
+L10n.weights = "Weights and probabilites";
 L10n.nos_oignons = "Nos oignons";
 L10n.others = "Others";
 L10n.t_1_month = "1 month";
index 67c10566a019489ff562bb4b4b4ee6b40eb324ae..d85a82ceaa15818d6c0d7a26bed21029906d5ffd 100644 (file)
@@ -3,6 +3,7 @@ L10n.loading = "Chargement…";
 L10n.consensus_weight = "Poids de Nos oignons dans le réseau Tor";
 L10n.exit_probability = "Probabilité d'utiliser un de nos nœuds de sortie";
 L10n.bandwidth = "Bande passante";
+L10n.weights = "Poids et probabilités";
 L10n.nos_oignons = "Nos oignons";
 L10n.others = "Autres";
 L10n.t_1_month = "1 mois";
diff --git a/assets/weights_graphs.css b/assets/weights_graphs.css
new file mode 100644 (file)
index 0000000..ca1207c
--- /dev/null
@@ -0,0 +1,19 @@
+#weights .axis path,
+#weights .axis line {
+  fill: none;
+  stroke: #000;
+  shape-rendering: crispEdges;
+}
+
+#weights form {
+  margin: auto;
+  width: 35em;
+}
+
+#weights div {
+  float: left;
+  width: 7em;
+}
+#weights svg {
+  clear: left;
+}
diff --git a/assets/weights_graphs.js b/assets/weights_graphs.js
new file mode 100644 (file)
index 0000000..915a8b8
--- /dev/null
@@ -0,0 +1,247 @@
+function WeightsDrawer(selector) {
+  this.selector = selector;
+  this.current_source = "consensus_weight_fraction";
+  this.current_period = "1_month";
+  this.weights_data = {};
+  this.svg = null;
+};
+WeightsDrawer.prototype = new WeightsDrawer();
+
+WeightsDrawer.margin = {top: 50, right: 10, bottom: 90, left: 130};
+WeightsDrawer.width = 600 - WeightsDrawer.margin.left - WeightsDrawer.margin.right;
+WeightsDrawer.height = 400 - WeightsDrawer.margin.top - WeightsDrawer.margin.bottom;
+
+WeightsDrawer.parseTime = d3.time.format("%Y-%m-%d %H:%M:%S").parse;
+WeightsDrawer.percentFormatter = d3.format(".2%");
+
+WeightsDrawer.x = d3.time.scale()
+    .range([0, WeightsDrawer.width]);
+
+WeightsDrawer.y = d3.scale.linear()
+    .range([WeightsDrawer.height, 0]);
+
+WeightsDrawer.xAxis = d3.svg.axis()
+    .scale(WeightsDrawer.x)
+    .orient("bottom");
+
+WeightsDrawer.yAxis = d3.svg.axis()
+    .scale(WeightsDrawer.y)
+    .orient("left")
+    .tickFormat(function(d) { return (d == 0) ? "" : WeightsDrawer.percentFormatter(d); });
+
+WeightsDrawer.area = d3.svg.area()
+    .x(function(d) { return WeightsDrawer.x(d.date); })
+    .y0(function(d) { return WeightsDrawer.y(d.y0); })
+    .y1(function(d) { return WeightsDrawer.y(d.y0 + d.y); });
+
+WeightsDrawer.stack = d3.layout.stack()
+    .values(function(d) { return d.values; });
+
+WeightsDrawer.onionoo_url = "https://onionoo.torproject.org/weights?type=relay&contact=adminsys@nos-oignons.net";
+
+WeightsDrawer.periods = [
+    { id: "1_month", label: L10n.t_1_month },
+    { id: "3_months", label: L10n.t_3_months },
+    { id: "1_year", label: L10n.t_1_year },
+    { id: "5_years", label: L10n.t_5_years },
+  ];
+
+WeightsDrawer.current_period = WeightsDrawer.periods[0].id;
+
+WeightsDrawer.sources = [
+    { id: "consensus_weight_fraction", label: L10n.consensus_weight },
+    { id: "exit_probability", label: L10n.exit_probability },
+  ];
+
+WeightsDrawer.current_source = WeightsDrawer.sources[0].id;
+
+WeightsDrawer.extract_values = function(history, interval, minTime, maxTime) {
+  var values = [];
+  var first = history ? WeightsDrawer.parseTime(history.first) : maxTime;
+  var last = history ? WeightsDrawer.parseTime(history.last) : minTime;
+  var i = 0;
+  for (var current = minTime; current <= maxTime; current = d3.time.second.offset(current, interval)) {
+    values.push({ date: current,
+                  y: (first <= current && current <= last) ? history.factor * history.values[i++] : 0
+                });
+  }
+  return values;
+}
+
+WeightsDrawer.color = d3.scale.ordinal();
+WeightsDrawer.color.domain(nos_oignons_relays.map(function(r) {return r.fingerprint}));
+WeightsDrawer.color.range(nos_oignons_relays.map(function(r) {return r.color}));
+
+WeightsDrawer.prototype.draw_weights_graph = function(raw_data) {
+  var drawer = this;
+
+  // Purge non running relays
+  raw_data.relays.forEach(function(r, i) {
+    if (typeof r.consensus_weight_fraction === 'undefined') {
+      raw_data.relays.splice(i, 1);
+    }
+  });
+
+  var form_source = d3.select(drawer.selector).append("form")
+      .attr("action", "#");
+  WeightsDrawer.sources.forEach(function(s) {
+    var div = form_source.append("div");
+    var radio = div.append("input")
+      .attr("type", "radio")
+      .attr("name", "source")
+      .attr("id", "source_" + s.id)
+      .on("click", function() { drawer.update_source(s.id); });
+    div.append("label")
+      .attr("for", "source_" + s.id)
+      .text(s.label);
+    if (s.id == WeightsDrawer.sources[0].id) {
+      radio.attr("checked", true);
+    }
+  });
+
+  drawer.svg = d3.select(drawer.selector).append("svg")
+      .attr("width", WeightsDrawer.width + WeightsDrawer.margin.left + WeightsDrawer.margin.right)
+      .attr("height", WeightsDrawer.height + WeightsDrawer.margin.top + WeightsDrawer.margin.bottom)
+    .append("g")
+      .attr("transform", "translate(" + WeightsDrawer.margin.left + "," + WeightsDrawer.margin.top + ")");
+
+  var form_period = d3.select(drawer.selector).append("form")
+      .attr("action", "#");
+  WeightsDrawer.periods.forEach(function(p) {
+    var div = form_period.append("div");
+    var radio = div.append("input")
+      .attr("type", "radio")
+      .attr("name", "period")
+      .attr("id", "period_" + p.id)
+      .on("click", function() { drawer.update_period(p.id); });
+    div.append("label")
+      .attr("for", "period_" + p.id)
+      .text(p.label);
+    if (p.id == WeightsDrawer.periods[0].id) {
+      radio.attr("checked", true);
+    }
+  });
+
+  WeightsDrawer.sources.map(function(s) { return s.id; }).forEach(function(source) {
+    drawer.weights_data[source] = {};
+    WeightsDrawer.periods.map(function(p) { return p.id; }).forEach(function(period) {
+      var interval = d3.max(raw_data.relays, function(d) {
+        return d[source][period] && d[source][period].interval;
+      });
+      raw_data.relays.forEach(function(d) {
+        if ((d[source][period] && d[source][period].interval != interval)) {
+          throw "PANIC: Different interval for different relays in the same time period.";
+        }
+      });
+      var minTime = d3.min(raw_data.relays, function(d) {
+        return d[source][period] && WeightsDrawer.parseTime(d[source][period].first);
+      });
+      var maxTime = d3.min(raw_data.relays, function(d) {
+        return d[source][period] && WeightsDrawer.parseTime(d[source][period].last);
+      });
+
+      var maxValue = 0;
+
+      var relays = WeightsDrawer.color.domain().map(function(fingerprint) {
+        var relay_data = raw_data["relays"].filter(function(d) { return d.fingerprint == fingerprint; })[0];
+
+        var history = relay_data[source][period];
+        var values = WeightsDrawer.extract_values(history, interval, minTime, maxTime);
+        maxValue = maxValue + d3.max(values, function(d) { return d.y; });
+
+        return {
+          fingerprint: fingerprint,
+          values: values,
+        };
+      });
+      drawer.weights_data[source][period] = {
+        minTime: minTime,
+        maxTime: maxTime,
+        maxValue: maxValue,
+        relays: relays
+      };
+    });
+  });
+
+  WeightsDrawer.y.domain([0, drawer.weights_data[WeightsDrawer.current_source][WeightsDrawer.current_period].maxValue]);
+
+  WeightsDrawer.x.domain([drawer.weights_data[WeightsDrawer.current_source][WeightsDrawer.current_period].minTime, drawer.weights_data[WeightsDrawer.current_source][WeightsDrawer.current_period].maxTime]);
+
+  var weight_graph = drawer.svg.selectAll(".weight_graph")
+      .data(WeightsDrawer.stack(drawer.weights_data[WeightsDrawer.current_source][WeightsDrawer.current_period].relays))
+    .enter().append("path")
+      .attr("class", "weight_graph area")
+      .attr("d", function(d) { return WeightsDrawer.area(d.values); })
+      .style("fill", function(d) { return WeightsDrawer.color(d.fingerprint); });
+
+  drawer.svg.append("g")
+      .attr("class", "x axis")
+      .attr("transform", "translate(0," + WeightsDrawer.height + ")")
+      .call(WeightsDrawer.xAxis)
+        .selectAll("text")
+        .style("text-anchor", "end")
+        .attr("transform", "rotate(-90) translate(-10, 0)");
+
+  drawer.svg.append("g")
+      .attr("class", "y axis")
+      .call(WeightsDrawer.yAxis);
+
+  var legend = drawer.svg.selectAll(".legend")
+      .data(WeightsDrawer.color.domain().slice().reverse())
+    .enter().append("g")
+      .attr("class", "legend")
+      .attr("transform", function(d, i) { return "translate(0," + ((i * 20) - WeightsDrawer.margin.top) + ")"; });
+
+  legend.append("rect")
+      .attr("x", WeightsDrawer.width - 18)
+      .attr("width", 18)
+      .attr("height", 18)
+      .style("fill", WeightsDrawer.color);
+
+  legend.append("text")
+      .attr("x", WeightsDrawer.width - 24)
+      .attr("y", 9)
+      .attr("dy", ".35em")
+      .style("text-anchor", "end")
+      .text(function(d) {
+        return nos_oignons_relays.filter(function(r) { return r.fingerprint == d; })[0].name;
+      });
+};
+
+WeightsDrawer.prototype.refresh_graph = function() {
+  var drawer = this;
+
+  WeightsDrawer.x.domain([drawer.weights_data[drawer.current_source][drawer.current_period].minTime, drawer.weights_data[drawer.current_source][drawer.current_period].maxTime]);
+  WeightsDrawer.y.domain([0, drawer.weights_data[drawer.current_source][drawer.current_period].maxValue]);
+  var t = drawer.svg.transition().duration(300);
+  t.select(".x.axis").call(WeightsDrawer.xAxis);
+  t.select(".y.axis").call(WeightsDrawer.yAxis);
+  t.selectAll(".weight_graph").style("fill-opacity", 0);
+  t.each("end", function() {
+    d3.selectAll(".weight_graph").data(WeightsDrawer.stack(drawer.weights_data[drawer.current_source][drawer.current_period].relays));
+    d3.selectAll(".weight_graph").attr("d", function(d) { return WeightsDrawer.area(d.values); })
+    var t2 = drawer.svg.transition().duration(100);
+    t2.selectAll(".weight_graph").style("fill-opacity", 1);
+  });
+  d3.selectAll(".x.axis text")
+    .style("text-anchor", "end")
+    .attr("transform", "rotate(-90) translate(-10, 0)");
+}
+
+WeightsDrawer.prototype.update_source = function(source) {
+  this.current_source = source;
+  this.refresh_graph();
+}
+
+WeightsDrawer.prototype.update_period = function(period) {
+  this.current_period = period;
+  this.refresh_graph();
+}
+
+WeightsDrawer.prototype.draw = function() {
+  var drawer = this;
+  d3.json(WeightsDrawer.onionoo_url, function(error, raw_data) {
+    d3.select(drawer.selector).text("");
+    drawer.draw_weights_graph(raw_data);
+  });
+};
index 53b5b54ebcc7e1e922754670b3f4109e96dc4656..ba0db98c77bfb0d435b5ecb0dff18eae1fcf2797 100644 (file)
--- a/local.css
+++ b/local.css
@@ -415,8 +415,8 @@ main .footnotes {
   text-align: center;
 }
 
-#bandwidth {text-align: center;}
-#bandwidth svg {text-align: left;}
+#bandwidth, #weights {text-align: center;}
+#bandwidth svg, #weights svg {text-align: left;}
 
 /* Tor nodes table */
 .tor-nodes {}