Changeset - acdbc94512eb
[Not reviewed]
Merge dev
0 6 2
Dennis Fink - 9 years ago 2016-03-01 23:16:45
dennis.fink@c3l.lu
Merged feature-worldmap
8 files changed with 116 insertions and 41 deletions:
0 comments (0 inline, 0 general)
ennstatus/__init__.py
Show inline comments
 
@@ -82,7 +82,10 @@ def create_app():
 
    app.register_blueprint(status_page, url_prefix='/status')
 

	
 
    from .statistics.views import statistics_page
 
    app.register_blueprint(statistics_page, url_prefix='/stats')
 
    app.register_blueprint(statistics_page, url_prefix='/statistics')
 

	
 
    from .data.views import data_page
 
    app.register_blueprint(data_page, url_prefix='/data')
 

	
 
    from .log import init_logging
 
    init_logging(app)
ennstatus/data/__init__.py
Show inline comments
 
new file 100644
 
# Ënnstatus
 
# Copyright (C) 2015  Dennis Fink
 
#
 
# This program is free software: you can redistribute it and/or modify
 
# it under the terms of the GNU General Public License as published by
 
# the Free Software Foundation, either version 3 of the License, or
 
# (at your option) any later version.
 
#
 
# This program is distributed in the hope that it will be useful,
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
# GNU General Public License for more details.
 
#
 
# You should have received a copy of the GNU General Public License
 
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 

	
ennstatus/data/views.py
Show inline comments
 
new file 100644
 
# Ënnstatus
 
# Copyright (C) 2015  Dennis Fink
 
#
 
# This program is free software: you can redistribute it and/or modify
 
# it under the terms of the GNU General Public License as published by
 
# the Free Software Foundation, either version 3 of the License, or
 
# (at your option) any later version.
 
#
 
# This program is distributed in the hope that it will be useful,
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
# GNU General Public License for more details.
 
#
 
# You should have received a copy of the GNU General Public License
 
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 

	
 
from collections import defaultdict
 

	
 
from flask import Blueprint, jsonify
 

	
 
from ennstatus.status.functions import split_all_servers_to_types
 

	
 
data_page = Blueprint('data', __name__)
 

	
 

	
 
@data_page.route('/worldmap')
 
def worldmap():
 
    servers = split_all_servers_to_types()
 
    countries = {}
 

	
 
    for key, value in servers.items():
 
        for server in value:
 
            if server.country not in countries:
 
                countries[server.country] = defaultdict(int)
 
            countries[server.country][server.type] += 1
 
            countries[server.country]['total'] += 1
 

	
 
    maximum = max(i['total'] for i in countries.values())
 

	
 
    countries['max'] = maximum
 

	
 
    return jsonify(countries)
ennstatus/static/css/map.css
Show inline comments
 
@@ -20,3 +20,14 @@
 
	stroke-linejoin: round;
 
	stroke-width: 0.1px;
 
}
 

	
 
.tooltip {
 
    color: #222;
 
    background: #fff;
 
    padding: .5em;
 
    text-shadow: #f5f5f5 0 1px 0;
 
    border-radius: 2px;
 
    box-shadow: 0px 0px 2px 0px #a6a6a6;
 
    opacity: 0.9;
 
    position: absolute;
 
}
ennstatus/static/js/worldmap.js
Show inline comments
 
@@ -35,9 +35,9 @@ setup(width, height);
 

	
 
function setup(width, height) {
 
	projection = d3.geo.mercator()
 
		.translate([(width / 2), (height / 2)])
 
		.scale(width / 2 / Math.PI)
 

	
 
	 	.translate([(width / 2), (height / 2)])
 
	 	.scale(width / 2 / Math.PI)
 
	
 
	path = d3.geo.path().projection(projection);
 

	
 
	svg = d3.select("#chart").append("svg")
 
@@ -70,44 +70,60 @@ function draw(topo) {
 
		.attr("d", path);
 

	
 
	var country = g.selectAll(".country").data(topo);
 
	d3.json("/stats/data/worldmap", function(err, data) {
 
	d3.json("/data/worldmap", function(err, data) {
 

	
 

	
 
		var colorscale = d3.scale.threshold().domain([2, 4, 8, 16, 32, 48]).range(["#f2f0f7", "#dadaeb", "#bcbddc", "#9e9ac8", "#756bb1", "#54278f"])
 
		var colorscale = d3.scale.threshold().domain(d3.range(1, (data.max+1)/3).map(function(n) { var a=1, b=1, f=1; for(var i = 2; i <= n; i++) { f = a+b; a=b; b=f } return f;})).range([
 
			"#aeffb9",
 
			"#87ff97",
 
			"#60ff76",
 
			"#38ff54",
 
			"#11ff32",
 
			"#00e920",
 
			"#00c21b",
 
			"#009a15",
 
			"#008713",
 
			"#007310",
 
			"#00600d",
 
			"#004c0a"
 
		])
 

	
 
		country.enter().insert("path")
 
			.attr("class", "country")
 
			.attr("d", path)
 
			.attr("id", function(d, i) { return d.id; })
 
			.attr("title", function(d, i) { 
 
				if (d.properties.name in data) {
 
					return "<p>" + d.properties.name + "</p>" + data[d.properties.name];
 
				} else {
 
					return d.properties.name;
 
				}
 
			})
 
			.style("fill", function(d, i) { 
 
				if (d.properties.name in data) {
 
					return colorscale(data[d.properties.name]);
 
					return colorscale(data[d.properties.name]['total']);
 
				} else {
 
					return "#fdf6e3";
 
				}
 
			});
 

	
 
		var offsetL = document.getElementById('chart').offsetLet+20;
 
		var offsetT = document.getElementById('chart').offsetTop+10;
 
		var tooltip = d3.select('#chart').append('div')
 
			.attr('class', 'tooltip')
 

	
 
		country.on("mousemove", function(d, i) {
 
	
 
			var mouse = d3.mouse(svg.node()).map(function(d) { return parseInt(d); });
 

	
 
			tooltip.classed("hidden", false)
 
				.attr("style", "left:"+(mouse[0]+offsetL)+"px;top:"+(mouse[1]+offsetT)+"px")
 
				.html(function(d, i) {
 
				.attr("style", "left:"+(mouse[0]+40)+"px;top:"+mouse[1]+"px")
 
				.html(function() {
 
					if (d.properties.name in data) {
 
						return d.properties.name + " " + data[d.properties.name];
 
						var text = "<b>" + d.properties.name + "</b>" + "<br>Total servers: " + data[d.properties.name]['total']
 
						if ('bridge' in data[d.properties.name]) {
 
							text = text + "<br>Bridge servers: " + data[d.properties.name]['bridge']
 
						}
 
						if ('exit' in data[d.properties.name]) {
 
							text = text + "<br>Exit servers: " + data[d.properties.name]['exit']
 
						}
 
						if ('relay' in data[d.properties.name]) {
 
							text = text + "<br>Relay server: " + data[d.properties.name]['relay']
 
						}
 
						return text
 
					} else {
 
						return d.properties.name;
 
						return "<b>" + d.properties.name + "</b>"
 
					}
 
				})
 
		})
ennstatus/statistics/views.py
Show inline comments
 
@@ -14,11 +14,7 @@
 
# You should have received a copy of the GNU General Public License
 
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 

	
 
from collections import defaultdict
 

	
 
from flask import Blueprint, render_template, current_app, jsonify
 

	
 
from ennstatus.status.functions import split_all_servers_to_types
 
from flask import Blueprint, render_template
 

	
 
statistics_page = Blueprint('statistics', __name__)
 

	
 
@@ -26,19 +22,3 @@ statistics_page = Blueprint('statistics'
 
@statistics_page.route('/worldmap')
 
def worldmap():
 
    return render_template('statistics/worldmap.html')
 

	
 

	
 
@statistics_page.route('/data/worldmap')
 
def data_worldmap():
 
    servers = split_all_servers_to_types()
 
    countries = defaultdict(int)
 

	
 
    for key, value in servers.items():
 
        for server in value:
 
            countries[server['country']] += 1
 

	
 
    maximum = max(countries.values())
 

	
 
    countries['max'] = maximum
 

	
 
    return jsonify(countries)
ennstatus/templates/base.html
Show inline comments
 
@@ -108,6 +108,12 @@
 
            <li><a href="http://lists.enn.lu/listinfo/discuss" target="blank">Mailing List</a></li>
 
          </ul>
 
        </li>
 
        <li class="dropdown">
 
          <a href="#" class="dropdown-toggle" data-toggle="dropdown">Statistics <b class="caret"></b></a>
 
          <ul class="dropdown-menu">
 
            <li><a href="{{ url_for('statistics.worldmap') }}">Worldmap</a></li>
 
          </ul>
 
        </li>
 
      </ul>
 
    </div>
 
  </div>
ennstatus/templates/statistics/worldmap.html
Show inline comments
 
@@ -26,6 +26,7 @@
 

	
 
{% block content %}
 
  <div class="col-md-12">
 
    <h2>Worldmap</h2>
 
    <div id="chart">
 
    </div>
 
  </div>
0 comments (0 inline, 0 general)