merge current master

This commit is contained in:
Spencer Alger 2014-04-07 12:06:05 -07:00
commit 7b27dfef14
66 changed files with 3293 additions and 1868 deletions

View file

@ -1,44 +0,0 @@
{
"name": "K4D3",
"main": "core.js",
"scripts": [
"k4.d3.js"
],
"homepage": "https://github.com/elasticsearch/K4D3",
"authors": [
"Shelby Sturgis",
"Juan Thomassie"
],
"description": "D3 Charting Library for Kibana 4",
"keywords": [
"data",
"visualization",
"elasticsearch",
"kibana"
],
"license": "MIT",
"private": true,
"ignore": [
"**/.*",
"node_modules",
"bower_components",
"test",
"tests"
],
"dependencies": {
"d3": "~3.4.1",
"requirejs": "~2.1.11",
"queue-async": "~1.0.7",
"topojson": "~1.4.6"
},
"devDependencies": {},
"_release": "482f0b6eaf",
"_resolution": {
"type": "branch",
"branch": "master",
"commit": "482f0b6eafa5996c835b45ba5df1d112c31ac071"
},
"_source": "git@github.com:elasticsearch/K4D3.git",
"_target": "*",
"_originalSource": "git@github.com:elasticsearch/K4D3.git"
}

3
src/bower_components/K4D3/.bowerrc vendored Normal file
View file

@ -0,0 +1,3 @@
{
"directory" : "lib"
}

3
src/bower_components/K4D3/.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
.DS_Store
node_modules/
test-results.xml

37
src/bower_components/K4D3/.jshintrc vendored Normal file
View file

@ -0,0 +1,37 @@
/*
* For an explanation of the different configuration
* options listed here, please visit:
* http://www.jshint.com/docs/options/
*/
{
"browser": true,
"node": false,
"undef": true,
"unused": true,
"globals": {
"d3": true,
"define": true,
"k4": true,
"window": true,
"require": true,
"console": true
},
"curly": true,
"eqeqeq": true,
"forin": true,
"freeze": true,
"indent": 4,
"latedef": "nofunc",
"newcap": true,
"noarg": true,
"nonbsp": true,
"nonew": true,
"plusplus": false,
"quotmark": "single",
"strict": true,
"trailing": true,
"maxparams": 3,
"maxlen": 140,
"devel": true,
"maxerr": 10
}

View file

@ -14,12 +14,7 @@ module.exports = function(grunt) {
},
dist: {
src: [
'src/start.js',
'src/core.js',
'src/tooltip.js',
'src/legend.js',
'src/modules/histogram.js',
'src/end.js'
'src/index.js'
],
dest: 'k4.d3.js'
}
@ -37,7 +32,7 @@ module.exports = function(grunt) {
},
jshint: {
foo: {
src: "src/**/*.js"
src: 'src/**/*.js'
},
options: {
jshintrc: '.jshintrc'
@ -45,7 +40,7 @@ module.exports = function(grunt) {
},
watch: {
js: {
files: ["src/**/*.js"],
files: ['src/**/*.js'],
tasks: ['concat']
}
},
@ -67,6 +62,7 @@ module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-karma');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-contrib-requirejs');
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');

View file

@ -1,5 +1,5 @@
JS_FILES = \
src/start.js \
src/index.js \
src/core.js \
src/modules/area.js \
src/modules/dendrogram.js \

View file

@ -17,11 +17,10 @@
<div id="element" style="height: 100%"></div>
<!-- javascript files -->
<script src="../lib/d3/d3.min.js"></script>
<script src="../k4.d3.js"></script>
<script src="http://code.jquery.com/jquery-1.11.0.min.js"></script>
<script>
<script src="../lib/requirejs/require.js"></script>
<!-- <script src="../require.config.js"></script> -->
<!--
<script>require(['../src/index'], function(k4) {
var data = {
"rows": [
{
@ -500,14 +499,19 @@
elem = $("#element")[0],
myChart;
$("#element").width("100%");
$("#element").height(0);
$(elem).width("100%");
$(elem).height(0);
d3.select(elem).style("padding-bottom", "40%");
myChart = new k4.Chart(elem, { type: "histogram", stacktype: "expand", yGroup: true, color: ['#81dfe2','#0762b7'] });
myChart.render(data);
console.log(d3.select(elem).style("padding-bottom"));
</script>
myChart = new k4.Chart(elem, {
type: "histogram",
stacktype: "group",
yGroup: true,
color: ['#81dfe2','#0762b7']
});
myChart.render(data);
})</script>
-->
</body>
</html>

View file

@ -8,677 +8,14 @@
} else {
root.k4 = factory();
}
}(this, function() {
var k4 = { version: '0.0.0' };
/*
* Main module
* Accepts an html element and a config object.
* Calls all other K4 modules.
* Returns the charting function.
*/
k4.Chart = function(elem, args) {
'use strict';
if (typeof(k4[args.type]) !== 'function') { throw args.type + " is not a supported k4 function."; }
var type = args.type,
chartFunc = k4[type](elem, args);
return chartFunc;
};
k4.tooltip = function() {
'use strict';
// Based on Justin Palmer's d3.tip() function
var direction = d3_tip_direction,
offset = d3_tip_offset,
html = d3_tip_html,
node = initNode(),
svg = null,
point = null,
target = null;
function tip(vis) {
svg = getSVGNode(vis);
point = svg.createSVGPoint();
document.body.appendChild(node);
}
// Public - show the tooltip on the screen
//
// Returns a tip
tip.show = function() {
var args = Array.prototype.slice.call(arguments);
if(args[args.length - 1] instanceof SVGElement) { target = args.pop(); }
var content = html.apply(this, args),
poffset = offset.apply(this, args),
dir = direction.apply(this, args),
nodel = d3.select(node),
i = directions.length,
coords;
nodel.html(content)
.style({ opacity: 1, 'pointer-events': 'all' });
while(i--) nodel.classed(directions[i], false);
coords = direction_callbacks.get(dir).apply(this);
nodel.classed(dir, true).style({
top: (coords.top + poffset[0]) + 'px',
left: (coords.left + poffset[1]) + 'px'
});
return tip;
}(this, function(require) {
var k4 = {
version: '0.0.0',
tooltip: require('./bower_components/K4D3/src/tooltip'),
legend: require('./bower_components/K4D3/src/legend'),
Chart: require('./bower_components/K4D3/src/core'),
histogram: require('./bower_components/K4D3/src/modules/histogram')
};
// Public - hide the tooltip
//
// Returns a tip
tip.hide = function() {
var nodel = d3.select(node);
nodel.style({ opacity: 0, 'pointer-events': 'none' });
return tip;
};
// Public: Proxy attr calls to the d3 tip container. Sets or gets attribute value.
//
// n - name of the attribute
// v - value of the attribute
//
// Returns tip or attribute value
tip.attr = function(n, v) {
if (arguments.length < 2 && typeof n === 'string') {
return d3.select(node).attr(n);
} else {
var args = Array.prototype.slice.call(arguments);
d3.selection.prototype.attr.apply(d3.select(node), args);
}
return tip;
};
// Public: Proxy style calls to the d3 tip container. Sets or gets a style value.
//
// n - name of the property
// v - value of the property
//
// Returns tip or style property value
tip.style = function(n, v) {
if (arguments.length < 2 && typeof n === 'string') {
return d3.select(node).style(n)
} else {
var args = Array.prototype.slice.call(arguments);
d3.selection.prototype.style.apply(d3.select(node), args);
}
return tip;
};
// Public: Set or get the direction of the tooltip
//
// v - One of n(north), s(south), e(east), or w(west), nw(northwest),
// sw(southwest), ne(northeast) or se(southeast)
//
// Returns tip or direction
tip.direction = function(v) {
if (!arguments.length) { return direction; }
direction = v === null ? v : d3.functor(v);
return tip;
};
// Public: Sets or gets the offset of the tip
//
// v - Array of [x, y] offset
//
// Returns offset or
tip.offset = function(v) {
if (!arguments.length) { return offset; }
offset = v === null ? v : d3.functor(v);
return tip;
};
// Public: sets or gets the html value of the tooltip
//
// v - String value of the tip
//
// Returns html value or tip
tip.html = function(v) {
if (!arguments.length) { return html; }
html = v === null ? v : d3.functor(v);
return tip;
};
function d3_tip_direction() { return 'n'; }
function d3_tip_offset() { return [0, 0]; }
function d3_tip_html() { return ' '; }
var direction_callbacks = d3.map({
n: direction_n,
s: direction_s,
e: direction_e,
w: direction_w,
nw: direction_nw,
ne: direction_ne,
sw: direction_sw,
se: direction_se
}),
directions = direction_callbacks.keys();
function direction_n() {
var bbox = getScreenBBox();
return {
top: bbox.n.y - node.offsetHeight,
left: bbox.n.x - node.offsetWidth / 2
};
}
function direction_s() {
var bbox = getScreenBBox();
return {
top: bbox.s.y,
left: bbox.s.x - node.offsetWidth / 2
};
}
function direction_e() {
var bbox = getScreenBBox();
return {
top: bbox.e.y - node.offsetHeight / 2,
left: bbox.e.x
};
}
function direction_w() {
var bbox = getScreenBBox();
return {
top: bbox.w.y - node.offsetHeight / 2,
left: bbox.w.x - node.offsetWidth
};
}
function direction_nw() {
var bbox = getScreenBBox();
return {
top: bbox.nw.y - node.offsetHeight,
left: bbox.nw.x - node.offsetWidth
};
}
function direction_ne() {
var bbox = getScreenBBox();
return {
top: bbox.ne.y - node.offsetHeight,
left: bbox.ne.x
};
}
function direction_sw() {
var bbox = getScreenBBox();
return {
top: bbox.sw.y,
left: bbox.sw.x - node.offsetWidth
};
}
function direction_se() {
var bbox = getScreenBBox();
return {
top: bbox.se.y,
left: bbox.e.x
};
}
function initNode() {
var node = d3.select(document.createElement('div'));
node.style({
position: 'absolute',
top: 0,
opacity: 0,
'pointer-events': 'none',
'box-sizing': 'border-box'
});
return node.node();
}
function getSVGNode(el) {
el = el.node();
if(el.tagName.toLowerCase() === 'svg') { return el; }
return el.ownerSVGElement
}
// Private - gets the screen coordinates of a shape
//
// Given a shape on the screen, will return an SVGPoint for the directions
// n(north), s(south), e(east), w(west), ne(northeast), se(southeast), nw(northwest),
// sw(southwest).
//
// +-+-+
// | |
// + +
// | |
// +-+-+
//
// Returns an Object {n, s, e, w, nw, sw, ne, se}
function getScreenBBox() {
var targetel = target || d3.event.target,
bbox = {},
matrix = targetel.getScreenCTM(),
tbbox = targetel.getBBox(),
width = tbbox.width,
height = tbbox.height,
x = tbbox.x,
y = tbbox.y,
scrollEl = document.documentElement ? document.documentElement : document.body,
scrollTop = scrollEl.scrollTop,
scrollLeft = scrollEl.scrollLeft;
point.x = x + scrollLeft;
point.y = y + scrollTop;
bbox.nw = point.matrixTransform(matrix);
point.x += width;
bbox.ne = point.matrixTransform(matrix);
point.y += height;
bbox.se = point.matrixTransform(matrix);
point.x -= width;
bbox.sw = point.matrixTransform(matrix);
point.y -= height / 2;
bbox.w = point.matrixTransform(matrix);
point.x += width;
bbox.e = point.matrixTransform(matrix);
point.x -= width / 2;
point.y -= height / 2;
bbox.n = point.matrixTransform(matrix);
point.y += height;
bbox.s = point.matrixTransform(matrix);
return bbox;
}
return tip;
};k4.legend = function(g) {
'use strict';
g.each(function() {
var g = d3.select(this),
items = {},
svg = d3.select(g.property("nearestViewportElement")),
legendPadding = g.attr("data-style-padding") || 5,
lb = g.selectAll(".legend-box").data([true]),
li = g.selectAll(".legend-items").data([true]),
lbbox;
lb.enter().append("rect").classed("legend-box",true);
li.enter().append("g").classed("legend-items",true);
svg.selectAll("[data-legend]").each(function() {
var self = d3.select(this);
items[self.attr("data-legend")] = {
pos : self.attr("data-legend-pos") || this.getBBox().y,
color : self.attr("data-legend-color") !== null ? self.attr("data-legend-color") :
self.style("fill") !== 'none' ? self.style("fill") : self.style("stroke")
};
});
items = d3.entries(items).sort(function(a, b) { return a.value.pos - b.value.pos; });
/*
li.selectAll('div')
.data(items, function(d) { return d.key; })
.call(function(d) { d.enter().append("div"); })
.call(function(d) { d.exit().remove(); })
.attr("class", "legend-div");
*/
li.selectAll("text")
.data(items, function(d) { return d.key; })
.call(function(d) { d.enter().append("text"); })
.call(function(d) { d.exit().remove(); })
.attr("class", "legend-text")
.attr("x", "0.7em")
.attr("y", function(d, i) { return i + "em"; })
.text(function(d) { return d.key; });
li.selectAll("circle")
.data(items, function(d) { return d.key; })
.call(function(d) { d.enter().append("circle"); })
.call(function(d) { d.exit().remove(); })
.attr("class", "legend-circle")
.attr("cx", 0)
.attr("cy", function(d, i) { return i - 0.25 + "em"; })
.attr("r", "0.4em")
.style("fill", function(d) { return d.value.color; });
// Reposition and resize the box
lbbox = li[0][0].getBBox();
lb.attr("x", (lbbox.x - legendPadding))
.attr("y", (lbbox.y - legendPadding))
.attr("height", (lbbox.height + 2 * legendPadding))
.attr("width", (lbbox.width + 2 * legendPadding));
});
return g;
};
k4.histogram = function(elem, args) {
'use strict';
var chart = {},
/* ********** Sizing DOM Elements ************* */
// accessing the element width/height
elemWidth = parseInt(d3.select(elem).style("width"), 10),
elemHeight = parseInt(d3.select(elem).style("padding-bottom"), 10),
// number of rows
numRows = data.rows.length,
// number of charts
n = data.rows[0].columns.length,
// number of layers per chart
m = data.rows[0].columns[0].layers.length,
// row width
outerWidth = elemWidth,
// row height
outerHeight = elemHeight / numRows,
margin = {
top: outerHeight * 0.05,
right: outerWidth * 0.01,
bottom: outerHeight * 0.15,
left: outerWidth * 0.05
},
// svg width/height
width = outerWidth/n - margin.left - margin.right,
height = outerHeight - margin.top - margin.bottom,
/* ************************************************** */
/* ************* Data manipulation **************** */
// pulls out the x-axis key values
keys = data.rows[0].columns[0].layers[0].values.map(function(item) { return item.x; }),
// defines the stack.offset()
stacktype = args.stacktype || 'zero', // 'zero', 'expand', 'group'
stack = d3.layout.stack().offset(stacktype).values(function(d) { return d.values; }),
// calculates the y-axis max value for all charts, i.e. grouped and stacked
yGroup = args.yGroup || false,
yGroupMax = d3.max(data.rows.map(function(data) {
return d3.max(data.columns, function(col) {
return d3.max(stack(col.layers), function(layer) {
return d3.max(layer.values, function(d) {
return d.y;
});
});
});
})),
yStackMax = d3.max(data.rows.map(function(data) {
return d3.max(data.columns, function(col) {
return d3.max(stack(col.layers), function(layer) {
return d3.max(layer.values, function(d) {
return d.y0 + d.y;
});
});
});
})),
/* **************************************************** */
/* *************** D3 parameters ********************* */
xScale = d3.scale.ordinal().domain(keys).rangeRoundBands([0, width], 0.1),
yScale = d3.scale.linear().range([height, 0]).nice(),
xAxis = d3.svg.axis().scale(xScale).ticks(6).tickSize(3, 0).tickPadding(6).orient('bottom'),
yAxis = d3.svg.axis().scale(yScale).ticks(6).tickSize(-(width), 0).tickPadding(4).orient('left'),
color = d3.scale.linear().domain([0, m - 1]).range(args.color) ||
d3.scale.linear().domain([0, m - 1]).range(['#e24700', '#f9e593']),
toolTip = k4.tooltip().attr('class', 'k4-tip').html(function(d) {
if (d.y < 1) { return '<span>x: ' + d.x + '</span><br><span>y: ' + d.y.toFixed(2) * 100 + '%</span>'; }
return '<span>x: ' + d.x + '</span><br><span>y: ' + d.y + '</span>';
}).offset([-12, 0]),
svg, g, layer;
/* ******************************************************** */
chart.render = function(data) {
// append svg(s)
svg = getSvg(elem, data);
// render each chart
g = svg.append('g')
.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')')
.each(function(d) {
var g = d3.select(this);
var yMax = d3.max(d.layers, function(d) {
return d3.max(d.values, function(e) {
return e.y;
});
});
console.log(yMax);
console.log(yGroupMax);
var yStack = d3.max(d.layers, function(d) {
return d3.max(d.values, function(e) {
return e.y0 + e.y;
});
});
// Change y/xScale domain based on stacktype
if (stacktype === 'expand') { yScale.domain([0, 1]); }
if (stacktype === 'group' && yGroup) {
xScale.rangeRoundBands([0, width], 0.2);
yScale.domain([0, yGroupMax]);
} else {
xScale.rangeRoundBands([0, width], 0.2);
yScale.domain([0, yMax]);
}
if (stacktype === 'zero' && yGroup) {
yScale.domain([0, yStackMax]);
} else {
yScale.domain([0, yStack]);
}
// background rect
g.append('g')
.append('rect')
.attr('class', 'bkgd')
.style('fill', '#fff')
.style('opacity', 0.35)
.attr('width', width)
.attr('height', height);
// x axis
g.append('g')
.attr('class', 'x axis')
.attr('transform', 'translate(0,' + height + ')')
.style('stroke-width', 0.5)
.call(xAxis);
// y axis
g.append('g')
.attr('class', 'y axis')
.style('stroke-width', 0.5)
.call(yAxis);
// layer of bars
layer = g.selectAll('.layer')
.data(function(d) { return stack(d.layers); })
.enter().append('g')
.attr('class', 'layer')
.style('fill', function(d, i) { return color(i); });
//Enter
// bars for stack, expand, group
layer.selectAll('rect')
.data(function(d) { return d.values; })
.enter().append('rect');
// Update
if (stacktype === 'group') {
layer.selectAll('rect')
.attr('x', function(d, i, j) { return xScale(d.x) + xScale.rangeBand() / m * j; })
.attr('width', xScale.rangeBand() / m)
.attr('y', function(d) { return yScale(d.y); })
.attr('height', function(d) { return height - yScale(d.y); })
.on('mouseover', toolTip.show)
.on('mouseout', toolTip.hide);
} else {
layer.selectAll('rect')
.attr('width', xScale.rangeBand())
.attr('x', function(d) { return xScale(d.x); })
.attr('y', function(d) { return yScale(d.y0 + d.y); })
.attr('height', function(d) { return yScale(d.y0) - yScale(d.y0 + d.y); })
.on('mouseover', toolTip.show)
.on('mouseout', toolTip.hide);
}
//Exit
layer.selectAll('rect').data(function(d) { return d.values; }).exit().remove();
});
// Window resize
d3.select(window).on('resize', resize);
// k4 tooltip function
g.call(toolTip);
return svg;
};
// append layout divs to elem and bind layout data
function getSvg(elem, data) {
var rows, cols, svg;
rows = d3.select(elem).selectAll('div')
.data(data.rows)
.enter().append('div')
.attr('class', function(d, i) { return 'row r' + i; });
cols = rows.selectAll('div')
.data(function(d) { return d.columns; })
.enter().append('div')
.attr('class', function(d,i){ return 'col c' + i; });
svg = cols.append('svg')
.attr("width", outerWidth/n)
.attr("height", outerHeight);
return svg;
}
function resize() {
/* Update graph using new width and height */
var elemWidth = parseInt(d3.select(elem).style("width"), 10),
elemHeight = parseInt(d3.select(elem).style("padding-bottom"), 10),
outerWidth = elemWidth / n,
outerHeight = elemHeight / numRows,
width = outerWidth - margin.left - margin.right,
height = outerHeight - margin.top - margin.bottom;
d3.select(".row r").style("width", elemWidth).style("height", outerHeight);
d3.select(".col c").style ("width", outerWidth).style("height", outerHeight);
svg.attr("width", outerWidth).attr("height", outerHeight);
g.each(function(d) {
var g = d3.select(this);
var yMax = d3.max(d.layers, function(d) { return d3.max(d.values, function(e) { return e.y; }); });
var yStack = d3.max(d.layers, function(d) { return d3.max(d.values, function(e) { return e.y0 + e.y; }); });
// Change y/xScale domain based on stacktype
// Change y/xScale domain based on stacktype
if (stacktype === 'expand') { yScale.domain([0, 1]); }
if (stacktype === 'group' && yGroup) {
yScale.domain([0, yGroupMax]);
xScale.rangeRoundBands([0, width], 0.2);
} else {
yScale.domain([0, yMax]);
xScale.rangeRoundBands([0, width], 0.2);
}
if (stacktype === 'zero' && yGroup) {
yScale.domain([0, yStackMax]);
} else {
yScale.domain([0, yStack]);
}
/* Update the range of the scale with new width/height */
if (stacktype === "group") { xScale.rangeRoundBands([0, width], 0.4); }
else { xScale.rangeRoundBands([0, width], 0.1); }
yScale.range([height, 0]).nice();
xAxis.ticks(Math.max(width/50, 2));
yAxis.ticks(Math.max(height/20, 2)).tickSize(-(width), 0);
if (width < 300 && height < 80) {
g.select('.x.axis').style('display', 'none');
} else {
g.select('.x.axis').style('display', 'initial');
g.select('.y.axis').style('display', 'initial');
}
g.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
g.selectAll(".bkgd").attr("width", width).attr("height", height);
/* Update the axis with the new scale */
g.select('.x.axis')
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
g.select('.y.axis')
.call(yAxis);
/* Force D3 to recalculate and update the line */
if (stacktype === "group") {
layer.selectAll("rect")
.attr( "x", function (d, i, j) { return xScale(d.x) + xScale.rangeBand() / n * j; })
.attr("width", xScale.rangeBand() / n)
.attr( "y", function (d) { return yScale(d.y); })
.attr( "height", function (d) { return height - yScale(d.y); });
}
g.selectAll('rect')
.attr("width", xScale.rangeBand())
.attr("x", function(d) { return xScale(d.x); })
.attr("height", function(d) { return yScale(d.y0) - yScale(d.y0 + d.y); })
.attr("y", function(d) { return yScale(d.y0 + d.y); });
});
}
chart.margin = function() {
if (!args.margin) { return margin; }
margin.top = typeof args.margin.top !== 'undefined' ? args.margin.top : margin.top;
margin.right = typeof args.margin.right !== 'undefined' ? args.margin.right : margin.right;
margin.bottom = typeof args.margin.bottom !== 'undefined' ? args.margin.bottom : margin.bottom;
margin.left = typeof args.margin.left !== 'undefined' ? args.margin.left : margin.left;
return margin;
};
chart.width = function() {
if (!args.width) { return width; }
width = args.width;
return width;
};
chart.height = function() {
if (!args.height) { return height; }
height = args.height;
return height;
};
chart.color = function() {
if (!args.color) { return color; }
color = args.color;
return color;
};
return chart;
}; return k4;
}));
return k4;
}));

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,18 @@
{
"name": "angular-route",
"version": "1.2.14-build.2338+sha.27873ac",
"main": "./angular-route.js",
"dependencies": {
"angular": "1.2.14-build.2338+sha.27873ac"
},
"homepage": "https://github.com/angular/bower-angular-route",
"_release": "1.2.14-build.2338+sha.27873ac",
"_resolution": {
"type": "version",
"tag": "v1.2.14-build.2338+sha.27873ac",
"commit": "dc4057d931755391886975255bb4a52fd24f6634"
},
"_source": "git://github.com/angular/bower-angular-route.git",
"_target": "~1.2.13",
"_originalSource": "angular-route"
}

View file

@ -0,0 +1,16 @@
{
"name": "angular",
"version": "1.2.14-build.2338+sha.27873ac",
"main": "./angular.js",
"dependencies": {},
"homepage": "https://github.com/angular/bower-angular",
"_release": "1.2.14-build.2338+sha.27873ac",
"_resolution": {
"type": "version",
"tag": "v1.2.14-build.2338+sha.27873ac",
"commit": "75d2b41ae7da8231ebe2d10940166e249c1262c0"
},
"_source": "git://github.com/angular/bower-angular.git",
"_target": "1.2.14-build.2338+sha.27873ac",
"_originalSource": "angular"
}

View file

@ -0,0 +1,35 @@
{
"name": "bootstrap",
"version": "3.1.1",
"main": [
"./dist/css/bootstrap.css",
"./dist/js/bootstrap.js",
"./dist/fonts/glyphicons-halflings-regular.eot",
"./dist/fonts/glyphicons-halflings-regular.svg",
"./dist/fonts/glyphicons-halflings-regular.ttf",
"./dist/fonts/glyphicons-halflings-regular.woff"
],
"ignore": [
"**/.*",
"_config.yml",
"CNAME",
"composer.json",
"CONTRIBUTING.md",
"docs",
"js/tests"
],
"dependencies": {
"jquery": ">= 1.9.0"
},
"homepage": "https://github.com/twbs/bootstrap",
"_release": "3.1.1",
"_resolution": {
"type": "version",
"tag": "v3.1.1",
"commit": "a365d8689c3f3cee7f1acf86b61270ecca8e106d"
},
"_source": "git://github.com/twbs/bootstrap.git",
"_target": "~3.1.1",
"_originalSource": "bootstrap",
"_direct": true
}

View file

@ -0,0 +1,34 @@
{
"name": "d3",
"version": "3.4.3",
"main": "d3.js",
"scripts": [
"d3.js"
],
"ignore": [
".DS_Store",
".git",
".gitignore",
".npmignore",
".travis.yml",
"Makefile",
"bin",
"component.json",
"index.js",
"lib",
"node_modules",
"package.json",
"src",
"test"
],
"homepage": "https://github.com/mbostock/d3",
"_release": "3.4.3",
"_resolution": {
"type": "version",
"tag": "v3.4.3",
"commit": "368a48205152483fb68e7423fefc87a90fbe9a9d"
},
"_source": "git://github.com/mbostock/d3.git",
"_target": "~3.4.1",
"_originalSource": "d3"
}

View file

@ -0,0 +1,24 @@
{
"name": "elasticsearch",
"version": "1.5.9",
"authors": [
"Spencer Alger <spencer@spenceralger.com>"
],
"description": "The official low-level Elasticsearch client, for use in the browser.",
"main": "elasticsearch.js",
"keywords": [
"elasticsearch",
"client"
],
"license": "Apache 2.0",
"homepage": "https://github.com/elasticsearch/bower-elasticsearch-js",
"_release": "1.5.9",
"_resolution": {
"type": "version",
"tag": "v1.5.9",
"commit": "02d4b405996c1be5e7adfb8922443a5e31db4a48"
},
"_source": "git://github.com/elasticsearch/bower-elasticsearch-js.git",
"_target": "~1.5.8",
"_originalSource": "elasticsearch"
}

View file

@ -0,0 +1,37 @@
{
"name": "jquery",
"version": "2.1.0",
"main": "dist/jquery.js",
"license": "MIT",
"ignore": [
"**/.*",
"build",
"speed",
"test",
"*.md",
"AUTHORS.txt",
"Gruntfile.js",
"package.json"
],
"devDependencies": {
"sizzle": "1.10.16",
"requirejs": "~2.1.8",
"qunit": "~1.12.0",
"sinon": "~1.7.3"
},
"keywords": [
"jquery",
"javascript",
"library"
],
"homepage": "https://github.com/jquery/jquery",
"_release": "2.1.0",
"_resolution": {
"type": "version",
"tag": "2.1.0",
"commit": "9434e03193c45d51bbd063a0edd1a07a6178d33f"
},
"_source": "git://github.com/jquery/jquery.git",
"_target": ">= 1.9.0",
"_originalSource": "jquery"
}

View file

@ -0,0 +1,34 @@
{
"name": "lodash",
"version": "2.4.1",
"main": "dist/lodash.compat.js",
"ignore": [
".*",
"*.custom.*",
"*.template.*",
"*.map",
"*.md",
"/*.min.*",
"/lodash.js",
"index.js",
"component.json",
"package.json",
"doc",
"modularize",
"node_modules",
"perf",
"test",
"vendor"
],
"homepage": "https://github.com/lodash/lodash",
"_release": "2.4.1",
"_resolution": {
"type": "version",
"tag": "2.4.1",
"commit": "c7aa842eded639d6d90a5714d3195a8802c86687"
},
"_source": "git://github.com/lodash/lodash.git",
"_target": "~2.4.1",
"_originalSource": "lodash",
"_direct": true
}

View file

@ -0,0 +1,16 @@
{
"name": "queue-async",
"version": "1.0.7",
"main": "./queue.js",
"homepage": "https://github.com/mbostock/queue",
"_release": "1.0.7",
"_resolution": {
"type": "version",
"tag": "v1.0.7",
"commit": "ca293e8c2e3654807ead7597cad0188e6f5b4dfe"
},
"_source": "git://github.com/mbostock/queue.git",
"_target": "~1.0.7",
"_originalSource": "queue-async",
"_direct": true
}

View file

@ -0,0 +1,2 @@
.DS_Store
node_modules

View file

@ -0,0 +1 @@
test/

View file

@ -0,0 +1,404 @@
var queue = require("../queue"),
fs = require("fs"),
vows = require("vows"),
assert = require("assert");
var suite = vows.describe("queue");
suite.addBatch({
"version": {
"is semantic": function() {
assert.isTrue(/^([0-9]+)\.([0-9]+)\.([0-9]+)/.test(queue.version));
}
},
"example queue of fs.stat": {
topic: function() {
queue()
.defer(fs.stat, __dirname + "/../Makefile")
.defer(fs.stat, __dirname + "/../README.md")
.defer(fs.stat, __dirname + "/../package.json")
.await(this.callback);
},
"does not fail": function(error, one, two, three) {
assert.isNull(error);
},
"successfully executes the three tasks": function(error, one, two, three) {
assert.greater(one.size, 0);
assert.greater(two.size, 0);
assert.greater(three.size, 0);
}
},
"queue of single synchronous task that errors": {
topic: function() {
queue()
.defer(function(callback) { callback(-1); })
.await(this.callback);
},
"fails": function(error, result) {
assert.equal(error, -1);
assert.isUndefined(result);
}
},
"queue of single asynchronous task that errors": {
topic: function() {
queue()
.defer(function(callback) { process.nextTick(function() { callback(-1); }); })
.await(this.callback);
},
"fails": function(error, result) {
assert.equal(error, -1);
assert.isUndefined(result);
}
},
"queue with multiple tasks that error": {
topic: function() {
queue()
.defer(function(callback) { setTimeout(function() { callback(-2); }, 100); })
.defer(function(callback) { process.nextTick(function() { callback(-1); }); })
.defer(function(callback) { setTimeout(function() { callback(-3); }, 200); })
.await(this.callback);
},
"the first error is returned": function(error, one, two, three) {
assert.equal(error, -1);
assert.isUndefined(one);
assert.isUndefined(two);
assert.isUndefined(three);
}
},
"queue with multiple tasks where one errors": {
topic: function() {
queue()
.defer(function(callback) { process.nextTick(function() { callback(-1); }); })
.defer(function(callback) { process.nextTick(function() { callback(null, 'ok'); }); })
.await(this.callback);
},
"the first error is returned": function(error, one, two) {
assert.equal(error, -1);
assert.isUndefined(one);
assert.isUndefined(two);
}
},
"queue with multiple synchronous tasks that error": {
topic: function() {
queue()
.defer(function(callback) { callback(-1); })
.defer(function(callback) { callback(-2); })
.defer(function(callback) { throw new Error(); })
.await(this.callback);
},
"the first error prevents the other tasks from running": function(error, one, two, three) {
assert.equal(error, -1);
assert.isUndefined(one);
assert.isUndefined(two);
assert.isUndefined(three);
}
},
"queue of asynchronous closures, processed serially": {
topic: function() {
var tasks = [], task = asynchronousTask(), n = 10, q = queue(1);
while (--n >= 0) tasks.push(task);
tasks.forEach(function(t) { q.defer(t); });
q.awaitAll(this.callback)
},
"does not fail": function(error, results) {
assert.isNull(error);
},
"executes all tasks in series": function(error, results) {
assert.deepEqual(results, [
{active: 1, index: 0},
{active: 1, index: 1},
{active: 1, index: 2},
{active: 1, index: 3},
{active: 1, index: 4},
{active: 1, index: 5},
{active: 1, index: 6},
{active: 1, index: 7},
{active: 1, index: 8},
{active: 1, index: 9}
]);
}
},
"fully-parallel queue of ten asynchronous tasks": {
topic: function() {
var t = asynchronousTask();
queue()
.defer(t)
.defer(t)
.defer(t)
.defer(t)
.defer(t)
.defer(t)
.defer(t)
.defer(t)
.defer(t)
.defer(t)
.awaitAll(this.callback);
},
"does not fail": function(error, results) {
assert.isNull(error);
},
"executes all tasks in parallel": function(error, results) {
assert.deepEqual(results, [
{active: 10, index: 0},
{active: 9, index: 1},
{active: 8, index: 2},
{active: 7, index: 3},
{active: 6, index: 4},
{active: 5, index: 5},
{active: 4, index: 6},
{active: 3, index: 7},
{active: 2, index: 8},
{active: 1, index: 9}
]);
}
},
"partly-parallel queue of ten asynchronous tasks": {
topic: function() {
var t = asynchronousTask();
queue(3)
.defer(t)
.defer(t)
.defer(t)
.defer(t)
.defer(t)
.defer(t)
.defer(t)
.defer(t)
.defer(t)
.defer(t)
.awaitAll(this.callback);
},
"does not fail": function(error, results) {
assert.isNull(error);
},
"executes at most three tasks in parallel": function(error, results) {
assert.deepEqual(results, [
{active: 3, index: 0},
{active: 3, index: 1},
{active: 3, index: 2},
{active: 3, index: 3},
{active: 3, index: 4},
{active: 3, index: 5},
{active: 3, index: 6},
{active: 3, index: 7},
{active: 2, index: 8},
{active: 1, index: 9}
]);
}
},
"serialized queue of ten asynchronous tasks": {
topic: function() {
var t = asynchronousTask();
queue(1)
.defer(t)
.defer(t)
.defer(t)
.defer(t)
.defer(t)
.defer(t)
.defer(t)
.defer(t)
.defer(t)
.defer(t)
.awaitAll(this.callback);
},
"does not fail": function(error, results) {
assert.isNull(error);
},
"executes all tasks in series": function(error, results) {
assert.deepEqual(results, [
{active: 1, index: 0},
{active: 1, index: 1},
{active: 1, index: 2},
{active: 1, index: 3},
{active: 1, index: 4},
{active: 1, index: 5},
{active: 1, index: 6},
{active: 1, index: 7},
{active: 1, index: 8},
{active: 1, index: 9}
]);
}
},
"serialized queue of ten deferred synchronous tasks": {
topic: function() {
var t = deferredSynchronousTask();
queue(1)
.defer(t)
.defer(t)
.defer(t)
.defer(t)
.defer(t)
.defer(t)
.defer(t)
.defer(t)
.defer(t)
.defer(t)
.awaitAll(this.callback);
t.finish();
},
"does not fail": function(error, results) {
assert.isNull(error);
},
"executes all tasks in series, within the callback of the first task": function(error, results) {
assert.deepEqual(results, [
{active: 1, index: 0},
{active: 2, index: 1},
{active: 2, index: 2},
{active: 2, index: 3},
{active: 2, index: 4},
{active: 2, index: 5},
{active: 2, index: 6},
{active: 2, index: 7},
{active: 2, index: 8},
{active: 2, index: 9}
]);
}
},
"partly-parallel queue of ten synchronous tasks": {
topic: function() {
var t = synchronousTask();
queue(3)
.defer(t)
.defer(t)
.defer(t)
.defer(t)
.defer(t)
.defer(t)
.defer(t)
.defer(t)
.defer(t)
.defer(t)
.awaitAll(this.callback);
},
"does not fail": function(error, results) {
assert.isNull(error);
},
"executes all tasks in series": function(error, results) {
assert.deepEqual(results, [
{active: 1, index: 0},
{active: 1, index: 1},
{active: 1, index: 2},
{active: 1, index: 3},
{active: 1, index: 4},
{active: 1, index: 5},
{active: 1, index: 6},
{active: 1, index: 7},
{active: 1, index: 8},
{active: 1, index: 9}
]);
}
},
"serialized queue of ten synchronous tasks": {
topic: function() {
var t = synchronousTask();
queue(1)
.defer(t)
.defer(t)
.defer(t)
.defer(t)
.defer(t)
.defer(t)
.defer(t)
.defer(t)
.defer(t)
.defer(t)
.awaitAll(this.callback);
},
"does not fail": function(error, results) {
assert.isNull(error);
},
"executes all tasks in series": function(error, results) {
assert.deepEqual(results, [
{active: 1, index: 0},
{active: 1, index: 1},
{active: 1, index: 2},
{active: 1, index: 3},
{active: 1, index: 4},
{active: 1, index: 5},
{active: 1, index: 6},
{active: 1, index: 7},
{active: 1, index: 8},
{active: 1, index: 9}
]);
}
}
});
suite.export(module);
function asynchronousTask(counter) {
var active = 0;
if (!counter) counter = {scheduled: 0};
return function(callback) {
var index = counter.scheduled++;
++active;
process.nextTick(function() {
try {
callback(null, {active: active, index: index});
} finally {
--active;
}
});
};
}
function synchronousTask(counter) {
var active = 0;
if (!counter) counter = {scheduled: 0};
return function(callback) {
try {
callback(null, {active: ++active, index: counter.scheduled++});
} finally {
--active;
}
};
}
function deferredSynchronousTask(counter) {
var active = 0, deferrals = [];
if (!counter) counter = {scheduled: 0};
function task(callback) {
if (deferrals) return deferrals.push({callback: callback, index: counter.scheduled++});
try {
callback(null, {active: ++active, index: counter.scheduled++});
} finally {
--active;
}
}
task.finish = function() {
var deferrals_ = deferrals.slice();
deferrals = null;
deferrals_.forEach(function(deferral) {
try {
deferral.callback(null, {active: ++active, index: deferral.index});
} finally {
--active;
}
});
};
return task;
}

View file

@ -0,0 +1,24 @@
{
"name": "requirejs",
"version": "2.1.11",
"homepage": "http://requirejs.org",
"authors": [
"jrburke.com"
],
"description": "A file and module loader for JavaScript",
"main": "require.js",
"keywords": [
"AMD"
],
"license": "new BSD, and MIT",
"_release": "2.1.11",
"_resolution": {
"type": "version",
"tag": "2.1.11",
"commit": "fc97e49f1ec9fb2f204bef2b60ed21a32d6a2e05"
},
"_source": "git://github.com/jrburke/requirejs-bower.git",
"_target": "~2.1.11",
"_originalSource": "requirejs",
"_direct": true
}

View file

@ -0,0 +1,30 @@
{
"name": "topojson",
"version": "1.4.8",
"main": "topojson.js",
"scripts": [
"topojson.js"
],
"ignore": [
".DS_Store",
".git",
"Makefile",
"bin",
"examples",
"index.js",
"lib",
"node_modules",
"package.json",
"test"
],
"homepage": "https://github.com/mbostock/topojson",
"_release": "1.4.8",
"_resolution": {
"type": "version",
"tag": "v1.4.8",
"commit": "0148855246c1234765048ef91e52392d05115476"
},
"_source": "git://github.com/mbostock/topojson.git",
"_target": "~1.4.6",
"_originalSource": "topojson"
}

View file

@ -0,0 +1,3 @@
.DS_Store
topojson.min.js
node_modules

View file

@ -0,0 +1,2 @@
.DS_Store
node_modules

View file

@ -51,7 +51,8 @@
"grunt-karma": "~0.6.2",
"karma-junit-reporter": "~0.2.1",
"karma-commonjs": "0.0.6",
"karma-safari-launcher": "~0.1.1"
"karma-safari-launcher": "~0.1.1",
"grunt-contrib-requirejs": "~0.4.3"
},
"dependencies": {}
}

View file

@ -5,15 +5,21 @@
* Returns the charting function.
*/
k4.Chart = function(elem, args) {
'use strict';
define(function(require) {
"use strict";
if (typeof(k4[args.type]) !== 'function') { throw args.type + " is not a supported k4 function."; }
var histogram = require('bower_components/K4D3/src/modules/histogram');
var type = args.type,
chartFunc = k4[type](elem, args);
return function(elem, args) {
var type = args.type,
charts = {
'histogram': histogram
};
return chartFunc;
};
if (typeof(charts[type]) !== 'function') { throw type + " is not a supported k4 function."; }
var chartFunc = charts[type](elem, args);
return chartFunc;
};
});

View file

@ -1,2 +0,0 @@
return k4;
}));

21
src/bower_components/K4D3/src/index.js vendored Normal file
View file

@ -0,0 +1,21 @@
(function(root, factory) {
'use strict';
if (typeof define === 'function' && define.amd) {
define(factory);
} else if (typeof module === 'object' && module.exports) {
module.exports = factory();
} else {
root.k4 = factory();
}
}(this, function(require) {
var k4 = {
version: '0.0.0',
tooltip: require('./bower_components/K4D3/src/tooltip'),
legend: require('./bower_components/K4D3/src/legend'),
Chart: require('./bower_components/K4D3/src/core'),
histogram: require('./bower_components/K4D3/src/modules/histogram')
};
return k4;
}));

View file

@ -1,64 +1,71 @@
k4.legend = function(g) {
'use strict';
define(function(require) {
"use strict";
g.each(function() {
var g = d3.select(this),
items = {},
svg = d3.select(g.property("nearestViewportElement")),
legendPadding = g.attr("data-style-padding") || 5,
lb = g.selectAll(".legend-box").data([true]),
li = g.selectAll(".legend-items").data([true]),
lbbox;
var d3 = require('d3');
lb.enter().append("rect").classed("legend-box",true);
li.enter().append("g").classed("legend-items",true);
return function(g) {
'use strict';
svg.selectAll("[data-legend]").each(function() {
var self = d3.select(this);
items[self.attr("data-legend")] = {
pos : self.attr("data-legend-pos") || this.getBBox().y,
color : self.attr("data-legend-color") !== null ? self.attr("data-legend-color") :
self.style("fill") !== 'none' ? self.style("fill") : self.style("stroke")
};
g.each(function() {
var g = d3.select(this),
items = {},
svg = d3.select(g.property("nearestViewportElement")),
legendPadding = g.attr("data-style-padding") || 5,
lb = g.selectAll(".legend-box").data([true]),
li = g.selectAll(".legend-items").data([true]),
lbbox;
lb.enter().append("rect").classed("legend-box",true);
li.enter().append("g").classed("legend-items",true);
svg.selectAll("[data-legend]").each(function() {
var self = d3.select(this);
items[self.attr("data-legend")] = {
pos : self.attr("data-legend-pos") || this.getBBox().y,
color : self.attr("data-legend-color") !== null ? self.attr("data-legend-color") :
self.style("fill") !== 'none' ? self.style("fill") : self.style("stroke")
};
});
items = d3.entries(items).sort(function(a, b) { return a.value.pos - b.value.pos; });
/*
li.selectAll('div')
.data(items, function(d) { return d.key; })
.call(function(d) { d.enter().append("div"); })
.call(function(d) { d.exit().remove(); })
.attr("class", "legend-div");
*/
li.selectAll("text")
.data(items, function(d) { return d.key; })
.call(function(d) { d.enter().append("text"); })
.call(function(d) { d.exit().remove(); })
.attr("class", "legend-text")
.attr("x", "0.7em")
.attr("y", function(d, i) { return i + "em"; })
.text(function(d) { return d.key; });
li.selectAll("circle")
.data(items, function(d) { return d.key; })
.call(function(d) { d.enter().append("circle"); })
.call(function(d) { d.exit().remove(); })
.attr("class", "legend-circle")
.attr("cx", 0)
.attr("cy", function(d, i) { return i - 0.25 + "em"; })
.attr("r", "0.4em")
.style("fill", function(d) { return d.value.color; });
// Reposition and resize the box
lbbox = li[0][0].getBBox();
lb.attr("x", (lbbox.x - legendPadding))
.attr("y", (lbbox.y - legendPadding))
.attr("height", (lbbox.height + 2 * legendPadding))
.attr("width", (lbbox.width + 2 * legendPadding));
});
items = d3.entries(items).sort(function(a, b) { return a.value.pos - b.value.pos; });
return g;
};
/*
li.selectAll('div')
.data(items, function(d) { return d.key; })
.call(function(d) { d.enter().append("div"); })
.call(function(d) { d.exit().remove(); })
.attr("class", "legend-div");
*/
li.selectAll("text")
.data(items, function(d) { return d.key; })
.call(function(d) { d.enter().append("text"); })
.call(function(d) { d.exit().remove(); })
.attr("class", "legend-text")
.attr("x", "0.7em")
.attr("y", function(d, i) { return i + "em"; })
.text(function(d) { return d.key; });
li.selectAll("circle")
.data(items, function(d) { return d.key; })
.call(function(d) { d.enter().append("circle"); })
.call(function(d) { d.exit().remove(); })
.attr("class", "legend-circle")
.attr("cx", 0)
.attr("cy", function(d, i) { return i - 0.25 + "em"; })
.attr("r", "0.4em")
.style("fill", function(d) { return d.value.color; });
// Reposition and resize the box
lbbox = li[0][0].getBBox();
lb.attr("x", (lbbox.x - legendPadding))
.attr("y", (lbbox.y - legendPadding))
.attr("height", (lbbox.height + 2 * legendPadding))
.attr("width", (lbbox.width + 2 * legendPadding));
});
return g;
};
});

View file

@ -1,311 +1,337 @@
k4.histogram = function(elem, args) {
define(function(require) {
'use strict';
var tooltip = require('bower_components/K4D3/src/tooltip'),
d3 = require('d3');
var chart = {},
return function(elem, args) {
/* ********** Sizing DOM Elements ************* */
// accessing the element width/height
elemWidth = parseInt(d3.select(elem).style("width"), 10),
elemHeight = parseInt(d3.select(elem).style("padding-bottom"), 10),
// number of rows
numRows = data.rows.length,
// number of charts
n = data.rows[0].columns.length,
// number of layers per chart
m = data.rows[0].columns[0].layers.length,
// row width
outerWidth = elemWidth,
// row height
outerHeight = elemHeight / numRows,
margin = {
top: outerHeight * 0.05,
right: outerWidth * 0.01,
bottom: outerHeight * 0.15,
left: outerWidth * 0.05
},
// svg width/height
width = outerWidth/n - margin.left - margin.right,
height = outerHeight - margin.top - margin.bottom,
/* ************************************************** */
var chart = {},
elemWidth = parseInt(d3.select(elem.parentNode).style('width'), 10),
elemHeight = d3.select(elem).attr('height'), //.80 * window.innerHeight, //parseInt(d3.select(elem.parentNode).style('height'), 10) < 100 ? 400 : parseInt(d3.select(elem.parentNode).style('height'), 10),
stacktype = args.stacktype || 'zero', // 'zero', 'expand', 'group'
yGroup = args.yGroup || false,
colors = args.color,
//displayToolTip = args.displayToolTip || true,
numRows, margin, svg, g, layer, n, m, width, height, outerWidth, outerHeight, keys, stack, toolTip,
xScale, yScale, xAxis, yAxis, yStackMax, yGroupMax, color;
/* ************* Data manipulation **************** */
// pulls out the x-axis key values
keys = data.rows[0].columns[0].layers[0].values.map(function(item) { return item.x; }),
// defines the stack.offset()
stacktype = args.stacktype || 'zero', // 'zero', 'expand', 'group'
stack = d3.layout.stack().offset(stacktype).values(function(d) { return d.values; }),
// calculates the y-axis max value for all charts, i.e. grouped and stacked
yGroup = args.yGroup || false,
yGroupMax = d3.max(data.rows.map(function(data) {
return d3.max(data.columns, function(col) {
return d3.max(stack(col.layers), function(layer) {
return d3.max(layer.values, function(d) {
return d.y;
chart.render = function(data) {
/* ********** Sizing DOM Elements ************* */
// number of rows
numRows = data.rows.length,
// number of charts
n = data.rows[0].columns.length,
// number of layers per chart
m = data.rows[0].columns[0].layers.length,
// row width
outerWidth = elemWidth,
// row height
outerHeight = elemHeight / numRows,
margin = {
top: outerHeight * 0.05,
right: outerWidth * 0.01,
bottom: outerHeight * 0.15,
left: outerWidth * 0.05
},
// svg width/height
width = outerWidth/n - margin.left - margin.right,
height = outerHeight - margin.top - margin.bottom,
/* ************************************************** */
/* ************* Data manipulation **************** */
// pulls out the x-axis key values
keys = data.rows[0].columns[0].layers[0].values.map(function(item) { return item.x; }),
stack = d3.layout.stack().offset(stacktype).values(function(d) { return d.values; }),
yGroupMax = d3.max(data.rows.map(function(data) {
return d3.max(data.columns, function(col) {
return d3.max(stack(col.layers), function(layer) {
return d3.max(layer.values, function(d) {
return d.y;
});
});
});
});
})),
yStackMax = d3.max(data.rows.map(function(data) {
return d3.max(data.columns, function(col) {
return d3.max(stack(col.layers), function(layer) {
return d3.max(layer.values, function(d) {
return d.y0 + d.y;
})),
yStackMax = d3.max(data.rows.map(function(data) {
return d3.max(data.columns, function(col) {
return d3.max(stack(col.layers), function(layer) {
return d3.max(layer.values, function(d) {
return d.y0 + d.y;
});
});
});
});
})),
/* **************************************************** */
})),
/* **************************************************** */
/* *************** D3 parameters ********************* */
xScale = d3.scale.ordinal().domain(keys).rangeRoundBands([0, width], 0.1),
yScale = d3.scale.linear().range([height, 0]).nice(),
xAxis = d3.svg.axis().scale(xScale).ticks(6).tickSize(3, 0).tickPadding(6).orient('bottom'),
yAxis = d3.svg.axis().scale(yScale).ticks(6).tickSize(-(width), 0).tickPadding(4).orient('left'),
color = d3.scale.linear().domain([0, m - 1]).range(args.color) ||
d3.scale.linear().domain([0, m - 1]).range(['#e24700', '#f9e593']),
toolTip = k4.tooltip().attr('class', 'k4-tip').html(function(d) {
if (d.y < 1) { return '<span>x: ' + d.x + '</span><br><span>y: ' + d.y.toFixed(2) * 100 + '%</span>'; }
return '<span>x: ' + d.x + '</span><br><span>y: ' + d.y + '</span>';
}).offset([-12, 0]),
svg, g, layer;
/* ******************************************************** */
/* *************** D3 parameters ********************* */
xScale = d3.scale.ordinal().domain(keys).rangeRoundBands([0, width], 0.1),
yScale = d3.scale.linear().range([height, 0]).nice(),
xAxis = d3.svg.axis().scale(xScale).tickSize(3, 0).tickPadding(6).tickValues(xScale.domain().filter(function(d, i) { return (i % 5); })).orient('bottom'),
yAxis = d3.svg.axis().scale(yScale).ticks(6).tickSize(-(width), 0).tickPadding(4).orient('left'),
color = d3.scale.linear().domain([0, m - 1]).range(['#e24700', '#f9e593']),
/*
toolTip = !displayToolTip ? "undefined" : tooltip().attr('class', 'k4-tip').html(function(d) {
if (d.y < 1) { return '<span>x: ' + d.x + '</span><br><span>y: ' + d.y.toFixed(2) * 100 + '%</span>'; }
return '<span>x: ' + d.x + '</span><br><span>y: ' + d.y + '</span>';
}).offset([-12, 0]);
*/
/* ******************************************************** */
chart.render = function(data) {
// Removing items off the element
d3.select(elem).selectAll('*').remove();
// append svg(s)
svg = getSvg(elem, data);
// append svg(s)
svg = getSvg(elem, data);
svg.attr('width', outerWidth/n).attr('height', outerHeight);
// render each chart
g = svg.append('g')
.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')')
.each(function(d) {
// render each chart
g = svg.append('g')
.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')')
.each(function(d) {
var g = d3.select(this);
var yMax = d3.max(d.layers, function(d) {
return d3.max(d.values, function(e) {
return e.y;
});
});
var yStack = d3.max(d.layers, function(d) {
return d3.max(d.values, function(e) {
return e.y0 + e.y;
});
});
// Change y/xScale domain based on stacktype
if (stacktype === 'expand') { yScale.domain([0, 1]); }
else if (stacktype === 'zero') {
if (yGroup) {
yScale.domain([0, yStackMax]).nice();
} else {
yScale.domain([0, yStack]).nice();
}
}
else if (stacktype === 'group') {
if (yGroup) {
xScale.rangeRoundBands([0, width], 0.2);
yScale.domain([0, yGroupMax]).nice();
} else {
xScale.rangeRoundBands([0, width], 0.2);
yScale.domain([0, yMax]).nice();
}
}
// background rect
g.append('g')
.append('rect')
.attr('class', 'bkgd')
.style('fill', '#fff')
.style('opacity', 0.35)
.attr('width', width)
.attr('height', height);
// x axis
g.append('g')
.attr('class', 'x axis')
.attr('transform', 'translate(0,' + height + ')')
.style('stroke-width', 0.5)
.call(xAxis);
// y axis
g.append('g')
.attr('class', 'y axis')
.style('stroke-width', 0.5)
.call(yAxis);
// layer of bars
layer = g.selectAll('.layer')
.data(function(d) { return stack(d.layers); })
.enter().append('g')
.attr('class', 'layer')
.style('fill', function(d, i) { return color(i); });
//Enter
// bars for stack, expand, group
layer.selectAll('rect')
.data(function(d) { return d.values; })
.enter().append('rect');
// Update
if (stacktype === 'group') {
layer.selectAll('rect')
.attr('x', function(d, i, j) { return xScale(d.x) + xScale.rangeBand() / m * j; })
.attr('width', xScale.rangeBand() / m)
.attr('y', function(d) { return yScale(d.y); })
.attr('height', function(d) { return height - yScale(d.y); })
//.on('mouseover', toolTip.show)
//.on('mouseout', toolTip.hide);
} else {
layer.selectAll('rect')
.attr('width', xScale.rangeBand())
.attr('x', function(d) { return xScale(d.x); })
.attr('y', function(d) { return yScale(d.y0 + d.y); })
.attr('height', function(d) { return yScale(d.y0) - yScale(d.y0 + d.y); })
//.on('mouseover', toolTip.show)
//.on('mouseout', toolTip.hide);
}
//Exit
layer.selectAll('rect').data(function(d) { return d.values; }).exit().remove();
});
// Window resize
d3.select(window).on('resize', resize);
// k4 tooltip function
//if (displayToolTip) { g.call(toolTip); }
return svg;
};
// append layout divs to elem and bind layout data
function getSvg(elem, data) {
var rows, cols, svg;
rows = d3.select(elem).selectAll('div')
.data(data.rows)
.enter().append('div')
.attr('class', function(d, i) { return 'row r' + i; })
.style('display', 'block');
cols = rows.selectAll('div')
.data(function(d) { return d.columns; })
.enter().append('div')
.attr('class', function(d,i){ return 'col c' + i; })
.style('display', 'inline-block');
svg = cols.append('svg');
return svg;
}
function resize() {
/* Update graph using new width and height */
var elemWidth = parseInt(d3.select(elem.parentNode).style('width'), 10),
elemHeight = d3.select(elem).attr('height'), //.80 * window.innerHeight, //parseInt(d3.select(elem.parentNode).style('height'), 10),
outerWidth = elemWidth / n,
outerHeight = elemHeight / numRows,
width = outerWidth - margin.left - margin.right,
height = outerHeight - margin.top - margin.bottom;
d3.select('.row r').style('width', elemWidth).style('height', outerHeight);
d3.select('.col c').style ('width', outerWidth).style('height', outerHeight);
svg.attr('width', outerWidth).attr('height', outerHeight);
g.each(function(d) {
var g = d3.select(this);
var yMax = d3.max(d.layers, function(d) {
return d3.max(d.values, function(e) {
return e.y;
});
});
console.log(yMax);
console.log(yGroupMax);
var yStack = d3.max(d.layers, function(d) {
return d3.max(d.values, function(e) {
return e.y0 + e.y;
});
});
var yMax = d3.max(d.layers, function(d) { return d3.max(d.values, function(e) { return e.y; }); });
var yStack = d3.max(d.layers, function(d) { return d3.max(d.values, function(e) { return e.y0 + e.y; }); });
// Change y/xScale domain based on stacktype
if (stacktype === 'expand') { yScale.domain([0, 1]); }
if (stacktype === 'group' && yGroup) {
xScale.rangeRoundBands([0, width], 0.2);
yScale.domain([0, yGroupMax]);
} else {
xScale.rangeRoundBands([0, width], 0.2);
yScale.domain([0, yMax]);
else if (stacktype === 'zero') {
if (yGroup) {
yScale.domain([0, yStackMax]).nice();
} else {
yScale.domain([0, yStack]).nice();
}
}
else if (stacktype === 'group') {
if (yGroup) {
xScale.rangeRoundBands([0, width], 0.2);
yScale.domain([0, yGroupMax]).nice();
} else {
xScale.rangeRoundBands([0, width], 0.2);
yScale.domain([0, yMax]).nice();
}
}
if (stacktype === 'zero' && yGroup) {
yScale.domain([0, yStackMax]);
/* Update the range of the scale with new width/height */
xScale.rangeRoundBands([0, width], 0.1);
yScale.range([height, 0]).nice();
xAxis.tickValues(xScale.domain().filter(function(d, i) { return (i % Math.min(width/80, 5)); }));
//xAxis.ticks(Math.max(width/50, 2));
yAxis.ticks(Math.max(height/20, 2)).tickSize(-(width), 0);
if (width < 300 && height < 80) {
g.select('.x.axis').style('display', 'none');
} else {
yScale.domain([0, yStack]);
g.select('.x.axis').style('display', 'initial');
g.select('.y.axis').style('display', 'initial');
}
// background rect
g.append('g')
.append('rect')
.attr('class', 'bkgd')
.style('fill', '#fff')
.style('opacity', 0.35)
.attr('width', width)
.attr('height', height);
g.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
g.selectAll('.bkgd').attr('width', width).attr('height', height);
// x axis
g.append('g')
.attr('class', 'x axis')
/* Update the axis with the new scale */
g.select('.x.axis')
.attr('transform', 'translate(0,' + height + ')')
.style('stroke-width', 0.5)
.call(xAxis);
// y axis
g.append('g')
.attr('class', 'y axis')
.style('stroke-width', 0.5)
g.select('.y.axis')
.call(yAxis);
// layer of bars
layer = g.selectAll('.layer')
.data(function(d) { return stack(d.layers); })
.enter().append('g')
.attr('class', 'layer')
.style('fill', function(d, i) { return color(i); });
//Enter
// bars for stack, expand, group
layer.selectAll('rect')
.data(function(d) { return d.values; })
.enter().append('rect');
// Update
/* Force D3 to recalculate and update the line */
if (stacktype === 'group') {
layer.selectAll('rect')
.attr('x', function(d, i, j) { return xScale(d.x) + xScale.rangeBand() / m * j; })
g.selectAll('.layer').selectAll('rect')
.attr( 'x', function (d, i, j) { return xScale(d.x) + xScale.rangeBand() / m * j; })
.attr('width', xScale.rangeBand() / m)
.attr('y', function(d) { return yScale(d.y); })
.attr('height', function(d) { return height - yScale(d.y); })
.on('mouseover', toolTip.show)
.on('mouseout', toolTip.hide);
.attr( 'y', function (d) { return yScale(d.y); })
.attr( 'height', function (d) { return height - yScale(d.y); });
} else {
layer.selectAll('rect')
g.selectAll('.layer').selectAll('rect')
.attr('width', xScale.rangeBand())
.attr('x', function(d) { return xScale(d.x); })
.attr('y', function(d) { return yScale(d.y0 + d.y); })
.attr('height', function(d) { return yScale(d.y0) - yScale(d.y0 + d.y); })
.on('mouseover', toolTip.show)
.on('mouseout', toolTip.hide);
.attr('y', function(d) { return yScale(d.y0 + d.y); });
}
//Exit
layer.selectAll('rect').data(function(d) { return d.values; }).exit().remove();
});
}
// Window resize
d3.select(window).on('resize', resize);
chart.margin = function() {
if (!args.margin) { return margin; }
margin.top = typeof args.margin.top !== 'undefined' ? args.margin.top : margin.top;
margin.right = typeof args.margin.right !== 'undefined' ? args.margin.right : margin.right;
margin.bottom = typeof args.margin.bottom !== 'undefined' ? args.margin.bottom : margin.bottom;
margin.left = typeof args.margin.left !== 'undefined' ? args.margin.left : margin.left;
return margin;
};
// k4 tooltip function
g.call(toolTip);
chart.type = function(_) {
if (!arguments.length) { return stacktype; }
stacktype = _;
return chart;
};
return svg;
/*
chart.tooltip = function(_) {
if (!arguments.length) { return tooltip; }
tooltip = _;
return chart;
}
*/
chart.width = function() {
if (!args.width) { return width; }
width = args.width;
return width;
};
chart.height = function() {
if (!args.height) { return height; }
height = args.height;
return height;
};
chart.color = function() {
if (!args.color) { return color; }
color = args.color;
return color;
};
return chart;
};
// append layout divs to elem and bind layout data
function getSvg(elem, data) {
var rows, cols, svg;
rows = d3.select(elem).selectAll('div')
.data(data.rows)
.enter().append('div')
.attr('class', function(d, i) { return 'row r' + i; });
cols = rows.selectAll('div')
.data(function(d) { return d.columns; })
.enter().append('div')
.attr('class', function(d,i){ return 'col c' + i; });
svg = cols.append('svg')
.attr("width", outerWidth/n)
.attr("height", outerHeight);
return svg;
}
function resize() {
/* Update graph using new width and height */
var elemWidth = parseInt(d3.select(elem).style("width"), 10),
elemHeight = parseInt(d3.select(elem).style("padding-bottom"), 10),
outerWidth = elemWidth / n,
outerHeight = elemHeight / numRows,
width = outerWidth - margin.left - margin.right,
height = outerHeight - margin.top - margin.bottom;
d3.select(".row r").style("width", elemWidth).style("height", outerHeight);
d3.select(".col c").style ("width", outerWidth).style("height", outerHeight);
svg.attr("width", outerWidth).attr("height", outerHeight);
g.each(function(d) {
var g = d3.select(this);
var yMax = d3.max(d.layers, function(d) { return d3.max(d.values, function(e) { return e.y; }); });
var yStack = d3.max(d.layers, function(d) { return d3.max(d.values, function(e) { return e.y0 + e.y; }); });
// Change y/xScale domain based on stacktype
// Change y/xScale domain based on stacktype
if (stacktype === 'expand') { yScale.domain([0, 1]); }
if (stacktype === 'group' && yGroup) {
yScale.domain([0, yGroupMax]);
xScale.rangeRoundBands([0, width], 0.2);
} else {
yScale.domain([0, yMax]);
xScale.rangeRoundBands([0, width], 0.2);
}
if (stacktype === 'zero' && yGroup) {
yScale.domain([0, yStackMax]);
} else {
yScale.domain([0, yStack]);
}
/* Update the range of the scale with new width/height */
if (stacktype === "group") { xScale.rangeRoundBands([0, width], 0.4); }
else { xScale.rangeRoundBands([0, width], 0.1); }
yScale.range([height, 0]).nice();
xAxis.ticks(Math.max(width/50, 2));
yAxis.ticks(Math.max(height/20, 2)).tickSize(-(width), 0);
if (width < 300 && height < 80) {
g.select('.x.axis').style('display', 'none');
} else {
g.select('.x.axis').style('display', 'initial');
g.select('.y.axis').style('display', 'initial');
}
g.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
g.selectAll(".bkgd").attr("width", width).attr("height", height);
/* Update the axis with the new scale */
g.select('.x.axis')
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
g.select('.y.axis')
.call(yAxis);
/* Force D3 to recalculate and update the line */
if (stacktype === "group") {
layer.selectAll("rect")
.attr( "x", function (d, i, j) { return xScale(d.x) + xScale.rangeBand() / n * j; })
.attr("width", xScale.rangeBand() / n)
.attr( "y", function (d) { return yScale(d.y); })
.attr( "height", function (d) { return height - yScale(d.y); });
}
g.selectAll('rect')
.attr("width", xScale.rangeBand())
.attr("x", function(d) { return xScale(d.x); })
.attr("height", function(d) { return yScale(d.y0) - yScale(d.y0 + d.y); })
.attr("y", function(d) { return yScale(d.y0 + d.y); });
});
}
chart.margin = function() {
if (!args.margin) { return margin; }
margin.top = typeof args.margin.top !== 'undefined' ? args.margin.top : margin.top;
margin.right = typeof args.margin.right !== 'undefined' ? args.margin.right : margin.right;
margin.bottom = typeof args.margin.bottom !== 'undefined' ? args.margin.bottom : margin.bottom;
margin.left = typeof args.margin.left !== 'undefined' ? args.margin.left : margin.left;
return margin;
};
chart.width = function() {
if (!args.width) { return width; }
width = args.width;
return width;
};
chart.height = function() {
if (!args.height) { return height; }
height = args.height;
return height;
};
chart.color = function() {
if (!args.color) { return color; }
color = args.color;
return color;
};
return chart;
};
});

View file

@ -1,13 +0,0 @@
(function(root, factory) {
'use strict';
if (typeof define === 'function' && define.amd) {
define(factory);
} else if (typeof module === 'object' && module.exports) {
module.exports = factory();
} else {
root.k4 = factory();
}
}(this, function() {
var k4 = { version: '0.0.0' };

View file

@ -1,278 +1,285 @@
k4.tooltip = function() {
'use strict';
define(function(require) {
"use strict";
// Based on Justin Palmer's d3.tip() function
var d3 = require('d3');
var direction = d3_tip_direction,
offset = d3_tip_offset,
html = d3_tip_html,
node = initNode(),
svg = null,
point = null,
target = null;
return function() {
'use strict';
function tip(vis) {
svg = getSVGNode(vis);
point = svg.createSVGPoint();
document.body.appendChild(node);
}
// Based on Justin Palmer's d3.tip() function
// Public - show the tooltip on the screen
//
// Returns a tip
tip.show = function() {
var args = Array.prototype.slice.call(arguments);
if(args[args.length - 1] instanceof SVGElement) { target = args.pop(); }
var direction = d3_tip_direction,
offset = d3_tip_offset,
html = d3_tip_html,
node = initNode(),
svg = null,
point = null,
target = null;
var content = html.apply(this, args),
poffset = offset.apply(this, args),
dir = direction.apply(this, args),
nodel = d3.select(node),
i = directions.length,
coords;
function tip(vis) {
svg = getSVGNode(vis);
point = svg.createSVGPoint();
document.body.appendChild(node);
}
nodel.html(content)
.style({ opacity: 1, 'pointer-events': 'all' });
// Public - show the tooltip on the screen
//
// Returns a tip
tip.show = function() {
var args = Array.prototype.slice.call(arguments);
if(args[args.length - 1] instanceof SVGElement) { target = args.pop(); }
while(i--) nodel.classed(directions[i], false);
coords = direction_callbacks.get(dir).apply(this);
nodel.classed(dir, true).style({
top: (coords.top + poffset[0]) + 'px',
left: (coords.left + poffset[1]) + 'px'
});
var content = html.apply(this, args),
poffset = offset.apply(this, args),
dir = direction.apply(this, args),
nodel = d3.select(node),
i = directions.length,
coords;
return tip;
};
nodel.html(content)
.style({ opacity: 1, 'pointer-events': 'all' });
// Public - hide the tooltip
//
// Returns a tip
tip.hide = function() {
var nodel = d3.select(node);
nodel.style({ opacity: 0, 'pointer-events': 'none' });
return tip;
};
while(i--) nodel.classed(directions[i], false);
coords = direction_callbacks.get(dir).apply(this);
nodel.classed(dir, true).style({
top: (coords.top + poffset[0]) + 'px',
left: (coords.left + poffset[1]) + 'px'
});
// Public: Proxy attr calls to the d3 tip container. Sets or gets attribute value.
//
// n - name of the attribute
// v - value of the attribute
//
// Returns tip or attribute value
tip.attr = function(n, v) {
if (arguments.length < 2 && typeof n === 'string') {
return d3.select(node).attr(n);
} else {
var args = Array.prototype.slice.call(arguments);
d3.selection.prototype.attr.apply(d3.select(node), args);
return tip;
};
// Public - hide the tooltip
//
// Returns a tip
tip.hide = function() {
var nodel = d3.select(node);
nodel.style({ opacity: 0, 'pointer-events': 'none' });
return tip;
};
// Public: Proxy attr calls to the d3 tip container. Sets or gets attribute value.
//
// n - name of the attribute
// v - value of the attribute
//
// Returns tip or attribute value
tip.attr = function(n, v) {
if (arguments.length < 2 && typeof n === 'string') {
return d3.select(node).attr(n);
} else {
var args = Array.prototype.slice.call(arguments);
d3.selection.prototype.attr.apply(d3.select(node), args);
}
return tip;
};
// Public: Proxy style calls to the d3 tip container. Sets or gets a style value.
//
// n - name of the property
// v - value of the property
//
// Returns tip or style property value
tip.style = function(n, v) {
if (arguments.length < 2 && typeof n === 'string') {
return d3.select(node).style(n)
} else {
var args = Array.prototype.slice.call(arguments);
d3.selection.prototype.style.apply(d3.select(node), args);
}
return tip;
};
// Public: Set or get the direction of the tooltip
//
// v - One of n(north), s(south), e(east), or w(west), nw(northwest),
// sw(southwest), ne(northeast) or se(southeast)
//
// Returns tip or direction
tip.direction = function(v) {
if (!arguments.length) { return direction; }
direction = v === null ? v : d3.functor(v);
return tip;
};
// Public: Sets or gets the offset of the tip
//
// v - Array of [x, y] offset
//
// Returns offset or
tip.offset = function(v) {
if (!arguments.length) { return offset; }
offset = v === null ? v : d3.functor(v);
return tip;
};
// Public: sets or gets the html value of the tooltip
//
// v - String value of the tip
//
// Returns html value or tip
tip.html = function(v) {
if (!arguments.length) { return html; }
html = v === null ? v : d3.functor(v);
return tip;
};
function d3_tip_direction() { return 'n'; }
function d3_tip_offset() { return [0, 0]; }
function d3_tip_html() { return ' '; }
var direction_callbacks = d3.map({
n: direction_n,
s: direction_s,
e: direction_e,
w: direction_w,
nw: direction_nw,
ne: direction_ne,
sw: direction_sw,
se: direction_se
}),
directions = direction_callbacks.keys();
function direction_n() {
var bbox = getScreenBBox();
return {
top: bbox.n.y - node.offsetHeight,
left: bbox.n.x - node.offsetWidth / 2
};
}
function direction_s() {
var bbox = getScreenBBox();
return {
top: bbox.s.y,
left: bbox.s.x - node.offsetWidth / 2
};
}
function direction_e() {
var bbox = getScreenBBox();
return {
top: bbox.e.y - node.offsetHeight / 2,
left: bbox.e.x
};
}
function direction_w() {
var bbox = getScreenBBox();
return {
top: bbox.w.y - node.offsetHeight / 2,
left: bbox.w.x - node.offsetWidth
};
}
function direction_nw() {
var bbox = getScreenBBox();
return {
top: bbox.nw.y - node.offsetHeight,
left: bbox.nw.x - node.offsetWidth
};
}
function direction_ne() {
var bbox = getScreenBBox();
return {
top: bbox.ne.y - node.offsetHeight,
left: bbox.ne.x
};
}
function direction_sw() {
var bbox = getScreenBBox();
return {
top: bbox.sw.y,
left: bbox.sw.x - node.offsetWidth
};
}
function direction_se() {
var bbox = getScreenBBox();
return {
top: bbox.se.y,
left: bbox.e.x
};
}
function initNode() {
var node = d3.select(document.createElement('div'));
node.style({
position: 'absolute',
top: 0,
opacity: 0,
'pointer-events': 'none',
'box-sizing': 'border-box'
});
return node.node();
}
function getSVGNode(el) {
el = el.node();
if(el.tagName.toLowerCase() === 'svg') { return el; }
return el.ownerSVGElement
}
// Private - gets the screen coordinates of a shape
//
// Given a shape on the screen, will return an SVGPoint for the directions
// n(north), s(south), e(east), w(west), ne(northeast), se(southeast), nw(northwest),
// sw(southwest).
//
// +-+-+
// | |
// + +
// | |
// +-+-+
//
// Returns an Object {n, s, e, w, nw, sw, ne, se}
function getScreenBBox() {
var targetel = target || d3.event.target,
bbox = {},
matrix = targetel.getScreenCTM(),
tbbox = targetel.getBBox(),
width = tbbox.width,
height = tbbox.height,
x = tbbox.x,
y = tbbox.y,
scrollEl = document.documentElement ? document.documentElement : document.body,
scrollTop = scrollEl.scrollTop,
scrollLeft = scrollEl.scrollLeft;
point.x = x + scrollLeft;
point.y = y + scrollTop;
bbox.nw = point.matrixTransform(matrix);
point.x += width;
bbox.ne = point.matrixTransform(matrix);
point.y += height;
bbox.se = point.matrixTransform(matrix);
point.x -= width;
bbox.sw = point.matrixTransform(matrix);
point.y -= height / 2;
bbox.w = point.matrixTransform(matrix);
point.x += width;
bbox.e = point.matrixTransform(matrix);
point.x -= width / 2;
point.y -= height / 2;
bbox.n = point.matrixTransform(matrix);
point.y += height;
bbox.s = point.matrixTransform(matrix);
return bbox;
}
return tip;
};
// Public: Proxy style calls to the d3 tip container. Sets or gets a style value.
//
// n - name of the property
// v - value of the property
//
// Returns tip or style property value
tip.style = function(n, v) {
if (arguments.length < 2 && typeof n === 'string') {
return d3.select(node).style(n)
} else {
var args = Array.prototype.slice.call(arguments);
d3.selection.prototype.style.apply(d3.select(node), args);
}
return tip;
};
// Public: Set or get the direction of the tooltip
//
// v - One of n(north), s(south), e(east), or w(west), nw(northwest),
// sw(southwest), ne(northeast) or se(southeast)
//
// Returns tip or direction
tip.direction = function(v) {
if (!arguments.length) { return direction; }
direction = v === null ? v : d3.functor(v);
return tip;
};
// Public: Sets or gets the offset of the tip
//
// v - Array of [x, y] offset
//
// Returns offset or
tip.offset = function(v) {
if (!arguments.length) { return offset; }
offset = v === null ? v : d3.functor(v);
return tip;
};
// Public: sets or gets the html value of the tooltip
//
// v - String value of the tip
//
// Returns html value or tip
tip.html = function(v) {
if (!arguments.length) { return html; }
html = v === null ? v : d3.functor(v);
return tip;
};
function d3_tip_direction() { return 'n'; }
function d3_tip_offset() { return [0, 0]; }
function d3_tip_html() { return ' '; }
var direction_callbacks = d3.map({
n: direction_n,
s: direction_s,
e: direction_e,
w: direction_w,
nw: direction_nw,
ne: direction_ne,
sw: direction_sw,
se: direction_se
}),
directions = direction_callbacks.keys();
function direction_n() {
var bbox = getScreenBBox();
return {
top: bbox.n.y - node.offsetHeight,
left: bbox.n.x - node.offsetWidth / 2
};
}
function direction_s() {
var bbox = getScreenBBox();
return {
top: bbox.s.y,
left: bbox.s.x - node.offsetWidth / 2
};
}
function direction_e() {
var bbox = getScreenBBox();
return {
top: bbox.e.y - node.offsetHeight / 2,
left: bbox.e.x
};
}
function direction_w() {
var bbox = getScreenBBox();
return {
top: bbox.w.y - node.offsetHeight / 2,
left: bbox.w.x - node.offsetWidth
};
}
function direction_nw() {
var bbox = getScreenBBox();
return {
top: bbox.nw.y - node.offsetHeight,
left: bbox.nw.x - node.offsetWidth
};
}
function direction_ne() {
var bbox = getScreenBBox();
return {
top: bbox.ne.y - node.offsetHeight,
left: bbox.ne.x
};
}
function direction_sw() {
var bbox = getScreenBBox();
return {
top: bbox.sw.y,
left: bbox.sw.x - node.offsetWidth
};
}
function direction_se() {
var bbox = getScreenBBox();
return {
top: bbox.se.y,
left: bbox.e.x
};
}
function initNode() {
var node = d3.select(document.createElement('div'));
node.style({
position: 'absolute',
top: 0,
opacity: 0,
'pointer-events': 'none',
'box-sizing': 'border-box'
});
return node.node();
}
function getSVGNode(el) {
el = el.node();
if(el.tagName.toLowerCase() === 'svg') { return el; }
return el.ownerSVGElement
}
// Private - gets the screen coordinates of a shape
//
// Given a shape on the screen, will return an SVGPoint for the directions
// n(north), s(south), e(east), w(west), ne(northeast), se(southeast), nw(northwest),
// sw(southwest).
//
// +-+-+
// | |
// + +
// | |
// +-+-+
//
// Returns an Object {n, s, e, w, nw, sw, ne, se}
function getScreenBBox() {
var targetel = target || d3.event.target,
bbox = {},
matrix = targetel.getScreenCTM(),
tbbox = targetel.getBBox(),
width = tbbox.width,
height = tbbox.height,
x = tbbox.x,
y = tbbox.y,
scrollEl = document.documentElement ? document.documentElement : document.body,
scrollTop = scrollEl.scrollTop,
scrollLeft = scrollEl.scrollLeft;
point.x = x + scrollLeft;
point.y = y + scrollTop;
bbox.nw = point.matrixTransform(matrix);
point.x += width;
bbox.ne = point.matrixTransform(matrix);
point.y += height;
bbox.se = point.matrixTransform(matrix);
point.x -= width;
bbox.sw = point.matrixTransform(matrix);
point.y -= height / 2;
bbox.w = point.matrixTransform(matrix);
point.x += width;
bbox.e = point.matrixTransform(matrix);
point.x -= width / 2;
point.y -= height / 2;
bbox.n = point.matrixTransform(matrix);
point.y += height;
bbox.s = point.matrixTransform(matrix);
return bbox;
}
return tip;
};
});

View file

@ -0,0 +1,11 @@
describe('Simple Tests:', function() {
it("b is true because its true man", function() {
var b = true;
expect(b).toBe(true);
});
it('e is not a number', function() {
var e = 1;
expect(e).toBe(1);
});
});

View file

@ -0,0 +1,46 @@
describe('Heatmap Chart Test Cases', function() {
'use strict';
var div, chart, cols = 50, rows = 24, data = [];
for (var x = 1; x < cols+1; x++) {
for (var y = 1; y < rows+1; y++) {
data.push({ x: x, y: y, z: Math.random() });
}
}
beforeEach(function() {
div = d3.select('body').append('div').attr('id', 'heatmap');
chart = k4.heatmap();
div.datum(data).call(chart);
});
afterEach(function() {
div.remove();
});
// Tests
it('should generate svg', function() {
expect(d3.select('svg')[0].length).not.toBe(0);
});
it('should set default svg height and width', function() {
expect(div.select('svg').attr('width')).toBe('500');
expect(div.select('svg').attr('height')).toBe('500');
});
it('should allow changing svg height and width', function() {
chart.width(760).height(400);
div.datum(data).call(chart);
expect(div.select('svg').attr('width')).toBe('760');
expect(div.select('svg').attr('height')).toBe('400');
});
it('should have random data selection with z value >= 0 && <= 1', function() {
var n = Math.floor(Math.random()*data.length);
expect(n).toBeGreaterThan(0);
expect(data[n].z).not.toBeGreaterThan(1);
expect(data[n].z).not.toBeLessThan(0);
});
});

View file

@ -0,0 +1,176 @@
describe('Unit tests', function() {
'use strict';
var chart,
data,
div,
formatDate;
// Tests
describe('Area Chart Test Cases', function() {
beforeEach(function() {
formatDate = d3.time.format("%b %Y").parse;
data = [
{x: "Jan 2013", y: 256},
{x: "Feb 2013", y: 770},
{x: "May 2013", y: 159},
{x: "Oct 2013", y: 106}
];
div = d3.select('body').append('div').attr('id', 'chart');
chart = k4.area()
.interpolate("cardinal")
.x(function(d) { return formatDate(d.x); })
.y(function(d) { return d.y; });
div.datum(data).call(chart);
});
afterEach(function() {
div.remove();
});
it('should generate svg', function() {
expect(d3.select('svg')[0][0]).not.toBe('undefined');
});
it('should set default svg height and width', function() {
expect(div.select('svg').attr('width')).toBe('960');
expect(div.select('svg').attr('height')).toBe('500');
});
it('should allow changing svg height and width', function() {
chart.width(1160).height(450);
div.datum(data).call(chart);
expect(div.select('svg').attr('width')).toBe('1160');
expect(div.select('svg').attr('height')).toBe('450');
});
});
describe('Pie Chart Test Cases', function() {
beforeEach(function() {
data = [
{label: "DEN", value: 256},
{label: "SEA", value: 770},
{label: "SF", value: 159},
{label: "NE", value: 106}
];
div = d3.select('body').append('div').attr('id', 'chart');
chart = k4.pie()
.label(function(d) { return d.label; })
.value(function(d) { return d.value; });
div.datum(data).call(chart);
});
afterEach(function() {
div.remove();
});
// Tests
it('should generate svg', function() {
expect(d3.select('svg')[0][0]).not.toBe('undefined');
});
it('should set default svg height and width', function() {
expect(div.select('svg').attr('width')).toBe('500');
expect(div.select('svg').attr('height')).toBe('500');
});
it('should allow changing svg height and width', function() {
chart.width(1160).height(450);
div.datum(data).call(chart);
expect(div.select('svg').attr('width')).toBe('1160');
expect(div.select('svg').attr('height')).toBe('450');
});
});
describe('Line Chart Test Cases', function() {
beforeEach(function() {
formatDate = d3.time.format("%b %Y").parse;
data = [
{x: "Jan 2013", y: 256},
{x: "Feb 2013", y: 770},
{x: "May 2013", y: 159},
{x: "Oct 2013", y: 106}
];
div = d3.select('body').append('div').attr('id', 'chart');
chart = k4.line()
.interpolate("cardinal")
.x(function(d) { return formatDate(d.x); })
.y(function(d) { return d.y; });
div.datum(data).call(chart);
});
afterEach(function() {
div.remove();
});
it('should generate svg', function() {
expect(d3.select('svg')[0][0]).not.toBe('undefined');
});
it('should set default svg height and width', function() {
expect(div.select('svg').attr('width')).toBe('960');
expect(div.select('svg').attr('height')).toBe('500');
});
it('should allow changing svg height and width', function() {
chart.width(1160).height(450);
div.datum(data).call(chart);
expect(div.select('svg').attr('width')).toBe('1160');
expect(div.select('svg').attr('height')).toBe('450');
});
});
describe('Sparkline Chart Test Cases', function() {
beforeEach(function() {
formatDate = d3.time.format("%b %Y").parse;
data = [
{x: "Jan 2013", y: 256},
{x: "Feb 2013", y: 770},
{x: "May 2013", y: 159},
{x: "Oct 2013", y: 106}
];
div = d3.select('body').append('div').attr('id', 'chart');
chart = k4.sparkline()
.interpolate("cardinal")
.x(function(d) { return formatDate(d.x); })
.y(function(d) { return d.y; });
div.datum(data).call(chart);
});
afterEach(function() {
div.remove();
});
it('should generate svg', function() {
expect(d3.select('svg')[0][0]).not.toBe('undefined');
});
it('should set default svg height and width', function() {
expect(div.select('svg').attr('width')).toBe('760');
expect(div.select('svg').attr('height')).toBe('120');
});
it('should allow changing svg height and width', function() {
chart.width(1160).height(450);
div.datum(data).call(chart);
expect(div.select('svg').attr('width')).toBe('1160');
expect(div.select('svg').attr('height')).toBe('450');
});
});
});

View file

@ -7,7 +7,10 @@
<meta name="viewport" content="width=device-width">
<title>Kibana 4</title>
<!-- load the root require context -->
<script src="bower_components/d3/d3.js"></script>
<script src="bower_components/requirejs/require.js"></script>
<script src="kibana/require.config.js"></script>
<script>require(['kibana'], function () {});</script>
<link rel="stylesheet" href="kibana/styles/main.css" >

View file

@ -45,10 +45,7 @@ define(function (require) {
min_cols: 12,
max_cols: 12,
resize: {
enabled: true,
stop: function (event, ui, widget) {
console.log(widget.height(), widget.width());
}
enabled: true
},
serialize_params: function (el, wgd) {
return {

View file

@ -69,16 +69,16 @@
clear: both;
}
body.application-dashboard {
background-color: #1e6d74;
background-color: #18bc9c;
}
div.application div.dashboard-container {
width: 100%;
background-color: #1e6d74;
background-color: #18bc9c;
}
[dashboard-grid].gridster {
list-style-type: none;
display: block;
background-color: #1e6d74;
background-color: #18bc9c;
margin-bottom: 0;
}
[dashboard-grid].gridster .preview-holder {
@ -88,7 +88,7 @@ div.application div.dashboard-container {
[dashboard-grid].gridster li.gs-w {
background: #fff;
padding: 5px;
color: #1e6d74;
color: #18bc9c;
font-weight: bold;
font-size: 20px;
padding: 10px;

View file

@ -1,7 +1,7 @@
@import (reference) "../../../../bower_components/bootstrap/less/bootstrap.less";
@import (reference) "../../../../bower_components/bootstrap/less/theme.less";
@import (reference) "../../../styles/_bootstrap.less";
@import (reference) "../../../styles/theme/_theme.less";
@dashboard-background: #1E6D74;
@dashboard-background: #18bc9c;
body.application-dashboard {
background-color: @dashboard-background;

View file

@ -7,6 +7,7 @@ define(function (require) {
var app = require('modules').get('app/discover');
require('services/state');
require('directives/fixed_scroll');
require('routes')
.when('/discover/:id?', {
@ -95,13 +96,27 @@ define(function (require) {
search.onResults().then(function onResults(resp) {
if (!$scope.fields) getFields();
$scope.rows = resp.hits.hits;
$scope.chart = {rows: [{columns: [{
label: 'Events over time',
xAxisLabel: 'DateTime',
yAxisLabel: 'Hits',
layers: [
{
key: 'somekey',
values: _.map(resp.aggregations.events.buckets, function (bucket) {
return { y: bucket.doc_count, x: bucket.key_as_string };
})
}
]
}]}]};
return search.onResults(onResults);
});
$scope.$on('$destroy', _.bindKey(search, 'cancelPending'));
$scope.getSort = function () {
return $scope.state.sort;
};
@ -153,6 +168,15 @@ define(function (require) {
query_string: {
query: $scope.state.query
}
})
.aggs({
events: {
date_histogram: {
field: '@timestamp',
interval: '12h',
format: 'yyyy-MM-dd'
}
}
});
}
@ -267,7 +291,6 @@ define(function (require) {
};
function refreshColumns() {
// Get all displayed field names;
var fields = _.pluck(_.filter($scope.fields, function (field) {
return field.display;

View file

@ -0,0 +1,17 @@
define(function (require) {
var app = require('modules').get('app/discover');
var html = require('text!../partials/discover_field.html');
var _ = require('lodash');
require('directives/css_truncate');
require('directives/field_name');
app.directive('discoverField', function () {
return {
restrict: 'E',
template: html,
replace: true
};
});
});

View file

@ -1,9 +1,13 @@
define(function (require) {
var app = require('modules').get('app/discover');
var html = require('text!./partials/field_chooser.html');
var html = require('text!../partials/field_chooser.html');
var _ = require('lodash');
require('directives/css_truncate');
require('directives/field_name');
require('./discover_field');
app.directive('discFieldChooser', function () {
return {
@ -43,23 +47,6 @@ define(function (require) {
$scope.filterFunc(field.name, value, operation);
};
$scope.typeIcon = function (fieldType) {
switch (fieldType)
{
case 'source':
return 'fa-file-text-o';
case 'string':
return 'fa-sort-alpha-asc';
case 'number':
return 'fa-sort-numeric-asc';
case 'date':
return 'fa-clock-o';
case 'ip':
return 'fa-laptop';
default:
}
};
var getFieldValues = function (data, field) {
return _.map(data, function (row) {
var val;

View file

@ -14,16 +14,19 @@ define(function (require) {
link: function ($scope, elem) {
var init = function () {
/*
// This elem should already have a height/width
var myChart = new k4.Chart(elem, {type: 'timechart', doSomething: true, draggable: false});
var myChart = new k4.Chart(elem[0], {
type: 'histogram',
stacktype: 'zero',
yGroup: true,
color: ['#81dfe2', '#0762b7']
});
myChart.on('hover', function (elem, event) {
})
*/
//myChart.render($scope.data);
$scope.$watch('data', function (data) {
if (!_.isUndefined(data)) {
myChart.render(data);
}
});
};
// Start the directive

View file

@ -9,16 +9,17 @@
<form class="navbar-form" ng-submit="fetch()">
<div class="form-group" style="display:inline;">
<div class="input-group">
<span class="input-group-addon"><span class="fa fa-search"></span></span>
<input placeholder="Search..." type="text" class="form-control" ng-model="state.query">
<span class="input-group-addon" ng-click="fetch()"><span class="fa fa-search"></span></span>
</div>
</div>
</form>
</nav>
<config config-template="configTemplate" config-object="opts" config-close="configClose" config-submit="fetch"></config>
<div class="container-fluid">
<div class="row">
<div class="col-md-2 discovery-field-container">
<div class="col-md-2 discover-field-container">
<disc-field-chooser
fields="fields"
toggle="toggleField"
@ -28,15 +29,20 @@
</disc-field-chooser>
</div>
<div class="col-md-10">
<discover-timechart></discover-timechart>
<kbn-table style="overflow-x:auto" class="table table-condensed"
rows="rows"
columns="state.columns"
refresh="fetch"
max-length="opts.maxSummaryLength"
get-sort="getSort"
set-sort="setSort">
</kbn-table>
<discover-timechart data="chart" height="150"></discover-timechart>
<div class="discover-table"
fixed-scroll='table'
fixed-scroll-trigger="state.columns">
<kbn-table class="table table-condensed"
rows="rows"
columns="state.columns"
refresh="fetch"
max-length="opts.maxSummaryLength"
get-sort="getSort"
set-sort="setSort">
</kbn-table>
</div>
</div>
</div>
</div>

View file

@ -1,7 +1,7 @@
define(function (require, module, exports) {
require('directives/table');
require('./field_chooser');
require('./saved_searches/service');
require('./timechart');
require('./directives/timechart');
require('./directives/field_chooser');
require('./controllers/discover');
});

View file

@ -0,0 +1,37 @@
<li class="discover-field-item">
<div ng-click="details(field)" class="discover-field-name">
<span field-name="field.name" field-type="field.type"></span>
</div>
<div class="discover-field-details" ng-if="field.details">
<a ng-click="toggle(field.name)" class="pull-right btn btn-default btn-xs discover-field-toggle">
{{field.display ? 'Hide' : 'Show'}}
</a>
<span bo-if="!field.details.error">Present in {{field.details.exists}}/{{field.details.total}} records</span>
<div class="clearfix"></div>
<div bo-if="field.details.error" class="discover-field-details-error">{{field.details.error}}</div>
<div bo-if="!field.details.error">
<div ng-repeat="bucket in field.details.buckets" class="discover-field-details-item">
<div>
<i class="fa fa-search-minus pull-right discover-field-details-filter"
ng-click="filter(field, bucket.value, '-')"></i>
<i class="fa fa-search-plus pull-right discover-field-details-filter"
ng-click="filter(field, bucket.value, '+')"></i>
<div css-truncate css-truncate-expandable="true" class="discover-field-details-value">
{{bucket.value}}
</div>
</div>
<progressbar value="bucket.percent" max="100" animate="false"><span>{{bucket.percent}}%</span></progressbar>
</div>
</div>
<div>
</li>

View file

@ -1,63 +1,17 @@
<div class="discover-field-list">
<h5>Selected</h5>
<div class="discover-field-list-header">
<h5>Selected</h5>
</div>
<ul bindonce class="list-unstyled">
<li ng-repeat="field in fields|filter:{display:true}" class="discover-field-item">
<a ng-click="toggle(field.name)" class="discover-field-add">
<i class="fa fa-minus-circle"></i>
</a>
<a ng-click="details(field)" class="discover-field-name"><i ng-click="clicked()" class="fa" bo-class="typeIcon(field.type)"></i> <span bo-text="field.name"></span></a>
<div class="discover-field-details" ng-if="field.details">
<div bo-if="field.details.error">{{field.details.error}}</div>
<div bo-if="!field.details.error">
<div ng-repeat="bucket in field.details.buckets" class="discover-field-details-item">
<div>
<i class="fa fa-search-minus pull-right discover-field-details-filter"
ng-click="filter(field, bucket.value, '-')"></i>
<i class="fa fa-search-plus pull-right discover-field-details-filter"
ng-click="filter(field, bucket.value, '+')"></i>
<div css-truncate css-truncate-expandable="true" class="discover-field-details-value">
{{bucket.value}}
</div>
</div>
<progressbar value="bucket.percent" max="100" animate="false"><span>{{bucket.percent}}%</span></progressbar>
</div>
</div>
<div>
</li>
<discover-field field="field" ng-repeat="field in fields|filter:{display:true}">
</discover-field>
</ul>
<h5>Available</h5>
<div class="discover-field-list-header">
<h5>Available</h5>
</div>
<ul bindonce class="list-unstyled">
<li ng-repeat="field in fields|filter:{display:!true}" class="discover-field-item">
<a ng-click="toggle(field.name)" class="discover-field-add">
<i class="fa fa-plus-circle"></i>
</a>
<a ng-click="details(field)" class="discover-field-name"><i ng-click="clicked()" class="fa" bo-class="typeIcon(field.type)"></i> <span bo-text="field.name"></span></a>
<div class="discover-field-details" ng-if="field.details">
<div bo-if="field.details.error">{{field.details.error}}</div>
<div bo-if="!field.details.error">
<div ng-repeat="bucket in field.details.buckets" class="discover-field-details-item">
<div>
<i class="fa fa-search-minus pull-right discover-field-details-filter"
ng-click="filter(field, bucket.value, '-')"></i>
<i class="fa fa-search-plus pull-right discover-field-details-filter"
ng-click="filter(field, bucket.value, '+')"></i>
<div css-truncate css-truncate-expandable="true" class="discover-field-details-value">
{{bucket.value}}
</div>
</div>
<progressbar value="bucket.percent" max="100" animate="false"><span>{{bucket.percent}}%</span></progressbar>
</div>
</div>
<div>
</li>
<discover-field field="field" ng-repeat="field in fields|filter:{display:false}">
</discover-field>
</ul>
</div>

View file

@ -68,23 +68,50 @@
.modal-footer:after {
clear: both;
}
.discover-field-list .discover-field-item .discover-field-add {
visibility: hidden;
.application-discover {
overflow-x: hidden;
}
.discover-field-list .discover-field-item:hover .discover-field-add {
visibility: visible;
.discover-table {
overflow-y: auto;
overflow-x: auto;
margin-top: 10px;
padding-left: 0px !important;
padding-right: 0px !important;
}
.discover-field-list .discover-field-name:hover {
text-decoration: none;
margin-left: 0;
.discover-field-container {
padding-left: 0px !important;
padding-right: 0px !important;
background-color: #f5f5f5;
border-right: 1px solid #e3e3e3;
border-bottom: 1px solid #e3e3e3;
}
.discover-field-list .discover-field-list-header {
padding-left: 10px;
color: #777777;
}
.discover-field-list .discover-field-item {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
font-size: 11px;
border-top: 1px solid #e3e3e3;
}
.discover-field-list .discover-field-name {
padding: 5px 10px;
}
.discover-field-list .discover-field-name:hover,
.discover-field-list .discover-field-name:hover .text-muted {
background-color: #428bca;
color: #ffffff;
}
.discover-field-list .discover-field-details {
font-size: 12px;
margin-left: 15px;
padding: 5px;
background-color: #f5f5f5;
border-radius: 4px;
border: 1px solid #dddddd;
border-top: 1px solid #e3e3e3;
padding: 5px 10px;
background-color: #ffffff;
color: #333333;
}
.discover-field-list .discover-field-details .discover-field-details-error {
margin-top: 5px;
}
.discover-field-list .discover-field-details .discover-field-details-item {
margin-top: 5px;

View file

@ -1,27 +1,61 @@
@import (reference) "../../../../bower_components/bootstrap/less/bootstrap.less";
@import (reference) "../../../../bower_components/bootstrap/less/theme.less";
@import (reference) "../../../styles/_bootstrap.less";
@import (reference) "../../../styles/theme/_theme.less";
@import (reference) "../../../styles/_variables.less";
.application-discover {
overflow-x: hidden;
}
.discover-table {
overflow-y: auto;
overflow-x: auto;
margin-top: 10px;
padding-left: 0px !important;
padding-right: 0px !important;
}
.discover-field-container {
padding-left: 0px !important;
padding-right: 0px !important;
background-color: @well-bg;
border-right: 1px solid @well-border;
border-bottom: 1px solid @well-border;
}
.discover-field-list {
.discover-field-item .discover-field-add {
visibility:hidden;
.discover-field-list-header {
padding-left: 10px;
color: @navbar-default-color;
}
.discover-field-item:hover .discover-field-add {
visibility:visible;
.discover-field-item {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
font-size: @font-size-smaller;
border-top: 1px solid @well-border;
}
.discover-field-name:hover {
text-decoration: none;
margin-left: 0;
.discover-field-name {
padding: 5px 10px;
}
.discover-field-name:hover, .discover-field-name:hover .text-muted {
background-color: @component-active-bg;
color: @component-active-color;
}
.discover-field-details {
font-size: @font-size-small;
margin-left: 15px;
padding: 5px;
background-color: @well-bg;
border-radius: @border-radius-base;
border: 1px solid @table-border-color;
border-top: 1px solid @well-border;
padding: 5px 10px;
background-color: @body-bg;
color: @text-color;
.discover-field-details-error {
margin-top: 5px;
}
.discover-field-details-item {
margin-top: 5px;

View file

@ -1,4 +1,5 @@
@import (reference) "../../../../bower_components/bootstrap/less/bootstrap.less";
@import (reference) "../../../styles/_bootstrap.less";
@import (reference) "../../../styles/theme/_theme.less";
.vis-config-panel {
padding: 0;

View file

@ -0,0 +1,39 @@
define(function (require) {
var module = require('modules').get('kibana/directives');
var $ = require('jquery');
var _ = require('lodash');
module.directive('fieldName', function ($compile) {
return {
restrict: 'A',
scope: {
fieldName: '=',
fieldType: '='
},
link: function ($scope, $elem, attrs) {
var typeIcon = function (fieldType) {
switch (fieldType)
{
case 'source':
return $('<i class="fa fa-file-text-o"></i> ');
case 'string':
return $('<i><strong>t</strong></i> ');
case 'number':
return $('<i><strong>#</strong></i> ');
case 'date':
return $('<i class="fa fa-clock-o"></i> ');
case 'ip':
return $('<i class="fa fa-laptop"></i> ');
default:
return $('<i><strong>?</strong></i> ');
}
};
var icon = typeIcon($scope.fieldType).addClass('text-muted').css({'margin-right': '5px'});
$elem.text($scope.fieldName).prepend(icon);
}
};
});
});

View file

@ -0,0 +1,110 @@
// Creates a fake scrollbar at the bottom of an element. Useful for infinite scrolling components
define(function (require) {
var module = require('modules').get('kibana/directives');
var $ = require('jquery');
var _ = require('lodash');
module.directive('fixedScroll', function ($timeout) {
return {
restrict: 'A',
scope: {
fixedScrollTrigger: '=fixedScrollTrigger',
anchor: '@fixedScroll',
},
link: function ($scope, $elem, attrs) {
var options = {
contentElement: _.isUndefined($scope.anchor) ? undefined : $elem.find($scope.anchor),
fixedScrollMarkup: '<div class="fixedScroll-container" ' +
'style="height: 20px;"><div class="fixedScroll-scroll" style="height: 20px;"></div></div>',
fixedScrollInnerSelector: '.fixedScroll-scroll'
};
var innerElem;
// Set the inner element that gives context to the scroll
if (options.contentElement !== undefined && $elem.find(options.contentElement).length !== 0) {
innerElem = $elem.find(options.contentElement);
} else {
innerElem = $elem.find('>:first-child');
}
var fixedScroll = $($(options.fixedScrollMarkup));
fixedScroll.css({position: 'fixed', bottom: 0});
var addScroll = function ($elem, options) {
// If content isn't wide enough to scroll, abort
if ($elem.get(0).scrollWidth <= $elem.width()) {
return;
}
// add container for fake scrollbar
$elem.after(fixedScroll);
// bind fixed scroll to real scroll
fixedScroll.bind('scroll.fixedScroll', function () {
$elem.scrollLeft(fixedScroll.scrollLeft());
});
// and bind real scroll to fixed scroll
var scrollHandler = function () {
fixedScroll.scrollLeft($elem.scrollLeft());
};
$elem.bind('scroll.fixedScroll', scrollHandler);
fixedScroll.css({'overflow-x': 'auto', 'overflow-y': 'hidden'});
$elem.css({'overflow-x': 'auto', 'overflow-y': 'hidden'});
// Check the width until it stops changing
var setWidth = function (innerElemWidth) {
$timeout(function () {
if (innerElemWidth !== innerElem.outerWidth()) {
setWidth(innerElem.outerWidth());
} else {
$(options.fixedScrollInnerSelector, fixedScroll).width(innerElem.outerWidth());
fixedScroll.width($elem.width());
}
}, 500);
};
setWidth(innerElem.outerWidth());
};
addScroll($elem, options);
var recompute = function () {
$elem.unbind('scroll.fixedScroll');
$elem.prev('div.fixedScroll-container').remove();
addScroll($elem, options);
};
// Create a watchable for the content element
$scope.innerElemWidth = function () {
return innerElem.outerWidth();
};
// Watch window size
$(window).resize(recompute);
// Watch the trigger if there is one
$scope.$watch('trigger', function () {
recompute();
});
// And watch the element width
$scope.$watch('innerElemWidth()', function (width) {
recompute();
});
// Clean up listeners
$scope.$on('$destroy', function () {
$elem.unbind('scroll.fixedScroll');
fixedScroll.unbind('scroll.fixedScroll');
});
}
};
});
});

View file

@ -28,10 +28,20 @@ define(function (require) {
if (column === sort[0]) {
return ['fa', sort[1] === 'asc' ? 'fa-sort-up' : 'fa-sort-down'];
} else {
return ['fa', 'fa-sort'];
return ['fa', 'fa-sort', 'table-header-sortchange'];
}
};
$scope.moveLeft = function (column) {
var index = _.indexOf($scope.columns, column);
_.move($scope.columns, index, --index);
};
$scope.moveRight = function (column) {
var index = _.indexOf($scope.columns, column);
_.move($scope.columns, index, ++index);
};
$scope.sort = function (column) {
var sort = $scope.getSort();
console.log('dir', sort);
@ -72,7 +82,8 @@ define(function (require) {
refresh: '=',
getSort: '=',
setSort: '=',
maxLength: '=?'
maxLength: '=?',
mapping: '=?'
},
link: function ($scope, element, attrs) {
// track a list of id's that are currently open, so that
@ -96,7 +107,7 @@ define(function (require) {
// rerender when either is changed
$scope.$watch('rows', render);
$scope.$watch('columns', render);
$scope.$watchCollection('columns', render);
$scope.$watch('maxLength', render);
// the body of the table
@ -104,6 +115,7 @@ define(function (require) {
// itterate the columns and rows, rebuild the table's html
function render() {
$body.empty();
if (!$scope.rows || $scope.rows.length === 0) return;
if (!$scope.columns || $scope.columns.length === 0) return;
@ -252,6 +264,7 @@ define(function (require) {
table.appendChild(tbody);
// itterate each row and append it to the tbody
// TODO: This doesn't work since _source is not flattened
_(row._source)
.keys()
.concat(topLevelDetails)

View file

@ -1 +1,7 @@
<th ng-repeat="name in columns">{{name}} <i ng-click="sort(name)" ng-class="headerClass(name)"></i></th>
<th ng-repeat="name in columns">
<span ng-click="sort(name)">{{name}} <i ng-class="headerClass(name)"></i> </span>
<span class="table-header-move">
<i ng-click="moveLeft(name)" class="fa fa-angle-double-left" ng-show="!$first"></i>
<i ng-click="moveRight(name)" class="fa fa-angle-double-right" ng-show="!$last"></i>
</span>
</th>

View file

@ -1,5 +1,6 @@
define(function (require) {
var _ = require('lodash');
require('utils/rison');
require('modules')
.get('kibana/services')

View file

@ -1,7 +1,10 @@
@bs-less-dir: "../../bower_components/bootstrap/less";
// Core variables and mixins
@import "@{bs-less-dir}/variables.less";
@import "theme/_variables.less";
@import "theme/_theme.less";
// Mixins
@import "@{bs-less-dir}/mixins.less";
// Reset
@ -49,6 +52,3 @@
// Utility classes
@import "@{bs-less-dir}/utilities.less";
@import "@{bs-less-dir}/responsive-utilities.less";
// automatically include the theme file
@import "@{bs-less-dir}/theme.less";

View file

@ -0,0 +1 @@
@font-size-smaller: ceil((@font-size-base * 0.75));

View file

@ -6499,346 +6499,6 @@ button.close {
display: none !important;
}
}
.btn-default,
.btn-primary,
.btn-success,
.btn-info,
.btn-warning,
.btn-danger {
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.2);
-webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 1px rgba(0, 0, 0, 0.075);
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 1px rgba(0, 0, 0, 0.075);
}
.btn-default:active,
.btn-primary:active,
.btn-success:active,
.btn-info:active,
.btn-warning:active,
.btn-danger:active,
.btn-default.active,
.btn-primary.active,
.btn-success.active,
.btn-info.active,
.btn-warning.active,
.btn-danger.active {
-webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
}
.btn:active,
.btn.active {
background-image: none;
}
.btn-default {
background-image: -webkit-linear-gradient(top, #ffffff 0%, #e0e0e0 100%);
background-image: linear-gradient(to bottom, #ffffff 0%, #e0e0e0 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0);
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
background-repeat: repeat-x;
border-color: #dbdbdb;
text-shadow: 0 1px 0 #fff;
border-color: #ccc;
}
.btn-default:hover,
.btn-default:focus {
background-color: #e0e0e0;
background-position: 0 -15px;
}
.btn-default:active,
.btn-default.active {
background-color: #e0e0e0;
border-color: #dbdbdb;
}
.btn-primary {
background-image: -webkit-linear-gradient(top, #428bca 0%, #2d6ca2 100%);
background-image: linear-gradient(to bottom, #428bca 0%, #2d6ca2 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff2d6ca2', GradientType=0);
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
background-repeat: repeat-x;
border-color: #2b669a;
}
.btn-primary:hover,
.btn-primary:focus {
background-color: #2d6ca2;
background-position: 0 -15px;
}
.btn-primary:active,
.btn-primary.active {
background-color: #2d6ca2;
border-color: #2b669a;
}
.btn-success {
background-image: -webkit-linear-gradient(top, #5cb85c 0%, #419641 100%);
background-image: linear-gradient(to bottom, #5cb85c 0%, #419641 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0);
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
background-repeat: repeat-x;
border-color: #3e8f3e;
}
.btn-success:hover,
.btn-success:focus {
background-color: #419641;
background-position: 0 -15px;
}
.btn-success:active,
.btn-success.active {
background-color: #419641;
border-color: #3e8f3e;
}
.btn-info {
background-image: -webkit-linear-gradient(top, #5bc0de 0%, #2aabd2 100%);
background-image: linear-gradient(to bottom, #5bc0de 0%, #2aabd2 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0);
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
background-repeat: repeat-x;
border-color: #28a4c9;
}
.btn-info:hover,
.btn-info:focus {
background-color: #2aabd2;
background-position: 0 -15px;
}
.btn-info:active,
.btn-info.active {
background-color: #2aabd2;
border-color: #28a4c9;
}
.btn-warning {
background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #eb9316 100%);
background-image: linear-gradient(to bottom, #f0ad4e 0%, #eb9316 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0);
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
background-repeat: repeat-x;
border-color: #e38d13;
}
.btn-warning:hover,
.btn-warning:focus {
background-color: #eb9316;
background-position: 0 -15px;
}
.btn-warning:active,
.btn-warning.active {
background-color: #eb9316;
border-color: #e38d13;
}
.btn-danger {
background-image: -webkit-linear-gradient(top, #d9534f 0%, #c12e2a 100%);
background-image: linear-gradient(to bottom, #d9534f 0%, #c12e2a 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0);
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
background-repeat: repeat-x;
border-color: #b92c28;
}
.btn-danger:hover,
.btn-danger:focus {
background-color: #c12e2a;
background-position: 0 -15px;
}
.btn-danger:active,
.btn-danger.active {
background-color: #c12e2a;
border-color: #b92c28;
}
.thumbnail,
.img-thumbnail {
-webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);
}
.dropdown-menu > li > a:hover,
.dropdown-menu > li > a:focus {
background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);
background-color: #e8e8e8;
}
.dropdown-menu > .active > a,
.dropdown-menu > .active > a:hover,
.dropdown-menu > .active > a:focus {
background-image: -webkit-linear-gradient(top, #428bca 0%, #357ebd 100%);
background-image: linear-gradient(to bottom, #428bca 0%, #357ebd 100%);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0);
background-color: #357ebd;
}
.navbar-default {
background-image: -webkit-linear-gradient(top, #ffffff 0%, #f8f8f8 100%);
background-image: linear-gradient(to bottom, #ffffff 0%, #f8f8f8 100%);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0);
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
border-radius: 4px;
-webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 5px rgba(0, 0, 0, 0.075);
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 5px rgba(0, 0, 0, 0.075);
}
.navbar-default .navbar-nav > .active > a {
background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f3f3f3 100%);
background-image: linear-gradient(to bottom, #ebebeb 0%, #f3f3f3 100%);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff3f3f3', GradientType=0);
-webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.075);
box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.075);
}
.navbar-brand,
.navbar-nav > li > a {
text-shadow: 0 1px 0 rgba(255, 255, 255, 0.25);
}
.navbar-inverse {
background-image: -webkit-linear-gradient(top, #3c3c3c 0%, #222222 100%);
background-image: linear-gradient(to bottom, #3c3c3c 0%, #222222 100%);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0);
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
}
.navbar-inverse .navbar-nav > .active > a {
background-image: -webkit-linear-gradient(top, #222222 0%, #282828 100%);
background-image: linear-gradient(to bottom, #222222 0%, #282828 100%);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222', endColorstr='#ff282828', GradientType=0);
-webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.25);
box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.25);
}
.navbar-inverse .navbar-brand,
.navbar-inverse .navbar-nav > li > a {
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
}
.navbar-static-top,
.navbar-fixed-top,
.navbar-fixed-bottom {
border-radius: 0;
}
.alert {
text-shadow: 0 1px 0 rgba(255, 255, 255, 0.2);
-webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25), 0 1px 2px rgba(0, 0, 0, 0.05);
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25), 0 1px 2px rgba(0, 0, 0, 0.05);
}
.alert-success {
background-image: -webkit-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%);
background-image: linear-gradient(to bottom, #dff0d8 0%, #c8e5bc 100%);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0);
border-color: #b2dba1;
}
.alert-info {
background-image: -webkit-linear-gradient(top, #d9edf7 0%, #b9def0 100%);
background-image: linear-gradient(to bottom, #d9edf7 0%, #b9def0 100%);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0);
border-color: #9acfea;
}
.alert-warning {
background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%);
background-image: linear-gradient(to bottom, #fcf8e3 0%, #f8efc0 100%);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0);
border-color: #f5e79e;
}
.alert-danger {
background-image: -webkit-linear-gradient(top, #f2dede 0%, #e7c3c3 100%);
background-image: linear-gradient(to bottom, #f2dede 0%, #e7c3c3 100%);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0);
border-color: #dca7a7;
}
.progress {
background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%);
background-image: linear-gradient(to bottom, #ebebeb 0%, #f5f5f5 100%);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0);
}
.progress-bar {
background-image: -webkit-linear-gradient(top, #428bca 0%, #3071a9 100%);
background-image: linear-gradient(to bottom, #428bca 0%, #3071a9 100%);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3071a9', GradientType=0);
}
.progress-bar-success {
background-image: -webkit-linear-gradient(top, #5cb85c 0%, #449d44 100%);
background-image: linear-gradient(to bottom, #5cb85c 0%, #449d44 100%);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0);
}
.progress-bar-info {
background-image: -webkit-linear-gradient(top, #5bc0de 0%, #31b0d5 100%);
background-image: linear-gradient(to bottom, #5bc0de 0%, #31b0d5 100%);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0);
}
.progress-bar-warning {
background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #ec971f 100%);
background-image: linear-gradient(to bottom, #f0ad4e 0%, #ec971f 100%);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0);
}
.progress-bar-danger {
background-image: -webkit-linear-gradient(top, #d9534f 0%, #c9302c 100%);
background-image: linear-gradient(to bottom, #d9534f 0%, #c9302c 100%);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0);
}
.list-group {
border-radius: 4px;
-webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);
}
.list-group-item.active,
.list-group-item.active:hover,
.list-group-item.active:focus {
text-shadow: 0 -1px 0 #3071a9;
background-image: -webkit-linear-gradient(top, #428bca 0%, #3278b3 100%);
background-image: linear-gradient(to bottom, #428bca 0%, #3278b3 100%);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3278b3', GradientType=0);
border-color: #3278b3;
}
.panel {
-webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
}
.panel-default > .panel-heading {
background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);
}
.panel-primary > .panel-heading {
background-image: -webkit-linear-gradient(top, #428bca 0%, #357ebd 100%);
background-image: linear-gradient(to bottom, #428bca 0%, #357ebd 100%);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0);
}
.panel-success > .panel-heading {
background-image: -webkit-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%);
background-image: linear-gradient(to bottom, #dff0d8 0%, #d0e9c6 100%);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0);
}
.panel-info > .panel-heading {
background-image: -webkit-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%);
background-image: linear-gradient(to bottom, #d9edf7 0%, #c4e3f3 100%);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0);
}
.panel-warning > .panel-heading {
background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%);
background-image: linear-gradient(to bottom, #fcf8e3 0%, #faf2cc 100%);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0);
}
.panel-danger > .panel-heading {
background-image: -webkit-linear-gradient(top, #f2dede 0%, #ebcccc 100%);
background-image: linear-gradient(to bottom, #f2dede 0%, #ebcccc 100%);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0);
}
.well {
background-image: -webkit-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%);
background-image: linear-gradient(to bottom, #e8e8e8 0%, #f5f5f5 100%);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0);
border-color: #dcdcdc;
-webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.05), 0 1px 0 rgba(255, 255, 255, 0.1);
box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.05), 0 1px 0 rgba(255, 255, 255, 0.1);
}
body {
margin: 0px;
}
@ -6854,6 +6514,10 @@ body {
position: relative;
z-index: 0;
}
.top-fixed {
position: fixed;
bottom: 0px;
}
notifications {
z-index: 1;
}
@ -6877,17 +6541,8 @@ notifications {
margin-bottom: 0px!important;
background-color: #f8f8f8;
border-color: #e7e7e7;
background-image: -webkit-linear-gradient(top, #ffffff 0%, #f8f8f8 100%);
background-image: linear-gradient(to bottom, #ffffff 0%, #f8f8f8 100%);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0);
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
border-radius: 4px;
-webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 5px rgba(0, 0, 0, 0.075);
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 5px rgba(0, 0, 0, 0.075);
z-index: 1000;
border-width: 0 0 1px;
border-radius: 0;
}
@media (min-width: 768px) {
.config {
@ -6973,14 +6628,6 @@ notifications {
.config .navbar-link:hover {
color: #333333;
}
.config .navbar-nav > .active > a {
background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f3f3f3 100%);
background-image: linear-gradient(to bottom, #ebebeb 0%, #f3f3f3 100%);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff3f3f3', GradientType=0);
-webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.075);
box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.075);
}
@media (min-width: 768px) {
.config {
border-radius: 0;
@ -7047,23 +6694,50 @@ kbn-table tr.even td {
word-break: normal;
word-wrap: normal;
}
.discover-field-list .discover-field-item .discover-field-add {
visibility: hidden;
.application-discover {
overflow-x: hidden;
}
.discover-field-list .discover-field-item:hover .discover-field-add {
visibility: visible;
.discover-table {
overflow-y: auto;
overflow-x: auto;
margin-top: 10px;
padding-left: 0px !important;
padding-right: 0px !important;
}
.discover-field-list .discover-field-name:hover {
text-decoration: none;
margin-left: 0;
.discover-field-container {
padding-left: 0px !important;
padding-right: 0px !important;
background-color: #f5f5f5;
border-right: 1px solid #e3e3e3;
border-bottom: 1px solid #e3e3e3;
}
.discover-field-list .discover-field-list-header {
padding-left: 10px;
color: #777777;
}
.discover-field-list .discover-field-item {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
font-size: 11px;
border-top: 1px solid #e3e3e3;
}
.discover-field-list .discover-field-name {
padding: 5px 10px;
}
.discover-field-list .discover-field-name:hover,
.discover-field-list .discover-field-name:hover .text-muted {
background-color: #428bca;
color: #ffffff;
}
.discover-field-list .discover-field-details {
font-size: 12px;
margin-left: 15px;
padding: 5px;
background-color: #f5f5f5;
border-radius: 4px;
border: 1px solid #dddddd;
border-top: 1px solid #e3e3e3;
padding: 5px 10px;
background-color: #ffffff;
color: #333333;
}
.discover-field-list .discover-field-details .discover-field-details-error {
margin-top: 5px;
}
.discover-field-list .discover-field-details .discover-field-details-item {
margin-top: 5px;
@ -7138,3 +6812,21 @@ fieldset[disabled] .kbn-timepicker .btn-info.active {
color: #5bc0de;
background-color: #ffffff;
}
kbn-table {
font-size: 11px;
}
kbn-table th {
white-space: nowrap;
padding-right: 10px;
}
kbn-table th .table-header-move,
kbn-table th .table-header-sortchange {
visibility: hidden;
}
kbn-table th .fa {
font-size: 1.1em;
}
kbn-table th:hover .table-header-move,
kbn-table th:hover .table-header-sortchange {
visibility: visible;
}

View file

@ -23,6 +23,11 @@ body {
}
}
.top-fixed {
position:fixed;
bottom:0px;
}
notifications {
z-index: 1;
}
@ -91,4 +96,31 @@ notifications {
.kbn-timepicker .btn-info {
.button-variant(@btn-info-color; @btn-info-bg; @btn-info-border);
text-shadow: none;
}
//== Table
kbn-table {
font-size: @font-size-smaller;
th {
white-space: nowrap;
padding-right: 10px;
.table-header-move, .table-header-sortchange {
visibility: hidden;
}
.fa {
font-size: 1.1em;
}
}
th:hover {
.table-header-move, .table-header-sortchange {
visibility: visible;
}
}
}

View file

View file

@ -0,0 +1,830 @@
//
// Variables
// --------------------------------------------------
//== Colors
//
//## Gray and brand colors for use across Bootstrap.
@gray-darker: lighten(#000, 13.5%); // #222
@gray-dark: lighten(#000, 20%); // #333
@gray: lighten(#000, 33.5%); // #555
@gray-light: lighten(#000, 60%); // #999
@gray-lighter: lighten(#000, 93.5%); // #eee
@brand-primary: #428bca;
@brand-success: #5cb85c;
@brand-info: #5bc0de;
@brand-warning: #f0ad4e;
@brand-danger: #d9534f;
//== Scaffolding
//
// ## Settings for some of the most global styles.
//** Background color for `<body>`.
@body-bg: #fff;
//** Global text color on `<body>`.
@text-color: @gray-dark;
//** Global textual link color.
@link-color: @brand-primary;
//** Link hover color set via `darken()` function.
@link-hover-color: darken(@link-color, 15%);
//== Typography
//
//## Font, line-height, and color for body text, headings, and more.
@font-family-sans-serif: "Helvetica Neue", Helvetica, Arial, sans-serif;
@font-family-serif: Georgia, "Times New Roman", Times, serif;
//** Default monospace fonts for `<code>`, `<kbd>`, and `<pre>`.
@font-family-monospace: Menlo, Monaco, Consolas, "Courier New", monospace;
@font-family-base: @font-family-sans-serif;
@font-size-base: 14px;
@font-size-large: ceil((@font-size-base * 1.25)); // ~18px
@font-size-small: ceil((@font-size-base * 0.85)); // ~12px
@font-size-h1: floor((@font-size-base * 2.6)); // ~36px
@font-size-h2: floor((@font-size-base * 2.15)); // ~30px
@font-size-h3: ceil((@font-size-base * 1.7)); // ~24px
@font-size-h4: ceil((@font-size-base * 1.25)); // ~18px
@font-size-h5: @font-size-base;
@font-size-h6: ceil((@font-size-base * 0.85)); // ~12px
//** Unit-less `line-height` for use in components like buttons.
@line-height-base: 1.428571429; // 20/14
//** Computed "line-height" (`font-size` * `line-height`) for use with `margin`, `padding`, etc.
@line-height-computed: floor((@font-size-base * @line-height-base)); // ~20px
//** By default, this inherits from the `<body>`.
@headings-font-family: inherit;
@headings-font-weight: 500;
@headings-line-height: 1.1;
@headings-color: inherit;
//-- Iconography
//
//## Specify custom locations of the include Glyphicons icon font. Useful for those including Bootstrap via Bower.
@icon-font-path: "../fonts/";
@icon-font-name: "glyphicons-halflings-regular";
@icon-font-svg-id: "glyphicons_halflingsregular";
//== Components
//
//## Define common padding and border radius sizes and more. Values based on 14px text and 1.428 line-height (~20px to start).
@padding-base-vertical: 6px;
@padding-base-horizontal: 12px;
@padding-large-vertical: 10px;
@padding-large-horizontal: 16px;
@padding-small-vertical: 5px;
@padding-small-horizontal: 10px;
@padding-xs-vertical: 1px;
@padding-xs-horizontal: 5px;
@line-height-large: 1.33;
@line-height-small: 1.5;
@border-radius-base: 4px;
@border-radius-large: 6px;
@border-radius-small: 3px;
//** Global color for active items (e.g., navs or dropdowns).
@component-active-color: #fff;
//** Global background color for active items (e.g., navs or dropdowns).
@component-active-bg: @brand-primary;
//** Width of the `border` for generating carets that indicator dropdowns.
@caret-width-base: 4px;
//** Carets increase slightly in size for larger components.
@caret-width-large: 5px;
//== Tables
//
//## Customizes the `.table` component with basic values, each used across all table variations.
//** Padding for `<th>`s and `<td>`s.
@table-cell-padding: 8px;
//** Padding for cells in `.table-condensed`.
@table-condensed-cell-padding: 5px;
//** Default background color used for all tables.
@table-bg: transparent;
//** Background color used for `.table-striped`.
@table-bg-accent: #f9f9f9;
//** Background color used for `.table-hover`.
@table-bg-hover: #f5f5f5;
@table-bg-active: @table-bg-hover;
//** Border color for table and cell borders.
@table-border-color: #ddd;
//== Buttons
//
//## For each of Bootstrap's buttons, define text, background and border color.
@btn-font-weight: normal;
@btn-default-color: #333;
@btn-default-bg: #fff;
@btn-default-border: #ccc;
@btn-primary-color: #fff;
@btn-primary-bg: @brand-primary;
@btn-primary-border: darken(@btn-primary-bg, 5%);
@btn-success-color: #fff;
@btn-success-bg: @brand-success;
@btn-success-border: darken(@btn-success-bg, 5%);
@btn-info-color: #fff;
@btn-info-bg: @brand-info;
@btn-info-border: darken(@btn-info-bg, 5%);
@btn-warning-color: #fff;
@btn-warning-bg: @brand-warning;
@btn-warning-border: darken(@btn-warning-bg, 5%);
@btn-danger-color: #fff;
@btn-danger-bg: @brand-danger;
@btn-danger-border: darken(@btn-danger-bg, 5%);
@btn-link-disabled-color: @gray-light;
//== Forms
//
//##
//** `<input>` background color
@input-bg: #fff;
//** `<input disabled>` background color
@input-bg-disabled: @gray-lighter;
//** Text color for `<input>`s
@input-color: @gray;
//** `<input>` border color
@input-border: #ccc;
//** `<input>` border radius
@input-border-radius: @border-radius-base;
//** Border color for inputs on focus
@input-border-focus: #66afe9;
//** Placeholder text color
@input-color-placeholder: @gray-light;
//** Default `.form-control` height
@input-height-base: (@line-height-computed + (@padding-base-vertical * 2) + 2);
//** Large `.form-control` height
@input-height-large: (ceil(@font-size-large * @line-height-large) + (@padding-large-vertical * 2) + 2);
//** Small `.form-control` height
@input-height-small: (floor(@font-size-small * @line-height-small) + (@padding-small-vertical * 2) + 2);
@legend-color: @gray-dark;
@legend-border-color: #e5e5e5;
//** Background color for textual input addons
@input-group-addon-bg: @gray-lighter;
//** Border color for textual input addons
@input-group-addon-border-color: @input-border;
//== Dropdowns
//
//## Dropdown menu container and contents.
//** Background for the dropdown menu.
@dropdown-bg: #fff;
//** Dropdown menu `border-color`.
@dropdown-border: rgba(0,0,0,.15);
//** Dropdown menu `border-color` **for IE8**.
@dropdown-fallback-border: #ccc;
//** Divider color for between dropdown items.
@dropdown-divider-bg: #e5e5e5;
//** Dropdown link text color.
@dropdown-link-color: @gray-dark;
//** Hover color for dropdown links.
@dropdown-link-hover-color: darken(@gray-dark, 5%);
//** Hover background for dropdown links.
@dropdown-link-hover-bg: #f5f5f5;
//** Active dropdown menu item text color.
@dropdown-link-active-color: @component-active-color;
//** Active dropdown menu item background color.
@dropdown-link-active-bg: @component-active-bg;
//** Disabled dropdown menu item background color.
@dropdown-link-disabled-color: @gray-light;
//** Text color for headers within dropdown menus.
@dropdown-header-color: @gray-light;
// Note: Deprecated @dropdown-caret-color as of v3.1.0
@dropdown-caret-color: #000;
//-- Z-index master list
//
// Warning: Avoid customizing these values. They're used for a bird's eye view
// of components dependent on the z-axis and are designed to all work together.
//
// Note: These variables are not generated into the Customizer.
@zindex-navbar: 1000;
@zindex-dropdown: 1000;
@zindex-popover: 1010;
@zindex-tooltip: 1030;
@zindex-navbar-fixed: 1030;
@zindex-modal-background: 1040;
@zindex-modal: 1050;
//== Media queries breakpoints
//
//## Define the breakpoints at which your layout will change, adapting to different screen sizes.
// Extra small screen / phone
// Note: Deprecated @screen-xs and @screen-phone as of v3.0.1
@screen-xs: 480px;
@screen-xs-min: @screen-xs;
@screen-phone: @screen-xs-min;
// Small screen / tablet
// Note: Deprecated @screen-sm and @screen-tablet as of v3.0.1
@screen-sm: 768px;
@screen-sm-min: @screen-sm;
@screen-tablet: @screen-sm-min;
// Medium screen / desktop
// Note: Deprecated @screen-md and @screen-desktop as of v3.0.1
@screen-md: 992px;
@screen-md-min: @screen-md;
@screen-desktop: @screen-md-min;
// Large screen / wide desktop
// Note: Deprecated @screen-lg and @screen-lg-desktop as of v3.0.1
@screen-lg: 1200px;
@screen-lg-min: @screen-lg;
@screen-lg-desktop: @screen-lg-min;
// So media queries don't overlap when required, provide a maximum
@screen-xs-max: (@screen-sm-min - 1);
@screen-sm-max: (@screen-md-min - 1);
@screen-md-max: (@screen-lg-min - 1);
//== Grid system
//
//## Define your custom responsive grid.
//** Number of columns in the grid.
@grid-columns: 12;
//** Padding between columns. Gets divided in half for the left and right.
@grid-gutter-width: 30px;
// Navbar collapse
//** Point at which the navbar becomes uncollapsed.
@grid-float-breakpoint: @screen-sm-min;
//** Point at which the navbar begins collapsing.
@grid-float-breakpoint-max: (@grid-float-breakpoint - 1);
//== Container sizes
//
//## Define the maximum width of `.container` for different screen sizes.
// Small screen / tablet
@container-tablet: ((720px + @grid-gutter-width));
//** For `@screen-sm-min` and up.
@container-sm: @container-tablet;
// Medium screen / desktop
@container-desktop: ((940px + @grid-gutter-width));
//** For `@screen-md-min` and up.
@container-md: @container-desktop;
// Large screen / wide desktop
@container-large-desktop: ((1140px + @grid-gutter-width));
//** For `@screen-lg-min` and up.
@container-lg: @container-large-desktop;
//== Navbar
//
//##
// Basics of a navbar
@navbar-height: 50px;
@navbar-margin-bottom: @line-height-computed;
@navbar-border-radius: @border-radius-base;
@navbar-padding-horizontal: floor((@grid-gutter-width / 2));
@navbar-padding-vertical: ((@navbar-height - @line-height-computed) / 2);
@navbar-collapse-max-height: 340px;
@navbar-default-color: #777;
@navbar-default-bg: #f8f8f8;
@navbar-default-border: darken(@navbar-default-bg, 6.5%);
// Navbar links
@navbar-default-link-color: #777;
@navbar-default-link-hover-color: #333;
@navbar-default-link-hover-bg: transparent;
@navbar-default-link-active-color: #555;
@navbar-default-link-active-bg: darken(@navbar-default-bg, 6.5%);
@navbar-default-link-disabled-color: #ccc;
@navbar-default-link-disabled-bg: transparent;
// Navbar brand label
@navbar-default-brand-color: @navbar-default-link-color;
@navbar-default-brand-hover-color: darken(@navbar-default-brand-color, 10%);
@navbar-default-brand-hover-bg: transparent;
// Navbar toggle
@navbar-default-toggle-hover-bg: #ddd;
@navbar-default-toggle-icon-bar-bg: #888;
@navbar-default-toggle-border-color: #ddd;
// Inverted navbar
// Reset inverted navbar basics
@navbar-inverse-color: @gray-light;
@navbar-inverse-bg: #222;
@navbar-inverse-border: darken(@navbar-inverse-bg, 10%);
// Inverted navbar links
@navbar-inverse-link-color: @gray-light;
@navbar-inverse-link-hover-color: #fff;
@navbar-inverse-link-hover-bg: transparent;
@navbar-inverse-link-active-color: @navbar-inverse-link-hover-color;
@navbar-inverse-link-active-bg: darken(@navbar-inverse-bg, 10%);
@navbar-inverse-link-disabled-color: #444;
@navbar-inverse-link-disabled-bg: transparent;
// Inverted navbar brand label
@navbar-inverse-brand-color: @navbar-inverse-link-color;
@navbar-inverse-brand-hover-color: #fff;
@navbar-inverse-brand-hover-bg: transparent;
// Inverted navbar toggle
@navbar-inverse-toggle-hover-bg: #333;
@navbar-inverse-toggle-icon-bar-bg: #fff;
@navbar-inverse-toggle-border-color: #333;
//== Navs
//
//##
//=== Shared nav styles
@nav-link-padding: 10px 15px;
@nav-link-hover-bg: @gray-lighter;
@nav-disabled-link-color: @gray-light;
@nav-disabled-link-hover-color: @gray-light;
@nav-open-link-hover-color: #fff;
//== Tabs
@nav-tabs-border-color: #ddd;
@nav-tabs-link-hover-border-color: @gray-lighter;
@nav-tabs-active-link-hover-bg: @body-bg;
@nav-tabs-active-link-hover-color: @gray;
@nav-tabs-active-link-hover-border-color: #ddd;
@nav-tabs-justified-link-border-color: #ddd;
@nav-tabs-justified-active-link-border-color: @body-bg;
//== Pills
@nav-pills-border-radius: @border-radius-base;
@nav-pills-active-link-hover-bg: @component-active-bg;
@nav-pills-active-link-hover-color: @component-active-color;
//== Pagination
//
//##
@pagination-color: @link-color;
@pagination-bg: #fff;
@pagination-border: #ddd;
@pagination-hover-color: @link-hover-color;
@pagination-hover-bg: @gray-lighter;
@pagination-hover-border: #ddd;
@pagination-active-color: #fff;
@pagination-active-bg: @brand-primary;
@pagination-active-border: @brand-primary;
@pagination-disabled-color: @gray-light;
@pagination-disabled-bg: #fff;
@pagination-disabled-border: #ddd;
//== Pager
//
//##
@pager-bg: @pagination-bg;
@pager-border: @pagination-border;
@pager-border-radius: 15px;
@pager-hover-bg: @pagination-hover-bg;
@pager-active-bg: @pagination-active-bg;
@pager-active-color: @pagination-active-color;
@pager-disabled-color: @pagination-disabled-color;
//== Jumbotron
//
//##
@jumbotron-padding: 30px;
@jumbotron-color: inherit;
@jumbotron-bg: @gray-lighter;
@jumbotron-heading-color: inherit;
@jumbotron-font-size: ceil((@font-size-base * 1.5));
//== Form states and alerts
//
//## Define colors for form feedback states and, by default, alerts.
@state-success-text: #3c763d;
@state-success-bg: #dff0d8;
@state-success-border: darken(spin(@state-success-bg, -10), 5%);
@state-info-text: #31708f;
@state-info-bg: #d9edf7;
@state-info-border: darken(spin(@state-info-bg, -10), 7%);
@state-warning-text: #8a6d3b;
@state-warning-bg: #fcf8e3;
@state-warning-border: darken(spin(@state-warning-bg, -10), 5%);
@state-danger-text: #a94442;
@state-danger-bg: #f2dede;
@state-danger-border: darken(spin(@state-danger-bg, -10), 5%);
//== Tooltips
//
//##
//** Tooltip max width
@tooltip-max-width: 200px;
//** Tooltip text color
@tooltip-color: #fff;
//** Tooltip background color
@tooltip-bg: #000;
@tooltip-opacity: .9;
//** Tooltip arrow width
@tooltip-arrow-width: 5px;
//** Tooltip arrow color
@tooltip-arrow-color: @tooltip-bg;
//== Popovers
//
//##
//** Popover body background color
@popover-bg: #fff;
//** Popover maximum width
@popover-max-width: 276px;
//** Popover border color
@popover-border-color: rgba(0,0,0,.2);
//** Popover fallback border color
@popover-fallback-border-color: #ccc;
//** Popover title background color
@popover-title-bg: darken(@popover-bg, 3%);
//** Popover arrow width
@popover-arrow-width: 10px;
//** Popover arrow color
@popover-arrow-color: #fff;
//** Popover outer arrow width
@popover-arrow-outer-width: (@popover-arrow-width + 1);
//** Popover outer arrow color
@popover-arrow-outer-color: fadein(@popover-border-color, 5%);
//** Popover outer arrow fallback color
@popover-arrow-outer-fallback-color: darken(@popover-fallback-border-color, 20%);
//== Labels
//
//##
//** Default label background color
@label-default-bg: @gray-light;
//** Primary label background color
@label-primary-bg: @brand-primary;
//** Success label background color
@label-success-bg: @brand-success;
//** Info label background color
@label-info-bg: @brand-info;
//** Warning label background color
@label-warning-bg: @brand-warning;
//** Danger label background color
@label-danger-bg: @brand-danger;
//** Default label text color
@label-color: #fff;
//** Default text color of a linked label
@label-link-hover-color: #fff;
//== Modals
//
//##
//** Padding applied to the modal body
@modal-inner-padding: 20px;
//** Padding applied to the modal title
@modal-title-padding: 15px;
//** Modal title line-height
@modal-title-line-height: @line-height-base;
//** Background color of modal content area
@modal-content-bg: #fff;
//** Modal content border color
@modal-content-border-color: rgba(0,0,0,.2);
//** Modal content border color **for IE8**
@modal-content-fallback-border-color: #999;
//** Modal backdrop background color
@modal-backdrop-bg: #000;
//** Modal backdrop opacity
@modal-backdrop-opacity: .5;
//** Modal header border color
@modal-header-border-color: #e5e5e5;
//** Modal footer border color
@modal-footer-border-color: @modal-header-border-color;
@modal-lg: 900px;
@modal-md: 600px;
@modal-sm: 300px;
//== Alerts
//
//## Define alert colors, border radius, and padding.
@alert-padding: 15px;
@alert-border-radius: @border-radius-base;
@alert-link-font-weight: bold;
@alert-success-bg: @state-success-bg;
@alert-success-text: @state-success-text;
@alert-success-border: @state-success-border;
@alert-info-bg: @state-info-bg;
@alert-info-text: @state-info-text;
@alert-info-border: @state-info-border;
@alert-warning-bg: @state-warning-bg;
@alert-warning-text: @state-warning-text;
@alert-warning-border: @state-warning-border;
@alert-danger-bg: @state-danger-bg;
@alert-danger-text: @state-danger-text;
@alert-danger-border: @state-danger-border;
//== Progress bars
//
//##
//** Background color of the whole progress component
@progress-bg: #f5f5f5;
//** Progress bar text color
@progress-bar-color: #fff;
//** Default progress bar color
@progress-bar-bg: @brand-primary;
//** Success progress bar color
@progress-bar-success-bg: @brand-success;
//** Warning progress bar color
@progress-bar-warning-bg: @brand-warning;
//** Danger progress bar color
@progress-bar-danger-bg: @brand-danger;
//** Info progress bar color
@progress-bar-info-bg: @brand-info;
//== List group
//
//##
//** Background color on `.list-group-item`
@list-group-bg: #fff;
//** `.list-group-item` border color
@list-group-border: #ddd;
//** List group border radius
@list-group-border-radius: @border-radius-base;
//** Background color of single list elements on hover
@list-group-hover-bg: #f5f5f5;
//** Text color of active list elements
@list-group-active-color: @component-active-color;
//** Background color of active list elements
@list-group-active-bg: @component-active-bg;
//** Border color of active list elements
@list-group-active-border: @list-group-active-bg;
@list-group-active-text-color: lighten(@list-group-active-bg, 40%);
@list-group-link-color: #555;
@list-group-link-heading-color: #333;
//== Panels
//
//##
@panel-bg: #fff;
@panel-body-padding: 15px;
@panel-border-radius: @border-radius-base;
//** Border color for elements within panels
@panel-inner-border: #ddd;
@panel-footer-bg: #f5f5f5;
@panel-default-text: @gray-dark;
@panel-default-border: #ddd;
@panel-default-heading-bg: #f5f5f5;
@panel-primary-text: #fff;
@panel-primary-border: @brand-primary;
@panel-primary-heading-bg: @brand-primary;
@panel-success-text: @state-success-text;
@panel-success-border: @state-success-border;
@panel-success-heading-bg: @state-success-bg;
@panel-info-text: @state-info-text;
@panel-info-border: @state-info-border;
@panel-info-heading-bg: @state-info-bg;
@panel-warning-text: @state-warning-text;
@panel-warning-border: @state-warning-border;
@panel-warning-heading-bg: @state-warning-bg;
@panel-danger-text: @state-danger-text;
@panel-danger-border: @state-danger-border;
@panel-danger-heading-bg: @state-danger-bg;
//== Thumbnails
//
//##
//** Padding around the thumbnail image
@thumbnail-padding: 4px;
//** Thumbnail background color
@thumbnail-bg: @body-bg;
//** Thumbnail border color
@thumbnail-border: #ddd;
//** Thumbnail border radius
@thumbnail-border-radius: @border-radius-base;
//** Custom text color for thumbnail captions
@thumbnail-caption-color: @text-color;
//** Padding around the thumbnail caption
@thumbnail-caption-padding: 9px;
//== Wells
//
//##
@well-bg: #f5f5f5;
@well-border: darken(@well-bg, 7%);
//== Badges
//
//##
@badge-color: #fff;
//** Linked badge text color on hover
@badge-link-hover-color: #fff;
@badge-bg: @gray-light;
//** Badge text color in active nav link
@badge-active-color: @link-color;
//** Badge background color in active nav link
@badge-active-bg: #fff;
@badge-font-weight: bold;
@badge-line-height: 1;
@badge-border-radius: 10px;
//== Breadcrumbs
//
//##
@breadcrumb-padding-vertical: 8px;
@breadcrumb-padding-horizontal: 15px;
//** Breadcrumb background color
@breadcrumb-bg: #f5f5f5;
//** Breadcrumb text color
@breadcrumb-color: #ccc;
//** Text color of current page in the breadcrumb
@breadcrumb-active-color: @gray-light;
//** Textual separator for between breadcrumb elements
@breadcrumb-separator: "/";
//== Carousel
//
//##
@carousel-text-shadow: 0 1px 2px rgba(0,0,0,.6);
@carousel-control-color: #fff;
@carousel-control-width: 15%;
@carousel-control-opacity: .5;
@carousel-control-font-size: 20px;
@carousel-indicator-active-bg: #fff;
@carousel-indicator-border-color: #fff;
@carousel-caption-color: #fff;
//== Close
//
//##
@close-font-weight: bold;
@close-color: #000;
@close-text-shadow: 0 1px 0 #fff;
//== Code
//
//##
@code-color: #c7254e;
@code-bg: #f9f2f4;
@kbd-color: #fff;
@kbd-bg: #333;
@pre-bg: #f5f5f5;
@pre-color: @gray-dark;
@pre-border-color: #ccc;
@pre-scrollable-max-height: 340px;
//== Type
//
//##
//** Text muted color
@text-muted: @gray-light;
//** Abbreviations and acronyms border color
@abbr-border-color: @gray-light;
//** Headings small color
@headings-small-color: @gray-light;
//** Blockquote small color
@blockquote-small-color: @gray-light;
//** Blockquote font size
@blockquote-font-size: (@font-size-base * 1.25);
//** Blockquote border color
@blockquote-border-color: @gray-lighter;
//** Page header border color
@page-header-border-color: @gray-lighter;
//== Miscellaneous
//
//##
//** Horizontal line color.
@hr-border: @gray-lighter;
//** Horizontal offset for forms and lists.
@component-offset-horizontal: 180px;

View file

@ -49,6 +49,9 @@
require([
'sinon/sinon',
'specs/apps/dashboard/index',
'specs/apps/dashboard/directives/panel',
'specs/apps/dashboard/directives/grid',
'specs/services/state',
'specs/courier/index'
], function (sinon) {

View file

@ -0,0 +1,145 @@
define(function (require) {
var angular = require('angular');
var mocks = require('angular-mocks');
var _ = require('lodash');
var $ = require('jquery');
// Load the kibana app dependencies.
require('angular-route');
// Load the code for the directive
require('apps/dashboard/directives/panel');
describe('Gridster', function () {
var $scope, $elem, compile;
beforeEach(function () {
module('app/dashboard');
// Create the scope
inject(function ($rootScope, $compile) {
// So we can use this in other sections
compile = $compile;
$scope = $rootScope;
$elem = angular.element(
'<ul dashboard-grid="" ' +
' grid="dashboard.panels" ' +
' control="gridControl" ' +
' class="ng-isolate-scope gridster" ' +
' style="position: relative; width: 1207px; height: 220px;">' +
'</ul>'
);
// The element must be attached to the DOM for gridster to work.
$elem.hide();
$elem.appendTo(document.body);
});
});
afterEach(function () {
$elem.remove();
});
describe('without parameters', function () {
beforeEach(function () {
compile($elem)($scope);
$scope.$digest();
});
it('should return without attaching anything', function (done) {
var panels = $elem.find('li.gs-w');
expect(panels.length).to.be(0);
done();
});
});
describe('with parameters', function () {
var grid;
beforeEach(function () {
$scope.gridControl = {};
$scope.dashboard = {
panels: [{
col: 1,
row: 1,
size_x: 3,
size_y: 2,
params: {
type: 'vis1'
}
}, {
col: 4,
row: 1,
size_x: 3,
size_y: 2,
params: {
type: 'vis2'
}
}]
};
compile($elem)($scope);
$scope.$digest();
grid = $scope.gridControl.serializeGrid;
});
it('should have 2 panels', function (done) {
var panels = $elem.find('li.gs-w');
expect(panels.length).to.be(2);
done();
});
it('should remove panels when remove is clicked', function (done) {
expect(grid().length).to.be(2);
// Click close button
$elem.find('li.gs-w:first i.remove').trigger('click');
expect(grid().length).to.be(1);
done();
});
it('should have a control.clearGrid that removes all widgets', function (done) {
expect(grid().length).to.be(2);
$scope.gridControl.clearGrid();
expect(grid().length).to.be(0);
done();
});
it('has an addWidget that adds a widget', function (done) {
expect(grid().length).to.be(2);
$scope.gridControl.addWidget({});
expect(grid().length).to.be(3);
done();
});
it('has an unserializeGrid that creates a grid from an object', function (done) {
expect(grid().length).to.be(2);
$scope.gridControl.clearGrid();
expect(grid().length).to.be(0);
$scope.gridControl.unserializeGrid({
panels: [{
col: 1,
row: 1,
size_x: 3,
size_y: 2,
params: {
type: 'vis1'
}
}]
});
expect(grid().length).to.be(1);
done();
});
});
});
});

View file

@ -0,0 +1,51 @@
define(function (require) {
var angular = require('angular');
var mocks = require('angular-mocks');
var _ = require('lodash');
var $ = require('jquery');
// Load the kibana app dependencies.
require('angular-route');
// Load the code for the directive
require('apps/dashboard/directives/panel');
describe('Dashboard panels', function () {
var $scope, $elem;
beforeEach(function () {
module('app/dashboard');
// Create the scope
inject(function ($rootScope, $compile) {
$scope = $rootScope;
var params = {
type: 'new'
};
$elem = angular.element(
'<dashboard-panel params=\'' + JSON.stringify(params) + '\'></dashboard-panel>'
);
$compile($elem)($scope);
$scope.$digest();
});
});
it('should have a close button', function (done) {
var closeIcon = $elem.find('i.remove');
expect(closeIcon.length).to.be(1);
done();
});
it('should have the name of the panel', function (done) {
expect($elem.text()).to.be('new');
done();
});
});
});

View file

@ -2,6 +2,8 @@ define(function (require) {
var mocks = require('angular-mocks');
var _ = require('lodash');
var $ = require('jquery');
var sinon = require('test_utils/auto_release_sinon');
// Load the kibana app dependencies.
require('angular-route');
@ -10,23 +12,30 @@ define(function (require) {
require('apps/dashboard/index');
describe('Dashboard app', function () {
var $scope;
var $scope,
location;
beforeEach(function () {
module('app/dashboard');
// Create the scope
inject(function ($rootScope, $controller) {
inject(function ($rootScope, $controller, $location) {
$scope = $rootScope.$new();
var dashCtrl = $controller('dashboard', {
$scope: $scope
});
location = $location;
// $scope is now available in tests
});
});
afterEach(function () {
$scope.$destroy();
});
it('should attach $routeParams to scope', function (done) {
expect($scope.routeParams).to.be.a(Object);
done();
@ -39,6 +48,56 @@ define(function (require) {
done();
});
describe('saving', function () {
beforeEach(function () {
sinon.stub($scope, 'save', function () {});
});
it('should open the save dialog with openSave()', function (done) {
expect($scope.configTemplate).to.be(undefined);
$scope.openSave();
expect($scope.configTemplate).to.be.a('string');
done();
});
it('should unset the dialog when called again', function (done) {
$scope.openSave();
$scope.openSave();
expect($scope.configTemplate).to.be(undefined);
done();
});
it('should save the dashboard when submitted', function (done) {
$scope.openSave();
$scope.configSubmit();
expect($scope.save.called).to.be(true);
done();
});
});
describe('loading', function () {
beforeEach(function () {
$scope.gridControl = {
clearGrid: function () {},
unserializeGrid: function () {},
};
_.each($scope.gridControl, function (value, key) {
sinon.spy($scope.gridControl, key);
});
});
it('should attach the schema to the dashboard object', function (done) {
$scope.load({foo: 'bar'});
expect($scope.dashboard.foo).to.be('bar');
done();
});
it('should clear the grid before loading a new one', function (done) {
$scope.load({foo: 'bar'});
expect($scope.gridControl.clearGrid.called).to.be(true);
expect($scope.gridControl.unserializeGrid.called).to.be(true);
done();
});
});
});
});

View file

@ -0,0 +1,52 @@
define(function (require) {
var angular = require('angular');
var mocks = require('angular-mocks');
var _ = require('lodash');
var $ = require('jquery');
// Load the kibana app dependencies.
require('angular-route');
// Load the code for the directive
require('services/state');
describe('State service', function () {
var state, location;
beforeEach(function () {
module('kibana/services');
// Create the scope
inject(function (_state_, $location) {
state = _state_;
location = $location;
});
});
afterEach(function () {
location.search({});
});
it('should have no state by default', function (done) {
expect(state.get()).to.eql({});
done();
});
it('should have a set(Object) that writes state to the search string', function (done) {
state.set({foo: 'bar'});
expect(location.search()._r).to.be('(foo:bar)');
done();
});
it('should have a get() that deserializes rison from the search string', function (done) {
location.search({_r: '(foo:bar)'});
expect(state.get()).to.eql({foo: 'bar'});
done();
});
});
});