Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
tree: 7b600ee48a
Fetching contributors…

Cannot retrieve contributors at this time

1206 lines (1005 sloc) 34.435 kB
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html lang="en">
<head>
<meta charset="utf-8">
<title>{% if page_title %}{{ page_title }}{% else %}No page title set. Bug a developer!{% endif %}</title>
<link rel="icon" href="{{ MEDIA_URL }}images/favicon.ico" type="image/x-icon">
<meta name="description" content="Network Analyzer for your pcap files">
<meta name="author" content="Oğuz Yarımtepe">
<!-- Le HTML5 shim, for IE6-8 support of HTML elements -->
<!--[if lt IE 9]>
<script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<!-- Le styles -->
<link href="/site_media/bootstrap/css/bootstrap.css" rel="stylesheet">
<link href="/site_media/bootstrap/css/bootstrap-responsive.css" rel="stylesheet">
<link href="/site_media/bootstrap/css/docs.css" rel="stylesheet">
<style>
body {
padding-top: 60px; /* 60px to make the container go all the way to the bottom of the topbar */
}
</style>
<!-- settings for jquery timeline widget-->
{% if pcap_operation in summary_li %}
<link rel="stylesheet" href="/site_media/jquery_widget/css/aristo/jquery-ui-1.8.5.custom.css" type="text/css"
media="screen" title="no title" charset="utf-8">
<link rel="stylesheet" href="/site_media/jquery_widget/js/timeglider/Timeglider.css" type="text/css"
media="screen" title="no title" charset="utf-8">
<style type='text/css'>
body {
font-family: Helvetica, Arial, sans-serif;
}
#summary_info {
margin:32px;
margin-bottom:0;
height:500px;
}
#output {
font-size:10px;
}
.shadow-years .timeglider-event-title {
color:#F0F0F0;
}
.shadow-years .timeglider-event-spanner {
background-color:#4C5408;
}
.bibliocene .timeglider-event-title {
color:#F0F0F0;
}
.bibliocene .timeglider-event-spanner {
background-color:orange;
}
.js-era .timeglider-event-title {
color:#323230;
}
.js-era .timeglider-event-spanner {
background-color:#f0db4e;
}
.hawt .timeglider-event-title {
color:white;
}
.hawt .timeglider-event-spanner {
background-color:#CC106B;
}
.browserwars .timeglider-event-title {
color:black;
}
.browserwars .timeglider-event-spanner {
background-color:#CC0000;
}
.inception .timeglider-event-title {
color:green;
}
.inception .timeglider-event-spanner {
background-color:white;
}
.tg-timeline-envelope .titleBar {
opacity:.2;
}
</style>
{% endif %}
{% ifequal pcap_operation "summary-size" %}
<script src="/site_media/d3/js/d3.v2.js"></script>
<link rel="stylesheet" href="/site_media/d3/css/treemap.css" type="text/css"
media="screen" title="no title" charset="utf-8">
{% endifequal %}
{% ifequal pcap_operation "welcome" %}
<link href="/site_media/nvd3/src/d3.css" rel="stylesheet" type="text/css">
<script src="/site_media/nvd3/lib/d3.v2.js"></script>
<script src="/site_media/nvd3/lib/fisheye.js"></script>
<script src="/site_media/nvd3/nv.d3.js"></script>
<script src="/site_media/nvd3/src/tooltip.js"></script>
<script src="/site_media/nvd3/src/models/legend.js"></script>
<script src="/site_media/nvd3/src/models/axis.js"></script>
<script src="/site_media/nvd3/src/models/distribution.js"></script>
<script src="/site_media/nvd3/src/models/scatter.js"></script>
<script src="/site_media/nvd3/src/models/scatterChart.js"></script>
{% endifequal %}
{% ifequal pcap_operation "file_details" %}
<link href="/site_media/nvd3/src/d3.css" rel="stylesheet" type="text/css">
<script src="/site_media/nvd3/lib/d3.v2.js"></script>
<script src="/site_media/nvd3/lib/fisheye.js"></script>
<script src="/site_media/nvd3/nv.d3.js"></script>
<script src="/site_media/nvd3/src/tooltip.js"></script>
<script src="/site_media/nvd3/src/models/legend.js"></script>
<script src="/site_media/nvd3/src/models/axis.js"></script>
<script src="/site_media/nvd3/src/models/distribution.js"></script>
<script src="/site_media/nvd3/src/models/scatter.js"></script>
<script src="/site_media/nvd3/src/models/scatterChart.js"></script>
{% endifequal %}
{% ifequal pcap_operation "parallel_coordinates" %}
<script src="/site_media/d3/js/d3.v2.js"></script>
<script src="/site_media/underscore/underscore.js"></script>
<link rel="stylesheet" type="text/css" href="/site_media/parallel/parallel.css" />
{% endifequal %}
</head>
<body>
{% block navigation %} {% endblock %}
{% block content %} {% endblock %}
<!-- Le javascript
================================================== -->
<!-- Placed at the end of the document so the pages load faster -->
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js" type="text/javascript"></script>
<script src="/site_media/bootstrap/js/bootstrap.js" type="text/javascript"></script>
<!-- js files for pcap summary -->
{% if pcap_operation in summary_li %}
<script src="/site_media/jquery_widget/js/jquery-ui.js" type="text/javascript" charset="utf-8"></script>
<script src="/site_media/jquery_widget/js/underscore-min.js" type="text/javascript" charset="utf-8"></script>
<script src="/site_media/jquery_widget/js/backbone-min.js" type="text/javascript" charset="utf-8"></script>
<script src="/site_media/jquery_widget/js/jquery.tmpl.js" type="text/javascript" charset="utf-8"></script>
<script src="/site_media/jquery_widget/js/ba-debug.min.js" type="text/javascript" charset="utf-8"></script>
<script src="/site_media/jquery_widget/js/ba-tinyPubSub.js" type="text/javascript" charset="utf-8"></script>
<script src="/site_media/jquery_widget/js/jquery.mousewheel.min.js" type="text/javascript" charset="utf-8"></script>
<script src="/site_media/jquery_widget/js/jquery.ui.ipad.js" type="text/javascript" charset="utf-8"></script>
<script src="/site_media/jquery_widget/js/jquery.global.js" type="text/javascript" charset="utf-8"></script>
<script src="/site_media/jquery_widget/js/timeglider/TG_Date.js" type="text/javascript" charset="utf-8"></script>
<script src="/site_media/jquery_widget/js/timeglider/TG_Org.js" type="text/javascript" charset="utf-8"></script>
<script src="/site_media/jquery_widget/js/timeglider/TG_Timeline.js" type="text/javascript" charset="utf-8"></script>
<script src="/site_media/jquery_widget/js/timeglider/TG_TimelineView.js" type="text/javascript" charset="utf-8"></script>
<script src="/site_media/jquery_widget/js/timeglider/TG_Mediator.js" type="text/javascript" charset="utf-8"></script>
<script src="/site_media/jquery_widget/js/timeglider/timeglider.timeline.widget.js" type="text/javascript"></script>
<script type='text/javascript'>
$(function () {
var tg_actor = {};
var tg1 = $("#summary_info").timeline({
"timezone":"+03:00",
"min_zoom":1,
"max_zoom":100,
"show_centerline":true,
"data_source":"{{ json_file_url }}",
"show_footer":false,
"display_zoom_level":true,
"icon_folder": "{{ icon_folder }}"
}).resizable({
stop:function(){
$(this).data("timeline").resize();
}
});
tg_actor = tg1.data("timeline");
timeglider.methods = {
zoomIn:function() { tg_actor.zoom("in"); }
};
// test to bring up filter by default, on load
setTimeout(function() {
$(".tg-timeline-legend-bt").trigger("click");
}, 2000);
$("#tags-button").bind("click", function() {
var txt = $("#tags-input").val();
tg_actor.filterBy("tags", txt);
});
}); // end document-ready
</script>
{% endif %}
{% if pcap_operation in select_update_li %}
<!-- javascript issue for select box change function -->
<script type='text/javascript'>
function update_link(id){
var select_id = id;
var select_id_selected = "'" + select_id+ "'";
var select_str = "\"" + "[name=" + select_id_selected + "]" + " "+":selected" + "\"";
var selected = $(select_str).val();
var url = "{{ ALTERNATE_BASE_URL }}" + "/pcap" + "/get_pcap_url/" + selected;
var id_array = select_id.split('_')
var div_id = "pcap_file_link_" + id_array[3];
var div_area = $("div").find("#" + div_id);
$.get(url, function(data) {
div_area.html(data);
});
}
</script>
{% endif %}
{% ifequal pcap_operation "summary-size" %}
<script type='text/javascript'>
var width = 960,
height = 500,
color = d3.scale.category20c();
var treemap = d3.layout.treemap()
.size([width, height])
.sticky(true)
.value(function(d) { return d.size; });
var div = d3.select("#summary_size_info").append("div")
.style("position", "relative")
.style("width", width + "px")
.style("height", height + "px");
d3.json("{{ json_file_url }}", function(json) {
div.data([json]).selectAll("div")
.data(treemap.nodes)
.enter().append("div")
.attr("class", "cell")
.style("background", function(d) { return d.children ? color(d.name) : null; })
.call(cell)
.text(function(d) { return d.children ? null : d.name; });
});
function cell() {
this
.style("left", function(d) { return d.x + "px"; })
.style("top", function(d) { return d.y + "px"; })
.style("width", function(d) { return Math.max(0, d.dx - 1) + "px"; })
.style("height", function(d) { return Math.max(0, d.dy - 1) + "px"; });
}
</script>
{% endifequal %}
{% ifequal pcap_operation "welcome" %}
<script>
var g_data = [];
//Format A
// nv.addGraph(function() {
// var chart = nv.models.scatterChart()
// .showDistX(true)
// .showDistY(true)
// //.height(500)
// .color(d3.scale.category10().range());
//
// chart.xAxis.tickFormat(d3.format('.02f'))
// chart.yAxis.tickFormat(d3.format('.02f'))
//
// d3.select('#chart svg')
// .datum(getData())
// .transition().duration(500)
// .call(chart);
//
// nv.utils.windowResize(chart.update);
//
// return chart;
// });
//function getData() {
d3.json('{{ json_file_url }}', function(jsondata) {
console.log("jsondata");
console.log(jsondata);
//alert(JSON.stringify(data));
nv.addGraph(function() {
var chart = nv.models.scatterChart()
.showDistX(true)
.showDistY(true)
//.height(500)
.color(d3.scale.category10().range());
//chart.xAxis.tickFormat(d3.format('.02f'))
//chart.yAxis.tickFormat(d3.format('.02f'))
chart.xAxis.tickFormat(d3.format('r'))
chart.yAxis.tickFormat(d3.format('r'))
//labeling
chart.xAxis.axisLabel('Year')
chart.yAxis.axisLabel('Number of Packets')
d3.select('#chart svg')
.datum(jsondata)
.transition().duration(500)
.call(chart);
nv.utils.windowResize(chart.update);
return chart;
});
console.log("chart is added");
});
// console.log("data is set")
// console.log(g_data);
// return g_data;
//}
function randomData(groups, points) { //# groups,# points per group
var data = [],
shapes = ['circle', 'cross', 'triangle-up', 'triangle-down', 'diamond', 'square'],
random = d3.random.normal();
for (i = 0; i < groups; i++) {
data.push({
key: 'Group ' + i,
values: []
});
for (j = 0; j < points; j++) {
data[i].values.push({
x: random(),
y: random(),
size: Math.random(),
shape: shapes[j % 6]
});
}
}
//alert(JSON.stringify(data));
return data;
}
</script>
{% endifequal %}
{% ifequal pcap_operation "file_details" %}
<script>
var g_data = [];
//Format A
// nv.addGraph(function() {
// var chart = nv.models.scatterChart()
// .showDistX(true)
// .showDistY(true)
// //.height(500)
// .color(d3.scale.category10().range());
//
// chart.xAxis.tickFormat(d3.format('.02f'))
// chart.yAxis.tickFormat(d3.format('.02f'))
//
// d3.select('#chart svg')
// .datum(getData())
// .transition().duration(500)
// .call(chart);
//
// nv.utils.windowResize(chart.update);
//
// return chart;
// });
//function getData() {
d3.json('{{ json_file_url }}', function(jsondata) {
console.log("jsondata");
console.log(jsondata);
//alert(JSON.stringify(data));
nv.addGraph(function() {
var chart = nv.models.scatterChart()
.showDistX(true)
.showDistY(true)
//.height(500)
.color(d3.scale.category10().range());
//chart.xAxis.tickFormat(d3.format('.02f'))
//chart.yAxis.tickFormat(d3.format('.02f'))
chart.xAxis.tickFormat(d3.format('r'))
chart.yAxis.tickFormat(d3.format('r'))
chart.showControls(false)
//labeling
chart.xAxis.axisLabel('Year')
chart.yAxis.axisLabel('Number of Packets')
d3.select('#chart svg')
.datum(jsondata)
.transition().duration(500)
.call(chart);
nv.utils.windowResize(chart.update);
return chart;
});
console.log("chart is added");
});
// console.log("data is set")
// console.log(g_data);
// return g_data;
//}
function randomData(groups, points) { //# groups,# points per group
var data = [],
shapes = ['circle', 'cross', 'triangle-up', 'triangle-down', 'diamond', 'square'],
random = d3.random.normal();
for (i = 0; i < groups; i++) {
data.push({
key: 'Group ' + i,
values: []
});
for (j = 0; j < points; j++) {
data[i].values.push({
x: random(),
y: random(),
size: Math.random(),
shape: shapes[j % 6]
});
}
}
//alert(JSON.stringify(data));
return data;
}
</script>
{% endifequal %}
{% ifequal pcap_operation "parallel_coordinates" %}
<script>
// Parallel Coordinates
// Copyright (c) 2012, Kai Chang
// Released under the BSD License: http://opensource.org/licenses/BSD-3-Clause
var width = document.body.clientWidth,
height = d3.max([document.body.clientHeight-540, 240]);
var m = [60, 0, 10, 0],
w = width - m[1] - m[3],
h = height - m[0] - m[2],
xscale = d3.scale.ordinal().rangePoints([0, w], 1),
yscale = {},
dragging = {},
line = d3.svg.line(),
axis = d3.svg.axis().orient("left").ticks(1+height/50),
data,
foreground,
background,
highlighted,
dimensions,
legend,
render_speed = 50,
brush_count = 0,
excluded_groups = [];
var colors = {
"smtp": [318,65,67],
"http": [300,45,47],
"dns": [290, 25, 27],
"unknown": [280, 15, 17]
};
// Scale chart and canvas height
d3.select("#chart")
.style("height", (h + m[0] + m[2]) + "px")
d3.selectAll("canvas")
.attr("width", w)
.attr("height", h)
.style("padding", m.join("px ") + "px");
// Foreground canvas for primary view
foreground = document.getElementById('foreground').getContext('2d');
foreground.globalCompositeOperation = "destination-over";
foreground.strokeStyle = "rgba(0,100,160,0.1)";
foreground.lineWidth = 1.7;
foreground.fillText("Loading...",w/2,h/2);
// Highlight canvas for temporary interactions
highlighted = document.getElementById('highlight').getContext('2d');
highlighted.strokeStyle = "rgba(0,100,160,1)";
highlighted.lineWidth = 4;
// Background canvas
background = document.getElementById('background').getContext('2d');
background.strokeStyle = "rgba(0,100,160,0.1)";
background.lineWidth = 1.7;
// SVG for ticks, labels, and interactions
var svg = d3.select("svg")
.attr("width", w + m[1] + m[3])
.attr("height", h + m[0] + m[2])
.append("svg:g")
.attr("transform", "translate(" + m[3] + "," + m[0] + ")");
// Load the data and visualization
d3.csv("{{ csv_file_url }}", function(raw_data) {
// Convert quantitative scales to floats
data = raw_data.map(function(d) {
for (var k in d) {
if (!_.isNaN(raw_data[0][k] - 0) && k != 'id') {
d[k] = parseFloat(d[k]) || 0;
}
};
return d;
});
// Extract the list of numerical dimensions and create a scale for each.
xscale.domain(dimensions = d3.keys(data[0]).filter(function(k) {
return (_.isNumber(data[0][k])) && (yscale[k] = d3.scale.linear()
.domain(d3.extent(data, function(d) { return +d[k]; }))
.range([h, 0]));
}).sort());
// Add a group element for each dimension.
var g = svg.selectAll(".dimension")
.data(dimensions)
.enter().append("svg:g")
.attr("class", "dimension")
.attr("transform", function(d) { return "translate(" + xscale(d) + ")"; })
.call(d3.behavior.drag()
.on("dragstart", function(d) {
dragging[d] = this.__origin__ = xscale(d);
this.__dragged__ = false;
d3.select("#foreground").style("opacity", "0.35");
})
.on("drag", function(d) {
dragging[d] = Math.min(w, Math.max(0, this.__origin__ += d3.event.dx));
dimensions.sort(function(a, b) { return position(a) - position(b); });
xscale.domain(dimensions);
g.attr("transform", function(d) { return "translate(" + position(d) + ")"; });
brush_count++;
this.__dragged__ = true;
// Feedback for axis deletion if dropped
if (dragging[d] < 12 || dragging[d] > w-12) {
d3.select(this).select(".background").style("fill", "#b00");
} else {
d3.select(this).select(".background").style("fill", null);
}
})
.on("dragend", function(d) {
if (!this.__dragged__) {
// no movement, invert axis
var extent = invert_axis(d);
} else {
// reorder axes
d3.select(this).transition().attr("transform", "translate(" + xscale(d) + ")");
var extent = yscale[d].brush.extent();
}
// remove axis if dragged all the way left
if (dragging[d] < 12 || dragging[d] > w-12) {
remove_axis(d,g);
}
// TODO required to avoid a bug
xscale.domain(dimensions);
update_ticks(d, extent);
// rerender
d3.select("#foreground").style("opacity", null);
brush();
delete this.__dragged__;
delete this.__origin__;
delete dragging[d];
}))
// Add an axis and title.
g.append("svg:g")
.attr("class", "axis")
.attr("transform", "translate(0,0)")
.each(function(d) { d3.select(this).call(axis.scale(yscale[d])); })
.append("svg:text")
.attr("text-anchor", "middle")
.attr("y", function(d,i) { return i%2 == 0 ? -14 : -30 } )
.attr("x", 0)
.attr("class", "label")
.text(String)
.append("title")
.text("Click to invert. Drag to reorder");
// Add and store a brush for each axis.
g.append("svg:g")
.attr("class", "brush")
.each(function(d) { d3.select(this).call(yscale[d].brush = d3.svg.brush().y(yscale[d]).on("brush", brush)); })
.selectAll("rect")
.style("visibility", null)
.attr("x", -23)
.attr("width", 36)
.append("title")
.text("Drag up or down to brush along this axis");
g.selectAll(".extent")
.append("title")
.text("Drag or resize this filter");
legend = create_legend(colors,brush);
// Render full foreground
brush();
});
// copy one canvas to another, grayscale
function gray_copy(source, target) {
var pixels = source.getImageData(0,0,w,h);
target.putImageData(grayscale(pixels),0,0);
}
// http://www.html5rocks.com/en/tutorials/canvas/imagefilters/
function grayscale(pixels, args) {
var d = pixels.data;
for (var i=0; i<d.length; i+=4) {
var r = d[i];
var g = d[i+1];
var b = d[i+2];
// CIE luminance for the RGB
// The human eye is bad at seeing red and blue, so we de-emphasize them.
var v = 0.2126*r + 0.7152*g + 0.0722*b;
d[i] = d[i+1] = d[i+2] = v
}
return pixels;
};
function create_legend(colors,brush) {
// create legend
var legend_data = d3.select("#legend")
.html("")
.selectAll(".row")
.data( _.keys(colors).sort() )
// filter by group
var legend = legend_data
.enter().append("div")
.attr("title", "Hide group")
.on("click", function(d) {
// toggle food group
if (_.contains(excluded_groups, d)) {
d3.select(this).attr("title", "Hide group")
excluded_groups = _.difference(excluded_groups,[d]);
brush();
} else {
d3.select(this).attr("title", "Show group")
excluded_groups.push(d);
brush();
}
});
legend
.append("span")
.style("background", function(d,i) { return color(d,0.85)})
.attr("class", "color-bar");
legend
.append("span")
.attr("class", "tally")
.text(function(d,i) { return 0});
legend
.append("span")
.text(function(d,i) { return " " + d});
return legend;
}
// render polylines i to i+render_speed
function render_range(selection, i, max, opacity) {
selection.slice(i,max).forEach(function(d) {
path(d, foreground, color(d.group,opacity));
});
};
// simple data table
function data_table(sample) {
// sort by first column
var sample = sample.sort(function(a,b) {
var col = d3.keys(a)[0];
return a[col] < b[col] ? -1 : 1;
});
var table = d3.select("#protocol-list")
.html("")
.selectAll(".row")
.data(sample)
.enter().append("div")
.on("mouseover", highlight)
.on("mouseout", unhighlight);
table
.append("span")
.attr("class", "color-block")
.style("background", function(d) { return color(d.group,0.85) })
table
.append("span")
.text(function(d) { return d.name; })
}
// Adjusts rendering speed
function optimize(timer) {
var delta = (new Date()).getTime() - timer;
render_speed = Math.max(Math.ceil(render_speed * 30 / delta), 8);
render_speed = Math.min(render_speed, 300);
return (new Date()).getTime();
}
// Feedback on rendering progress
function render_stats(i,n,render_speed) {
d3.select("#rendered-count").text(i);
d3.select("#rendered-bar")
.style("width", (100*i/n) + "%");
d3.select("#render-speed").text(render_speed);
}
// Feedback on selection
function selection_stats(opacity, n, total) {
d3.select("#data-count").text(total);
d3.select("#selected-count").text(n);
d3.select("#selected-bar").style("width", (100*n/total) + "%");
d3.select("#opacity").text((""+(opacity*100)).slice(0,4) + "%");
}
// Highlight single polyline
function highlight(d) {
d3.select("#foreground").style("opacity", "0.25");
d3.selectAll(".row").style("opacity", function(p) { return (d.group == p) ? null : "0.3" });
path(d, highlighted, color(d.group,1));
}
// Remove highlight
function unhighlight() {
d3.select("#foreground").style("opacity", null);
d3.selectAll(".row").style("opacity", null);
highlighted.clearRect(0,0,w,h);
}
function invert_axis(d) {
// save extent before inverting
if (!yscale[d].brush.empty()) {
var extent = yscale[d].brush.extent();
}
if (yscale[d].inverted == true) {
yscale[d].range([h, 0]);
d3.selectAll('.label')
.filter(function(p) { return p == d; })
.style("text-decoration", null);
yscale[d].inverted = false;
} else {
yscale[d].range([0, h]);
d3.selectAll('.label')
.filter(function(p) { return p == d; })
.style("text-decoration", "underline");
yscale[d].inverted = true;
}
return extent;
}
// Draw a single polyline
/*
function path(d, ctx, color) {
if (color) ctx.strokeStyle = color;
var x = xscale(0)-15;
y = yscale[dimensions[0]](d[dimensions[0]]); // left edge
ctx.beginPath();
ctx.moveTo(x,y);
dimensions.map(function(p,i) {
x = xscale(p),
y = yscale[p](d[p]);
ctx.lineTo(x, y);
});
ctx.lineTo(x+15, y); // right edge
ctx.stroke();
}
*/
function path(d, ctx, color) {
if (color) ctx.strokeStyle = color;
ctx.beginPath();
var x0 = xscale(0)-15,
y0 = yscale[dimensions[0]](d[dimensions[0]]); // left edge
ctx.moveTo(x0,y0);
dimensions.map(function(p,i) {
var x = xscale(p),
y = yscale[p](d[p]);
var cp1x = x - 0.88*(x-x0);
var cp1y = y0;
var cp2x = x - 0.12*(x-x0);
var cp2y = y;
ctx.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y);
x0 = x;
y0 = y;
});
ctx.lineTo(x0+15, y0); // right edge
ctx.stroke();
};
function color(d,a) {
var c = colors[d];
return ["hsla(",c[0],",",c[1],"%,",c[2],"%,",a,")"].join("");
}
function position(d) {
var v = dragging[d];
return v == null ? xscale(d) : v;
}
// Handles a brush event, toggling the display of foreground lines.
// TODO refactor
function brush() {
brush_count++;
var actives = dimensions.filter(function(p) { return !yscale[p].brush.empty(); }),
extents = actives.map(function(p) { return yscale[p].brush.extent(); });
// hack to hide ticks beyond extent
var b = d3.selectAll('.dimension')[0]
.forEach(function(element, i) {
var dimension = d3.select(element).data()[0];
if (_.include(actives, dimension)) {
var extent = extents[actives.indexOf(dimension)];
d3.select(element)
.selectAll('text')
.style('font-weight', 'bold')
.style('font-size', '13px')
.style('display', function() {
var value = d3.select(this).data();
return extent[0] <= value && value <= extent[1] ? null : "none"
});
} else {
d3.select(element)
.selectAll('text')
.style('font-size', null)
.style('font-weight', null)
.style('display', null);
}
d3.select(element)
.selectAll('.label')
.style('display', null);
});
;
// bold dimensions with label
d3.selectAll('.label')
.style("font-weight", function(dimension) {
if (_.include(actives, dimension)) return "bold";
return null;
});
// Get lines within extents
var selected = [];
data
.filter(function(d) {
return !_.contains(excluded_groups, d.group);
})
.map(function(d) {
return actives.every(function(p, dimension) {
return extents[dimension][0] <= d[p] && d[p] <= extents[dimension][1];
}) ? selected.push(d) : null;
});
// free text search
var query = d3.select("#search")[0][0].value;
if (query.length > 0) {
selected = search(selected, query);
}
if (selected.length < data.length && selected.length > 0) {
d3.select("#keep-data").attr("disabled", null);
d3.select("#exclude-data").attr("disabled", null);
} else {
d3.select("#keep-data").attr("disabled", "disabled");
d3.select("#exclude-data").attr("disabled", "disabled");
};
// total by food group
var tallies = _(selected)
.groupBy(function(d) { return d.group; })
// include empty groups
_(colors).each(function(v,k) { tallies[k] = tallies[k] || []; });
legend
.style("text-decoration", function(d) { return _.contains(excluded_groups,d) ? "line-through" : null; })
.attr("class", function(d) {
return (tallies[d].length > 0)
? "row"
: "row off";
});
legend.selectAll(".color-bar")
.style("width", function(d) {
return Math.ceil(600*tallies[d].length/data.length) + "px"
});
legend.selectAll(".tally")
.text(function(d,i) { return tallies[d].length });
// Render selected lines
paths(selected, foreground, brush_count, true);
}
// render a set of polylines on a canvas
function paths(selected, ctx, count) {
var n = selected.length,
i = 0,
opacity = d3.min([2/Math.pow(n,0.3),1]),
timer = (new Date()).getTime();
selection_stats(opacity, n, data.length)
shuffled_data = _.shuffle(selected);
data_table(shuffled_data.slice(0,25));
ctx.clearRect(0,0,w+1,h+1);
// render all lines until finished or a new brush event
function animloop(){
if (i >= n || count < brush_count) return true;
var max = d3.min([i+render_speed, n]);
render_range(shuffled_data, i, max, opacity);
render_stats(max,n,render_speed);
i = max;
timer = optimize(timer); // adjusts render_speed
};
d3.timer(animloop);
}
// transition ticks for reordering, rescaling and inverting
function update_ticks(d, extent) {
// update brushes
if (d) {
var brush_el = d3.selectAll(".brush")
.filter(function(key) { return key == d; });
// single tick
if (extent) {
// restore previous extent
brush_el.call(yscale[d].brush = d3.svg.brush().y(yscale[d]).extent(extent).on("brush", brush));
} else {
brush_el.call(yscale[d].brush = d3.svg.brush().y(yscale[d]).on("brush", brush));
}
} else {
// all ticks
d3.selectAll(".brush")
.each(function(d) { d3.select(this).call(yscale[d].brush = d3.svg.brush().y(yscale[d]).on("brush", brush)); })
}
brush_count++;
show_ticks();
// update axes
d3.selectAll(".axis")
.each(function(d,i) {
// hide lines for better performance
d3.select(this).selectAll('line').style("display", "none");
// transition axis numbers
d3.select(this)
.transition()
.duration(720)
.call(axis.scale(yscale[d]));
// bring lines back
d3.select(this).selectAll('line').transition().delay(800).style("display", null);
d3.select(this)
.selectAll('text')
.style('font-weight', null)
.style('font-size', null)
.style('display', null);
});
}
// Rescale to new dataset domain
function rescale() {
// reset yscales, preserving inverted state
dimensions.forEach(function(d,i) {
if (yscale[d].inverted) {
yscale[d] = d3.scale.linear()
.domain(d3.extent(data, function(p) { return +p[d]; }))
.range([0, h]);
yscale[d].inverted = true;
} else {
yscale[d] = d3.scale.linear()
.domain(d3.extent(data, function(p) { return +p[d]; }))
.range([h, 0]);
}
});
update_ticks();
// Render selected data
paths(data, foreground, brush_count);
}
// Get polylines within extents
function actives() {
var actives = dimensions.filter(function(p) { return !yscale[p].brush.empty(); }),
extents = actives.map(function(p) { return yscale[p].brush.extent(); });
// filter extents and excluded groups
var selected = [];
data
.filter(function(d) {
return !_.contains(excluded_groups, d.group);
})
.map(function(d) {
return actives.every(function(p, i) {
return extents[i][0] <= d[p] && d[p] <= extents[i][1];
}) ? selected.push(d) : null;
});
// free text search
var query = d3.select("#search")[0][0].value;
if (query > 0) {
selected = search(selected, query);
}
return selected;
}
// Export data
function export_csv() {
var keys = d3.keys(data[0]);
var rows = actives().map(function(row) {
return keys.map(function(k) { return row[k]; })
});
var csv = d3.csv.format([keys].concat(rows)).replace(/\n/g,"<br/>\n");
var styles = "<style>body { font-family: sans-serif; font-size: 12px; }</style>";
window.open("text/csv").document.write(styles + csv);
}
// scale to window size
window.onresize = function() {
width = document.body.clientWidth,
height = d3.max([document.body.clientHeight-500, 220]);
w = width - m[1] - m[3],
h = height - m[0] - m[2];
d3.select("#chart")
.style("height", (h + m[0] + m[2]) + "px")
d3.selectAll("canvas")
.attr("width", w)
.attr("height", h)
.style("padding", m.join("px ") + "px");
d3.select("svg")
.attr("width", w + m[1] + m[3])
.attr("height", h + m[0] + m[2])
.select("g")
.attr("transform", "translate(" + m[3] + "," + m[0] + ")");
xscale = d3.scale.ordinal().rangePoints([0, w], 1).domain(dimensions);
dimensions.forEach(function(d) {
yscale[d].range([h, 0]);
});
d3.selectAll(".dimension")
.attr("transform", function(d) { return "translate(" + xscale(d) + ")"; })
// update brush placement
d3.selectAll(".brush")
.each(function(d) { d3.select(this).call(yscale[d].brush = d3.svg.brush().y(yscale[d]).on("brush", brush)); })
brush_count++;
// update axis placement
axis = axis.ticks(1+height/50),
d3.selectAll(".axis")
.each(function(d) { d3.select(this).call(axis.scale(yscale[d])); });
// render data
brush();
};
// Remove all but selected from the dataset
function keep_data() {
new_data = actives();
if (new_data.length == 0) {
alert("I don't mean to be rude, but I can't let you remove all the data.\n\nTry removing some brushes to get your data back. Then click 'Keep' when you've selected data you want to look closer at.");
return false;
}
data = new_data;
rescale();
}
// Exclude selected from the dataset
function exclude_data() {
new_data = _.difference(data, actives());
if (new_data.length == 0) {
alert("I don't mean to be rude, but I can't let you remove all the data.\n\nTry selecting just a few data points then clicking 'Exclude'.");
return false;
}
data = new_data;
rescale();
}
function remove_axis(d,g) {
dimensions = _.difference(dimensions, [d]);
xscale.domain(dimensions);
g.attr("transform", function(p) { return "translate(" + position(p) + ")"; });
g.filter(function(p) { return p == d; }).remove();
update_ticks();
}
d3.select("#keep-data").on("click", keep_data);
d3.select("#exclude-data").on("click", exclude_data);
d3.select("#export-data").on("click", export_csv);
d3.select("#search").on("keyup", brush);
// Appearance toggles
d3.select("#hide-ticks").on("click", hide_ticks);
d3.select("#show-ticks").on("click", show_ticks);
d3.select("#dark-theme").on("click", dark_theme);
d3.select("#light-theme").on("click", light_theme);
function hide_ticks() {
d3.selectAll(".axis g").style("display", "none");
//d3.selectAll(".axis path").style("display", "none");
d3.selectAll(".background").style("visibility", "hidden");
d3.selectAll("#hide-ticks").attr("disabled", "disabled");
d3.selectAll("#show-ticks").attr("disabled", null);
};
function show_ticks() {
d3.selectAll(".axis g").style("display", null);
//d3.selectAll(".axis path").style("display", null);
d3.selectAll(".background").style("visibility", null);
d3.selectAll("#show-ticks").attr("disabled", "disabled");
d3.selectAll("#hide-ticks").attr("disabled", null);
};
function dark_theme() {
d3.select("body").attr("class", "dark");
d3.selectAll("#dark-theme").attr("disabled", "disabled");
d3.selectAll("#light-theme").attr("disabled", null);
}
function light_theme() {
d3.select("body").attr("class", null);
d3.selectAll("#light-theme").attr("disabled", "disabled");
d3.selectAll("#dark-theme").attr("disabled", null);
}
function search(selection,str) {
pattern = new RegExp(str,"i")
return _(selection).filter(function(d) { return pattern.exec(d.name); });
}
</script>
{% endifequal %}
</body>
</html>
Jump to Line
Something went wrong with that request. Please try again.