]> nos-oignons.net Git - graphnion.git/blob - graphnion.js
Use 'width' setting in demo.
[graphnion.git] / graphnion.js
1 (function(window){
2     'use strict';
3
4     /*global define, module, exports, require */
5     var Graphnion = {};
6
7     Graphnion.pie = function (selector, options) {
8         return new GraphnionPie(selector, options);
9     };
10
11
12     /**
13      * Pie graphs
14      */
15
16     function GraphnionPie(selector, options) {
17
18         // Default settings
19         var defaults = {
20             type: 'consensus',
21             size : 150,
22             colors : {
23                 relays : "#111",
24                 others : "#666"
25             }
26         }
27         // main element
28         this.selector = selector;
29
30         // option cache
31         this.options = {};
32         options = options || {};
33
34         this.options.type = options.type || defaults.type;
35         this.options.size = options.size || defaults.size;
36         this.options.width = options.width || (this.options.size / 5); // Radius * 10%
37         this.options.colors = options.colors || defaults.colors;
38         this.options.onionoo = options.onionoo;
39
40
41         // initialize some attributes
42         this.init();
43         this.callOnionoo();
44     }
45
46     Graphnion.version = "0.1";
47
48     GraphnionPie.prototype = {
49         constructor: GraphnionPie,
50
51         init : function() {
52             var self = this;
53
54             this.radius = this.options.size / 2,
55             this.formatPercent = d3.format(".2%");
56             this.arc = d3.svg.arc()
57                 .outerRadius(this.radius)
58                 .innerRadius(this.radius - this.options.width);
59
60             this.pie = d3.layout.pie()
61                 .sort(null)
62                 .value(function(d) { return d.frac; });
63
64             switch (this.options.type) {
65                 case 'consensus':
66                     this.field = "consensus_weight_fraction";
67                     break;
68                 case 'guard':
69                     this.field = "guard_probability";
70                     break;
71                 case 'middle':
72                     this.field = "middle_probability";
73                     break;
74                 case 'exit':
75                     this.field= "exit_probability";
76                     break;
77             }
78         },
79
80         draw : function(frac) {
81             var self = this;
82
83             var data = [
84                 {
85                     frac: frac,
86                     color: this.options.colors.relays
87                 },
88                 {
89                     frac: (1 - frac),
90                     color: this.options.colors.others
91                 }
92             ];
93
94             var svg = d3.select(this.selector).append("svg")
95                 .style("margin", "auto")
96                 .attr("width", this.options.size)
97                 .attr("height", this.options.size)
98                 .append("g")
99                 .attr("transform", "translate(" + this.options.size / 2 + "," + this.options.size / 2 + ")");
100
101
102             var text = svg.append("text")
103                 .attr("text-anchor", "middle")
104                 .attr("dy", ".35em")
105                 .text(this.formatPercent(frac));
106
107             var g = svg.selectAll(".arc")
108                 .data(this.pie(data))
109                 .enter()
110                     .append("g")
111                     .attr("class", "arc");
112
113             g.append("path")
114                 .attr("d", this.arc)
115                 .style("fill", function(d) { return d.data.color; });
116
117         },
118
119         callOnionoo : function() {
120             var self = this;
121
122             // Create Onionoo url
123             var url = "https://onionoo.torproject.org/details?type=relay&fields=fingerprint,nickname," + this.field;
124             if (typeof this.options.onionoo.contact !== 'undefined') {
125                 url += "&contact=" + this.options.onionoo.contact;
126             }
127             else if (typeof this.options.onionoo.family !== 'undefined') {
128                 url += "&family=" + this.options.onionoo.family;
129             }
130
131             // Load data, and draw graph
132             d3.json(url, function(error, data) {
133                 if (error) return console.warn(error);
134
135                 var frac = self.computeData(data);
136                 self.draw(frac);
137             });
138         },
139
140         computeData : function(rawData) {
141             var self = this;
142
143             var frac = 0;
144             rawData['relays'].forEach(function(d) {
145                 frac += d[self.field];
146             });
147             return frac;
148         }
149
150     }
151
152
153     if (typeof define === 'function' && define.amd) {
154         define("Graphnion", ["d3"], Graphnion);
155     } else if ('undefined' !== typeof exports && 'undefined' !== typeof module) {
156         module.exports = Graphnion;
157     } else {
158         window.Graphnion = Graphnion;
159     }
160
161 })(window);