return { width: this.props.width, height: this.props.height };
},
+ getRatingScale(availableHeight) {
+ return d3.scale.ordinal()
+ .domain([5, 4, 3, 2, 1])
+ .rangePoints([availableHeight, 0]);
+ },
+
+ getLevelScale(availableHeight) {
+ return d3.scale.ordinal()
+ .domain(['ERROR', 'WARN', 'OK'])
+ .rangePoints([availableHeight, 0]);
+ },
+
+ getYScale(availableHeight) {
+ if (this.props.metricType === 'RATING') {
+ return this.getRatingScale(availableHeight);
+ } else if (this.props.metricType === 'LEVEL') {
+ return this.getLevelScale(availableHeight);
+ } else {
+ return d3.scale.linear()
+ .range([availableHeight, 0])
+ .domain([0, d3.max(this.props.data, d => d.y || 0)])
+ .nice();
+ }
+ },
+
renderHorizontalGrid (xScale, yScale) {
- let ticks = yScale.ticks(4);
+ let hasTicks = typeof yScale.ticks === 'function';
+ let ticks = hasTicks ? yScale.ticks(4) : yScale.domain();
if (!ticks.length) {
ticks.push(yScale.domain()[1]);
}
}
let opts = {
x: xScale(this.props.leakPeriodDate),
- y: yScale.range()[1],
+ y: _.last(yScale.range()),
width: xScale.range()[1] - xScale(this.props.leakPeriodDate),
- height: yScale.range()[0] - yScale.range()[1],
+ height: _.first(yScale.range()) - _.last(yScale.range()),
fill: '#fffae7'
};
return <rect {...opts}/>;
.domain(d3.extent(this.props.data, d => d.x || 0))
.range([0, availableWidth])
.clamp(true);
- let yScale = d3.scale.linear()
- .range([availableHeight, 0])
- .domain([0, d3.max(this.props.data, d => d.y || 0)])
- .nice();
+ let yScale = this.getYScale(availableHeight);
return <svg className="line-chart" width={this.state.width} height={this.state.height}>
<g transform={`translate(${this.props.padding[3]}, ${this.props.padding[0]})`}>
describe('TimelineChart', function () {
+ it('should work with LEVEL', function () {
+ const DATA = [
+ { x: new Date(2015, 0, 1), y: 'OK' },
+ { x: new Date(2015, 0, 2), y: 'WARN' },
+ { x: new Date(2015, 0, 3), y: 'ERROR' },
+ { x: new Date(2015, 0, 4), y: 'WARN' }
+ ];
+
+ let timeline = <Timeline width={100} height={100} data={DATA} metricType="LEVEL" events={[]}
+ formatYTick={FORMAT}/>;
+ let output = TestUtils.renderIntoDocument(timeline);
+ let ticks = TestUtils.scryRenderedDOMComponentsWithClass(output, 'line-chart-tick-x');
+ expect(ticks).to.have.length(3);
+ expect(ticks[0].textContent).to.equal('ERROR');
+ expect(ticks[1].textContent).to.equal('WARN');
+ expect(ticks[2].textContent).to.equal('OK');
+ });
+
+ it('should work with RATING', function () {
+ const DATA = [
+ { x: new Date(2015, 0, 1), y: 1 },
+ { x: new Date(2015, 0, 2), y: 3 },
+ { x: new Date(2015, 0, 3), y: 1 },
+ { x: new Date(2015, 0, 4), y: 4 }
+ ];
+
+ let timeline = <Timeline width={100} height={100} data={DATA} metricType="RATING" events={[]}
+ formatYTick={FORMAT}/>;
+ let output = TestUtils.renderIntoDocument(timeline);
+ let ticks = TestUtils.scryRenderedDOMComponentsWithClass(output, 'line-chart-tick-x');
+ expect(ticks).to.have.length(5);
+ expect(ticks[0].textContent).to.equal('5');
+ expect(ticks[1].textContent).to.equal('4');
+ expect(ticks[2].textContent).to.equal('3');
+ expect(ticks[3].textContent).to.equal('2');
+ expect(ticks[4].textContent).to.equal('1');
+ });
+
it('should display the zero Y tick if all values are zero', function () {
let timeline = <Timeline width={100} height={100} data={ZERO_DATA} events={[]} formatYTick={FORMAT}/>;
let output = TestUtils.renderIntoDocument(timeline);