Skip to content

Commit

Permalink
Merge pull request #8253 from ppisljar/vislibaxis/2
Browse files Browse the repository at this point in the history
move YAxis inside Axis
  • Loading branch information
spalger authored Sep 14, 2016
2 parents 785221f + 39cc117 commit f168565
Show file tree
Hide file tree
Showing 3 changed files with 199 additions and 16 deletions.
3 changes: 2 additions & 1 deletion src/ui/public/vislib/__tests__/lib/x_axis.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ describe('Vislib xAxis Class Test Suite', function () {

dataObj = new Data(data, {}, persistedState);
xAxis = new Axis({
type: 'category',
el: $('.x-axis-div')[0],
xValues: dataObj.xValues(),
ordered: dataObj.get('ordered'),
Expand Down Expand Up @@ -217,7 +218,7 @@ describe('Vislib xAxis Class Test Suite', function () {
});

it('should create an xAxisFormatter function on the xAxis class', function () {
expect(_.isFunction(xAxis.xAxisFormatter)).to.be(true);
expect(_.isFunction(xAxis.axisFormatter)).to.be(true);
});
});

Expand Down
205 changes: 194 additions & 11 deletions src/ui/public/vislib/lib/axis.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import $ from 'jquery';
import _ from 'lodash';
import moment from 'moment';
import VislibLibErrorHandlerProvider from 'ui/vislib/lib/_error_handler';
import errors from 'ui/errors';

export default function AxisFactory(Private) {

const ErrorHandler = Private(VislibLibErrorHandlerProvider);
Expand All @@ -21,9 +23,13 @@ export default function AxisFactory(Private) {
this.el = args.el;
this.xValues = args.xValues;
this.ordered = args.ordered;
this.xAxisFormatter = args.xAxisFormatter;
this.axisFormatter = args.type === 'category' ? args.xAxisFormatter : args.yAxisFormatter;
this.expandLastBucket = args.expandLastBucket == null ? true : args.expandLastBucket;
this._attr = _.defaults(args._attr || {});
this.scale = null;
this.domain = [args.yMin, args.yMax];
this.elSelector = args.type === 'category' ? '.x-axis-div' : '.y-axis-div';
this.type = args.type;
}

/**
Expand All @@ -33,7 +39,7 @@ export default function AxisFactory(Private) {
* @returns {D3.UpdateSelection} Appends x axis to visualization
*/
render() {
d3.select(this.el).selectAll('.x-axis-div').call(this.draw());
d3.select(this.el).selectAll(this.elSelector).call(this.draw());
};

/**
Expand Down Expand Up @@ -221,7 +227,7 @@ export default function AxisFactory(Private) {
this.xAxis = d3.svg.axis()
.scale(this.xScale)
.ticks(10)
.tickFormat(this.xAxisFormatter)
.tickFormat(this.axisFormatter)
.orient('bottom');
};

Expand All @@ -234,6 +240,9 @@ export default function AxisFactory(Private) {
draw() {
const self = this;
this._attr.isRotated = false;
const margin = this._attr.margin;
const mode = this._attr.mode;
const isWiggleOrSilhouette = (mode === 'wiggle' || mode === 'silhouette');

return function (selection) {
const n = selection[0].length;
Expand All @@ -247,21 +256,48 @@ export default function AxisFactory(Private) {
const width = parentWidth / n;
const height = $(this.parentElement).height();

self.validateWidthandHeight(width, height);
/*
const width = $(el).parent().width();
const height = $(el).height();
*/
const adjustedHeight = height - margin.top - margin.bottom;

self.getXAxis(width);

self.validateWidthandHeight(width, height);

const svg = div.append('svg')
.attr('width', width)
.attr('height', height);

svg.append('g')
.attr('class', 'x axis')
.attr('transform', 'translate(0,0)')
.call(self.xAxis);
if (self.type === 'category') {
self.getXAxis(width);
svg.append('g')
.attr('class', 'x axis')
.attr('transform', 'translate(0,0)')
.call(self.xAxis);
} else {
const yAxis = self.getYAxis(adjustedHeight);
if (!isWiggleOrSilhouette) {
svg.append('g')
.attr('class', 'y axis')
.attr('transform', 'translate(' + (width - 2) + ',' + margin.top + ')')
.call(yAxis);

const container = svg.select('g.y.axis').node();
if (container) {
const cWidth = Math.max(width, container.getBBox().width);
svg.attr('width', cWidth);
svg.select('g')
.attr('transform', 'translate(' + (cWidth - 2) + ',' + margin.top + ')');
}
}

}
});

selection.call(self.filterOrRotate());
if (self.type === 'category') {
selection.call(self.filterOrRotate());
}
};
};

Expand Down Expand Up @@ -346,6 +382,153 @@ export default function AxisFactory(Private) {
};
};

_isPercentage() {
return (this._attr.mode === 'percentage');
};

_isUserDefined() {
return (this._attr.setYExtents);
};

_isYExtents() {
return (this._attr.defaultYExtents);
};

_validateUserExtents(domain) {
const self = this;

return domain.map(function (val) {
val = parseInt(val, 10);

if (isNaN(val)) throw new Error(val + ' is not a valid number');
if (self._isPercentage() && self._attr.setYExtents) return val / 100;
return val;
});
};

_getExtents(domain) {
const min = domain[0];
const max = domain[1];

if (this._isUserDefined()) return this._validateUserExtents(domain);
if (this._isYExtents()) return domain;
if (this._attr.scale === 'log') return this._logDomain(min, max); // Negative values cannot be displayed with a log scale.
if (!this._isYExtents() && !this._isUserDefined()) return [Math.min(0, min), Math.max(0, max)];
return domain;
};

_throwCustomError(message) {
throw new Error(message);
};

_throwLogScaleValuesError() {
throw new errors.InvalidLogScaleValues();
};

/**
* Returns the appropriate D3 scale
*
* @param fnName {String} D3 scale
* @returns {*}
*/
_getScaleType(fnName) {
if (fnName === 'square root') fnName = 'sqrt'; // Rename 'square root' to 'sqrt'
fnName = fnName || 'linear';

if (typeof d3.scale[fnName] !== 'function') return this._throwCustomError('YAxis.getScaleType: ' + fnName + ' is not a function');

return d3.scale[fnName]();
};

/**
* Return the domain for log scale, i.e. the extent of the log scale.
* Log scales must begin at 1 since the log(0) = -Infinity
*
* @param {Number} min
* @param {Number} max
* @returns {Array}
*/
_logDomain(min, max) {
if (min < 0 || max < 0) return this._throwLogScaleValuesError();
return [1, max];
};

/**
* Creates the d3 y scale function
*
* @method getYScale
* @param height {Number} DOM Element height
* @returns {D3.Scale.QuantitiveScale|*} D3 yScale function
*/
getYScale(height) {
const scale = this._getScaleType(this._attr.scale);
const domain = this._getExtents(this.domain);

this.yScale = scale
.domain(domain)
.range([height, 0]);

if (!this._isUserDefined()) this.yScale.nice(); // round extents when not user defined
// Prevents bars from going off the chart when the y extents are within the domain range
if (this._attr.type === 'histogram') this.yScale.clamp(true);
return this.yScale;
};

getScaleType() {
return this._attr.scale;
};

tickFormat() {
const isPercentage = this._attr.mode === 'percentage';
if (isPercentage) return d3.format('%');
if (this.axisFormatter) return this.axisFormatter;
return d3.format('n');
};

_validateYScale(yScale) {
if (!yScale || _.isNaN(yScale)) throw new Error('yScale is ' + yScale);
};

/**
* Creates the d3 y axis function
*
* @method getYAxis
* @param height {Number} DOM Element height
* @returns {D3.Svg.Axis|*} D3 yAxis function
*/
getYAxis(height) {
const yScale = this.getYScale(height);
this._validateYScale(yScale);

// Create the d3 yAxis function
this.yAxis = d3.svg.axis()
.scale(yScale)
.tickFormat(this.tickFormat(this.domain))
.ticks(this.tickScale(height))
.orient('left');

return this.yAxis;
};

/**
* Create a tick scale for the y axis that modifies the number of ticks
* based on the height of the wrapping DOM element
* Avoid using even numbers in the yTickScale.range
* Causes the top most tickValue in the chart to be missing
*
* @method tickScale
* @param height {Number} DOM element height
* @returns {number} Number of y axis ticks
*/
tickScale(height) {
const yTickScale = d3.scale.linear()
.clamp(true)
.domain([20, 40, 1000])
.range([0, 3, 11]);

return Math.ceil(yTickScale(height));
};

/**
* Returns a string that is truncated to fit size
*
Expand Down Expand Up @@ -404,7 +587,7 @@ export default function AxisFactory(Private) {

if ((startX + halfWidth) < myX && maxW > (myX + halfWidth)) {
startX = myX + halfWidth;
return self.xAxisFormatter(d);
return self.axisFormatter(d);
} else {
d3.select(this.parentNode).remove();
}
Expand Down
7 changes: 3 additions & 4 deletions src/ui/public/vislib/lib/handler/types/point_series.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import VislibComponentsZeroInjectionInjectZerosProvider from 'ui/vislib/componen
import VislibLibHandlerHandlerProvider from 'ui/vislib/lib/handler/handler';
import VislibLibDataProvider from 'ui/vislib/lib/data';
import VislibLibAxisProvider from 'ui/vislib/lib/axis';
import VislibLibYAxisProvider from 'ui/vislib/lib/y_axis';
import VislibLibAxisTitleProvider from 'ui/vislib/lib/axis_title';
import VislibLibChartTitleProvider from 'ui/vislib/lib/chart_title';
import VislibLibAlertsProvider from 'ui/vislib/lib/alerts';
Expand All @@ -12,7 +11,6 @@ export default function ColumnHandler(Private) {
const Handler = Private(VislibLibHandlerHandlerProvider);
const Data = Private(VislibLibDataProvider);
const Axis = Private(VislibLibAxisProvider);
const YAxis = Private(VislibLibYAxisProvider);
const AxisTitle = Private(VislibLibAxisTitleProvider);
const ChartTitle = Private(VislibLibChartTitleProvider);
const Alerts = Private(VislibLibAlertsProvider);
Expand Down Expand Up @@ -40,6 +38,7 @@ export default function ColumnHandler(Private) {
axisTitle: new AxisTitle(vis.el, data.get('xAxisLabel'), data.get('yAxisLabel')),
chartTitle: new ChartTitle(vis.el),
xAxis: new Axis({
type : 'category',
el : vis.el,
xValues : data.xValues(),
ordered : data.get('ordered'),
Expand All @@ -48,15 +47,15 @@ export default function ColumnHandler(Private) {
_attr : vis._attr
}),
alerts: new Alerts(vis, data, opts.alerts),
yAxis: new YAxis({
yAxis: new Axis({
type : 'value',
el : vis.el,
yMin : isUserDefinedYAxis ? vis._attr.yAxis.min : data.getYMin(),
yMax : isUserDefinedYAxis ? vis._attr.yAxis.max : data.getYMax(),
yAxisFormatter: data.get('yAxisFormatter'),
_attr: vis._attr
})
});

};
}

Expand Down

0 comments on commit f168565

Please sign in to comment.