diff --git a/modules/tinyweb/tinyweb/tinyweb.js b/modules/tinyweb/tinyweb/tinyweb.js index 3a62c1de04e54893c7abede290bf7815e02ebf9e..66f219c0bc0aa4804177c0a1a8a72372c487535e 100644 --- a/modules/tinyweb/tinyweb/tinyweb.js +++ b/modules/tinyweb/tinyweb/tinyweb.js @@ -9,7 +9,7 @@ window.onload = function() { var now = Date.now(); for (i = 0; i < statsLabels.length; ++i) { statsHistory.push({ label: 'Layer ' + statsLabels[i], values: [{time: now, y:0}] }); - $('.legend').append('<li class="l-' + statsLabels[i] + '">' + statsLabels[i]); + $('.stats-legend').append('<li class="l-' + statsLabels[i] + '">' + statsLabels[i]); } var statsChart = $('#stats').epoch({ type: 'time.area', @@ -29,10 +29,44 @@ window.onload = function() { data: statsHistory }); var statsPrev = null; + /* Map colour brackets. */ + var colours = [ + '#F5F5F5', + 'rgb(198,219,239)', + 'rgb(158,202,225)', + 'rgb(107,174,214)', + 'rgb(66,146,198)', + 'rgb(33,113,181)', + 'rgb(8,81,156)', + 'rgb(8,48,107)', + ]; + var fills = { defaultFill: '#F5F5F5' }; + for (var i in colours) { + fills['q' + i] = colours[i]; + } var map = new Datamap({ element: document.getElementById('map'), - fills: { defaultFill: '#F5F5F5' }, + fills: fills, + data: {}, + geographyConfig: { + popupTemplate: function(geo, data) { + return ['<div class="hoverinfo">', + '<strong>', geo.properties.name, '</strong>', + '<br>Queries: <strong>', data ? data.queries : '0', '</strong>', + '</div>'].join(''); + } + } }); + /* Draw map legend */ + var legendBarWidth = 30, legendBarHeight = 10, legendOffset = 150; + d3.select('#map svg').append('g').attr('class', 'map-legend'); + d3.select('.map-legend').selectAll('.map-legend') + .data(colours).enter() + .append('rect') + .attr('y', function(d,i) { return legendOffset + legendBarHeight*i; }) + .attr('width', legendBarWidth) + .attr('height', legendBarHeight) + .attr('fill', function(d){ return d; }); /* Realtime updates */ function poller(feed, interval, cb) { var func = function() { @@ -62,7 +96,7 @@ window.onload = function() { statsPrev = next; }); poller('feed', 2000, function(resp) { - var feed = $('#feed') + var feed = $('#feed'); feed.children().remove(); feed.append('<tr><th>Type</th><th>Query</th><th>Nameserver</th><th>DNSSEC</th></tr>') for (i = 0; i < resp.length; ++i) { @@ -81,23 +115,41 @@ window.onload = function() { } }); poller('geo', 2000, function(resp) { - var update = {}; - var max = 0.0; - /* Convert country code, calculate maximum. */ + var min = 0.0, max = 0.0; + /* Calculate dataset limits. */ for (var key in resp) { if (resp.hasOwnProperty(key)) { + min = Math.min(min, resp[key]); max = Math.max(max, resp[key]); + } + } + /* Map frequency to palette. */ + var dataset = {}; + var quantize = d3.scale.quantize() + .domain([min, max]) + .range(d3.range(colours.length).map(function(i) { return "q" + i; })); + for (var key in resp) { + if (resp.hasOwnProperty(key)) { var iso3_key = iso2_to_iso3[key]; if (iso3_key) { - update[iso3_key] = resp[key]; + var val = resp[key]; + dataset[iso3_key] = { queries: val, fillColor: quantize(val) }; } } } - /* Normalize, convert to HSL. */ - for (var key in update) { - var ratio = 1.0 - update[key]/max; - update[key] = 'hsl(205,70%,' + Math.round((10.0 + 70.0 * (ratio * ratio)) / 10) * 10 + '%)' - } - map.updateChoropleth(update); + map.updateChoropleth(dataset); + /* Update legend */ + d3.select('.map-legend').selectAll('text').remove(); + d3.select('.map-legend').selectAll('.map-legend') + .data(colours).enter() + .append('text') + .text(function(d, i) { + var quantizedRange = quantize.invertExtent('q' + i); + return parseInt(quantizedRange[0]) + ' - ' + parseInt(quantizedRange[1]); + }) + .attr('x', (legendBarWidth*1.25)) + .attr('y', function(d, i){ + return legendOffset + (legendBarHeight*0.9) + legendBarHeight*i; + }) }); } diff --git a/modules/tinyweb/tinyweb/tinyweb.tpl b/modules/tinyweb/tinyweb/tinyweb.tpl index 3dd563e8f8d9d883eb489132499e91bf3597c4e4..8fd00d71a55c77058fba8152dc85562022a31b06 100644 --- a/modules/tinyweb/tinyweb/tinyweb.tpl +++ b/modules/tinyweb/tinyweb/tinyweb.tpl @@ -7,7 +7,7 @@ th { text-align: left; font-weight: normal; margin-bottom: 0.5em; } #page { font-weight: 300; } #page { width: 800px; margin: 0 auto; } - #stats, #map { height: 300px; } + #stats, #map { width: 800px; height: 300px; } #stats .layer-cached .area, .l-cached { fill: #2CA02C; color: #2CA02C; } #stats .layer-10ms .area , .l-10ms { fill: #165683; color: #165683; } #stats .layer-100ms .area , .l-100ms { fill: #258FDA; color: #258FDA; } @@ -15,8 +15,9 @@ #stats .layer-slow .area , .l-slow { fill: #E1AC51; color: #E1AC51; } #feed { width: 100%; } #feed .secure { color: #74c476; } - .legend { text-align: center; } - .legend li { display: inline; list-style-type: none; padding-right: 20px; } + .stats-legend { text-align: center; } + .stats-legend li { display: inline; list-style-type: none; padding-right: 20px; } + .map-legend { font-size: 10px; } </style> <script type="text/javascript" src="jquery.js"></script> <script type="text/javascript" src="d3.js"></script> @@ -28,7 +29,7 @@ <div id="page"> <h1>{{.Title}}</h1> <div class="epoch" id="stats"></div> - <ul class="legend"></ul> + <ul class="stats-legend"></ul> <h2>Queried servers</h2> <div id="map" style="position: relative;"></div> <h2>Last queries</h2>