mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
revised x-axis, y-axis, handler, main.less to use flexbox to handle resizing
This commit is contained in:
parent
8a48d1c79a
commit
96b5eb3067
8 changed files with 113 additions and 286 deletions
|
@ -48,11 +48,6 @@ visualize {
|
|||
.flex-direction(column);
|
||||
}
|
||||
|
||||
.y-axis-div {
|
||||
.flex(4 1);
|
||||
min-width: 25px
|
||||
}
|
||||
|
||||
.y-axis-filler-div {
|
||||
.flex(1 1);
|
||||
}
|
||||
|
@ -81,11 +76,11 @@ div.y-axis-label {
|
|||
|
||||
/* legend */
|
||||
.legend-col-wrapper {
|
||||
.flex(0.3 1 auto);
|
||||
.flex(0 1 auto);
|
||||
z-index: 10;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
min-width: 40px
|
||||
min-width: 40px;
|
||||
}
|
||||
|
||||
.header {
|
||||
|
@ -269,36 +264,46 @@ path, line, .axis line, .axis path {
|
|||
/* YAxis logic */
|
||||
.y-axis-col-wrapper {
|
||||
.display(flex);
|
||||
.flex(0.1 1);
|
||||
.flex(0 0 auto);
|
||||
.flex-direction(column);
|
||||
min-width: 40px;
|
||||
}
|
||||
|
||||
.y-axis-col {
|
||||
.display(flex);
|
||||
.flex(35 1);
|
||||
.flex-direction(row);
|
||||
.flex(1 0 50px);
|
||||
}
|
||||
|
||||
.y-axis-spacer-block {
|
||||
.flex(0 1 50px);
|
||||
}
|
||||
|
||||
.y-axis-div-wrapper {
|
||||
.display(flex);
|
||||
.flex-direction(column);
|
||||
.flex(0 0 33px);
|
||||
}
|
||||
|
||||
.y-axis-div {
|
||||
.flex(1 1 100%);
|
||||
}
|
||||
|
||||
.y-axis-title {
|
||||
// flex: 1 1;
|
||||
width: 15px;
|
||||
min-width: 15px;
|
||||
.flex(0 0 15px);
|
||||
}
|
||||
|
||||
.y-axis-chart-title {
|
||||
.display(flex);
|
||||
.flex-direction(column);
|
||||
.flex(0 0 15px);
|
||||
}
|
||||
|
||||
.y-axis-title text {
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.y-axis-chart-title {
|
||||
.display(flex);
|
||||
// flex: 1 1;
|
||||
.flex-direction(column);
|
||||
width: 15px
|
||||
}
|
||||
|
||||
.chart-title {
|
||||
.flex(1 1);
|
||||
.flex(1 1 100%);
|
||||
}
|
||||
|
||||
.chart-title text {
|
||||
|
@ -306,35 +311,28 @@ path, line, .axis line, .axis path {
|
|||
fill: #848e96;
|
||||
}
|
||||
|
||||
.y-axis-div-wrapper {
|
||||
.display(flex);
|
||||
//flex: 1 1 auto;
|
||||
.flex-direction(column);
|
||||
min-width: 20px
|
||||
}
|
||||
|
||||
.vis-col-wrapper {
|
||||
.display(flex);
|
||||
.flex(35 1);
|
||||
.flex(1 0 20px);
|
||||
.flex-direction(column);
|
||||
}
|
||||
|
||||
.chart-wrapper {
|
||||
.display(flex);
|
||||
.flex(35 1);
|
||||
.flex(1 0 20px);
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.chart-wrapper-column {
|
||||
.display(flex);
|
||||
.flex(35 1);
|
||||
.flex(1 0 20px);
|
||||
.flex-direction(row);
|
||||
}
|
||||
|
||||
.chart-wrapper-row {
|
||||
.display(flex);
|
||||
.flex(35 1);
|
||||
.flex-direction(column);
|
||||
.flex(1 0 50px);
|
||||
}
|
||||
|
||||
.chart {
|
||||
|
@ -350,36 +348,27 @@ path, line, .axis line, .axis path {
|
|||
.flex(1 1);
|
||||
}
|
||||
|
||||
.y-axis-spacer-block {
|
||||
.flex(8 1);
|
||||
}
|
||||
|
||||
.x-axis-wrapper {
|
||||
.display(flex);
|
||||
.flex(8 1);
|
||||
.flex-direction(column);
|
||||
.flex(0 1 50px);
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.x-axis-div-wrapper {
|
||||
.display(flex);
|
||||
.flex(8 1);
|
||||
.flex-direction(row);
|
||||
min-height: 20px;
|
||||
.flex(0 1 15px);
|
||||
}
|
||||
|
||||
.x-axis-chart-title {
|
||||
.display(flex);
|
||||
.flex(1 1);
|
||||
.flex-direction(row);
|
||||
min-height: 15px;
|
||||
max-height: 15px;
|
||||
.flex(0 0 15px);
|
||||
}
|
||||
|
||||
.x-axis-title {
|
||||
.flex(1 1);
|
||||
min-height: 15px;
|
||||
max-height: 15px;
|
||||
.flex(0 0 15px);
|
||||
}
|
||||
|
||||
.x-axis-title text {
|
||||
|
@ -387,8 +376,7 @@ path, line, .axis line, .axis path {
|
|||
}
|
||||
|
||||
.x-axis-div {
|
||||
.flex(8 1);
|
||||
overflow: visible;
|
||||
.flex(1 1 100%);
|
||||
margin-top: -5px;
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ define(function (require) {
|
|||
|
||||
// Validate that the height and width are not 0 or NaN
|
||||
ErrorHandler.prototype.validateWidthandHeight = function (width, height) {
|
||||
console.log(width, height);
|
||||
if (_.isNaN(height) || height <= 0 || _.isNaN(width) || width <= 0) {
|
||||
throw new Error('The height and/or width of this container is too ' +
|
||||
'small for this chart.');
|
||||
|
|
|
@ -95,9 +95,9 @@ define(function (require) {
|
|||
.attr('transform', function () {
|
||||
if (dataType === 'rows') {
|
||||
// if `rows`, rotate the chart titles
|
||||
return 'translate(11,' + height / 2.2 + ')rotate(270)';
|
||||
return 'translate(11,' + height / 2 + ')rotate(270)';
|
||||
}
|
||||
return 'translate(' + width / 2 + ',11)';
|
||||
return 'translate(' + width / 2 + ',8)';
|
||||
})
|
||||
.attr('text-anchor', 'middle')
|
||||
.text(function (d) {
|
||||
|
|
|
@ -76,10 +76,10 @@ define(function (require) {
|
|||
this.layout,
|
||||
this.legend,
|
||||
this.tooltip,
|
||||
this.xAxis,
|
||||
this.yAxis,
|
||||
this.axisTitle,
|
||||
this.chartTitle
|
||||
this.chartTitle,
|
||||
this.yAxis,
|
||||
this.xAxis
|
||||
];
|
||||
}
|
||||
|
||||
|
|
|
@ -71,8 +71,8 @@ define(function (require) {
|
|||
var tipHeight = tooltipDiv[0][0].clientHeight;
|
||||
var yOffset = 5;
|
||||
// apply y offset to keep tooltip within bottom of chart
|
||||
if ((chartHeight - offsetY + 10) < (tipHeight)) {
|
||||
yOffset = tipHeight - (chartHeight - offsetY + 5);
|
||||
if ((chartHeight - offsetY + 5) < (tipHeight)) {
|
||||
yOffset = tipHeight - (chartHeight - offsetY + 0);
|
||||
}
|
||||
|
||||
// return text and position for tooltip
|
||||
|
|
|
@ -4,6 +4,7 @@ define(function (require) {
|
|||
var _ = require('lodash');
|
||||
|
||||
var ErrorHandler = Private(require('components/vislib/lib/_error_handler'));
|
||||
var ChartTitle = Private(require('components/vislib/lib/chart_title'));
|
||||
|
||||
/*
|
||||
* Add an x axis to the visualization
|
||||
|
@ -148,6 +149,7 @@ define(function (require) {
|
|||
// save a reference to the xAxis
|
||||
this.xAxis = d3.svg.axis()
|
||||
.scale(this.xScale)
|
||||
.ticks(10)
|
||||
.tickFormat(this.xAxisFormatter)
|
||||
.orient('bottom');
|
||||
};
|
||||
|
@ -187,7 +189,6 @@ define(function (require) {
|
|||
});
|
||||
|
||||
selection.call(self.filterOrRotate());
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -215,40 +216,7 @@ define(function (require) {
|
|||
}
|
||||
});
|
||||
|
||||
selection.call(self.resizeAxisLayoutForLabels());
|
||||
};
|
||||
};
|
||||
|
||||
// Filter out text labels by width and position on axis
|
||||
XAxis.prototype.filterAxisLabels = function () {
|
||||
var self = this;
|
||||
var startX = 0;
|
||||
var maxW = $('.x-axis-div').width();
|
||||
var par;
|
||||
var myX;
|
||||
var myWidth;
|
||||
var halfWidth;
|
||||
|
||||
return function (selection) {
|
||||
selection.selectAll('.tick text')
|
||||
.text(function (d, i) {
|
||||
par = d3.select(this.parentNode).node();
|
||||
myX = +self.xScale(d).toFixed(1);
|
||||
myWidth = +par.getBBox().width.toFixed(1);
|
||||
halfWidth = +((par.getBBox().width / 2).toFixed(1));
|
||||
|
||||
// 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).select('line').remove();
|
||||
return '';
|
||||
}
|
||||
});
|
||||
selection.call(self.fitTitles());
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -312,95 +280,69 @@ define(function (require) {
|
|||
};
|
||||
};
|
||||
|
||||
// Returns a function that resizes layout divs and
|
||||
// adds css flexbox values to fit axis labels
|
||||
XAxis.prototype.resizeAxisLayoutForLabels = function () {
|
||||
// Filter out text labels by width and position on axis
|
||||
XAxis.prototype.filterAxisLabels = function () {
|
||||
var self = this;
|
||||
var visEl = $(self.el);
|
||||
var div;
|
||||
var svg;
|
||||
var tick;
|
||||
var chartwrap;
|
||||
var titlespace;
|
||||
var xwrapper;
|
||||
var xdiv;
|
||||
var xdivwrapper;
|
||||
var yspacerblock;
|
||||
var ratio;
|
||||
var flex;
|
||||
var chartToXaxis;
|
||||
var dataType;
|
||||
var tickHt;
|
||||
var chartHt;
|
||||
var startX = 0;
|
||||
var maxW;
|
||||
var par;
|
||||
var myX;
|
||||
var myWidth;
|
||||
var halfWidth;
|
||||
|
||||
return function (selection) {
|
||||
selection.each(function () {
|
||||
div = d3.select(this);
|
||||
svg = div.select('svg');
|
||||
tick = svg.select('.tick');
|
||||
dataType = this.parentNode.__data__.series ? 'series' : this.parentNode.__data__.rows ? 'rows' : 'columns';
|
||||
|
||||
xwrapper = visEl.find('.x-axis-wrapper');
|
||||
xdiv = visEl.find('.x-axis-div');
|
||||
xdivwrapper = visEl.find('.x-axis-div-wrapper');
|
||||
yspacerblock = visEl.find('.y-axis-spacer-block');
|
||||
|
||||
// define chartwrap and titlespace, for chart title
|
||||
// and axis title based on data type
|
||||
if (dataType === 'series') {
|
||||
chartwrap = visEl.find('.chart-wrapper');
|
||||
titlespace = 15;
|
||||
} else if (dataType === 'rows') {
|
||||
chartwrap = visEl.find('.chart-wrapper-row');
|
||||
titlespace = 15;
|
||||
} else {
|
||||
chartwrap = visEl.find('.chart-wrapper-column');
|
||||
titlespace = 30;
|
||||
}
|
||||
|
||||
// should have a tick node
|
||||
if (!tick.node()) {
|
||||
throw new Error('x-axis tick.node() is undefined');
|
||||
}
|
||||
|
||||
tickHt = tick.node().getBBox().height;
|
||||
chartHt = chartwrap.height();
|
||||
flex = self.getFlexVal(self._attr.isRotated, titlespace, tickHt, chartHt);
|
||||
|
||||
// set height of svg, transform to fit axis labels
|
||||
svg.attr('height', chartHt);
|
||||
xwrapper.css('flex', flex + ' 1');
|
||||
xdiv.css('flex', flex + ' 1');
|
||||
yspacerblock.css('flex', flex + ' 1');
|
||||
|
||||
});
|
||||
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();
|
||||
}
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
// Returns flexbox css value using linear scales
|
||||
XAxis.prototype.getFlexVal = function (isRotated, titleSpace, tickHt, chartHt) {
|
||||
var ratio;
|
||||
|
||||
var rotScale = d3.scale.linear()
|
||||
.domain([0.1, 0.5, 2])
|
||||
.range([3.3, 22, 70]);
|
||||
// Returns a function that adjusts axis title and
|
||||
// all chart title transforms to fit axis labels
|
||||
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 text;
|
||||
var titles;
|
||||
var titleWidth;
|
||||
|
||||
var flatScale = d3.scale.linear()
|
||||
.domain([0.2, 1, 2, 20])
|
||||
.range([1.1, 1, 2, 20]);
|
||||
|
||||
if (!isRotated) {
|
||||
// flat labels
|
||||
ratio = flatScale(35 * (titleSpace + tickHt) / chartHt);
|
||||
//console.log('flat', +ratio.toFixed(1), 35 * (titleSpace + tickHt) / chartHt);
|
||||
|
||||
} else {
|
||||
// rotated labels
|
||||
ratio = rotScale((titleSpace + tickHt) / chartHt);
|
||||
//console.log('rotated', +ratio.toFixed(1), (titleSpace + tickHt) / chartHt);
|
||||
|
||||
}
|
||||
return ratio.toFixed(1);
|
||||
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)
|
||||
.select('svg')
|
||||
.select('text')
|
||||
.attr('transform', 'translate(' + (titleWidth / 2) + ',11)');
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
return XAxis;
|
||||
|
|
|
@ -30,7 +30,6 @@ define(function (require) {
|
|||
// Render the y axis
|
||||
YAxis.prototype.render = function () {
|
||||
d3.select(this.el).selectAll('.y-axis-div').call(this.draw());
|
||||
d3.select(this.el).selectAll('.y-axis-div').call(this.resizeAxisLayoutForLabels());
|
||||
};
|
||||
|
||||
// Determine if data should be stacked
|
||||
|
@ -99,6 +98,7 @@ define(function (require) {
|
|||
|
||||
// Return the d3 y axis
|
||||
YAxis.prototype.getYAxis = function (height) {
|
||||
var self = this;
|
||||
var yScale = this.getYScale(height);
|
||||
|
||||
// y scale should never be `NaN`
|
||||
|
@ -112,6 +112,11 @@ define(function (require) {
|
|||
.tickFormat(d3.format('s'))
|
||||
.ticks(this.tickScale(height))
|
||||
.orient('left');
|
||||
|
||||
if (self.yScale.domain()[1] <= 10) {
|
||||
this.yAxis.tickFormat(d3.format('n'));
|
||||
}
|
||||
|
||||
return this.yAxis;
|
||||
};
|
||||
|
||||
|
@ -138,12 +143,14 @@ define(function (require) {
|
|||
var svg;
|
||||
|
||||
return function (selection) {
|
||||
|
||||
selection.each(function () {
|
||||
div = d3.select(this);
|
||||
width = $(this).width();
|
||||
height = $(this).height() - margin.top - margin.bottom;
|
||||
|
||||
// Validate whether width and height are not 0 or `NaN`
|
||||
console.log('y-axis', width, height);
|
||||
self.validateWidthandHeight(width, height);
|
||||
|
||||
var yAxis = self.getYAxis(height);
|
||||
|
@ -161,118 +168,6 @@ define(function (require) {
|
|||
};
|
||||
};
|
||||
|
||||
// Returns max tick label length
|
||||
YAxis.prototype.getMaxLabelLength = function (labels) {
|
||||
var arr = [];
|
||||
|
||||
// get max tick label length
|
||||
_.forEach(labels[0], function (n) {
|
||||
arr.push(n.getBBox().width);
|
||||
});
|
||||
|
||||
return _.max(arr);
|
||||
};
|
||||
|
||||
// Set width of svg and trnasform axis to fit labels
|
||||
YAxis.prototype.updateLayoutForRotatedLabels = function (svg, length) {
|
||||
var margin = this._attr.margin;
|
||||
var tickspace = 14;
|
||||
|
||||
length += tickspace;
|
||||
|
||||
// set width of svg, x-axis-div and x-axis-div-wrapper to fit ticklabels
|
||||
svg.attr('width', length + 6);
|
||||
d3.selectAll('.y.axis').attr('transform', 'translate(' + (length + 2) + ',' + margin.top + ')');
|
||||
};
|
||||
|
||||
// Return a function that resizes layout divs and
|
||||
// adds css flexbox values to fit axis labels
|
||||
YAxis.prototype.resizeAxisLayoutForLabels = function () {
|
||||
var self = this;
|
||||
var visEl = $(self.el);
|
||||
var div;
|
||||
var svg;
|
||||
var tick;
|
||||
var titlespace;
|
||||
var flex;
|
||||
var dataType;
|
||||
|
||||
var visWrap = visEl.find('.vis-col-wrapper');
|
||||
var yAxisColWrap = visEl.find('.y-axis-col-wrapper');
|
||||
var yAxisDivWrap = visEl.find('.y-axis-div-wrapper');
|
||||
var yAxisDiv = visEl.find('.y-axis-div');
|
||||
var yAxisTitle = visEl.find('.y-axis-title');
|
||||
var yAxisChartTitle = visEl.find('.y-axis-chart-title');
|
||||
var legendColWrap = visEl.find('.legend-col-wrapper');
|
||||
var labelWidths = [];
|
||||
var maxWidth;
|
||||
var labels;
|
||||
|
||||
return function (selection) {
|
||||
selection.each(function () {
|
||||
div = d3.select(this);
|
||||
svg = div.select('svg');
|
||||
dataType = this.parentNode.__data__.series ? 'series' : this.parentNode.__data__.rows ? 'rows' : 'columns';
|
||||
labels = selection.selectAll('.tick text');
|
||||
|
||||
if (dataType === 'series') {
|
||||
titlespace = 15;
|
||||
} else if (dataType === 'rows') {
|
||||
titlespace = 15;
|
||||
} else {
|
||||
titlespace = 30;
|
||||
}
|
||||
|
||||
// get max width tick
|
||||
_.forEach(labels[0], function (n) {
|
||||
labelWidths.push(n.getBBox().width);
|
||||
});
|
||||
|
||||
maxWidth = d3.max(labelWidths) + 18;
|
||||
flex = self.getFlexVal(dataType, titlespace, maxWidth, visWrap.width());
|
||||
|
||||
// set flex values
|
||||
yAxisColWrap.css('flex', flex + ' 1');
|
||||
yAxisDiv.css('width', maxWidth + 'px');
|
||||
yAxisDivWrap.css('width', (maxWidth + 12) + 'px');
|
||||
|
||||
// set width of svg, transform to fit axis labels
|
||||
svg.attr('width', maxWidth);
|
||||
svg.attr('transform', 'translate(0,0)');
|
||||
svg.select('g').attr('transform', 'translate(' + (maxWidth - 1) + ',10)');
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
// Return flexbox css value using linear scales
|
||||
YAxis.prototype.getFlexVal = function (dataType, titleSpace, tickWidth, visWidth) {
|
||||
var ratio;
|
||||
|
||||
var seriesScale = d3.scale.linear()
|
||||
.domain([0.2, 2])
|
||||
.range([0.24, 2]);
|
||||
|
||||
var rowsScale = d3.scale.linear()
|
||||
.domain([0.2, 2])
|
||||
.range([0.26, 2.6]);
|
||||
|
||||
var colsScale = d3.scale.linear()
|
||||
.domain([0.2, 2])
|
||||
.range([0.16, 1.6]);
|
||||
|
||||
// define ratio based on datatype
|
||||
if (dataType === 'rows') {
|
||||
ratio = rowsScale(35 * (titleSpace + tickWidth) / visWidth);
|
||||
} else if (dataType === 'columns') {
|
||||
ratio = colsScale(35 * (titleSpace + tickWidth) / visWidth);
|
||||
} else {
|
||||
ratio = seriesScale(35 * (titleSpace + tickWidth) / visWidth);
|
||||
}
|
||||
//console.log(dataType, ratio.toFixed(1), 35 * (titleSpace + tickWidth) / visWidth);
|
||||
return ratio.toFixed(1);
|
||||
|
||||
};
|
||||
|
||||
return YAxis;
|
||||
};
|
||||
});
|
||||
|
|
|
@ -126,11 +126,12 @@ define(function (require) {
|
|||
|
||||
el = d3.select('body').append('div')
|
||||
.attr('class', 'y-axis-wrapper')
|
||||
.style('width', '40px')
|
||||
.style('height', '40px')
|
||||
.datum(data);
|
||||
|
||||
yAxisDiv = el.append('div')
|
||||
.attr('class', 'y-axis-div')
|
||||
.style('height', '40px');
|
||||
.attr('class', 'y-axis-div');
|
||||
|
||||
dataObj = new Data(data);
|
||||
yAxis = new YAxis({
|
||||
|
@ -145,7 +146,7 @@ define(function (require) {
|
|||
});
|
||||
|
||||
afterEach(function () {
|
||||
el.remove();
|
||||
//el.remove();
|
||||
});
|
||||
|
||||
describe('render Method', function () {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue