diff --git a/panels/parallelcoordinates/editor.html b/panels/parallelcoordinates/editor.html deleted file mode 100644 index 7141eeae846..00000000000 --- a/panels/parallelcoordinates/editor.html +++ /dev/null @@ -1,21 +0,0 @@ -
-
-
-
Query
- - -
-
-
-
Panel Spy
-
-
- -
-
- The panel spy shows 'behind the scenes' information about a panel. It can - be accessed by clicking the in the top right - of the panel. -
-
- diff --git a/panels/parallelcoordinates/module.html b/panels/parallelcoordinates/module.html deleted file mode 100644 index 1401501ab74..00000000000 --- a/panels/parallelcoordinates/module.html +++ /dev/null @@ -1,42 +0,0 @@ - - - - - -
-
\ No newline at end of file diff --git a/panels/parallelcoordinates/module.js b/panels/parallelcoordinates/module.js deleted file mode 100644 index 32d47ee21d3..00000000000 --- a/panels/parallelcoordinates/module.js +++ /dev/null @@ -1,514 +0,0 @@ -angular.module('kibana.parallelcoordinates', []) - .controller('parallelcoordinates', function ($scope, eventBus) { - - - $scope.activeDocs = []; - - // Set and populate defaults - var _d = { - status : "Broken", - query : "*", - size : 100, // Per page - pages : 5, // Pages available - offset : 0, - sort : ['@timestamp','desc'], - group : "default", - style : {'font-size': '9pt'}, - fields : [], - sortable: true, - spyable: true - } - - _.defaults($scope.panel, _d) - - $scope.init = function () { - - $scope.set_listeners($scope.panel.group); - // Now that we're all setup, request the time from our group - eventBus.broadcast($scope.$id,$scope.panel.group,"get_time") - - //and get the currently selected fields - eventBus.broadcast($scope.$id,$scope.panel.group,"get_fields") - }; - - $scope.set_listeners = function(group) { - eventBus.register($scope,'time',function(event,time) { - $scope.panel.offset = 0; - set_time(time) - }); - eventBus.register($scope,'query',function(event,query) { - $scope.panel.offset = 0; - $scope.panel.query = _.isArray(query) ? query[0] : query; - $scope.get_data(); - }); - eventBus.register($scope,'sort', function(event,sort){ - $scope.panel.sort = _.clone(sort); - $scope.get_data(); - }); - eventBus.register($scope,'selected_fields', function(event, fields) { - $scope.panel.fields = _.clone(fields) - $scope.$emit('render'); - }); - }; - - - $scope.get_data = function (segment,query_id) { - - // Make sure we have everything for the request to complete - if (_.isUndefined($scope.index) || _.isUndefined($scope.time)) - return; - - var _segment = _.isUndefined(segment) ? 0 : segment - $scope.segment = _segment; - - $scope.panel.loading = true; - var request = $scope.ejs.Request().indices($scope.index[_segment]) - .query(ejs.FilteredQuery( - ejs.QueryStringQuery($scope.panel.query || '*'), - ejs.RangeFilter($scope.time.field) - .from($scope.time.from) - .to($scope.time.to) - ) - ) - .size($scope.panel.size*$scope.panel.pages) - .sort($scope.panel.sort[0],$scope.panel.sort[1]); - - $scope.populate_modal(request); - - var results = request.doSearch(); - - - // Populate scope when we have results - results.then(function (results) { - $scope.panel.loading = false; - if(_segment === 0) { - $scope.hits = 0; - $scope.data = []; - query_id = $scope.query_id = new Date().getTime() - } - - // Check for error and abort if found - if(!(_.isUndefined(results.error))) { - $scope.panel.error = $scope.parse_error(results.error); - return; - } - - // Check that we're still on the same query, if not stop - if($scope.query_id === query_id) { - $scope.data= $scope.data.concat(_.map(results.hits.hits, function(hit) { - return flatten_json(hit['_source']); - })); - - $scope.hits += results.hits.total; - - // Sort the data - $scope.data = _.sortBy($scope.data, function(v){ - return v[$scope.panel.sort[0]] - }); - - // Reverse if needed - if($scope.panel.sort[1] == 'desc') - $scope.data.reverse(); - - // Keep only what we need for the set - $scope.data = $scope.data.slice(0,$scope.panel.size * $scope.panel.pages) - - } else { - return; - } - $scope.$emit('render') - }); - - - - }; - - // I really don't like this function, too much dom manip. Break out into directive? - $scope.populate_modal = function (request) { - $scope.modal = { - title: "Inspector", - body: "
Last Elasticsearch Query
" + 'curl -XGET ' + config.elasticsearch + '/' + $scope.index + "/_search?pretty -d'\n" + angular.toJson(JSON.parse(request.toString()), true) + "'
" - } - }; - - function set_time(time) { - $scope.time = time; - $scope.index = _.isUndefined(time.index) ? $scope.index : time.index - $scope.get_data(); - } - - - $scope.$watch('activeDocs', function(v) { - eventBus.broadcast($scope.$id,$scope.panel.group,"table_documents", - {query:$scope.panel.query,docs:$scope.activeDocs}); - }); - - }) - .directive('parallelcoordinates', function () { - return { - restrict: 'A', - link: function (scope, elem, attrs) { - - //used to store a variety of directive-level variables - var directive = {}; - - scope.initializing = false; - - - /** - * Initialize the panels if new, or render existing panels - */ - scope.init_or_render = function() { - if (typeof directive.svg === 'undefined') { - - //prevent duplicate initialization steps, if render is called again - //before the svg is setup - if (!scope.initializing) { - init_panel(); - } - } else { - render_panel(); - } - }; - - - /** - * Receive render events - */ - scope.$on('render', function () { - scope.init_or_render(); - }); - - /** - * On window resize, re-render the panel - */ - angular.element(window).bind('resize', function () { - scope.init_or_render(); - }); - - - /** - * Load the various panel-specific scripts then initialize - * the svg and set appropriate D3 settings - */ - function init_panel() { - - directive.m = [80, 100, 80, 100]; - directive.w = $(elem[0]).width() - directive.m[1] - directive.m[3]; - directive.h = $(elem[0]).height() - directive.m[0] - directive.m[2]; - - - 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)); - - scripts.wait(function () { - - directive.x = d3.scale.ordinal().domain(scope.panel.fields).rangePoints([0, directive.w]); - directive.y = {}; - - directive.line = d3.svg.line().interpolate('cardinal'); - directive.axis = d3.svg.axis().orient("left"); - - var viewbox = "0 0 " + (directive.w + directive.m[1] + directive.m[3]) + " " + (directive.h + directive.m[0] + directive.m[2]); - directive.svg = d3.select(elem[0]).append("svg") - .attr("width", "100%") - .attr("height", "100%") - .attr("viewbox", viewbox) - .append("svg:g") - .attr("transform", "translate(" + directive.m[3] + "," + directive.m[0] + ")"); - - // Add foreground lines. - directive.foreground = directive.svg.append("svg:g") - .attr("class", "foreground"); - - scope.initializing = false; - render_panel(); - }); - - - } - - // Returns the path for a given data point. - function path(d) { - return directive.line(scope.panel.fields.map(function(p) { return [directive.x(p), directive.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 !directive.y[p].brush.empty(); }), - extents = actives.map(function(p) { return directive.y[p].brush.extent(); }); - - //.fade class hides the "inactive" lines, helps speed up rendering significantly - directive.foregroundLines.classed("fade", function(d) { - return !actives.every(function(p, i) { - - var pointValue; - - if (directive.ordinals[p] === true) { - pointValue = directive.y[p](d[p]); - } else { - pointValue = d[p]; - } - - var inside = extents[i][0] <= pointValue && pointValue <= extents[i][1]; - return inside; - }); - }); - - //activeDocs contains the actual doc records for selected lines. - //will be broadcast out to the table - var activeDocs = _.filter(scope.data, function(v) { - return actives.every(function(p,i) { - var inside = extents[i][0] <= v[p] && v[p] <= extents[i][1]; - return inside; - }); - }) - - scope.$apply(function() { - scope.activeDocs = activeDocs; - }); - } - - - //Drag functions are used for dragging the axis aroud - function dragstart(d) { - directive.i = scope.panel.fields.indexOf(d); - } - - function drag(d) { - directive.x.range()[directive.i] = d3.event.x; - scope.panel.fields.sort(function(a, b) { return directive.x(a) - directive.x(b); }); - directive.foregroundLines.attr("transform", function(d) { return "translate(" + directive.x(d) + ")"; }); - directive.traits.attr("transform", function(d) { return "translate(" + directive.x(d) + ")"; }); - directive.brushes.attr("transform", function(d) { return "translate(" + directive.x(d) + ")"; }); - directive.axisLines.attr("transform", function(d) { return "translate(" + directive.x(d) + ")"; }); - directive.foregroundLines.attr("d", path); - } - - function dragend(d) { - directive.x.domain(scope.panel.fields).rangePoints([0, directive.w]); - var t = d3.transition().duration(500); - t.selectAll(".trait").attr("transform", function(d) { return "translate(" + directive.x(d) + ")"; }); - t.selectAll(".axis").attr("transform", function(d) { return "translate(" + directive.x(d) + ")"; }); - t.selectAll(".brush").attr("transform", function(d) { return "translate(" + directive.x(d) + ")"; }); - t.selectAll(".foregroundlines").attr("d", path); - } - - - - - /** - * Render updates to the SVG. Typically happens when the data changes (time, query) - * or when new options are selected - */ - function render_panel() { - - - //update the svg if the size has changed - directive.w = $(elem[0]).width() - directive.m[1] - directive.m[3]; - directive.h = $(elem[0]).height() - directive.m[0] - directive.m[2]; - directive.svg.attr("viewbox", "0 0 " + (directive.w + directive.m[1] + directive.m[3]) + " " + (directive.h + directive.m[0] + directive.m[2])); - - - directive.x = d3.scale.ordinal().domain(scope.panel.fields).rangePoints([0, directive.w]); - directive.y = {}; - - directive.line = d3.svg.line().interpolate('cardinal'); - directive.axis = d3.svg.axis().orient("left").ticks(5); - directive.ordinals = {}; - - scope.panel.fields.forEach(function(d) { - var firstField = scope.data[0][d]; - - if (_.isString(firstField)) { - if (isValidDate(new Date(firstField))) { - - //convert date timestamps to actual dates - _.map(scope.data, function(v) { - v[d] = new Date(v[d]); - }); - - var extents = d3.extent(scope.data, function(p) { return p[d]; }); - - directive.y[d] = d3.time.scale() - .domain([extents[0],extents[1]]) - .range([directive.h, 0]); - - } else { - directive.ordinals[d] = true; - - var value = function(v) { return v[d]; }; - var values = _.map(_.uniq(scope.data, value),value); - - directive.y[d] = d3.scale.ordinal() - .domain(values) - .rangePoints([directive.h, 0]); - - } - - } else if (_.isNumber(firstField)) { - directive.y[d] = d3.scale.linear() - .domain(d3.extent(scope.data, function(p) { return +p[d]; })) - .range([directive.h, 0]); - - } else if (_.isDate(firstField)) { - //this section is only used after timestamps have been parsed into actual date objects... - //avoids reparsing - - var extents = d3.extent(scope.data, function(p) { return p[d]; }); - - directive.y[d] = d3.time.scale() - .domain([extents[0],extents[1]]) - .range([directive.h, 0]); - - } - - directive.y[d].brush = d3.svg.brush() - .y(directive.y[d]) - .on("brush", brush); - }); - - //setup the colors for the lines - setColors(); - - //pull out the actively selected columns for rendering the axis/lines - var activeData = _.map(scope.data, function(d) { - var t = {}; - _.each(scope.panel.fields, function(f) { - t[f] = d[f]; - }); - return t; - }); - - - //Lines - directive.foregroundLines = directive.foreground - .selectAll(".foregroundlines") - .data(activeData, function(d, i){ - var id = ""; - _.each(d, function(v) { - id += i + "_" + v; - }); - return id; - }); - directive.foregroundLines - .enter().append("svg:path") - .attr("d", path) - .attr("class", "foregroundlines") - .attr("style", function(d) { - return "stroke:" + directive.colors(d[scope.panel.fields[0]]) + ";"; - }); - directive.foregroundLines.exit().remove(); - - - - //Axis group - directive.traits = directive.svg.selectAll(".trait") - .data(scope.panel.fields, String); - directive.traits - .enter().append("svg:g") - .attr("class", "trait") - .attr("transform", function(d) { return "translate(" + directive.x(d) + ")"; }); - directive.traits - .exit().remove(); - - - //brushes used to select lines - directive.brushes = directive.svg.selectAll(".brush") - .data(scope.panel.fields, String); - directive.brushes - .enter() - .append("svg:g") - .attr("class", "brush") - .each(function(d) { - d3.select(this) - .call(directive.y[d].brush) - .attr("transform", function(d) { return "translate(" + directive.x(d) + ")"; }); - }) - .selectAll("rect") - .attr("x", -8) - .attr("width", 16); - - //this section is repeated because enter() only works on "new" data, but we always need to - //update the brushes if things change. This just calls the brushing function, so it doesn't - //affect currently active rects - directive.brushes - .each(function(d) { - d3.select(this) - .call(directive.y[d].brush) - .attr("transform", function(d) { return "translate(" + directive.x(d) + ")"; }); - }); - directive.brushes - .exit().remove(); - - - //vertical axis and labels - directive.axisLines = directive.svg.selectAll(".axis") - .data(scope.panel.fields, String); - directive.axisLines - .enter() - .append("svg:g") - .attr("class", "axis") - .each(function(d) { - d3.select(this) - .call(directive.axis.scale(directive.y[d])) - .attr("transform", function(d) { return "translate(" + directive.x(d) + ")"; }); - }).call(d3.behavior.drag() - .origin(function(d) { return {x: directive.x(d)}; }) - .on("dragstart", dragstart) - .on("drag", drag) - .on("dragend", dragend)) - - .append("svg:text") - .attr("text-anchor", "middle") - .attr("y", -9) - .text(String); - directive.axisLines - .exit().remove(); - - //Simulate a dragend in case there is new data and we need to rearrange - dragend(); - - } - - function setColors() { - - var firstPanelField = scope.data[0][scope.panel.fields[0]]; - var extents = d3.extent(scope.data, function(p) { return p[scope.panel.fields[0]]; }); - - if (_.isString(firstPanelField)) { - - var value = function(v) { return v[firstPanelField]; }; - var values = _.map(_.uniq(scope.data, value),value); - - values = scope.data; - directive.colors = d3.scale.ordinal() - .domain(values) - .range(d3.range(values.length).map(d3.scale.linear() - .domain([0, values.length - 1]) - .range(["red", "blue"]) - .interpolate(d3.interpolateLab))); - - } else if (_.isNumber(firstPanelField)) { - directive.colors = d3.scale.linear() - .domain([extents[0],extents[1]]) - .range(["#4580FF", "#FF9245"]); - - } else if (_.isDate(firstPanelField)) { - directive.colors = d3.time.scale() - .domain([extents[0],extents[1]]) - .range(["#4580FF", "#FF9245"]); - } - - } - - function isValidDate(d) { - if ( Object.prototype.toString.call(d) !== "[object Date]" ) - return false; - return !isNaN(d.getTime()); - } - - } - }; - }); \ No newline at end of file