зеркало из https://github.com/mozilla/lightbeam.git
move filters to aggregate.js
This commit is contained in:
Родитель
4e296120da
Коммит
5d2cd74333
|
@ -9,19 +9,17 @@ var nodemap, edgemap;
|
|||
|
||||
var aggregate = new Emitter();
|
||||
global.aggregate = aggregate;
|
||||
global.filteredAggregate = {
|
||||
nodes: [],
|
||||
edges: []
|
||||
};
|
||||
|
||||
aggregate.allnodes = [];
|
||||
aggregate.sitenodes = [];
|
||||
aggregate.thirdnodes = [];
|
||||
aggregate.bothnodes = [];
|
||||
aggregate.nodes = [];
|
||||
aggregate.edges = [];
|
||||
|
||||
function resetData(){
|
||||
aggregate.allnodes.length = 0;
|
||||
aggregate.nodes.length = 0;
|
||||
nodemap = {};
|
||||
aggregate.sitenodes.length = 0;
|
||||
aggregate.thirdnodes.length = 0;
|
||||
aggregate.bothnodes.length = 0;
|
||||
edgemap = {};
|
||||
aggregate.edges.length = 0;
|
||||
}
|
||||
|
@ -71,15 +69,16 @@ aggregate.connectionAsObject = function(conn){
|
|||
|
||||
|
||||
function applyFilter(filter){
|
||||
resetData();
|
||||
currentFilter = filter;
|
||||
onLoad(allConnections);
|
||||
|
||||
}
|
||||
|
||||
aggregate.on('filter', applyFilter);
|
||||
|
||||
function onLoad(connections){
|
||||
currentFilter(connections).forEach(onConnection);
|
||||
connections.forEach(onConnection);
|
||||
currentFilter();
|
||||
currentVisualization.emit('init', filteredAggregate);
|
||||
}
|
||||
|
||||
aggregate.on('load', onLoad);
|
||||
|
@ -112,34 +111,20 @@ function onConnection(conn){
|
|||
var sourcenode, targetnode, edge, nodelist, updated = false;
|
||||
if (nodemap[connection.source]){
|
||||
sourcenode = nodemap[connection.source];
|
||||
var oldNodeType = sourcenode.nodeType;
|
||||
sourcenode.update(connection, true);
|
||||
if (oldNodeType !== sourcenode.nodeType){
|
||||
moveNode(sourcenode, oldNodeType);
|
||||
updated = true;
|
||||
}
|
||||
}else{
|
||||
sourcenode = new GraphNode(connection, true);
|
||||
nodemap[connection.source] = sourcenode;
|
||||
nodelist = getNodeList(sourcenode.nodeType);
|
||||
nodelist.push(sourcenode);
|
||||
aggregate.allnodes.push(sourcenode);
|
||||
aggregate.nodes.push(sourcenode);
|
||||
updated = true;
|
||||
}
|
||||
if (nodemap[connection.target]){
|
||||
targetnode = nodemap[connection.target];
|
||||
var oldNodeType = targetnode.nodeType;
|
||||
targetnode.update(connection, false);
|
||||
if (oldNodeType !== targetnode.nodeType){
|
||||
moveNode(targetnode, oldNodeType);
|
||||
updated = true;
|
||||
}
|
||||
}else{
|
||||
targetnode = new GraphNode(connection, false);
|
||||
nodemap[connection.target] = targetnode;
|
||||
nodelist = getNodeList(targetnode.nodeType);
|
||||
nodelist.push(targetnode);
|
||||
aggregate.allnodes.push(targetnode); // all nodes
|
||||
aggregate.nodes.push(targetnode); // all nodes
|
||||
updated = true
|
||||
}
|
||||
if (edgemap[connection.source + '->' + connection.target]){
|
||||
|
@ -158,28 +143,14 @@ function onConnection(conn){
|
|||
|
||||
aggregate.on('connection', onConnection);
|
||||
|
||||
function getNodeList(nodeType){
|
||||
switch(nodeType){
|
||||
case 'site': return aggregate.sitenodes;
|
||||
case 'thirdparty': return aggregate.thirdnodes;
|
||||
case 'both': return aggregate.bothnodes;
|
||||
default: throw new Error('It has to be one of the choices above');
|
||||
}
|
||||
}
|
||||
|
||||
function moveNode(node, oldNodeType){
|
||||
var oldlist = getNodeList(oldNodeType);
|
||||
var newlist = getNodeList(node.nodeType);
|
||||
oldlist.splice(oldlist.indexOf(node), 1);
|
||||
newlist.push(node);
|
||||
}
|
||||
|
||||
|
||||
function GraphEdge(source, target, connection){
|
||||
this.source = source;
|
||||
this.target = target;
|
||||
this.name = source.name + '->' + target.name;
|
||||
this.cookieCount = connection.cookie ? 1 : 0;
|
||||
if (connection){
|
||||
this.cookieCount = connection.cookie ? 1 : 0;
|
||||
}
|
||||
// console.log('edge: %s', this.name);
|
||||
}
|
||||
GraphEdge.prototype.lastAccess = function(){
|
||||
|
@ -273,5 +244,123 @@ GraphNode.prototype.update = function(connection, isSource){
|
|||
return this;
|
||||
};
|
||||
|
||||
// Filtering
|
||||
|
||||
function nodesSortedByDate(nodes){
|
||||
return nodes.map(function(node){
|
||||
return [node.lastAccess, node];
|
||||
}).sort().map(function(arr){
|
||||
return arr[1];
|
||||
});
|
||||
}
|
||||
|
||||
function edgesForNodes(nodes){
|
||||
var edgemap = {};
|
||||
nodes.forEach(function(node){
|
||||
node.linkedFrom.forEach(function)
|
||||
})
|
||||
}
|
||||
|
||||
function aggregateFromNodes(nodes){
|
||||
var localmap = {};
|
||||
var edgemap = {};
|
||||
nodes.forEach(function(node){
|
||||
localmap[node.name] = node;
|
||||
node.linkedFrom.forEach(function(nodename){
|
||||
var linkedNode = nodemap[nodename];
|
||||
var edge = new GraphEdge(node, linkedNode);
|
||||
edgemap[edge.name] = edge;
|
||||
localmap[nodename] = linkedNode;
|
||||
});
|
||||
node.linkedTo.forEach(function(nodename){
|
||||
var linkedNode = nodemap[nodename];
|
||||
var edge = new GraphEdge(node, linkedNode);
|
||||
edgemap[edge.name] = edge;
|
||||
localmap[nodename] = linkedNode;
|
||||
});
|
||||
});
|
||||
return {
|
||||
nodes: Object.keys(localmap).map(function(name){
|
||||
return localmap[name];
|
||||
}),
|
||||
edges: Object.keys(edgemap).map(function(name){
|
||||
return edgemap[name];
|
||||
})
|
||||
};
|
||||
}
|
||||
|
||||
// filters
|
||||
aggregate.filters = {
|
||||
daily: function daily(connections){
|
||||
var now = Date.now();
|
||||
var then = now - (24 * 60 * 60 * 1000);
|
||||
var sortedNodes = nodesSortedByDate(aggregate.nodes);
|
||||
console.log('daily filter before: %s', aggregate.nodes.length);
|
||||
// filter
|
||||
// find index where we go beyond date
|
||||
var i;
|
||||
for (i = sortedNodes.length - 1; i > -1, i--){
|
||||
if (sortedNodes[i].lastAccess < then){
|
||||
break;
|
||||
}
|
||||
}
|
||||
var filteredNodes = sortedNodes.slice(i);
|
||||
// Done filtering
|
||||
console.log('daily filter after: %s', filteredNodes.length);
|
||||
return aggregateFromNodes(filteredNodes);
|
||||
},
|
||||
weekly: function weekly(connections){
|
||||
var now = Date.now();
|
||||
var then = now - (7 * 24 * 60 * 60 * 1000);
|
||||
var sortedNodes = nodesSortedByDate(aggregate.nodes);
|
||||
console.log('weekly filter before: %s', sortedNodes.length);
|
||||
// filter
|
||||
// find index where we go beyond date
|
||||
var i;
|
||||
for (i = sortedNodes.length - 1; i > -1, i--){
|
||||
if (sortedNodes[i].lastAccess < then){
|
||||
break;
|
||||
}
|
||||
}
|
||||
var filteredNodes = sortedNodes.slice(i);
|
||||
console.log('weekly filter after: %s', filteredNodes.length);
|
||||
return aggregateFromNodes(filteredNodes);
|
||||
},
|
||||
last10sites: function last10sites(connections){
|
||||
var indices = [];
|
||||
for (var i = 0; i < connections.length; i++){
|
||||
if (connections[i][SOURCE_VISITED]){
|
||||
indices.push(i);
|
||||
}
|
||||
}
|
||||
console.log('last10sites filter before: %s', connections.length);
|
||||
console.log('indices: %o', indices);
|
||||
var filtered = connections;
|
||||
if (indices.length > 9){
|
||||
var cutpoint = indices.slice(-10)[0];
|
||||
filtered = connections.slice(cutpoint);
|
||||
}
|
||||
console.log('last10sites filter after: %s', filtered.length)
|
||||
return filtered;
|
||||
},
|
||||
recent: function recent(connections){
|
||||
var indices = [];
|
||||
for (var i = 0; i < connections.length; i++){
|
||||
if (connections[i][SOURCE_VISITED]){
|
||||
indices.push(i);
|
||||
}
|
||||
}
|
||||
console.log('recent filter before: %s', connections.length);
|
||||
console.log('indices: %o', indices);
|
||||
var filtered = connections;
|
||||
if (indices.length > 0){
|
||||
var cutpoint = indices.slice(-1)[0];
|
||||
filtered = connections.slice(cutpoint);
|
||||
}
|
||||
console.log('recent filter after: %s', filtered.length)
|
||||
return filtered;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
})(this);
|
||||
|
|
|
@ -26,11 +26,6 @@ clock.name = "clock";
|
|||
clock.on('init', onInit);
|
||||
clock.on('connection', onConnection);
|
||||
clock.on('remove', onRemove);
|
||||
clock.on('setFilter', setFilter);
|
||||
|
||||
function setFilter(){
|
||||
addon.emit('setFilter', 'filter24hours');
|
||||
}
|
||||
|
||||
function onInit(connections){
|
||||
console.log("= onInit = allConnections.length = %s" , allConnections.length);
|
||||
|
|
|
@ -132,70 +132,12 @@ function switchVisualization(name){
|
|||
}
|
||||
localStorage.visualization = initCap(name);
|
||||
currentVisualization = visualizations[name];
|
||||
// currentVisualization.emit('setFilter');
|
||||
resetAddtionalUI();
|
||||
addon.emit('uiready');
|
||||
}
|
||||
|
||||
|
||||
// filters
|
||||
var filters = {
|
||||
daily: function daily(connections){
|
||||
var now = Date.now();
|
||||
var then = now - (24 * 60 * 60 * 1000);
|
||||
console.log('then: %s and now: %s', then, now);
|
||||
console.log('daily filter, before: %s', connections.length);
|
||||
var filtered = connections.filter(function(connection){
|
||||
return connection[TIMESTAMP] > then;
|
||||
});
|
||||
console.log('daily filter, after: %s', filtered.length);
|
||||
return filtered;
|
||||
},
|
||||
weekly: function weekly(connections){
|
||||
var now = Date.now();
|
||||
var then = now - (7 * 24 * 60 * 60 * 1000);
|
||||
console.log('then: %s and now: %s', then, now);
|
||||
console.log('weekly filter: before: %s', connections.length);
|
||||
var filtered = connections.filter(function(connection){
|
||||
return connection[TIMESTAMP] > then;
|
||||
});
|
||||
console.log('weekly filter: after: %s', connections.length);
|
||||
return filtered;
|
||||
},
|
||||
last10sites: function last10sites(connections){
|
||||
var indices = [];
|
||||
for (var i = 0; i < connections.length; i++){
|
||||
if (connections[i][SOURCE_VISITED]){
|
||||
indices.push(i);
|
||||
}
|
||||
}
|
||||
console.log('last10sites filter: before: %s', connections.length);
|
||||
console.log('indices: %o', indices);
|
||||
if (indices > 9){
|
||||
var cutpoint = indices.slice(-10)[0];
|
||||
return connections.slice(cutpoint);
|
||||
}else{
|
||||
return connections;
|
||||
}
|
||||
},
|
||||
recent: function recent(connections){
|
||||
var indices = [];
|
||||
for (var i = 0; i < connections.length; i++){
|
||||
if (connections[i][SOURCE_VISITED]){
|
||||
indices.push(i);
|
||||
}
|
||||
}
|
||||
console.log('recent filter: before: %s', connections.length);
|
||||
console.log('indices: %o', indices);
|
||||
if (indices > 0){
|
||||
var cutpoint = indices.slice(-1)[0];
|
||||
return connections.slice(cutpoint);
|
||||
}else{
|
||||
return connections;
|
||||
}
|
||||
}
|
||||
};
|
||||
var currentFilter = filters[localStorage.currentFilter || 'last24Hours'];
|
||||
var currentFilter = aggregate.filters[localStorage.currentFilter || 'last24Hours'];
|
||||
|
||||
function switchFilter(name){
|
||||
console.log('switchFilter(' + name + ')');
|
||||
|
|
|
@ -11,6 +11,7 @@ visualizations.graph = graph;
|
|||
graph.name = "graph";
|
||||
var width = 1000, height = 1000;
|
||||
var force, vis;
|
||||
var filteredAggregate;
|
||||
|
||||
// There are three phases for a visualization life-cycle:
|
||||
// init does initialization and receives the existing set of connections
|
||||
|
@ -20,12 +21,6 @@ graph.on('init', onInit);
|
|||
graph.on('connection', onConnection);
|
||||
graph.on('remove', onRemove);
|
||||
graph.on('reset', onReset);
|
||||
graph.on('setFilter', setFilter);
|
||||
|
||||
function setFilter(){
|
||||
//addon.emit('setFilter', 'filterLastXSites', 5);
|
||||
//addon.emit('setFilter', 'filter24hours');
|
||||
}
|
||||
|
||||
function onInit(connections){
|
||||
console.log("= onInit = allConnections.length = %s" , allConnections.length);
|
||||
|
@ -97,7 +92,7 @@ function polygonAsString(points, size){
|
|||
function initGraph(){
|
||||
// Initialize D3 layout and bind data
|
||||
force = d3.layout.force()
|
||||
.nodes(aggregate.allnodes)
|
||||
.nodes(aggregate.nodes)
|
||||
.links(aggregate.edges)
|
||||
.charge(-500)
|
||||
.size([width,height])
|
||||
|
@ -149,22 +144,19 @@ function updateGraph(){
|
|||
.remove();
|
||||
|
||||
var nodes = vis.selectAll('.node')
|
||||
.data(aggregate.allnodes, function(node){ return node.name; });
|
||||
.data(aggregate.nodes, function(node){ return node.name; });
|
||||
|
||||
nodes.call(force.drag);
|
||||
|
||||
nodes.enter().append('g')
|
||||
.classed('visitedYes', function(node){ return node.visitedCount/node.howMany === 1 })
|
||||
.classed('visitedNo', function(node){ return node.visitedCount/node.howMany === 0 })
|
||||
.classed('visitedBoth', function(node){ return node.visitedCount/node.howMany > 0 && node.visitedCount/node.howMany < 1 })
|
||||
.call(addShape)
|
||||
.attr('data-name', function(node){ return node.name; })
|
||||
.on('mouseenter', tooltip.show)
|
||||
.on('mouseleave', tooltip.hide)
|
||||
.classed('node', true);
|
||||
|
||||
|
||||
|
||||
nodes.exit()
|
||||
.remove();
|
||||
|
||||
|
@ -175,7 +167,7 @@ window.updategGraph = updateGraph;
|
|||
function addFavicon(selection){
|
||||
selection.append("svg:image")
|
||||
.attr("class", "favicon")
|
||||
.attr("width", "16")
|
||||
.attr("width", "16") // move these to the favicon class in css
|
||||
.attr("height", "16")
|
||||
.attr("x", "-8") // offset to make 16x16 favicon appear centered
|
||||
.attr("y", "-8")
|
||||
|
@ -194,8 +186,6 @@ function addCircle(selection){
|
|||
function addShape(selection){
|
||||
selection.filter('.visitedYes').call(addCircle).call(addFavicon);
|
||||
selection.filter('.visitedNo').call(addTriangle).call(addFavicon);
|
||||
selection.filter('.visitedBoth').call(addCircle).call(addFavicon);
|
||||
// selection.filter('.visitedBoth').call(addSquare).call(addFavicon);
|
||||
}
|
||||
|
||||
function addTriangle(selection){
|
||||
|
@ -205,32 +195,15 @@ function addTriangle(selection){
|
|||
.attr('data-name', function(node){ return node.name; });
|
||||
}
|
||||
|
||||
// function addSquare(selection){
|
||||
// selection
|
||||
// .append('rect')
|
||||
// .attr('x', -9)
|
||||
// .attr('y', -9)
|
||||
// .attr('width', 18)
|
||||
// .attr('height', 18);
|
||||
// }
|
||||
|
||||
|
||||
function updateNodes(thenodes){
|
||||
thenodes
|
||||
.attr('transform', function(node){ return 'translate(' + node.x + ',' + node.y + ') scale(' + (1 + .03 * node.weight) + ')'; })
|
||||
.classed('visitedYes', function(node){ return node.visitedCount/node.howMany == 1 })
|
||||
.classed('visitedNo', function(node){ return node.visitedCount/node.howMany == 0 })
|
||||
.classed('visitedBoth', function(node){ return node.visitedCount/node.howMany > 0 && node.visitedCount/node.howMany < 1 })
|
||||
.classed('secureYes', function(node){ return node.secureCount/node.howMany == 1 })
|
||||
.classed('secureNo', function(node){ return node.secureCount/node.howMany == 0 })
|
||||
.classed('secureBoth', function(node){ return node.secureCount/node.howMany > 0 && node.secureCount/node.howMany < 1 })
|
||||
// .classed('cookieYes', function(node){ return node.cookieCount/node.howMany == 1 })
|
||||
// .classed('cookieNo', function(node){ return node.cookieCount/node.howMany == 0 })
|
||||
// .classed('cookieBoth', function(node){ return node.cookieCount/node.howMany > 0 && node.cookieCount/node.howMany < 1 })
|
||||
.attr('transform', function(node){ return 'translate(' + node.x + ',' + node.y + ') scale(' + (1 + .05 * node.weight) + ')'; })
|
||||
.classed('visitedYes', function(node){ return node.visitedCount > 0 })
|
||||
.classed('visitedNo', function(node){ return node.visitedCount == 0 })
|
||||
.classed('secureYes', function(node){ return node.secureCount > 0 })
|
||||
.classed('secureNo', function(node){ return node.secureCount == 0 })
|
||||
.attr('data-timestamp', function(node){ return node.lastAccess.toISOString(); })
|
||||
.attr('visited-scale', function(node){ return node.visitedCount/node.howMany; })
|
||||
.attr('secure-scale', function(node){ return node.secureCount/node.howMany; })
|
||||
.attr('cookie-scale', function(node){ return node.cookieCount/node.howMany; })
|
||||
.classed('highlighted', function(edge){ return ( edge.visitedCount > 0 ) ? highlightVisited : highlightNeverVisited; });
|
||||
// change shape if needed
|
||||
}
|
||||
|
@ -257,7 +230,7 @@ var graphLegend = document.querySelector(".graph-footer");
|
|||
legendBtnClickHandler(graphLegend);
|
||||
|
||||
graphLegend.querySelector(".toggle-visited").addEventListener("click", function(event){
|
||||
var visited = document.querySelectorAll(".visitedYes, .visitedBoth");
|
||||
var visited = document.querySelectorAll(".visitedYes");
|
||||
toggleVizElements(visited,"highlighted");
|
||||
highlightVisited = !highlightVisited;
|
||||
});
|
||||
|
|
|
@ -13,16 +13,10 @@ list.name = "list";
|
|||
list.on("init", onInit);
|
||||
list.on("conneciton", onConnection);
|
||||
list.on("remove", onRemove);
|
||||
list.on('setFilter', setFilter);
|
||||
list.on("showFilteredTable", function(filter){
|
||||
showFilteredTable(filter);
|
||||
});
|
||||
|
||||
function setFilter(){
|
||||
addon.emit('setFilter', 'filterNothing');
|
||||
}
|
||||
|
||||
|
||||
function onInit(connections){
|
||||
vizcanvas.classList.add("hide"); // we don't need vizcanvas here, so hide it
|
||||
// A D3 visualization has a two main components, data-shaping, and setting up the D3 callbacks
|
||||
|
|
Загрузка…
Ссылка в новой задаче