Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 8 additions & 4 deletions src/components/TimeBasedLineChart.js
Original file line number Diff line number Diff line change
Expand Up @@ -272,9 +272,11 @@ const TimeBasedLineChart = React.createClass({
},

_yRangeContainsZero () {
const minMaxValues = ChartUtils.getDataMinMaxValues(this.props.data, 'y');
const max = d3.max(this.props.data, d => d.y);
const min = d3.min(this.props.data, d => d.y);
const tickSpec = ChartUtils.getAxisTickSpecification(min, max);

return minMaxValues.min <= 0 && minMaxValues.max >= 0;
return tickSpec.min <= 0 && tickSpec.max >= 0;
},

// Handle functions
Expand Down Expand Up @@ -365,11 +367,13 @@ const TimeBasedLineChart = React.createClass({
},

_getYScaleFunction () {
const minMaxValues = ChartUtils.getDataMinMaxValues(this.props.data, 'y');
const max = d3.max(this.props.data, d => d.y);
const min = d3.min(this.props.data, d => d.y);
const tickSpec = ChartUtils.getAxisTickSpecification(min, max);

return d3.scale.linear()
.range([this.state.adjustedHeight, 0])
.domain([minMaxValues.min, minMaxValues.max]);
.domain([tickSpec.min, tickSpec.max]);
},

_getYScaleValue (value) {
Expand Down
5 changes: 4 additions & 1 deletion src/components/d3/AxisGroup.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,10 @@ const AxisGroup = React.createClass({
},

_renderAxis () {
const tickValues = ChartUtils.getAxisTickValues(this.props.data, this .props.axis);
const max = d3.max(this.props.data, d => d[this.props.axis]);
const min = d3.min(this.props.data, d => d[this.props.axis]);
const { tickValues } = ChartUtils.getAxisTickSpecification(min, max);

const axisFunction = d3.svg.axis()
.scale(this.props.scaleFunction())
.orient(this.props.orientation)
Expand Down
4 changes: 3 additions & 1 deletion src/components/d3/GridLinesGroup.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,9 @@ const GridLinesGroup = React.createClass({
},

_renderGridLines () {
const tickValues = ChartUtils.getAxisTickValues(this.props.data, this.props.axis);
const max = d3.max(this.props.data, d => d[this.props.axis]);
const min = d3.min(this.props.data, d => d[this.props.axis]);
const { tickValues } = ChartUtils.getAxisTickSpecification(min, max);

const gridLinesFunction = d3.svg.axis()
.scale(this.props.scaleFunction())
Expand Down
80 changes: 45 additions & 35 deletions src/utils/Chart.js
Original file line number Diff line number Diff line change
@@ -1,44 +1,54 @@
const d3 = require('d3');

const Chart = {
getDataMinMaxValues (data, axis) {
let max = d3.max(data, d => {
return d[axis];
});

let min = d3.min(data, d => {
return d[axis];
});

const maxDigits = Math.ceil(Math.abs(max)).toString().length - 1;
const minDigits = Math.floor(Math.abs(min)).toString().length - 1;

const maxMultiplier = Math.pow(10, maxDigits) < 100 ? 100 : Math.pow(10, maxDigits);
const minMultiplier = Math.pow(10, minDigits) < 100 ? 100 : Math.pow(10, maxDigits);

max = Math.ceil(max / maxMultiplier) * maxMultiplier;
min = Math.floor(min / minMultiplier) * minMultiplier;

return { min, max };
},

getAxisTickValues (data, axis) {
const estimatedNumberOfTicks = 6;
const minMaxValues = this.getDataMinMaxValues(data, axis);
const range = minMaxValues.max - minMaxValues.min;
const tempStep = range / estimatedNumberOfTicks;
const magnitude = Math.floor(Math.log(tempStep) / Math.LN10);
const magnitudePower = Math.pow(10, magnitude);
const magnitudeMultiplier = parseInt(tempStep / magnitudePower + 0.5, 10);
const stepSize = magnitudeMultiplier * magnitudePower;
getAxisTickSpecification (min, max) {
// Needs to maintain parity with mobile app.
// https://git.moneydesktop.com/dev/moneymobilex/blob/master/Classes/utils/maths.cpp
// generate_tick_specification method

let step = 0;
let numberOfTicks = 0;
let start = 0;
let end = 0;

if (min < max) {
// Math.Log10 not supported in IE 10/11 so we have to use Math.log / Math.LN10
step = Math.pow(10, Math.floor(Math.log(max - min) / Math.LN10));

if (step >= 100) {
const range = Math.ceil(max / step) * step - Math.floor(min / step) * step;

numberOfTicks = range / step;

if (numberOfTicks <= 3) {
step /= 2;
} else if (numberOfTicks >= 7) {
step *= 2;
}
} else {
step = 100;
}

start = Math.floor(min / step) * step;
end = Math.ceil(max / step) * step;
numberOfTicks = Math.max((end - start) / step, 2);
} else {
if (min === max) {
start = Math.floor(min / 100) * 100;
} else {
start = 0;
}

step = 50;
numberOfTicks = 2;
end = start + 100;
}

const values = [];

for (let min = minMaxValues.min; min <= minMaxValues.max; min += stepSize) {
values.push(min);
for (let value = start; value <= end; value += step) {
values.push(value);
}

return values;
return { min: start, max: end, tickValues: values };
}
};

Expand Down