Skip to content

Commit

Permalink
Merge pull request #24 from spenceralger/visualize_skelly
Browse files Browse the repository at this point in the history
Visualize skeleton in place
  • Loading branch information
spenceralger committed Mar 21, 2014
2 parents d0c76cd + b5e128f commit 9e91ea6
Show file tree
Hide file tree
Showing 26 changed files with 1,175 additions and 29 deletions.
140 changes: 140 additions & 0 deletions src/kibana/apps/visualize/controllers/visualize.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
define(function (require) {
var _ = require('lodash');
var app = require('modules').get('app/visualize');

require('../factories/vis');
require('../services/aggs');

app.controller('Visualize', function ($scope, courier, createNotifier, Vis, Aggs) {
var notify = createNotifier({
location: 'Visualize Controller'
});

// the object detailing the visualization
var vis = $scope.vis = window.vis = new Vis({
metric: {
label: 'Y-Axis',
min: 1,
max: 1
},
segment: {
label: 'X-Axis',
min: 1,
max: 1
},
group: {
label: 'Color',
max: 10
},
split: {
label: 'Rows & Columns',
max: 2
}
}, {
split: [
{
field: 'response',
size: 5,
agg: 'terms'
},
{
field: '_type',
size: 5,
agg: 'terms'
}
],
segment: [
{
field: '@timestamp',
interval: 'week'
}
],
group: [
{
field: 'extension',
size: 5,
agg: 'terms',
global: true
}
]
});

vis.dataSource.$scope($scope);

$scope.refreshFields = function () {
$scope.fields = null;
vis.dataSource.clearFieldCache().then(getFields, notify.error);
};

function getFields() {
vis.dataSource.getFields(function (err, fieldsHash) {
if (err) return notify.error(err);

// create a sorted list of the fields for display purposes
$scope.fields = _(fieldsHash)
.keys()
.sort()
.transform(function (fields, name) {
var field = fieldsHash[name];
field.name = name;
fields.push(field);
})
.value();

$scope.fields.byName = fieldsHash;
});
}
// get the fields for initial display
getFields();

$scope.Vis = Vis;
$scope.Aggs = Aggs;

$scope.updateDataSource = function () {
notify.event('update data source');
var config = _.groupBy(vis.getConfig(), function (config) {
switch (config.categoryName) {
case 'group':
case 'segment':
return 'dimension';
default:
return config.categoryName;
}
});

if (!config.dimension) {
// use the global aggregation if we don't have any dimensions
config.dimension = [{
agg: 'global'
}];
}

var dsl = {};
var i = 0;

var nest = (function () {
var current = dsl;
return function (config) {
current.aggs = {};
var key = '_agg_' + (i++);

var aggDsl = {};
aggDsl[config.agg] = config.aggParams;

current = current.aggs[key] = aggDsl;
};
}());

config.split && config.split.forEach(nest);
config.dimension && config.dimension.forEach(nest);
config.metric && config.metric.forEach(nest);

notify.log('config', config);
notify.log('aggs', dsl.aggs);

vis.dataSource.aggs(dsl.aggs).fetch();
notify.event('update data source', true);
};

});
});
25 changes: 25 additions & 0 deletions src/kibana/apps/visualize/directives/canvas.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
define(function (require) {
var module = require('modules').get('app/visualize');
var $ = require('jquery');

module.directive('visCanvas', function () {
return {
restrict: 'A',
link: function ($scope, $el) {
var $window = $(window);
var $header = $('.content > nav.navbar:first()');

function stretchVis() {
$el.css('height', $window.height() - $header.height() - 30);
}

stretchVis();

$window.on('resize', stretchVis);
$scope.$on('$destroy', function () {
$window.off('resize', stretchVis);
});
}
};
});
});
22 changes: 22 additions & 0 deletions src/kibana/apps/visualize/directives/config_category.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
define(function (require) {
var html = require('text!../partials/config_category.html');

require('./config_editor');

require('modules')
.get('app/visualize')
.directive('visConfigCategory', function () {
return {
restrict: 'E',
scope: {
categoryName: '=',
vis: '=',
fields: '='
},
template: html,
link: function ($scope, $el) {
$scope.category = $scope.vis[$scope.categoryName];
}
};
});
});
58 changes: 58 additions & 0 deletions src/kibana/apps/visualize/directives/config_controlls.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
define(function (require) {
var app = require('modules').get('app/visualize');
var _ = require('lodash');

var templates = {
orderAndSize: require('text!../partials/controls/order_and_size.html'),
interval: require('text!../partials/controls/interval.html'),
globalLocal: require('text!../partials/controls/global_local.html')
};

app.directive('visConfigControls', function ($compile, Vis, Aggs) {
return {
restrict: 'E',
scope: {
config: '='
},
link: function ($scope, $el, attr) {
var $controls = $el.find('.agg-param-controls');

$scope.$watch('config.agg', function (aggName) {
var agg = Aggs.aggsByName[aggName];
var controlsHtml = '';

if (agg) {
var aggParams = $scope.aggParams = agg.params;

_.forOwn(aggParams, function (param, name) {
// if the param doesn't have options, or a default value, skip it
if (!param.options) return;
// if there isn't currently a value, or the current value is not one of the options, set it to the default
if (!$scope.config[name] || !_.find(param.options, { val: $scope.config[name] })) {
$scope.config[name] = param.default;
}
});

if (aggParams.order && aggParams.size) {
controlsHtml += ' ' + templates.orderAndSize;
}

if (aggParams.interval) {
controlsHtml += ' ' + templates.interval;
}

if ($scope.config.categoryName === 'group') {
controlsHtml += ' ' + templates.globalLocal;
}
}

$controls.html($compile(controlsHtml)($scope));
});

$scope.Aggs = Aggs;
$scope.Vis = Vis;
}
};
});

});
133 changes: 133 additions & 0 deletions src/kibana/apps/visualize/directives/config_editor.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
define(function (require) {
var app = require('modules').get('app/visualize');
var _ = require('lodash');
var $ = require('jquery');

require('filters/field_type');

app.directive('visConfigEditor', function ($compile, Vis, Aggs) {
var categoryOptions = {
metric: {
template: require('text!../partials/editor/metric.html')
},
segment: {
template: require('text!../partials/editor/dimension.html'),
setup: setupDimension
},
group: {
template: require('text!../partials/editor/dimension.html'),
setup: setupDimension
},
split: {
template: require('text!../partials/editor/dimension.html'),
setup: setupDimension
}
};

var controlTemplates = {
orderAndSize: require('text!../partials/controls/order_and_size.html'),
interval: require('text!../partials/controls/interval.html'),
globalLocal: require('text!../partials/controls/global_local.html')
};

// generalized setup for group and segment
function setupDimension($scope, $el) {
var $controls = $el.find('.agg-param-controls');

function getAvailableAggsForField() {
if (!$scope.config.field || !$scope.fields) return;

var field = $scope.fields.byName[$scope.config.field];

// clear the previous choices
$scope.availableAggs = void 0;
// get the new choices
var aggs = Aggs.aggsByFieldType[field.type];

if (!aggs || aggs.length === 0) {
// init or invalid field type
$scope.config.agg = void 0;
return;
}

if (aggs.length === 1) {
// only once choice, make it for the user
$scope.config.agg = aggs[0].name;
return;
}

// set the new choices
$scope.availableAggs = aggs;

// update the agg only if it is not currently a valid option
if (!$scope.config.agg || !_.find(aggs, { name: $scope.config.agg })) {
$scope.config.agg = aggs[0].name;
return;
}
}

// since this depends on the field and field list, watch both
$scope.$watch('config.field', getAvailableAggsForField);
$scope.$watch('fields', getAvailableAggsForField);

$scope.$watch('config.agg', function (aggName) {
var agg = Aggs.aggsByName[aggName];
var controlsHtml = '';

if (agg) {
var params = $scope.aggParams = agg.params;

_.forOwn(params, function (param, name) {
// if the param doesn't have options, or a default value, skip it
if (!param.options) return;
// if there isn't currently a value, or the current value is not one of the options, set it to the default
if (!$scope.config[name] || !_.find(param.options, { val: $scope.config[name] })) {
$scope.config[name] = param.default;
}
});

if (params.order && params.size) {
controlsHtml += ' ' + controlTemplates.orderAndSize;
}

if (params.interval) {
controlsHtml += ' ' + controlTemplates.interval;
if (!controlsHtml.match(/aggParams\.interval\.options/)) debugger;
}

if ($scope.config.categoryName === 'group') {
controlsHtml += ' ' + controlTemplates.globalLocal;
}
}

$controls.html($compile(controlsHtml)($scope));
});
}

return {
restrict: 'E',
scope: {
config: '=',
fields: '=',
vis: '='
},
link: function ($scope, $el, attr) {
var categoryName = $scope.config.categoryName;
var opts = categoryOptions[categoryName];

$scope.Aggs = Aggs;
$scope.Vis = Vis;

// attach a copy of the template to the scope and render
$el.html($compile(opts.template)($scope));

_.defaults($scope.val, opts.defVal || {});
if (opts.setup) opts.setup($scope, $el);

// rather than accessing vis.{{categoryName}} everywhere
$scope[categoryName] = $scope.vis[categoryName];
}
};
});

});
Loading

0 comments on commit 9e91ea6

Please sign in to comment.