mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 09:19:04 -04:00
Merge branch 'master' into feature/tooltip
Conflicts: src/kibana/components/vislib/lib/handler/handler.js
This commit is contained in:
commit
549b5f113a
48 changed files with 505 additions and 250 deletions
2
.esvmrc
2
.esvmrc
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"defaults": {
|
||||
"branch": "1.x",
|
||||
"plugins": ["elasticsearch/marvel/latest"]
|
||||
"plugins": ["elasticsearch/marvel/latest", "mobz/elasticsearch-head"]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,4 @@ notifications:
|
|||
format: html
|
||||
on_success: change
|
||||
template:
|
||||
- ! '%{repository_slug}/%{branch} by %{author}: %{commit_message} (<a href="%{build_url}">open</a>)'
|
||||
env:
|
||||
global:
|
||||
secure: AX9xidE0quyS07ZfOcecxEGjlNDT9YlM+fvtQHqOaODBII2jg5rgz0SyyxmTPSG68aqUNk8ML9slbRE4h0iPqNkB6fbDE2Dc6oTrRE7XFGDBjw66OHV2ZbsobdORf4UtWO06JBgLUEU2pzRYphe/B14dyA+ZO6p+bAgBmcdLd8k=
|
||||
- ! '%{repository_slug}/%{branch} by %{author}: %{commit_message} (<a href="%{build_url}">open</a>)'
|
2
TODOS.md
2
TODOS.md
|
@ -447,6 +447,8 @@
|
|||
- refactor this code to simplify and possibly merge with data converter code below
|
||||
- **[src/kibana/components/vislib/lib/data.js](https://github.com/elasticsearch/kibana4/blob/master/src/kibana/components/vislib/lib/data.js)**
|
||||
- need to make this more generic
|
||||
- **[src/kibana/components/vislib/lib/x_axis.js](https://github.com/elasticsearch/kibana4/blob/master/src/kibana/components/vislib/lib/x_axis.js)**
|
||||
- need to add mouseover to show tooltip on truncated labels
|
||||
- **[src/kibana/components/vislib/vis.js](https://github.com/elasticsearch/kibana4/blob/master/src/kibana/components/vislib/vis.js)**
|
||||
- need to come up with a solution for resizing when no data is available
|
||||
- **[src/kibana/components/vislib/visualizations/column_chart.js](https://github.com/elasticsearch/kibana4/blob/master/src/kibana/components/vislib/visualizations/column_chart.js)**
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
"elasticsearch": "*",
|
||||
"Faker": "~1.1.0",
|
||||
"FileSaver": "*",
|
||||
"font-awesome": "~4.0.3",
|
||||
"font-awesome": "~4.2.0",
|
||||
"gridster": "~0.5.0",
|
||||
"inflection": "~1.3.5",
|
||||
"jquery": "~2.1.0",
|
||||
|
|
|
@ -30,11 +30,21 @@
|
|||
</form>
|
||||
|
||||
<div class="button-group">
|
||||
<button ng-click="newDashboard()"><i class="fa fa-file-o"></i></button>
|
||||
<button ng-click="openAdd()"><i class="fa fa-plus"></i></button>
|
||||
<button ng-click="openSave()"><i class="fa fa-save"></i></button>
|
||||
<button ng-click="openLoad()"><i class="fa fa-folder-open"></i></button>
|
||||
<button ng-click="openShare()"><i class="fa fa-code"></i></button>
|
||||
<kbn-tooltip text="New Dashboard" placement="bottom" append-to-body="1">
|
||||
<button ng-click="newDashboard()"><i class="fa fa-file-new-o"></i></button>
|
||||
</kbn-tooltip>
|
||||
<kbn-tooltip text="Save Dashboard" placement="bottom" append-to-body="1">
|
||||
<button ng-click="openSave()"><i class="fa fa-save"></i></button>
|
||||
</kbn-tooltip>
|
||||
<kbn-tooltip text="Load Saved Dashboard" placement="bottom" append-to-body="1">
|
||||
<button ng-click="openLoad()"><i class="fa fa-folder-open-o"></i></button>
|
||||
</kbn-tooltip>
|
||||
<kbn-tooltip text="Share" placement="bottom" append-to-body="1">
|
||||
<button ng-click="openShare()"><i class="fa fa-external-link"></i></button>
|
||||
</kbn-tooltip>
|
||||
<kbn-tooltip text="Add Visualization" placement="bottom" append-to-body="1">
|
||||
<button ng-click="openAdd()"><i class="fa fa-plus-circle"></i></button>
|
||||
</kbn-tooltip>
|
||||
</div>
|
||||
</navbar>
|
||||
</nav>
|
||||
|
|
|
@ -66,8 +66,7 @@ dashboard-grid {
|
|||
.justify-content(flex-start);
|
||||
|
||||
.panel-heading {
|
||||
.flex();
|
||||
min-height: 25px;
|
||||
.flex(0 0 auto);
|
||||
white-space: nowrap;
|
||||
display: flex;
|
||||
|
||||
|
|
|
@ -121,8 +121,6 @@ define(function (require) {
|
|||
$scope.opts = {
|
||||
// number of records to fetch, then paginate through
|
||||
sampleSize: config.get('discover:sampleSize'),
|
||||
// max length for summaries in the table
|
||||
maxSummaryLength: 100,
|
||||
// Index to match
|
||||
index: $state.index,
|
||||
savedSearch: savedSearch,
|
||||
|
|
|
@ -86,7 +86,6 @@ define(function (require) {
|
|||
sorting: '=',
|
||||
filtering: '=',
|
||||
refresh: '=',
|
||||
maxLength: '=',
|
||||
mapping: '=',
|
||||
timefield: '=?'
|
||||
},
|
||||
|
@ -120,7 +119,6 @@ define(function (require) {
|
|||
columns: '=',
|
||||
filtering: '=',
|
||||
mapping: '=',
|
||||
maxLength: '=',
|
||||
timefield: '=?',
|
||||
row: '=kbnTableRow'
|
||||
},
|
||||
|
@ -138,11 +136,6 @@ define(function (require) {
|
|||
// whenever we compile, we should create a child scope that we can then detroy
|
||||
var $child;
|
||||
|
||||
// set the maxLength for summaries
|
||||
if ($scope.maxLength === void 0) {
|
||||
$scope.maxLength = 250;
|
||||
}
|
||||
|
||||
// toggle display of the rows details, a full list of the fields from each row
|
||||
$scope.toggleRow = function () {
|
||||
var row = $scope.row;
|
||||
|
@ -235,10 +228,11 @@ define(function (require) {
|
|||
/**
|
||||
* Fill an element with the value of a field
|
||||
*/
|
||||
function _displayField(el, row, field, truncate) {
|
||||
var val = _getValForField(row, field, truncate);
|
||||
el.text(val);
|
||||
return el;
|
||||
function _displayField(el, row, field) {
|
||||
return el.html(
|
||||
$('<div>').addClass('truncate-by-height')
|
||||
.text(_getValForField(row, field))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -247,10 +241,9 @@ define(function (require) {
|
|||
*
|
||||
* @param {object} row - the row to pull the value from
|
||||
* @param {string} field - the name of the field (dot-seperated paths are accepted)
|
||||
* @param {boolean} untruncate - Should truncated values have a "more" link to expand the text?
|
||||
* @return {[type]} a string, which should be inserted as text, or an element
|
||||
*/
|
||||
function _getValForField(row, field, untruncate) {
|
||||
function _getValForField(row, field) {
|
||||
var val;
|
||||
|
||||
// discover formats all of the values and puts them in _formatted for display
|
||||
|
@ -259,11 +252,6 @@ define(function (require) {
|
|||
// undefined and null should just be an empty string
|
||||
val = (val == null) ? '' : val;
|
||||
|
||||
// truncate the column text, not the details
|
||||
if (typeof val === 'string' && val.length > $scope.maxLength) {
|
||||
val = val.substring(0, $scope.maxLength) + '...';
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
|
|
|
@ -21,10 +21,18 @@
|
|||
</form>
|
||||
|
||||
<div class="button-group">
|
||||
<button ng-click="newQuery()"><i class="fa fa-file-o"></i></button>
|
||||
<button ng-click="toggleSave()"><i class="fa fa-save"></i></button>
|
||||
<button ng-click="toggleLoad()"><i class="fa fa-folder-open"></i></button>
|
||||
<button ng-click="toggleConfig()"><i class="fa fa-gear"></i></button>
|
||||
<kbn-tooltip text="New Search" placement="bottom" append-to-body="1">
|
||||
<button ng-click="newQuery()"><i class="fa fa-file-new-o"></i></button>
|
||||
</kbn-tooltip>
|
||||
<kbn-tooltip text="Save Search" placement="bottom" append-to-body="1">
|
||||
<button ng-click="toggleSave()"><i class="fa fa-save"></i></button>
|
||||
</kbn-tooltip>
|
||||
<kbn-tooltip text="Load Saved Search" placement="bottom" append-to-body="1">
|
||||
<button ng-click="toggleLoad()"><i class="fa fa-folder-open-o"></i></button>
|
||||
</kbn-tooltip>
|
||||
<kbn-tooltip text="Settings" placement="bottom" append-to-body="1">
|
||||
<button ng-click="toggleConfig()"><i class="fa fa-gear"></i></button>
|
||||
</kbn-tooltip>
|
||||
</div>
|
||||
</navbar>
|
||||
|
||||
|
@ -137,7 +145,6 @@
|
|||
sorting="state.sort"
|
||||
filtering="filterQuery"
|
||||
refresh="fetch"
|
||||
max-length="opts.maxSummaryLength"
|
||||
timefield="opts.timefield"
|
||||
mapping="fieldsByName">
|
||||
</kbn-table>
|
||||
|
|
|
@ -28,9 +28,7 @@
|
|||
tooltip-placement="top"
|
||||
tooltip="No cached mapping for this field. Refresh your mapping from the Settings > Indices page"
|
||||
class="fa fa-warning text-color-warning ng-scope"></i>
|
||||
<kbn-truncated class="discover-table-details-value"
|
||||
orig="{{row._formatted[field] || row[field]}}"
|
||||
length=100></kbn-truncated>
|
||||
<span class="discover-table-details-value">{{row._formatted[field] || row[field]}}</span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
mapping="mapping"
|
||||
sorting="sorting"
|
||||
timefield="timefield"
|
||||
max-length="maxLength"
|
||||
filtering="filtering"
|
||||
class="discover-table-row"></tr>
|
||||
</tbody>
|
||||
|
|
|
@ -20,7 +20,11 @@
|
|||
<tbody>
|
||||
<tr ng-repeat="conf in configs | filter:advancedFilter" ng-class="conf.value === undefined ? 'default' : 'custom'">
|
||||
<td class="name">
|
||||
<b>{{conf.name}}</b><br>
|
||||
<b>{{conf.name}}</b>
|
||||
<span class="smaller" ng-show="conf.value !== undefined">
|
||||
(Default: <i>{{conf.defVal == undefined ? 'null' : conf.defVal}}</i>)
|
||||
</span>
|
||||
<br>
|
||||
<span class="smaller">{{conf.description}}</span>
|
||||
</td>
|
||||
<td class="value">
|
||||
|
|
|
@ -50,30 +50,35 @@
|
|||
</select>
|
||||
</div>
|
||||
|
||||
<div class="alert alert-danger" ng-repeat="err in index.patternErrors">{{err}}</div>
|
||||
<div class="alert alert-danger" ng-repeat="err in index.patternErrors">
|
||||
{{err}}
|
||||
</div>
|
||||
|
||||
<div class="alert alert-info" ng-if="index.samples">
|
||||
Sample index names
|
||||
Attempted to match the following indices:
|
||||
<ul>
|
||||
<li ng-repeat="sample in index.samples">{{sample}}</li>
|
||||
</ul>
|
||||
<a ng-click="moreSamples(true)" class="alert-link">more</a>
|
||||
<button ng-click="moreSamples(true)" class="btn btn-default">
|
||||
Expand Search
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="alert alert-{{index.existing.class}}" ng-if="index.existing">
|
||||
Pattern matches {{index.existing.matchPercent}} of similar indices
|
||||
Pattern matches {{index.existing.matchPercent}} of existing indices
|
||||
<ul>
|
||||
<li ng-repeat="match in index.existing.matches | orderBy:'toString()'| limitTo: index.sampleCount">{{match}}</li>
|
||||
</ul>
|
||||
<a
|
||||
<button
|
||||
ng-if="index.sampleCount < index.existing.matches.length"
|
||||
ng-click="moreSamples()"
|
||||
class="alert-link">
|
||||
more
|
||||
</a>
|
||||
class="btn btn-default">
|
||||
Expand Search
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="alert alert-danger" ng-if="index.existing.failures.length">
|
||||
Indices that did not match:
|
||||
Indices that were found, but did not match the pattern:
|
||||
<ul>
|
||||
<li ng-repeat="match in index.existing.failures | limitTo: index.sampleCount">{{match}}</li>
|
||||
</ul>
|
||||
|
@ -83,9 +88,7 @@
|
|||
class="alert-link">
|
||||
more
|
||||
</a>
|
||||
</section>
|
||||
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="form-group" ng-if="index.isTimeBased">
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
<ul class="nav nav-tabs">
|
||||
<li class="kbn-settings-tab" ng-class="{ active: state.tab === service.title }" ng-repeat="service in services">
|
||||
<a ng-click="changeTab(service)">{{ service.title }} <small>({{service.hits}})</small></a>
|
||||
<a ng-click="changeTab(service)">{{ service.title }} <small>({{service.data.length}})</small></a>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="tab-content">
|
||||
|
|
|
@ -29,7 +29,7 @@ define(function (require) {
|
|||
var services = registry.all().map(function (obj) {
|
||||
var service = $injector.get(obj.service);
|
||||
return service.find(filter).then(function (data) {
|
||||
return { service: obj.service, title: obj.title, data: data.hits, hits: data.total };
|
||||
return { service: obj.service, title: obj.title, data: data.hits };
|
||||
});
|
||||
});
|
||||
$q.all(services).then(function (data) {
|
||||
|
|
|
@ -44,21 +44,31 @@
|
|||
</div>
|
||||
|
||||
<div class="button-group">
|
||||
<button ng-click="startOver()"><i class="fa fa-file-o"></i></button>
|
||||
<kbn-tooltip text="New Visualization" placement="bottom" append-to-body="1">
|
||||
<button ng-click="startOver()"><i class="fa fa-file-new-o"></i></button>
|
||||
</kbn-tooltip>
|
||||
|
||||
<!-- normal save -->
|
||||
<button ng-if="!editableVis.dirty" ng-click="toggleSave()">
|
||||
<i class="fa fa-save"></i>
|
||||
</button>
|
||||
<kbn-tooltip text="Save Visualization" placement="bottom" append-to-body="1">
|
||||
<!-- normal save -->
|
||||
<button ng-if="!editableVis.dirty" ng-click="toggleSave()">
|
||||
<i class="fa fa-save"></i>
|
||||
</button>
|
||||
|
||||
<!-- save stub with tooltip -->
|
||||
<button disabled ng-if="editableVis.dirty" tooltip="Apply or Discard your changes before saving">
|
||||
<i class="fa fa-save"></i>
|
||||
</button>
|
||||
<!-- save stub with tooltip -->
|
||||
<button disabled ng-if="editableVis.dirty" tooltip="Apply or Discard your changes before saving">
|
||||
<i class="fa fa-save"></i>
|
||||
</button>
|
||||
</kbn-tooltip>
|
||||
|
||||
<button ng-click="toggleLoad()"><i class="fa fa-folder-open"></i></button>
|
||||
<button ng-click="toggleShare()"><i class="fa fa-code"></i></button>
|
||||
<button ng-click="fetch()"><i class="fa fa-refresh"></i></button>
|
||||
<kbn-tooltip text="Load Saved Visualization" placement="bottom" append-to-body="1">
|
||||
<button ng-click="toggleLoad()"><i class="fa fa-folder-open-o"></i></button>
|
||||
</kbn-tooltip>
|
||||
<kbn-tooltip text="Share Visualization" placement="bottom" append-to-body="1">
|
||||
<button ng-click="toggleShare()"><i class="fa fa-external-link"></i></button>
|
||||
</kbn-tooltip>
|
||||
<kbn-tooltip text="Refresh" placement="bottom" append-to-body="1">
|
||||
<button ng-click="fetch()"><i class="fa fa-refresh"></i></button>
|
||||
</kbn-tooltip>
|
||||
</div>
|
||||
</navbar>
|
||||
|
||||
|
|
|
@ -10,4 +10,8 @@
|
|||
}
|
||||
}
|
||||
|
||||
.visualizations .visualization i {
|
||||
margin-right: @padding-base-horizontal;
|
||||
}
|
||||
|
||||
@import "../editor/editor.less";
|
|
@ -3,12 +3,12 @@
|
|||
<span class="pull-right label label-default">Step 2</span>
|
||||
</h1>
|
||||
|
||||
<ul class="list-group list-group-menu">
|
||||
<a class="list-group-item list-group-menu-item"
|
||||
<ul class="visualizations list-group list-group-menu">
|
||||
<a class="visualization list-group-item list-group-menu-item"
|
||||
ng-repeat="type in visTypes"
|
||||
ng-href="{{ visTypeUrl(type) }}">
|
||||
<li>
|
||||
<i ng-class="type.icon"></i>{{type.title}}
|
||||
<i class="fa" ng-class="type.icon"></i>{{type.title}}
|
||||
</li>
|
||||
</a>
|
||||
</ul>
|
|
@ -46,5 +46,9 @@ define(function (require) {
|
|||
value: false,
|
||||
description: 'Shorten long fields, for example, instead of foo.bar.baz, show f.b.baz',
|
||||
},
|
||||
'truncate:maxHeight': {
|
||||
value: 100,
|
||||
description: 'The maximum height that a cell in a table should occupy. Set to 0 to disable truncation.'
|
||||
}
|
||||
};
|
||||
});
|
|
@ -168,7 +168,8 @@ define(function (require) {
|
|||
};
|
||||
|
||||
obj.saveSource = function (source) {
|
||||
return docSource.doIndex(source).then(function (id) {
|
||||
return docSource.doIndex(source)
|
||||
.then(function (id) {
|
||||
obj.id = id;
|
||||
})
|
||||
.then(function () {
|
||||
|
|
|
@ -8,6 +8,8 @@ define(function (require) {
|
|||
var clearTO = clearTimeout;
|
||||
var consoleGroups = ('group' in window.console) && ('groupCollapsed' in window.console) && ('groupEnd' in window.console);
|
||||
|
||||
var fatalSplashScreen = require('text!components/notify/partials/fatal_splash_screen.html');
|
||||
|
||||
var log = _.noop;
|
||||
if (typeof KIBANA_DIST === 'undefined') {
|
||||
log = function () {
|
||||
|
@ -170,16 +172,17 @@ define(function (require) {
|
|||
});
|
||||
|
||||
var $container = $('#fatal-splash-screen');
|
||||
if ($container.size()) {
|
||||
$container.append(html);
|
||||
return;
|
||||
|
||||
if (!$container.size()) {
|
||||
$(document.body)
|
||||
// in case the app has not completed boot
|
||||
.removeAttr('ng-cloak')
|
||||
.html(fatalSplashScreen);
|
||||
|
||||
$container = $('#fatal-splash-screen');
|
||||
}
|
||||
|
||||
// in case the app has not completed boot
|
||||
$(document.body)
|
||||
.removeAttr('ng-cloak')
|
||||
.html('<div id="fatal-splash-screen" class="container-fuild">' + html + '</div>');
|
||||
|
||||
$container.append(html);
|
||||
console.error(err.stack);
|
||||
};
|
||||
|
||||
|
|
|
@ -9,9 +9,6 @@
|
|||
<div class="panel-heading">
|
||||
<h1 class="panel-title">
|
||||
<i class="fa fa-warning"></i> Fatal Error
|
||||
<a class="pull-right" onclick="window.location.reload();" href="#">
|
||||
Reload <i class="refresh fa fa-refresh"></i>
|
||||
</a>
|
||||
</h1>
|
||||
</div>
|
||||
<div class="panel-body"><%- msg %></div>
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
<div id="fatal-splash-screen-header" class="container">
|
||||
<center>
|
||||
<h1>Oops!</h1>
|
||||
<p>
|
||||
Looks like something went wrong. Refreshing may do the trick.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<button class="btn btn-success" onclick="window.location.reload();">
|
||||
<i class="refresh fa fa-refresh"></i> Reload
|
||||
</button>
|
||||
or
|
||||
<a
|
||||
onclick="localStorage.clear(); sessionStorage.clear(); window.location.hash = ''; window.location.reload();"
|
||||
href="#" >
|
||||
clear your session
|
||||
</a>
|
||||
</p>
|
||||
</center>
|
||||
<div id="fatal-splash-screen">
|
||||
</div>
|
||||
</div>
|
|
@ -6,7 +6,7 @@ define(function (require) {
|
|||
return new VisType({
|
||||
name: 'histogram',
|
||||
title: 'Vertical bar chart',
|
||||
icon: 'icon-chart-bar',
|
||||
icon: 'fa-bar-chart',
|
||||
vislibParams: {
|
||||
shareYAxis: true,
|
||||
addTooltip: true,
|
||||
|
|
|
@ -6,7 +6,7 @@ define(function (require) {
|
|||
return new VisType({
|
||||
name: 'line',
|
||||
title: 'Line chart',
|
||||
icon: 'icon-chart-bar',
|
||||
icon: 'fa-line-chart',
|
||||
vislibParams: {
|
||||
shareYAxis: true,
|
||||
addTooltip: true,
|
||||
|
|
|
@ -7,7 +7,7 @@ define(function (require) {
|
|||
return new VisType({
|
||||
name: 'pie',
|
||||
title: 'Pie chart',
|
||||
icon: 'icon-chart-bar',
|
||||
icon: 'fa-pie-chart',
|
||||
vislibParams: {
|
||||
addEvents: true,
|
||||
addTooltip: true,
|
||||
|
|
|
@ -32,10 +32,11 @@ define(function (require) {
|
|||
|
||||
return function (selection) {
|
||||
selection.each(function () {
|
||||
var div = d3.select(this);
|
||||
var width = $(this).width();
|
||||
var height = $(this).height();
|
||||
|
||||
var el = this;
|
||||
var div = d3.select(el);
|
||||
var width = $(el).width();
|
||||
var height = $(el).height();
|
||||
|
||||
self.validateWidthandHeight(width, height);
|
||||
|
||||
div.append('svg')
|
||||
|
|
|
@ -79,6 +79,7 @@ define(function (require) {
|
|||
var width = $(this).width();
|
||||
var height = $(this).height();
|
||||
var size = dataType === 'rows' ? height : width;
|
||||
var txtHtOffset = 11;
|
||||
|
||||
// Check if width or height are 0 or NaN
|
||||
self.validateWidthandHeight(width, height);
|
||||
|
@ -95,9 +96,9 @@ define(function (require) {
|
|||
.attr('transform', function () {
|
||||
if (dataType === 'rows') {
|
||||
// if `rows`, rotate the chart titles
|
||||
return 'translate(11,' + height / 2 + ')rotate(270)';
|
||||
return 'translate(' + txtHtOffset + ',' + height / 2 + ')rotate(270)';
|
||||
}
|
||||
return 'translate(' + width / 2 + ',8)';
|
||||
return 'translate(' + width / 2 + ',' + txtHtOffset + ')';
|
||||
})
|
||||
.attr('text-anchor', 'middle')
|
||||
.text(function (d) {
|
||||
|
|
|
@ -150,6 +150,19 @@ define(function (require) {
|
|||
});
|
||||
};
|
||||
|
||||
Data.prototype.getNames = function () {
|
||||
var data = this.pieData();
|
||||
var names = [];
|
||||
|
||||
data.forEach(function returnNames(obj) {
|
||||
if (obj.names) {
|
||||
names = names.concat(obj.names);
|
||||
}
|
||||
});
|
||||
|
||||
return _.unique(names);
|
||||
};
|
||||
|
||||
// Inject zeros into the data
|
||||
Data.prototype.injectZeros = function () {
|
||||
return injectZeros(this.data);
|
||||
|
@ -172,7 +185,7 @@ define(function (require) {
|
|||
|
||||
// Return a function that does color lookup on names for pie charts
|
||||
Data.prototype.getPieColorFunc = function () {
|
||||
return color(this.get('names'));
|
||||
return color(this.getNames());
|
||||
};
|
||||
|
||||
return Data;
|
||||
|
|
|
@ -40,11 +40,12 @@ define(function (require) {
|
|||
// Array of objects to render to the visualization
|
||||
this.renderArray = _.filter([
|
||||
this.layout,
|
||||
this.xAxis,
|
||||
this.yAxis,
|
||||
this.chartTitle,
|
||||
this.axisTitle,
|
||||
this.legend,
|
||||
this.tooltip,
|
||||
this.axisTitle,
|
||||
this.chartTitle,
|
||||
this.xAxis,
|
||||
this.yAxis
|
||||
], Boolean);
|
||||
}
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ define(function (require) {
|
|||
var data = new Data(vis.data, vis._attr);
|
||||
|
||||
var PieHandler = new Handler(vis, {
|
||||
legend: new Legend(vis, vis.el, data.get('names'), data.getPieColorFunc(), vis._attr),
|
||||
legend: new Legend(vis, vis.el, data.getNames(), data.getPieColorFunc(), vis._attr),
|
||||
chartTitle: new ChartTitle(vis.el)
|
||||
});
|
||||
|
||||
|
|
|
@ -24,37 +24,36 @@ define(function (require) {
|
|||
this.xValues = args.xValues;
|
||||
this.ordered = args.ordered;
|
||||
this.xAxisFormatter = args.xAxisFormatter;
|
||||
this._attr = _.defaults(args._attr || {}, {
|
||||
// isDiscover: false,
|
||||
//isRotated: true
|
||||
});
|
||||
this._attr = _.defaults(args._attr || {});
|
||||
}
|
||||
|
||||
_(XAxis.prototype).extend(ErrorHandler.prototype);
|
||||
|
||||
// Render the x axis
|
||||
XAxis.prototype.render = function () {
|
||||
d3.select(this.el).selectAll('.x-axis-div').call(this.draw());
|
||||
d3.select(this.el)
|
||||
.selectAll('.x-axis-div')
|
||||
.call(this.draw());
|
||||
};
|
||||
|
||||
// Get the d3 scale
|
||||
// if time, return time scale
|
||||
// return d3 ordinal scale for nominal data
|
||||
XAxis.prototype.getScale = function (ordered) {
|
||||
// if time, return time scale
|
||||
if (ordered && ordered.date) {
|
||||
return d3.time.scale();
|
||||
}
|
||||
// return d3 ordinal scale for nominal data
|
||||
return d3.scale.ordinal();
|
||||
};
|
||||
|
||||
// Add domain to the scale
|
||||
// if time, return a time domain
|
||||
// Calculate the min date, max date, and time interval;
|
||||
// return a nominal domain, i.e. array of x values
|
||||
XAxis.prototype.getDomain = function (scale, ordered) {
|
||||
// if time, return a time domain
|
||||
if (ordered && ordered.date) {
|
||||
// Calculate the min date, max date, and time interval;
|
||||
return this.getTimeDomain(scale, ordered);
|
||||
}
|
||||
// return a nominal domain, i.e. array of x values
|
||||
return this.getOrdinalDomain(scale, this.xValues);
|
||||
};
|
||||
|
||||
|
@ -70,12 +69,12 @@ define(function (require) {
|
|||
};
|
||||
|
||||
// Return the range for the x axis scale
|
||||
// if time, return a normal range
|
||||
// if nominal, return rangeBands with a default (0.1) spacer specified
|
||||
XAxis.prototype.getRange = function (scale, ordered, width) {
|
||||
// if time, return a normal range
|
||||
if (ordered && ordered.date) {
|
||||
return scale.range([0, width]);
|
||||
}
|
||||
// if nominal, return rangeBands with a default (0.1) spacer specified
|
||||
return scale.rangeBands([0, width], 0.1);
|
||||
};
|
||||
|
||||
|
@ -89,21 +88,20 @@ define(function (require) {
|
|||
};
|
||||
|
||||
// Create the d3 xAxis function
|
||||
// save a reference to the xScale
|
||||
// Scale should never === `NaN`
|
||||
XAxis.prototype.getXAxis = function (width) {
|
||||
// save a reference to the xScale
|
||||
this.xScale = this.getXScale(this.ordered, width);
|
||||
|
||||
// Scale should never === `NaN`
|
||||
if (!this.xScale || _.isNaN(this.xScale)) {
|
||||
throw new Error('xScale is ' + this.xScale);
|
||||
}
|
||||
|
||||
// save a reference to the xAxis
|
||||
this.xAxis = d3.svg.axis()
|
||||
.scale(this.xScale)
|
||||
.ticks(10)
|
||||
.tickFormat(this.xAxisFormatter)
|
||||
.orient('bottom');
|
||||
.scale(this.xScale)
|
||||
.ticks(10)
|
||||
.tickFormat(this.xAxisFormatter)
|
||||
.orient('bottom');
|
||||
};
|
||||
|
||||
// Returns a function that renders the x axis
|
||||
|
@ -114,29 +112,37 @@ define(function (require) {
|
|||
var width;
|
||||
var height;
|
||||
var svg;
|
||||
var parentWidth;
|
||||
var n;
|
||||
this._attr.isRotated = false;
|
||||
|
||||
return function (selection) {
|
||||
n = selection[0].length;
|
||||
parentWidth = $(self.el)
|
||||
.find('.x-axis-div-wrapper')
|
||||
.width();
|
||||
|
||||
selection.each(function () {
|
||||
|
||||
// Validate that width and height are not 0 or `NaN`
|
||||
// return access to xAxis variable on the object
|
||||
// append svg and x axis
|
||||
div = d3.select(this);
|
||||
width = $(this).width();
|
||||
width = parentWidth / n;
|
||||
height = $(this).height();
|
||||
|
||||
// Validate that the width and height are not 0 or `NaN`
|
||||
self.validateWidthandHeight(width, height);
|
||||
|
||||
// Return access to xAxis variable on the object
|
||||
self.getXAxis(width);
|
||||
|
||||
// Append svg and x axis
|
||||
svg = div.append('svg')
|
||||
.attr('width', width)
|
||||
.attr('height', height);
|
||||
.attr('width', width)
|
||||
.attr('height', height);
|
||||
|
||||
svg.append('g')
|
||||
.attr('class', 'x axis')
|
||||
.attr('transform', 'translate(0,0)')
|
||||
.call(self.xAxis);
|
||||
.attr('class', 'x axis')
|
||||
.attr('transform', 'translate(0,0)')
|
||||
.call(self.xAxis);
|
||||
});
|
||||
|
||||
selection.call(self.filterOrRotate());
|
||||
|
@ -158,80 +164,90 @@ define(function (require) {
|
|||
labels = axis.selectAll('.tick text');
|
||||
|
||||
if (!self.ordered) {
|
||||
// nominal/ordinal scale
|
||||
axis.call(self.rotateAxisLabels());
|
||||
axis.call(self.truncateLabels(100));
|
||||
} else {
|
||||
// time scale
|
||||
axis.call(self.filterAxisLabels());
|
||||
}
|
||||
});
|
||||
|
||||
self.updateXaxisHeight();
|
||||
|
||||
selection.call(self.fitTitles());
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
// Rotate the axis tick labels within selection
|
||||
XAxis.prototype.rotateAxisLabels = function () {
|
||||
this._attr.isRotated = true;
|
||||
var self = this;
|
||||
var text;
|
||||
var maxWidth = self.xScale.rangeBand();
|
||||
var textWidth = 0;
|
||||
var xAxisPadding = 15;
|
||||
var svg;
|
||||
var xAxisLabelHt = 15;
|
||||
var width;
|
||||
self._attr.isRotated = false;
|
||||
|
||||
return function (selection) {
|
||||
selection.selectAll('.tick text')
|
||||
|
||||
text = selection.selectAll('.tick text');
|
||||
|
||||
text.each(function textWidths() {
|
||||
width = d3.select(this).node().getBBox().width;
|
||||
if (width > maxWidth) {
|
||||
self._attr.isRotated = true;
|
||||
xAxisLabelHt = _.max([textWidth, (Math.ceil(width + xAxisPadding))]);
|
||||
}
|
||||
});
|
||||
self._attr.xAxisLabelHt = xAxisLabelHt;
|
||||
|
||||
|
||||
if (self._attr.isRotated) {
|
||||
text
|
||||
.text(function truncate() {
|
||||
return self.truncateLabel(this, xAxisLabelHt);
|
||||
})
|
||||
.style('text-anchor', 'end')
|
||||
.attr('dx', '-.8em')
|
||||
.attr('dy', '-.60em')
|
||||
.attr('transform', function () {
|
||||
.attr('transform', function rotate() {
|
||||
return 'rotate(-90)';
|
||||
});
|
||||
selection.select('svg')
|
||||
.attr('height', xAxisLabelHt);
|
||||
}
|
||||
|
||||
// TODO: need to add mouseover to show tooltip on truncated labels
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
// Returns a function that truncates tick labels
|
||||
XAxis.prototype.truncateLabels = function (size) {
|
||||
var self = this;
|
||||
var labels;
|
||||
var node;
|
||||
var str;
|
||||
var n;
|
||||
var maxWidth;
|
||||
var maxLength;
|
||||
var pixPerChar;
|
||||
var endChar;
|
||||
// Returns a string that is truncated to fit size
|
||||
XAxis.prototype.truncateLabel = function (text, size) {
|
||||
var node = d3.select(text).node();
|
||||
var str = $(node).text();
|
||||
var width = node.getBBox().width;
|
||||
var chars = str.length;
|
||||
var pxPerChar = width / chars;
|
||||
var endChar = 0;
|
||||
var ellipsesPad = 4;
|
||||
|
||||
return function (selection) {
|
||||
|
||||
// get label maxWidth
|
||||
labels = selection.selectAll('.tick text');
|
||||
maxWidth = 0;
|
||||
maxLength = 0;
|
||||
labels.each(function () {
|
||||
node = d3.select(this).node();
|
||||
n = node.innerHTML.length;
|
||||
maxWidth = _.max([maxWidth, node.getComputedTextLength() * 0.9]);
|
||||
maxLength = _.max([maxLength, n]);
|
||||
});
|
||||
pixPerChar = maxWidth / maxLength;
|
||||
|
||||
// truncate str
|
||||
selection.selectAll('.tick text')
|
||||
.text(function (d) {
|
||||
str = d;
|
||||
if (maxWidth > size) {
|
||||
endChar = 0;
|
||||
if (Math.floor((size / pixPerChar) - 4) >= 4) {
|
||||
endChar = Math.floor((size / pixPerChar) - 4);
|
||||
while (str[endChar - 1] === ' ' || str[endChar - 1] === '-' || str[endChar - 1] === ',') {
|
||||
endChar = endChar - 1;
|
||||
}
|
||||
}
|
||||
str = str.substr(0, endChar) + '...';
|
||||
return str;
|
||||
}
|
||||
return str;
|
||||
});
|
||||
};
|
||||
if (width > size) {
|
||||
endChar = Math.floor((size / pxPerChar) - ellipsesPad);
|
||||
while (str[endChar - 1] === ' ' || str[endChar - 1] === '-' || str[endChar - 1] === ',') {
|
||||
endChar = endChar - 1;
|
||||
}
|
||||
str = str.substr(0, endChar) + '...';
|
||||
}
|
||||
return str;
|
||||
};
|
||||
|
||||
// Filter out text labels by width and position on axis
|
||||
// trims labels that would overlap each other
|
||||
// or extend past left or right edges
|
||||
// if prev label pos (or 0) + half of label width is < label pos
|
||||
// and label pos + half width is not > width of axis
|
||||
XAxis.prototype.filterAxisLabels = function () {
|
||||
var self = this;
|
||||
var startX = 0;
|
||||
|
@ -240,62 +256,136 @@ define(function (require) {
|
|||
var myX;
|
||||
var myWidth;
|
||||
var halfWidth;
|
||||
var padding = 1.1;
|
||||
|
||||
return function (selection) {
|
||||
selection.selectAll('.tick text')
|
||||
.text(function (d, i) {
|
||||
par = d3.select(this.parentNode).node();
|
||||
myX = self.xScale(d);
|
||||
myWidth = par.getBBox().width;
|
||||
halfWidth = par.getBBox().width / 2;
|
||||
maxW = $('.x-axis-div').width();
|
||||
// trims labels that would overlap each other
|
||||
// or extend past left or right edges
|
||||
// if prev label pos (or 0) + half of label width is < label pos
|
||||
// and label pos + half width is not > width of axis
|
||||
if ((startX + halfWidth) < myX && maxW > (myX + halfWidth)) {
|
||||
startX = myX + halfWidth;
|
||||
return self.xAxisFormatter(d);
|
||||
} else {
|
||||
d3.select(this.parentNode).remove();
|
||||
}
|
||||
});
|
||||
.text(function (d, i) {
|
||||
par = d3.select(this.parentNode).node();
|
||||
myX = self.xScale(d);
|
||||
myWidth = par.getBBox().width * padding;
|
||||
halfWidth = myWidth / 2;
|
||||
maxW = $(self.el).find('.x-axis-div').width();
|
||||
|
||||
if ((startX + halfWidth) < myX && maxW > (myX + halfWidth)) {
|
||||
startX = myX + halfWidth;
|
||||
return self.xAxisFormatter(d);
|
||||
} else {
|
||||
d3.select(this.parentNode).remove();
|
||||
}
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
// Returns a function that adjusts axis title and
|
||||
// all chart title transforms to fit axis labels
|
||||
// Returns a function that adjusts axis titles and
|
||||
// chart title transforms to fit axis label divs.
|
||||
// Sets transform of x-axis-title to fit .x-axis-title div width
|
||||
// if x-axis-chart-titles, set transform of x-axis-chart-titles
|
||||
// to fit .chart-title div width
|
||||
XAxis.prototype.fitTitles = function () {
|
||||
var self = this;
|
||||
var visEl = $(self.el);
|
||||
var xAxisTitle = visEl.find('.x-axis-title');
|
||||
var xAxisChartTitle = visEl.find('.x-axis-chart-title');
|
||||
var visEls = $('.vis-wrapper');
|
||||
var visEl;
|
||||
var xAxisTitle;
|
||||
var yAxisTitle;
|
||||
var xAxisChartTitle;
|
||||
var yAxisChartTitle;
|
||||
var titleWidth;
|
||||
var titleHeight;
|
||||
var text;
|
||||
var titles;
|
||||
var titleWidth;
|
||||
|
||||
return function () {
|
||||
// set transform of x-axis-title text to fit .x-axis-title div width
|
||||
titleWidth = xAxisTitle.width();
|
||||
text = d3.select('.x-axis-title')
|
||||
.select('svg')
|
||||
.select('text')
|
||||
.attr('transform', 'translate(' + (titleWidth / 2) + ',11)');
|
||||
|
||||
// set transform of x-axis-chart-titles text to fit .chart-title div width
|
||||
titleWidth = xAxisChartTitle.find('.chart-title').width();
|
||||
titles = d3.select('.x-axis-chart-title')
|
||||
.selectAll('.chart-title');
|
||||
titles.each(function () {
|
||||
text = d3.select(this)
|
||||
visEls.each(function () {
|
||||
var visEl = d3.select(this);
|
||||
var $visEl = $(this);
|
||||
var xAxisTitle = $visEl.find('.x-axis-title');
|
||||
var yAxisTitle = $visEl.find('.y-axis-title');
|
||||
var titleWidth = xAxisTitle.width();
|
||||
var titleHeight = yAxisTitle.height();
|
||||
|
||||
text = visEl.select('.x-axis-title')
|
||||
.select('svg')
|
||||
.attr('width', titleWidth)
|
||||
.select('text')
|
||||
.attr('transform', 'translate(' + (titleWidth / 2) + ',11)');
|
||||
|
||||
text = visEl.select('.y-axis-title')
|
||||
.select('svg')
|
||||
.attr('height', titleHeight)
|
||||
.select('text')
|
||||
.attr('transform', 'translate(11,' + (titleHeight / 2) + ')rotate(-90)');
|
||||
|
||||
if ($visEl.find('.x-axis-chart-title').length) {
|
||||
xAxisChartTitle = $visEl.find('.x-axis-chart-title');
|
||||
titleWidth = xAxisChartTitle.find('.chart-title').width();
|
||||
|
||||
titles = visEl.select('.x-axis-chart-title').selectAll('.chart-title');
|
||||
titles.each(function () {
|
||||
text = d3.select(this)
|
||||
.select('svg')
|
||||
.attr('width', titleWidth)
|
||||
.select('text')
|
||||
.attr('transform', 'translate(' + (titleWidth / 2) + ',11)');
|
||||
});
|
||||
}
|
||||
|
||||
if ($visEl.find('.y-axis-chart-title').length) {
|
||||
yAxisChartTitle = $visEl.find('.y-axis-chart-title');
|
||||
titleHeight = yAxisChartTitle.find('.chart-title').height();
|
||||
|
||||
titles = visEl.select('.y-axis-chart-title').selectAll('.chart-title');
|
||||
titles.each(function () {
|
||||
text = d3.select(this)
|
||||
.select('svg')
|
||||
.attr('height', titleHeight)
|
||||
.select('text')
|
||||
.attr('transform', 'translate(11,' + (titleHeight / 2) + ')rotate(-90)');
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
// Appends div to make .y-axis-spacer-block
|
||||
// match height of .x-axis-wrapper
|
||||
XAxis.prototype.updateXaxisHeight = function () {
|
||||
var self = this;
|
||||
var selection = d3.selectAll('.vis-wrapper');
|
||||
var $selection = $('.vis-wrapper');
|
||||
var titleHts = 30;
|
||||
var xAxisLabelHt = 15;
|
||||
|
||||
if (self._attr.isRotated && self._attr.xAxisLabelHt) {
|
||||
xAxisLabelHt = self._attr.xAxisLabelHt;
|
||||
} else {
|
||||
xAxisLabelHt = self._attr.xAxisLabelHt = xAxisLabelHt;
|
||||
}
|
||||
|
||||
selection.each(function () {
|
||||
var visEl = d3.select(this);
|
||||
var $visEl = $(this);
|
||||
|
||||
$visEl.find('.x-axis-wrapper')
|
||||
.height(xAxisLabelHt + titleHts);
|
||||
$visEl.find('.x-axis-div-wrapper')
|
||||
.height(xAxisLabelHt);
|
||||
|
||||
if (visEl.select('.inner-spacer-block').node() === null) {
|
||||
visEl.select('.y-axis-spacer-block')
|
||||
.append('div')
|
||||
.attr('class', 'inner-spacer-block');
|
||||
}
|
||||
|
||||
visEl.select('.inner-spacer-block')
|
||||
.style('height', (xAxisLabelHt + titleHts) + 'px');
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
return XAxis;
|
||||
};
|
||||
});
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
/* vislib styles */
|
||||
.arc path {
|
||||
stroke: #fff;
|
||||
/* stroke-width: 3px; */
|
||||
}
|
||||
|
||||
div.columns {
|
||||
|
@ -155,14 +154,10 @@ li.color {
|
|||
|
||||
/* histogram axis and label styles */
|
||||
.vis-canvas {
|
||||
/* background-color: #fff; */
|
||||
}
|
||||
|
||||
.chart-bkgd {
|
||||
fill: #ffffff;
|
||||
/*fill: #eff3f4;*/
|
||||
/*stroke: #ddd;*/
|
||||
/*shape-rendering: crispEdges;*/
|
||||
}
|
||||
|
||||
p.rows-label, p.columns-label {
|
||||
|
@ -189,7 +184,6 @@ p.rows-label, p.columns-label {
|
|||
.tick text {
|
||||
font-size: 7pt;
|
||||
fill: #848e96;
|
||||
/*cursor: pointer;*/
|
||||
}
|
||||
|
||||
.axis {
|
||||
|
@ -233,16 +227,14 @@ p.rows-label, p.columns-label {
|
|||
}
|
||||
|
||||
.rect {
|
||||
/*shape-rendering: crispEdges;*/
|
||||
stroke: transparent;
|
||||
stroke-width: 2;
|
||||
}
|
||||
.rect.hover {
|
||||
/*shape-rendering: crispEdges;*/
|
||||
stroke: #333;
|
||||
}
|
||||
|
||||
/* Flex Box */
|
||||
/* Flex Box Layout */
|
||||
.vis-wrapper {
|
||||
.display(flex);
|
||||
.flex(1 1 100%);
|
||||
|
@ -252,22 +244,19 @@ p.rows-label, p.columns-label {
|
|||
|
||||
.error {
|
||||
.flex(1 1 100%);
|
||||
.display(flex);
|
||||
.align-items(center);
|
||||
text-align: center;
|
||||
|
||||
p {
|
||||
.flex(1 1 auto);
|
||||
margin-top: 15%;
|
||||
font-size: 18px;
|
||||
text-wrap: wrap;
|
||||
}
|
||||
}
|
||||
|
||||
/* YAxis logic */
|
||||
.y-axis-col-wrapper {
|
||||
.display(flex);
|
||||
.flex(0 0 auto);
|
||||
.flex-direction(column);
|
||||
min-width: 35px;
|
||||
}
|
||||
|
||||
.y-axis-col {
|
||||
|
@ -277,27 +266,32 @@ p.rows-label, p.columns-label {
|
|||
}
|
||||
|
||||
.y-axis-spacer-block {
|
||||
.flex(0 1 50px);
|
||||
min-height: 45px;
|
||||
}
|
||||
|
||||
.y-axis-div-wrapper {
|
||||
.display(flex);
|
||||
.flex-direction(column);
|
||||
.flex(0 0 33px);
|
||||
width: 38px;
|
||||
min-height: 20px;
|
||||
}
|
||||
|
||||
.y-axis-div {
|
||||
.flex(1 1 100%);
|
||||
.flex(1 1 25px);
|
||||
min-width: 14px;
|
||||
min-height: 14px;
|
||||
}
|
||||
|
||||
.y-axis-title {
|
||||
.flex(0 0 15px);
|
||||
min-height: 14px;
|
||||
min-width: 14px;
|
||||
}
|
||||
|
||||
.y-axis-chart-title {
|
||||
.display(flex);
|
||||
.flex-direction(column);
|
||||
.flex(0 0 15px);
|
||||
min-height: 14px;
|
||||
width: 14px;
|
||||
}
|
||||
|
||||
.y-axis-title text {
|
||||
|
@ -306,6 +300,8 @@ p.rows-label, p.columns-label {
|
|||
|
||||
.chart-title {
|
||||
.flex(1 1 100%);
|
||||
min-height: 14px;
|
||||
min-width: 14px;
|
||||
}
|
||||
|
||||
.chart-title text {
|
||||
|
@ -323,7 +319,7 @@ p.rows-label, p.columns-label {
|
|||
.display(flex);
|
||||
.flex(1 0 20px);
|
||||
overflow: visible;
|
||||
margin: 0 4px 0 0;
|
||||
margin: 0 5px 0 0;
|
||||
}
|
||||
|
||||
.chart-wrapper-column {
|
||||
|
@ -335,11 +331,11 @@ p.rows-label, p.columns-label {
|
|||
.chart-wrapper-row {
|
||||
.display(flex);
|
||||
.flex-direction(column);
|
||||
.flex(1 0 50px);
|
||||
.flex(1 0 100%);
|
||||
}
|
||||
|
||||
.chart {
|
||||
.flex(1 1);
|
||||
.flex(1 1 100%);
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
|
@ -354,24 +350,28 @@ p.rows-label, p.columns-label {
|
|||
.x-axis-wrapper {
|
||||
.display(flex);
|
||||
.flex-direction(column);
|
||||
.flex(0 1 50px);
|
||||
min-height: 45px;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.x-axis-div-wrapper {
|
||||
.display(flex);
|
||||
.flex-direction(row);
|
||||
.flex(0 1 15px);
|
||||
min-height: 15px;
|
||||
}
|
||||
|
||||
.x-axis-chart-title {
|
||||
.display(flex);
|
||||
.flex-direction(row);
|
||||
.flex(0 0 15px);
|
||||
min-height: 15px;
|
||||
max-height: 15px;
|
||||
min-width: 20px;
|
||||
}
|
||||
|
||||
.x-axis-title {
|
||||
.flex(0 0 15px);
|
||||
min-height: 15px;
|
||||
max-height: 15px;
|
||||
min-width: 20px;
|
||||
}
|
||||
|
||||
.x-axis-title text {
|
||||
|
@ -379,8 +379,9 @@ p.rows-label, p.columns-label {
|
|||
}
|
||||
|
||||
.x-axis-div {
|
||||
.flex(1 1 100%);
|
||||
margin-top: -5px;
|
||||
min-height: 20px;
|
||||
min-width: 20px;
|
||||
}
|
||||
|
||||
.x.axis path {
|
||||
|
|
|
@ -4,6 +4,7 @@ define(function (require) {
|
|||
var $ = require('jquery');
|
||||
|
||||
var Chart = Private(require('components/vislib/visualizations/_chart'));
|
||||
var errors = require('errors');
|
||||
|
||||
// Dynamically adds css file
|
||||
require('css!components/vislib/styles/main');
|
||||
|
@ -120,6 +121,12 @@ define(function (require) {
|
|||
var div = d3.select(el);
|
||||
var width = $(el).width();
|
||||
var height = $(el).height();
|
||||
var minWidth = 20;
|
||||
var minHeight = 20;
|
||||
|
||||
if (width <= minWidth || height <= minHeight) {
|
||||
throw new errors.ContainerTooSmall();
|
||||
}
|
||||
|
||||
var svg = div.append('svg')
|
||||
.attr('width', width)
|
||||
|
|
|
@ -16,9 +16,11 @@ define(function (require) {
|
|||
require('components/url/url');
|
||||
require('directives/click_focus');
|
||||
require('directives/info');
|
||||
require('directives/tooltip');
|
||||
require('directives/spinner');
|
||||
require('directives/paginate');
|
||||
require('directives/pretty_duration');
|
||||
require('directives/style_compile');
|
||||
require('directives/rows');
|
||||
|
||||
|
||||
|
|
36
src/kibana/directives/style_compile.js
Normal file
36
src/kibana/directives/style_compile.js
Normal file
|
@ -0,0 +1,36 @@
|
|||
define(function (require) {
|
||||
var _ = require('lodash');
|
||||
var $ = require('jquery');
|
||||
|
||||
require('modules')
|
||||
.get('kibana')
|
||||
.directive('styleCompile', function ($compile, config) {
|
||||
return {
|
||||
restrict: 'E',
|
||||
link: function ($scope, $el) {
|
||||
|
||||
var truncateGradientHeight = 15;
|
||||
|
||||
// watch the value of the truncate:maxHeight config param
|
||||
$scope.$watch(function () {
|
||||
return config.get('truncate:maxHeight');
|
||||
}, function (maxHeight) {
|
||||
if (maxHeight > 0) {
|
||||
$scope.truncateMaxHeight = maxHeight + 'px !important';
|
||||
$scope.truncateGradientTop = maxHeight - truncateGradientHeight + 'px';
|
||||
} else {
|
||||
$scope.truncateMaxHeight = 'none';
|
||||
$scope.truncateGradientTop = '-' + truncateGradientHeight + 'px';
|
||||
}
|
||||
});
|
||||
|
||||
var $style = $('<style>');
|
||||
$el.after($style);
|
||||
|
||||
$scope.$watch(function () { return $el.html(); }, function (stagedCss) {
|
||||
$style.html(stagedCss);
|
||||
});
|
||||
}
|
||||
};
|
||||
});
|
||||
});
|
20
src/kibana/directives/tooltip.js
Normal file
20
src/kibana/directives/tooltip.js
Normal file
|
@ -0,0 +1,20 @@
|
|||
define(function (require) {
|
||||
var html = require('text!partials/tooltip.html');
|
||||
|
||||
require('modules')
|
||||
.get('kibana')
|
||||
.directive('kbnTooltip', function () {
|
||||
return {
|
||||
restrict: 'E',
|
||||
template: html,
|
||||
transclude: true,
|
||||
replace: true,
|
||||
link: function ($scope, $el, attr) {
|
||||
$scope.text = attr.text;
|
||||
$scope.placement = attr.placement || 'top';
|
||||
$scope.delay = attr.delay || 400;
|
||||
$scope.appendToBody = attr.appendToBody || 0;
|
||||
}
|
||||
};
|
||||
});
|
||||
});
|
|
@ -67,5 +67,13 @@
|
|||
|
||||
<div class="application" ng-view></div>
|
||||
</div>
|
||||
<style-compile>
|
||||
.truncate-by-height {
|
||||
max-height: {{ truncateMaxHeight }};
|
||||
}
|
||||
.truncate-by-height::before {
|
||||
top: {{ truncateGradientTop }};
|
||||
}
|
||||
</style-compile>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -64,7 +64,7 @@ define(function (require) {
|
|||
angular
|
||||
.bootstrap(document, ['kibana'])
|
||||
.invoke(function () {
|
||||
$(document.body).children().show();
|
||||
$(document.body).children(':not(style-compile)').show();
|
||||
cb();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<i class="fa fa-info-circle"
|
||||
<i class="fa fa-info-circle"
|
||||
tooltip="{{info}}"
|
||||
tooltip-placement="{{placement}}"
|
||||
tooltip-popup-delay="250"></i>
|
|
@ -20,7 +20,7 @@
|
|||
ng-href="{{ makeUrl(hit) }}"
|
||||
ng-click="onChoose(hit, $event)">
|
||||
<li>
|
||||
<i ng-class="hit.icon"></i> {{hit.title}}
|
||||
<i class="fa" ng-if="hit.icon" ng-class="hit.icon"></i> {{hit.title}}
|
||||
<p ng-if="hit.description" ng-bind="hit.description"></p>
|
||||
</li>
|
||||
</a>
|
||||
|
|
6
src/kibana/partials/tooltip.html
Normal file
6
src/kibana/partials/tooltip.html
Normal file
|
@ -0,0 +1,6 @@
|
|||
<div
|
||||
tooltip="{{text}}"
|
||||
tooltip-placement="{{placement}}"
|
||||
tooltip-popup-delay="{{delay}}"
|
||||
tooltip-append-to-body="{{appendToBody}}"
|
||||
ng-transclude></div>
|
5
src/kibana/styles/_font_icons.less
Normal file
5
src/kibana/styles/_font_icons.less
Normal file
|
@ -0,0 +1,5 @@
|
|||
// shims for font-awesome
|
||||
|
||||
// new file icon
|
||||
.@{fa-css-prefix}-file-new-o:before { content: @fa-var-file-o; }
|
||||
.@{fa-css-prefix}-file-new-o:after { content: @fa-var-plus; position: relative; margin-left: -1.0em; font-size: 0.5em; }
|
|
@ -1,7 +1,3 @@
|
|||
#fatal-splash-screen {
|
||||
margin: 15px;
|
||||
}
|
||||
|
||||
.toaster-container {
|
||||
visibility: visible;
|
||||
width: 100%;
|
||||
|
|
19
src/kibana/styles/_truncate.less
Normal file
19
src/kibana/styles/_truncate.less
Normal file
|
@ -0,0 +1,19 @@
|
|||
.truncate-by-height {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
|
||||
&:before {
|
||||
content: " ";
|
||||
width: 100%;
|
||||
height: 15px; // copied into index.html!
|
||||
position: absolute;
|
||||
left: 0;
|
||||
|
||||
background: -moz-linear-gradient(top, rgba(255,255,255,0) 0%, rgba(255,255,255,0.01) 1%, rgba(255,255,255,0.99) 99%, rgba(255,255,255,1) 100%); /* FF3.6+ */
|
||||
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,rgba(255,255,255,0)), color-stop(1%,rgba(255,255,255,0.01)), color-stop(99%,rgba(255,255,255,0.99)), color-stop(100%,rgba(255,255,255,1))); /* Chrome,Safari4+ */
|
||||
background: -webkit-linear-gradient(top, rgba(255,255,255,0) 0%,rgba(255,255,255,0.01) 1%,rgba(255,255,255,0.99) 99%,rgba(255,255,255,1) 100%); /* Chrome10+,Safari5.1+ */
|
||||
background: -o-linear-gradient(top, rgba(255,255,255,0) 0%,rgba(255,255,255,0.01) 1%,rgba(255,255,255,0.99) 99%,rgba(255,255,255,1) 100%); /* Opera 11.10+ */
|
||||
background: -ms-linear-gradient(top, rgba(255,255,255,0) 0%,rgba(255,255,255,0.01) 1%,rgba(255,255,255,0.99) 99%,rgba(255,255,255,1) 100%); /* IE10+ */
|
||||
background: linear-gradient(to bottom, rgba(255,255,255,0) 0%,rgba(255,255,255,0.01) 1%,rgba(255,255,255,0.99) 99%,rgba(255,255,255,1) 100%); /* W3C */
|
||||
}
|
||||
}
|
|
@ -16,8 +16,9 @@
|
|||
// call outs
|
||||
@import "./_callout.less";
|
||||
|
||||
// call outs
|
||||
// font icons
|
||||
@import "./icon_font.css";
|
||||
@import "./_font_icons.less";
|
||||
|
||||
// FontAwesome fills for glyphicons in bootstrap components
|
||||
@import "./_glyphicons.less";
|
||||
|
@ -30,8 +31,8 @@
|
|||
|
||||
// custom navbar style
|
||||
@import "./_navbar.less";
|
||||
|
||||
@import "./_sidebar.less";
|
||||
@import "./_truncate.less";
|
||||
|
||||
html,
|
||||
body {
|
||||
|
@ -400,5 +401,8 @@ input[type="checkbox"],
|
|||
margin-left: 10px !important;
|
||||
}
|
||||
|
||||
style-compile {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@import '../components/filter_bar/filter_bar.less';
|
||||
|
|
|
@ -13,7 +13,7 @@ module.exports = {
|
|||
build: buildId,
|
||||
concurrency: 10,
|
||||
'max-duration': 60,
|
||||
maxRetries: 1,
|
||||
maxRetries: 2,
|
||||
browsers: [
|
||||
{
|
||||
browserName: 'chrome',
|
||||
|
|
|
@ -270,7 +270,6 @@ define(function (require) {
|
|||
'columns="columns" ' +
|
||||
'sorting="sorting"' +
|
||||
'filtering="filtering"' +
|
||||
'max-length=maxLength ' +
|
||||
'mapping="mapping"' +
|
||||
'timefield="timefield" ' +
|
||||
'></tr>'
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue