Commit 20848b13 by Zachary Tong

Mostly working parallel coordinates

parent 0c4d4aa6
......@@ -3,15 +3,14 @@
font-size: 14px;
}
.foreground path {
.foregroundlines {
fill: none;
stroke-opacity: .5;
stroke-opacity: 0.3;
stroke-width: 1.5px;
}
.foreground path.fade {
stroke: #000;
stroke-opacity: .05;
.foregroundlines.fade {
display:none
}
.legend {
......
......@@ -15,7 +15,7 @@ angular.module('kibana.parallelcoordinates', [])
style : {'font-size': '9pt'},
fields : [],
sortable: true,
spyable: true,
spyable: true
}
_.defaults($scope.panel, _d)
......@@ -47,6 +47,7 @@ angular.module('kibana.parallelcoordinates', [])
eventBus.register($scope,'selected_fields', function(event, fields) {
console.log("selected_fields", fields);
$scope.panel.fields = _.clone(fields)
$scope.$emit('render');
});
};
......@@ -194,14 +195,6 @@ angular.module('kibana.parallelcoordinates', [])
var species = ["setosa", "versicolor", "virginica"],
traits = ["sepal length", "petal length", "sepal width", "petal width"];
var m = [80, 160, 200, 160],
w = 1280 - m[1] - m[3],
h = 800 - m[0] - m[2];
var x, y,line,axis,foreground,svg;
......@@ -211,95 +204,43 @@ angular.module('kibana.parallelcoordinates', [])
*/
function init_panel() {
scope.m = [80, 160, 200, 160];
scope.w = $(elem[0]).width() - scope.m[1] - scope.m[3],
scope.h = $(elem[0]).height() - scope.m[0] - scope.m[2];
console.log("init");
console.log("fields", scope.panel.fields);
scope.initializing = true;
// Using LABjs, wait until all scripts are loaded before rendering panel
var scripts = $LAB.script("common/lib/d3.v3.min.js?rand="+Math.floor(Math.random()*10000))
.script("panels/parallelcoordinates/lib/d3.csv.js?rand="+Math.floor(Math.random()*10000));
var scripts = $LAB.script("common/lib/d3.v3.min.js?rand="+Math.floor(Math.random()*10000));
scripts.wait(function () {
console.log("scripts loaded");
x = d3.scale.ordinal().domain(traits).rangePoints([0, w]);
y = {};
scope.x = d3.scale.ordinal().domain(scope.panel.fields).rangePoints([0, scope.w]);
scope.y = {};
line = d3.svg.line();
axis = d3.svg.axis().orient("left");
scope.line = d3.svg.line().interpolate('cardinal');
scope.axis = d3.svg.axis().orient("left");
svg = d3.select(elem[0]).append("svg")
scope.svg = d3.select(elem[0]).append("svg")
.attr("width", "100%")
.attr("height", "100%")
.attr("viewbox", "0 0 " + (w + m[1] + m[3]) + " " + (h + m[0] + m[2]))
.attr("viewbox", "0 0 " + (scope.w + scope.m[1] + scope.m[3]) + " " + (scope.h + scope.m[0] + scope.m[2]))
.append("svg:g")
.attr("transform", "translate(" + m[3] + "," + m[0] + ")");
console.log("loaded");
//console.log(flowers);
// Create a scale and brush for each trait.
scope.panel.fields.forEach(function(d) {
console.log("extent", d3.extent(scope.data, function(p) { return +p[d]; }));
y[d] = d3.scale.linear()
.domain(d3.extent(scope.data, function(p) { return +p[d]; }))
.range([h, 0]);
y[d].brush = d3.svg.brush()
.y(y[d])
.on("brush", brush);
});
console.log("y", y);
.attr("transform", "translate(" + scope.m[3] + "," + scope.m[0] + ")");
// Add foreground lines.
foreground = svg.append("svg:g")
.attr("class", "foreground")
.selectAll("path")
.data(scope.data)
.enter().append("svg:path")
.attr("d", path)
.attr("class", 'setosa');
// Add a group element for each trait.
scope.g = svg.selectAll(".trait")
.data(scope.panel.fields)
.enter().append("svg:g")
.attr("class", "trait")
.attr("transform", function(d) { return "translate(" + x(d) + ")"; })
.call(d3.behavior.drag()
.origin(function(d) { return {x: x(d)}; })
.on("dragstart", dragstart)
.on("drag", drag)
.on("dragend", dragend));
// Add a brush for each axis.
scope.g.append("svg:g")
.attr("class", "brush")
.each(function(d) { d3.select(this).call(y[d].brush); })
.selectAll("rect")
.attr("x", -8)
.attr("width", 16);
scope.foreground = scope.svg.append("svg:g")
.attr("class", "foreground");
// Add an axis and title.
scope.g.append("svg:g")
.attr("class", "axis")
.each(function(d) { d3.select(this).call(axis.scale(y[d])); })
.append("svg:text")
.attr("text-anchor", "middle")
.attr("y", -9)
.text(String);
scope.initializing = false;
console.log("init done");
render_panel();
});
......@@ -308,16 +249,16 @@ angular.module('kibana.parallelcoordinates', [])
// Returns the path for a given data point.
function path(d) {
return line(scope.panel.fields.map(function(p) { return [x(p), y[p](d[p])]; }));
return scope.line(scope.panel.fields.map(function(p) { return [scope.x(p), scope.y[p](d[p])]; }));
}
// Handles a brush event, toggling the display of foreground lines.
function brush() {
var actives = scope.panel.fields.filter(function(p) { return !y[p].brush.empty(); }),
extents = actives.map(function(p) { return y[p].brush.extent(); });
var actives = scope.panel.fields.filter(function(p) { return !scope.y[p].brush.empty(); }),
extents = actives.map(function(p) { return scope.y[p].brush.extent(); });
foreground.classed("fade", function(d) {
scope.foregroundLines.classed("fade", function(d) {
return !actives.every(function(p, i) {
return extents[i][0] <= d[p] && d[p] <= extents[i][1];
});
......@@ -325,21 +266,29 @@ angular.module('kibana.parallelcoordinates', [])
}
function dragstart(d) {
i = scope.panel.fields.indexOf(d);
scope.i = scope.panel.fields.indexOf(d);
console.log("dragstart", d, scope.i)
}
function drag(d) {
x.range()[i] = d3.event.x;
scope.panel.fields.sort(function(a, b) { return x(a) - x(b); });
scope.g.attr("transform", function(d) { return "translate(" + x(d) + ")"; });
foreground.attr("d", path);
console.log("drag", d, scope.i)
scope.x.range()[scope.i] = d3.event.x;
scope.panel.fields.sort(function(a, b) { return scope.x(a) - scope.x(b); });
scope.foregroundLines.attr("transform", function(d) { return "translate(" + scope.x(d) + ")"; });
scope.traits.attr("transform", function(d) { return "translate(" + scope.x(d) + ")"; });
scope.brushes.attr("transform", function(d) { return "translate(" + scope.x(d) + ")"; });
scope.axisLines.attr("transform", function(d) { return "translate(" + scope.x(d) + ")"; });
scope.foregroundLines.attr("d", path);
}
function dragend(d) {
x.domain(scope.panel.fields).rangePoints([0, w]);
console.log("dragend", d)
scope.x.domain(scope.panel.fields).rangePoints([0, scope.w]);
var t = d3.transition().duration(500);
t.selectAll(".trait").attr("transform", function(d) { return "translate(" + x(d) + ")"; });
t.selectAll(".foreground path").attr("d", path);
t.selectAll(".trait").attr("transform", function(d) { return "translate(" + scope.x(d) + ")"; });
t.selectAll(".axis").attr("transform", function(d) { return "translate(" + scope.x(d) + ")"; });
t.selectAll(".brush").attr("transform", function(d) { return "translate(" + scope.x(d) + ")"; });
t.selectAll(".foregroundlines").attr("d", path);
}
......@@ -351,8 +300,195 @@ angular.module('kibana.parallelcoordinates', [])
*/
function render_panel() {
var width = $(elem[0]).width(),
height = $(elem[0]).height();
console.log("render_panel");
scope.x = d3.scale.ordinal().domain(scope.panel.fields).rangePoints([0, scope.w]);
scope.y = {};
scope.line = d3.svg.line().interpolate('cardinal');
scope.axis = d3.svg.axis().orient("left");
var colorExtent = d3.extent(scope.data, function(p) { return +p['phpmemory']; });
scope.colors = d3.scale.linear()
.domain([colorExtent[0],colorExtent[1]])
.range(["#4580FF", "#FF9245"]);
scope.panel.fields.forEach(function(d) {
scope.y[d] = d3.scale.linear()
.domain(d3.extent(scope.data, function(p) { return +p[d]; }))
.range([scope.h, 0]);
scope.y[d].brush = d3.svg.brush()
.y(scope.y[d])
.on("brush", brush);
});
console.log("render y", scope.y);
var activeData = _.map(scope.data, function(d) {
var t = {};
_.each(scope.panel.fields, function(f) {
t[f] = d[f];
});
return t;
});
scope.foregroundLines = scope.foreground
.selectAll(".foregroundlines")
.data(activeData, function(d, i){
var id = "";
_.each(d, function(v) {
id += i + "_" + v;
});
return id;
});
scope.foregroundLines
.enter().append("svg:path")
.attr("d", path)
.attr("class", "foregroundlines")
.attr("style", function(d) {
return "stroke:" + scope.colors(d.phpmemory) + ";";
});
scope.foregroundLines.exit().remove();
console.log("Render Fields",scope.panel.fields);
scope.traits = scope.svg.selectAll(".trait")
.data(scope.panel.fields, String);
scope.traits
.enter().append("svg:g")
.attr("class", "trait")
.attr("transform", function(d) { return "translate(" + scope.x(d) + ")"; });
scope.brushes = scope.svg.selectAll(".brush")
.data(scope.panel.fields, String);
scope.brushes
.enter()
.append("svg:g")
.attr("class", "brush")
.each(function(d) {
d3.select(this)
.call(scope.y[d].brush)
.attr("transform", function(d) { return "translate(" + scope.x(d) + ")"; });
})
.selectAll("rect")
.attr("x", -8)
.attr("width", 16);
scope.brushes
.each(function(d) {
d3.select(this)
.call(scope.y[d].brush)
.attr("transform", function(d) { return "translate(" + scope.x(d) + ")"; });
});
scope.axisLines = scope.svg.selectAll(".axis")
.data(scope.panel.fields, String);
scope.axisLines
.enter()
.append("svg:g")
.attr("class", "axis")
.each(function(d) {
console.log("axis",d)
d3.select(this)
.call(scope.axis.scale(scope.y[d]))
.attr("transform", function(d) { return "translate(" + scope.x(d) + ")"; });
}).call(d3.behavior.drag()
.origin(function(d) { return {x: scope.x(d)}; })
.on("dragstart", dragstart)
.on("drag", drag)
.on("dragend", dragend))
.append("svg:text")
.attr("text-anchor", "middle")
.attr("y", -9)
.text(String);
scope.brushes
.exit().remove();
scope.axisLines
.exit().remove();
scope.traits
.exit().remove();
dragend();
/*
// Add a brush for each axis.
scope.brushes = scope.g.append("svg:g")
.attr("class", "brush");
scope.axisLines = scope.g.append("svg:g")
.attr("class", "axis");
//Draw the brushes
//If the field is no longer in the list of actives,
//remove the element. Sorta like a poor-man's enter() / exit()
scope.brushes
.each(function(d) {
if (typeof scope.y[d] !== 'undefined') {
console.log("brushes.each", d);
d3.select(this).attr("style", "display").call(scope.y[d].brush);
} else {
console.log("none");
d3.select(this).attr("style", "display:none");
}
})
.selectAll("rect")
.attr("x", -8)
.attr("width", 16);
//Draw the axis lines
//If the field is no longer in the list of actives,
//remove the element. Sorta like a poor-man's enter() / exit()
scope.axisLines
.each(function(d) {
if (typeof scope.y[d] !== 'undefined') {
d3.select(this).attr("style", "display").call(scope.axis.scale(scope.y[d]));
} else {
d3.select(this).attr("style", "display:none");
}
})
.append("svg:text")
.attr("text-anchor", "middle")
.attr("y", -9)
.text(String)
.call(dragend); //call dragend so that the axis reshuffle.
*/
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment