From 8432d2f44740eaccd47c14abe52b1df01f5bb6d6 Mon Sep 17 00:00:00 2001 From: Lunar <lunar@anargeek.net> Date: Sat, 23 Nov 2013 17:41:51 +0100 Subject: [PATCH] Proprification et mise en place des graphs --- README | 7 + Services.en.po | 156 ++++++++++++++++- Services.mdwn | 58 +++++++ Services/Participation.html | 328 ------------------------------------ assets/bw_graphs.css | 19 +++ assets/bw_graphs.js | 224 ++++++++++++++++++++++++ assets/l10n.en.js | 12 ++ assets/l10n.fr.js | 12 ++ assets/pie_graphs.js | 94 +++++++++++ 9 files changed, 580 insertions(+), 330 deletions(-) delete mode 100644 Services/Participation.html create mode 100644 assets/bw_graphs.css create mode 100644 assets/bw_graphs.js create mode 100644 assets/l10n.en.js create mode 100644 assets/l10n.fr.js create mode 100644 assets/pie_graphs.js diff --git a/README b/README index 44cdc40..089fb03 100644 --- a/README +++ b/README @@ -49,3 +49,10 @@ Images Les sources des images utilisés se trouve dans le répertoire `Site_web` du dépôt « comm ». + +Modification de la liste des relais +----------------------------------- + +La liste des relais gérés par Nos oignons se trouve à deux endroits : +`Services.mdwn` et `assets/relays.js`. Il faut bien penser à tout mettre à +jour. diff --git a/Services.en.po b/Services.en.po index ba68054..3d0d655 100644 --- a/Services.en.po +++ b/Services.en.po @@ -1,8 +1,8 @@ msgid "" msgstr "" "Project-Id-Version: Nos oignons website\n" -"POT-Creation-Date: 2013-11-17 15:40+0100\n" -"PO-Revision-Date: 2013-11-17 16:00+0100\n" +"POT-Creation-Date: 2013-11-23 19:39+0100\n" +"PO-Revision-Date: 2013-11-23 19:50+0100\n" "Last-Translator: Nos oignons <webmaster@nos-oignons.net>\n" "Language-Team: English <webmaster@nos-oignons.net>\n" "Language: en\n" @@ -10,11 +10,137 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +#. type: Plain text +#, no-wrap +msgid "[[!meta script=\"assets/l10n.fr\"]]\n" +msgstr "[[!meta script=\"assets/l10n.en\"]]\n" + +#. type: Plain text +#, no-wrap +msgid "[[!meta script=\"assets/relays\"]]\n" +msgstr "[[!meta script=\"assets/relays\"]]\n" + +#. type: Plain text +#, no-wrap +msgid "[[!meta script=\"assets/d3/d3.v3.min\"]]\n" +msgstr "[[!meta script=\"assets/d3/d3.v3.min\"]]\n" + +#. type: Plain text +#, no-wrap +msgid "[[!meta script=\"assets/bw_graphs\"]]\n" +msgstr "[[!meta script=\"assets/bw_graphs\"]]\n" + +#. type: Plain text +#, no-wrap +msgid "[[!meta stylesheet=\"assets/bw_graphs\" rel=\"stylesheet\"]]\n" +msgstr "[[!meta stylesheet=\"assets/bw_graphs\" rel=\"stylesheet\"]]\n" + +#. type: Plain text +#, no-wrap +msgid "[[!meta script=\"assets/pie_graphs\"]]\n" +msgstr "[[!meta script=\"assets/pie_graphs\"]]\n" + #. type: Plain text #, no-wrap msgid "[[!meta title=\"Services\"]]\n" msgstr "[[!meta title=\"Services\"]]\n" +#. type: Plain text +#, no-wrap +msgid "<script>\n" +msgstr "<script>\n" + +#. type: Plain text +#, no-wrap +msgid "" +"var content = d3.select(\"#content\");\n" +"var consensus_div = content.append(\"div\")\n" +"consensus_div.append(\"div\")\n" +" .attr(\"id\", \"consensus-pie\")\n" +" .style(\"width\", PieDrawer.width + \"px\")\n" +" .style(\"height\", PieDrawer.height + \"px\")\n" +" .style(\"float\", \"left\");\n" +"consensus_div.append(\"div\")\n" +" .style(\"width\", \"400px\")\n" +" .style(\"margin-left\", \"5px\")\n" +" .style(\"line-height\", PieDrawer.height + \"px\")\n" +" .style(\"font-weight\", \"bold\")\n" +" .style(\"float\", \"left\")\n" +" .text(L10n.consensus_weight);\n" +msgstr "" +"var content = d3.select(\"#content\");\n" +"var consensus_div = content.append(\"div\")\n" +"consensus_div.append(\"div\")\n" +" .attr(\"id\", \"consensus-pie\")\n" +" .style(\"width\", PieDrawer.width + \"px\")\n" +" .style(\"height\", PieDrawer.height + \"px\")\n" +" .style(\"float\", \"left\");\n" +"consensus_div.append(\"div\")\n" +" .style(\"width\", \"400px\")\n" +" .style(\"margin-left\", \"5px\")\n" +" .style(\"line-height\", PieDrawer.height + \"px\")\n" +" .style(\"font-weight\", \"bold\")\n" +" .style(\"float\", \"left\")\n" +" .text(L10n.consensus_weight);\n" + +#. type: Plain text +#, no-wrap +msgid "" +"var exit_div = content.append(\"div\")\n" +"exit_div.append(\"div\")\n" +" .attr(\"id\", \"exit-pie\")\n" +" .style(\"width\", PieDrawer.width)\n" +" .style(\"height\", PieDrawer.height)\n" +" .style(\"clear\", \"left\")\n" +" .style(\"float\", \"left\");\n" +"exit_div.append(\"div\")\n" +" .style(\"width\", \"400px\")\n" +" .style(\"margin-left\", \"5px\")\n" +" .style(\"line-height\", PieDrawer.height + \"px\")\n" +" .style(\"font-weight\", \"bold\")\n" +" .style(\"float\", \"left\")\n" +" .text(L10n.exit_probability);\n" +msgstr "" +"var exit_div = content.append(\"div\")\n" +"exit_div.append(\"div\")\n" +" .attr(\"id\", \"exit-pie\")\n" +" .style(\"width\", PieDrawer.width)\n" +" .style(\"height\", PieDrawer.height)\n" +" .style(\"clear\", \"left\")\n" +" .style(\"float\", \"left\");\n" +"exit_div.append(\"div\")\n" +" .style(\"width\", \"400px\")\n" +" .style(\"margin-left\", \"5px\")\n" +" .style(\"line-height\", PieDrawer.height + \"px\")\n" +" .style(\"font-weight\", \"bold\")\n" +" .style(\"float\", \"left\")\n" +" .text(L10n.exit_probability);\n" + +#. type: Plain text +#, no-wrap +msgid "" +"content.append(\"div\")\n" +" .style(\"clear\", \"left\");\n" +msgstr "" +"content.append(\"div\")\n" +" .style(\"clear\", \"left\");\n" + +#. type: Plain text +#, no-wrap +msgid "" +"new ConsensusPieDrawer(\"#consensus-pie\").draw();\n" +"new ExitPieDrawer(\"#exit-pie\").draw();\n" +"</script>\n" +msgstr "" +"new ConsensusPieDrawer(\"#consensus-pie\").draw();\n" +"new ExitPieDrawer(\"#exit-pie\").draw();\n" +"</script>\n" + +#. type: Title = +#, no-wrap +msgid "Relais\n" +msgstr "Relays\n" + #. type: Plain text msgid "Nos oignons fait actuellement fonctionner les relais Tor suivants :" msgstr "Nos Oignons currently runs the following Tor relays:" @@ -114,3 +240,29 @@ msgstr "" " </tr>\n" " </tfoot>\n" "</table>\n" + +#. type: Plain text +#, no-wrap +msgid "" +"<script>\n" +"d3.select(\"#content\").append(\"h1\")\n" +" .text(L10n.bandwidth);\n" +"d3.select(\"#content\").append(\"div\")\n" +" .attr(\"id\", \"bandwidth\")\n" +" .text(L10n.loading);\n" +msgstr "" +"<script>\n" +"d3.select(\"#content\").append(\"h1\")\n" +" .text(L10n.bandwidth);\n" +"d3.select(\"#content\").append(\"div\")\n" +" .attr(\"id\", \"bandwidth\")\n" +" .text(L10n.loading);\n" + +#. type: Plain text +#, no-wrap +msgid "" +"new BwDrawer(\"#bandwidth\").draw();\n" +"</script>\n" +msgstr "" +"new BwDrawer(\"#bandwidth\").draw();\n" +"</script>\n" diff --git a/Services.mdwn b/Services.mdwn index 084f720..88bb60c 100644 --- a/Services.mdwn +++ b/Services.mdwn @@ -1,5 +1,53 @@ +[[!meta script="assets/l10n.fr"]] +[[!meta script="assets/relays"]] +[[!meta script="assets/d3/d3.v3.min"]] +[[!meta script="assets/bw_graphs"]] +[[!meta stylesheet="assets/bw_graphs" rel="stylesheet"]] +[[!meta script="assets/pie_graphs"]] [[!meta title="Services"]] +<script> + +var content = d3.select("#content"); +var consensus_div = content.append("div") +consensus_div.append("div") + .attr("id", "consensus-pie") + .style("width", PieDrawer.width + "px") + .style("height", PieDrawer.height + "px") + .style("float", "left"); +consensus_div.append("div") + .style("width", "400px") + .style("margin-left", "5px") + .style("line-height", PieDrawer.height + "px") + .style("font-weight", "bold") + .style("float", "left") + .text(L10n.consensus_weight); + +var exit_div = content.append("div") +exit_div.append("div") + .attr("id", "exit-pie") + .style("width", PieDrawer.width) + .style("height", PieDrawer.height) + .style("clear", "left") + .style("float", "left"); +exit_div.append("div") + .style("width", "400px") + .style("margin-left", "5px") + .style("line-height", PieDrawer.height + "px") + .style("font-weight", "bold") + .style("float", "left") + .text(L10n.exit_probability); + +content.append("div") + .style("clear", "left"); + +new ConsensusPieDrawer("#consensus-pie").draw(); +new ExitPieDrawer("#exit-pie").draw(); +</script> + +Relais +====== + Nos oignons fait actuellement fonctionner les relais Tor suivants : <table> @@ -48,3 +96,13 @@ Nos oignons fait actuellement fonctionner les relais Tor suivants : </tr> </tfoot> </table> + +<script> +d3.select("#content").append("h1") + .text(L10n.bandwidth); +d3.select("#content").append("div") + .attr("id", "bandwidth") + .text(L10n.loading); + +new BwDrawer("#bandwidth").draw(); +</script> diff --git a/Services/Participation.html b/Services/Participation.html deleted file mode 100644 index e3edb65..0000000 --- a/Services/Participation.html +++ /dev/null @@ -1,328 +0,0 @@ -[[!meta script="assets/relays"]] -[[!meta script="assets/d3/d3.v3.min"]] - -<style type="text/css"> - -.arc path { - stroke: #fff; -} - -</style> - -<div style="float: left; width: 45%"> - <h2 style="text-align: center;">Consensus weight</h2> - <div id="consensus-pie"></div> -</div> -<div style="float: left; width: 45%; margin-left: 3%"> - <h2 style="text-align: center;">Exit probability</h2> - <div id="exit-pie"></div> -</div> -<div style="clear: left;"></div> - -<script type="text/javascript"> - -var width = 250, - height = 250, - radius = Math.min(width, height) / 2, - formatPercent = d3.format(".2%"); - -var color_nos_oignons = "#ffa430"; -var color_others = "#57075f"; - -var arc = d3.svg.arc() - .outerRadius(radius - 30) - .innerRadius(radius - 80); - -var labelRadius = radius - 15; - -var pie = d3.layout.pie() - .sort(null) - .value(function(d) { return d.frac; }); - -var onionoo_url = "https://onionoo.torproject.org/details?type=relay&contact=adminsys@nos-oignons.net"; - -var search_terms = ""; -nos_oignons_relays.forEach(function(r) { - search_terms += " $" + r.fingerprint -}); - -function PieDrawer() { }; -PieDrawer.prototype.getSelector = undefined; -PieDrawer.prototype.getFieldName = undefined; -PieDrawer.prototype.getField = undefined; -PieDrawer.prototype.draw = function() { - var svg = d3.select(this.getSelector()).append("svg") - .style("margin", "auto") - .attr("width", width) - .attr("height", height) - .append("g") - .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")"); - - var text = svg.append("text") - .attr("text-anchor", "middle") - .attr("dy", ".35em") - .text("Loadingâ¦"); - - var field_getter = this.getField; - d3.json(onionoo_url + "&fields=fingerprint," + this.getFieldName(), function(error, raw_data) { - var frac_nos_oignons = 0; - raw_data['relays'].forEach(function(d) { - nos_oignons_relays.forEach(function(r) { - if (r.fingerprint == d.fingerprint) { - var value = field_getter(d); - if (value) { - frac_nos_oignons += value; - } - } - }); - }); - var frac_others = 1 - frac_nos_oignons; - - data = [ { name: 'Nos oignons', frac: frac_nos_oignons, color: color_nos_oignons, }, - { name: 'Others', frac: frac_others, color: color_others }, ]; - - text.text(formatPercent(data[0].frac)); - - var g = svg.selectAll(".arc") - .data(pie(data)) - .enter().append("g") - .attr("class", "arc"); - - g.append("path") - .attr("d", arc) - .style("fill", function(d) { return d.data.color; }); - - }); -} - -function ConsensusPieDrawer() { }; -ConsensusPieDrawer.prototype = new PieDrawer(); -ConsensusPieDrawer.prototype.getSelector = function() { - return "#consensus-pie"; -}; -ConsensusPieDrawer.prototype.getFieldName = function() { - return "consensus_weight_fraction"; -}; -ConsensusPieDrawer.prototype.getField = function(r) { - return r.consensus_weight_fraction; -}; - -function ExitPieDrawer() { }; -ExitPieDrawer.prototype = new PieDrawer(); -ExitPieDrawer.prototype.getSelector = function() { - return "#exit-pie"; -}; -ExitPieDrawer.prototype.getFieldName = function() { - return "exit_probability"; -}; -ExitPieDrawer.prototype.getField = function(r) { - return r.exit_probability; -}; -/* -new ConsensusPieDrawer().draw(); -new ExitPieDrawer().draw(); -*/ -</script> - -<h2>Bandwidth</h2> - -<h3>3 days / read</h3> -<div id="bandwidth-3d-read"></div> -<h3>3 days / write</h3> -<div id="bandwidth-3d-write"></div> -<h3>1 week / read</h3> -<div id="bandwidth-1w-read"></div> -<h3>1 week / write</h3> -<div id="bandwidth-1w-write"></div> -<h3>1 month / read</h3> -<div id="bandwidth-1m-read"></div> -<h3>1 month / write</h3> -<div id="bandwidth-1m-write"></div> -<h3>3 months / read</h3> -<div id="bandwidth-3m-read"></div> -<h3>3 months / write</h3> -<div id="bandwidth-3m-write"></div> -<h3>1 year / read</h3> -<div id="bandwidth-1y-read"></div> -<h3>1 year / write</h3> -<div id="bandwidth-1y-write"></div> - -<style type="text/css"> - -.axis path, -.axis line { - fill: none; - stroke: #000; - shape-rendering: crispEdges; -} - -</style> - -<script type="text/javascript"> - -var margin = {top: 50, right: 90, bottom: 90, left: 130}, - width = 700 - margin.left - margin.right, - height = 400 - margin.top - margin.bottom; - -var parseTime = d3.time.format("%Y-%m-%d %H:%M:%S").parse, - bwFormatter = d3.format(".f"); - -var x = d3.time.scale() - .range([0, width]); - -var y = d3.scale.linear() - .range([height, 0]); - -var color = d3.scale.category20(); - -var xAxis = d3.svg.axis() - .scale(x) - .orient("bottom"); - -var yAxis = d3.svg.axis() - .scale(y) - .orient("left") - .tickFormat(function(d) { return (d == 0) ? "" : bwFormatter(Math.abs(d)) + " Mbit/s " + ((d > 0) ? "in" : "out"); }); - -var area = d3.svg.area() - .x(function(d) { return x(d.date); }) - .y0(function(d) { return y(d.y0); }) - .y1(function(d) { return y(d.y0 + d.y); }); - -var read_stack = d3.layout.stack() - .values(function(d) { console.log(JSON.stringify(d)); return d.read_values; }); -var write_stack = d3.layout.stack() - .values(function(d) { console.log(JSON.stringify(d)); return d.write_values; }) - .y(function(d) { return -d.y; }); - -var onionoo_url = "https://onionoo.torproject.org/bandwidth?type=relay&contact=adminsys@nos-oignons.net"; - -function extract_values(history, minTime, maxTime) { - var values = []; - var first = parseTime(history.first); - var last = parseTime(history.last); - var i = 0; - for (var current = minTime; current <= maxTime; current = d3.time.second.offset(current, history.interval)) { - if (first <= current && current <= last) { - values.push({ date: current, y: history.factor * history.values[i++] * 8 / 1000000 }); - } - } - return values; -} - -function draw_bandwidth_graph(raw_data, selector, period) { - var svg = d3.select(selector).append("svg") - .attr("width", width + margin.left + margin.right) - .attr("height", height + margin.top + margin.bottom) - .append("g") - .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); - - var valid_fingerprints = []; - nos_oignons_relays.forEach(function(r) { - var relay_data = raw_data["relays"].filter(function(d) { return d.fingerprint == r.fingerprint; })[0]; - if (relay_data && relay_data['read_history'][period] && relay_data['write_history'][period]) { - valid_fingerprints.push(r.fingerprint); - } - }); - color.domain(valid_fingerprints); - - var minTime = d3.max(raw_data.relays.map(function(d) { - return d['read_history'][period] && parseTime(d['read_history'][period].first) && - d['write_history'][period] && parseTime(d['write_history'][period].first); - })); - var maxTime = d3.min(raw_data.relays.map(function(d) { - return d['read_history'][period] && parseTime(d['read_history'][period].last) && - d['write_history'][period] && parseTime(d['write_history'][period].last); - })); - var maxReadBandwidth = 0; - var maxWriteBandwidth = 0; - - var data = color.domain().map(function(fingerprint) { - var relay_data = raw_data["relays"].filter(function(d) { return d.fingerprint == fingerprint; })[0]; - var read_history = relay_data['read_history'][period]; - var write_history = relay_data['write_history'][period]; - var read_values = extract_values(read_history, minTime, maxTime); - var write_values = extract_values(write_history, minTime, maxTime); - - maxReadBandwidth = maxReadBandwidth + d3.max(read_values.map(function(d) { return d.y; })); - maxWriteBandwidth = maxWriteBandwidth + d3.max(write_values.map(function(d) { return d.y; })); - - return { - fingerprint: fingerprint, - read_values: read_values, - write_values: write_values, - }; - }); - - x.domain([minTime, maxTime]); - y.domain([-maxWriteBandwidth, maxReadBandwidth]); - - var read_graph = svg.selectAll(".read_graph") - .data(read_stack(data)) - .enter().append("g") - .attr("class", "read_graph"); - read_graph.append("path") - .attr("class", "area") - .attr("d", function(d) { return area(d.read_values); }) - .style("fill", function(d) { return color(d.fingerprint); }); - - var write_graph = svg.selectAll(".write_graph") - .data(write_stack(data)) - .enter().append("g") - .attr("class", "write_graph"); - write_graph.append("path") - .attr("class", "area") - .attr("d", function(d) { return area(d.write_values); }) - .style("fill", function(d) { return color(d.fingerprint); }); - - svg.append("g") - .attr("class", "x axis") - .attr("transform", "translate(0," + height + ")") - .call(xAxis) - .selectAll("text") - .style("text-anchor", "end") - .attr("transform", "rotate(-90) translate(-10, 0)"); - - svg.append("g") - .attr("class", "y axis") - .call(yAxis); - - var legend = svg.selectAll(".legend") - .data(color.domain().slice().reverse()) - .enter().append("g") - .attr("class", "legend") - .attr("transform", function(d, i) { return "translate(0," + ((i * 20) - margin.top) + ")"; }); - - legend.append("rect") - .attr("x", width - 18) - .attr("width", 18) - .attr("height", 18) - .style("fill", color); - - legend.append("text") - .attr("x", 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; - }); -}; - -d3.json(onionoo_url, function(error, raw_data) { - draw_bandwidth_graph(raw_data, "#bandwidth-3d-read", "3_days"); - draw_bandwidth_graph(raw_data, "#bandwidth-3d-read", "3_months"); -/* - draw_bandwidth_graph(raw_data, "#bandwidth-3d-write", "write_history", "3_days"); - draw_bandwidth_graph(raw_data, "#bandwidth-1w-read", "read_history", "1_week"); - draw_bandwidth_graph(raw_data, "#bandwidth-1w-write", "write_history", "1_week"); - draw_bandwidth_graph(raw_data, "#bandwidth-1m-read", "read_history", "1_month"); - draw_bandwidth_graph(raw_data, "#bandwidth-1m-write", "write_history", "1_month"); - draw_bandwidth_graph(raw_data, "#bandwidth-3m-read", "read_history", "3_months"); - draw_bandwidth_graph(raw_data, "#bandwidth-3m-write", "write_history", "3_months"); - draw_bandwidth_graph(raw_data, "#bandwidth-1y-read", "read_history", "1_year"); - draw_bandwidth_graph(raw_data, "#bandwidth-1y-write", "write_history", "1_year"); -*/ -}); - -</script> diff --git a/assets/bw_graphs.css b/assets/bw_graphs.css new file mode 100644 index 0000000..a455147 --- /dev/null +++ b/assets/bw_graphs.css @@ -0,0 +1,19 @@ +.axis path, +.axis line { + fill: none; + stroke: #000; + shape-rendering: crispEdges; +} + +#bandwidth form { + margin: auto; + width: 35em; +} + +#bandwidth div { + float: left; + width: 7em; +} +#bandwidth svg { + clear: left; +} diff --git a/assets/bw_graphs.js b/assets/bw_graphs.js new file mode 100644 index 0000000..bcd0216 --- /dev/null +++ b/assets/bw_graphs.js @@ -0,0 +1,224 @@ +function BwDrawer(selector) { + this.selector = selector; +}; +BwDrawer.prototype = new BwDrawer(); + +BwDrawer.margin = {top: 50, right: 10, bottom: 90, left: 130}; +BwDrawer.width = 600 - BwDrawer.margin.left - BwDrawer.margin.right; +BwDrawer.height = 400 - BwDrawer.margin.top - BwDrawer.margin.bottom; + +BwDrawer.parseTime = d3.time.format("%Y-%m-%d %H:%M:%S").parse; +BwDrawer.bwFormatter = d3.format(".f"); + +BwDrawer.x = d3.time.scale() + .range([0, BwDrawer.width]); + +BwDrawer.y = d3.scale.linear() + .range([BwDrawer.height, 0]); + +BwDrawer.color = d3.scale.category20(); + +BwDrawer.xAxis = d3.svg.axis() + .scale(BwDrawer.x) + .orient("bottom"); + +BwDrawer.yAxis = d3.svg.axis() + .scale(BwDrawer.y) + .orient("left") + .tickFormat(function(d) { return (d == 0) ? "" : BwDrawer.bwFormatter(Math.abs(d)) + " Mbit/s " + ((d > 0) ? "in" : "out"); }); + +BwDrawer.area = d3.svg.area() + .x(function(d) { return BwDrawer.x(d.date); }) + .y0(function(d) { return BwDrawer.y(d.y0); }) + .y1(function(d) { return BwDrawer.y(d.y0 + d.y); }); + +BwDrawer.read_stack = d3.layout.stack() + .values(function(d) { return d.read_values; }); +BwDrawer.write_stack = d3.layout.stack() + .values(function(d) { return d.write_values; }); + +BwDrawer.onionoo_url = "https://onionoo.torproject.org/bandwidth?type=relay&contact=adminsys@nos-oignons.net"; + +BwDrawer.periods = [ + { id: "3_days", label: L10n.t_3_days }, + { id: "1_week", label: L10n.t_1_week }, + { id: "1_month", label: L10n.t_1_month }, + { id: "3_months", label: L10n.t_3_months }, + { id: "1_year", label: L10n.t_1_year }, + ]; + +BwDrawer.extract_values = function(history, interval, minTime, maxTime) { + var values = []; + var first = history ? BwDrawer.parseTime(history.first) : maxTime; + var last = history ? BwDrawer.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++] * 8 / 1000000 : 0 + }); + } + return values; +} + +BwDrawer.draw_bandwidth_graph = function(raw_data, selector, period) { + var update_period; + + var svg = d3.select(selector).append("svg") + .attr("width", BwDrawer.width + BwDrawer.margin.left + BwDrawer.margin.right) + .attr("height", BwDrawer.height + BwDrawer.margin.top + BwDrawer.margin.bottom) + .append("g") + .attr("transform", "translate(" + BwDrawer.margin.left + "," + BwDrawer.margin.top + ")"); + + var form = d3.select(selector).append("form") + .attr("action", "#"); + BwDrawer.periods.forEach(function(p) { + var div = form.append("div"); + var radio = div.append("input") + .attr("type", "radio") + .attr("name", "period") + .attr("id", "period_" + p.id) + .on("click", function() { update_period(p.id); }); + div.append("label") + .attr("for", "period_" + p.id) + .text(p.label); + if (p.id == BwDrawer.periods[0].id) { + radio.attr("checked", true); + } + }); + + var valid_fingerprints = []; + nos_oignons_relays.forEach(function(r) { + var relay_data = raw_data["relays"].filter(function(d) { return d.fingerprint == r.fingerprint; })[0]; + valid_fingerprints.push(r.fingerprint); + }); + BwDrawer.color.domain(valid_fingerprints); + + var bw_data = {}; + BwDrawer.periods.map(function(p) { return p.id; }).forEach(function(period) { + var interval = d3.max(raw_data.relays, function(d) { + return d['read_history'][period] && d['read_history'][period].interval; + }); + raw_data.relays.forEach(function(d) { + if ((d['read_history'][period] && d['read_history'][period].interval != interval) || + (d['write_history'][period] && d['write_history'][period].interval != interval)) { + throw "PANIC: Different interval for different relays in the same time period."; + } + }); + var minTime = d3.max(raw_data.relays, function(d) { + return d['read_history'][period] && BwDrawer.parseTime(d['read_history'][period].first) && + d['write_history'][period] && BwDrawer.parseTime(d['write_history'][period].first); + }); + var maxTime = d3.min(raw_data.relays, function(d) { + return d['read_history'][period] && BwDrawer.parseTime(d['read_history'][period].last) && + d['write_history'][period] && BwDrawer.parseTime(d['write_history'][period].last); + }); + + var maxReadBandwidth = 0; + var maxWriteBandwidth = 0; + + var values = BwDrawer.color.domain().map(function(fingerprint) { + var relay_data = raw_data["relays"].filter(function(d) { return d.fingerprint == fingerprint; })[0]; + var read_history = relay_data['read_history'][period]; + var write_history = relay_data['write_history'][period]; + var read_values = BwDrawer.extract_values(read_history, interval, minTime, maxTime); + var write_values = BwDrawer.extract_values(write_history, interval, minTime, maxTime); + + maxReadBandwidth = maxReadBandwidth + d3.max(read_values, function(d) { return d.y; }); + maxWriteBandwidth = maxWriteBandwidth + d3.max(write_values, function(d) { return d.y; }); + + return { + fingerprint: fingerprint, + read_values: read_values, + write_values: write_values.map(function(d) { d.y = -d.y; return d }) + }; + }); + bw_data[period] = { minTime: minTime, + maxTime: maxTime, + maxReadBandwidth: maxReadBandwidth, + maxWriteBandwidth: maxWriteBandwidth, + values: values }; + }); + + BwDrawer.y.domain([-d3.max(d3.values(bw_data), function(d) { return d.maxWriteBandwidth; }), + d3.max(d3.values(bw_data), function(d) { return d.maxReadBandwidth; })]); + + var initial_period = BwDrawer.periods[0].id; + + BwDrawer.x.domain([bw_data[initial_period].minTime, bw_data[initial_period].maxTime]); + + var read_graph = svg.selectAll(".read_graph") + .data(BwDrawer.read_stack(bw_data[initial_period].values)) + .enter().append("path") + .attr("class", "read_graph area") + .attr("d", function(d) { return BwDrawer.area(d.read_values); }) + .style("fill", function(d) { return BwDrawer.color(d.fingerprint); }); + + var write_graph = svg.selectAll(".write_graph") + .data(BwDrawer.write_stack(bw_data[initial_period].values)) + .enter().append("path") + .attr("class", "write_graph area") + .attr("d", function(d) { return BwDrawer.area(d.write_values); }) + .style("fill", function(d) { return BwDrawer.color(d.fingerprint); }); + + update_period = function(period) { + BwDrawer.x.domain([bw_data[period].minTime, bw_data[period].maxTime]); + var t = svg.transition().duration(300); + t.select(".x.axis").call(BwDrawer.xAxis); + t.selectAll(".read_graph").style("fill-opacity", 0); + t.selectAll(".write_graph").style("fill-opacity", 0); + t.each("end", function() { + d3.selectAll(".read_graph").data(BwDrawer.read_stack(bw_data[period].values)); + d3.selectAll(".write_graph").data(BwDrawer.write_stack(bw_data[period].values)); + d3.selectAll(".read_graph").attr("d", function(d) { return BwDrawer.area(d.read_values); }) + d3.selectAll(".write_graph") + .attr("d", function(d) { return BwDrawer.area(d.write_values); }) + var t2 = svg.transition().duration(100); + t2.selectAll(".read_graph").style("fill-opacity", 1); + t2.selectAll(".write_graph").style("fill-opacity", 1); + }); + d3.selectAll(".x.axis text") + .style("text-anchor", "end") + .attr("transform", "rotate(-90) translate(-10, 0)"); + } + + svg.append("g") + .attr("class", "x axis") + .attr("transform", "translate(0," + BwDrawer.height + ")") + .call(BwDrawer.xAxis) + .selectAll("text") + .style("text-anchor", "end") + .attr("transform", "rotate(-90) translate(-10, 0)"); + + svg.append("g") + .attr("class", "y axis") + .call(BwDrawer.yAxis); + + var legend = svg.selectAll(".legend") + .data(BwDrawer.color.domain().slice().reverse()) + .enter().append("g") + .attr("class", "legend") + .attr("transform", function(d, i) { return "translate(0," + ((i * 20) - BwDrawer.margin.top) + ")"; }); + + legend.append("rect") + .attr("x", BwDrawer.width - 18) + .attr("width", 18) + .attr("height", 18) + .style("fill", BwDrawer.color); + + legend.append("text") + .attr("x", BwDrawer.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; + }); +}; + +BwDrawer.prototype.draw = function() { + var selector = this.selector; + d3.json(BwDrawer.onionoo_url, function(error, raw_data) { + d3.select(selector).text(""); + BwDrawer.draw_bandwidth_graph(raw_data, selector); + }); +}; diff --git a/assets/l10n.en.js b/assets/l10n.en.js new file mode 100644 index 0000000..f89d7a5 --- /dev/null +++ b/assets/l10n.en.js @@ -0,0 +1,12 @@ +function L10n() { }; +L10n.loading = "Loadingâ¦"; +L10n.consensus_weight = "Weight in the whole network"; +L10n.exit_probability = "Probability to be used as exit node"; +L10n.bandwidth = "Bandwidth"; +L10n.nos_oignons = "Nos oignons"; +L10n.others = "Others"; +L10n.t_3_days = "3 days"; +L10n.t_1_week = "1 week"; +L10n.t_1_month = "1 month"; +L10n.t_3_months = "3 months"; +L10n.t_1_year = "1 year"; diff --git a/assets/l10n.fr.js b/assets/l10n.fr.js new file mode 100644 index 0000000..0e948d5 --- /dev/null +++ b/assets/l10n.fr.js @@ -0,0 +1,12 @@ +function L10n() { }; +L10n.loading = "Chargementâ¦"; +L10n.consensus_weight = "Poid dans l'ensemble du réseau"; +L10n.exit_probability = "Probabilité d'être utilisé comme nÅud de sortie"; +L10n.bandwidth = "Bande passante"; +L10n.nos_oignons = "Nos oignons"; +L10n.others = "Autres"; +L10n.t_3_days = "3 jours"; +L10n.t_1_week = "1 semaine"; +L10n.t_1_month = "1 mois"; +L10n.t_3_months = "3 mois"; +L10n.t_1_year = "1 an"; diff --git a/assets/pie_graphs.js b/assets/pie_graphs.js new file mode 100644 index 0000000..e607fa5 --- /dev/null +++ b/assets/pie_graphs.js @@ -0,0 +1,94 @@ +function PieDrawer(selector) { + this.selector = selector; +}; +PieDrawer.width = 150; +PieDrawer.height = 150; +PieDrawer.radius = Math.min(PieDrawer.width, PieDrawer.height) / 2; +PieDrawer.formatPercent = d3.format(".2%"); + +PieDrawer.color_nos_oignons = "#ffa430"; +PieDrawer.color_others = "#57075f"; + +PieDrawer.arc = d3.svg.arc() + .outerRadius(PieDrawer.radius - 10) + .innerRadius(PieDrawer.radius - 40); + +PieDrawer.labelRadius = PieDrawer.radius - 15; + +PieDrawer.pie = d3.layout.pie() + .sort(null) + .value(function(d) { return d.frac; }); + +PieDrawer.onionoo_url = "https://onionoo.torproject.org/details?type=relay&contact=adminsys@nos-oignons.net"; + +PieDrawer.prototype.getFieldName = undefined; +PieDrawer.prototype.getField = undefined; +PieDrawer.prototype.draw = function() { + var svg = d3.select(this.selector).append("svg") + .style("margin", "auto") + .attr("width", PieDrawer.width) + .attr("height", PieDrawer.height) + .append("g") + .attr("transform", "translate(" + PieDrawer.width / 2 + "," + PieDrawer.height / 2 + ")"); + + var text = svg.append("text") + .attr("text-anchor", "middle") + .attr("dy", ".35em") + .text(L10n.loading); + + var field_getter = this.getField; + d3.json(PieDrawer.onionoo_url + "&fields=fingerprint," + this.getFieldName(), function(error, raw_data) { + var frac_nos_oignons = 0; + raw_data['relays'].forEach(function(d) { + nos_oignons_relays.forEach(function(r) { + if (r.fingerprint == d.fingerprint) { + var value = field_getter(d); + if (value) { + frac_nos_oignons += value; + } + } + }); + }); + var frac_others = 1 - frac_nos_oignons; + + data = [ { name: L10n.nos_oignons, frac: frac_nos_oignons, color: PieDrawer.color_nos_oignons, }, + { name: L10n.others, frac: frac_others, color: PieDrawer.color_others }, ]; + + text.text(PieDrawer.formatPercent(data[0].frac)); + + var g = svg.selectAll(".arc") + .data(PieDrawer.pie(data)) + .enter().append("g") + .attr("class", "arc"); + + g.append("path") + .attr("d", PieDrawer.arc) + .style("fill", function(d) { return d.data.color; }); + + }); +} + +function ConsensusPieDrawer(selector) { + this.selector = selector; +}; +ConsensusPieDrawer.prototype = new PieDrawer(); +ConsensusPieDrawer.prototype.getSelector = function() { + return "#consensus-pie"; +}; +ConsensusPieDrawer.prototype.getFieldName = function() { + return "consensus_weight_fraction"; +}; +ConsensusPieDrawer.prototype.getField = function(r) { + return r.consensus_weight_fraction; +}; + +function ExitPieDrawer(selector) { + this.selector = selector; +}; +ExitPieDrawer.prototype = new PieDrawer(); +ExitPieDrawer.prototype.getFieldName = function() { + return "exit_probability"; +}; +ExitPieDrawer.prototype.getField = function(r) { + return r.exit_probability; +}; -- 2.39.5