Skip to content

Commit 4ab516e

Browse files
committed
Fix #61 render span graph as canvas instead of SVG
- Render span graph via canvas instead of SVG - Zoom range changed to [0, 1], e.g. time and trace agnostic allowed removal of some utils - "Timeline" -> 0ms - Use props instead of context to provide span graph with viewing range - Move all span graph related classes into same folder - Misc CSS cleanup
1 parent ecacc5c commit 4ab516e

26 files changed

+687
-776
lines changed
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/*
2+
Copyright (c) 2017 Uber Technologies, Inc.
3+
4+
Permission is hereby granted, free of charge, to any person obtaining a copy
5+
of this software and associated documentation files (the "Software"), to deal
6+
in the Software without restriction, including without limitation the rights
7+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8+
copies of the Software, and to permit persons to whom the Software is
9+
furnished to do so, subject to the following conditions:
10+
11+
The above copyright notice and this permission notice shall be included in
12+
all copies or substantial portions of the Software.
13+
14+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20+
THE SOFTWARE.
21+
*/
22+
23+
.CanvasSpanGraph {
24+
background: #fafafa;
25+
height: 60px;
26+
position: absolute;
27+
width: 100%;
28+
}

src/components/TracePage/SpanGraph/CanvasSpanGraph.js

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,9 @@ import React from 'react';
2424
import renderIntoCanvas from './render-into-canvas';
2525
import colorGenerator from '../../../utils/color-generator';
2626

27-
import './index.css';
27+
import './CanvasSpanGraph.css';
2828

29-
const MIN_SPAN_WIDTH = 0.002;
30-
31-
const CV_WIDTH = 10000;
29+
const CV_WIDTH = 4000;
3230

3331
const getColor = str => colorGenerator.getColorByKey(str);
3432

@@ -52,11 +50,10 @@ export default class CanvasSpanGraph extends React.PureComponent {
5250
}
5351

5452
_draw() {
55-
if (!this._canvasElm) {
56-
return;
53+
if (this._canvasElm) {
54+
const { valueWidth: totalValueWidth, items } = this.props;
55+
renderIntoCanvas(this._canvasElm, items, totalValueWidth, getColor);
5756
}
58-
const { valueWidth: totalValueWidth, items } = this.props;
59-
renderIntoCanvas(this._canvasElm, items, totalValueWidth, getColor);
6057
}
6158

6259
render() {
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/*
2+
Copyright (c) 2017 Uber Technologies, Inc.
3+
4+
Permission is hereby granted, free of charge, to any person obtaining a copy
5+
of this software and associated documentation files (the "Software"), to deal
6+
in the Software without restriction, including without limitation the rights
7+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8+
copies of the Software, and to permit persons to whom the Software is
9+
furnished to do so, subject to the following conditions:
10+
11+
The above copyright notice and this permission notice shall be included in
12+
all copies or substantial portions of the Software.
13+
14+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20+
THE SOFTWARE.
21+
*/
22+
23+
.GraphTick {
24+
stroke: #aaa;
25+
stroke-width: 1px;
26+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// Copyright (c) 2017 Uber Technologies, Inc.
2+
//
3+
// Permission is hereby granted, free of charge, to any person obtaining a copy
4+
// of this software and associated documentation files (the "Software"), to deal
5+
// in the Software without restriction, including without limitation the rights
6+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7+
// copies of the Software, and to permit persons to whom the Software is
8+
// furnished to do so, subject to the following conditions:
9+
//
10+
// The above copyright notice and this permission notice shall be included in
11+
// all copies or substantial portions of the Software.
12+
//
13+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19+
// THE SOFTWARE.
20+
21+
import PropTypes from 'prop-types';
22+
import React from 'react';
23+
24+
import './GraphTicks.css';
25+
26+
export default function SpanGraph(props) {
27+
const { numTicks } = props;
28+
const ticks = [];
29+
// i starts at 1, limit is `i < numTicks` so the first and last ticks aren't drawn
30+
for (let i = 1; i < numTicks; i++) {
31+
const x = `${i / numTicks * 100}%`;
32+
ticks.push(<line className="GraphTick" x1={x} y1="0%" x2={x} y2="100%" key={i / numTicks} />);
33+
}
34+
35+
return (
36+
<g data-test="ticks" aria-hidden="true">
37+
{ticks}
38+
</g>
39+
);
40+
}
41+
42+
SpanGraph.propTypes = {
43+
numTicks: PropTypes.number.isRequired,
44+
};
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
// Copyright (c) 2017 Uber Technologies, Inc.
2+
//
3+
// Permission is hereby granted, free of charge, to any person obtaining a copy
4+
// of this software and associated documentation files (the "Software"), to deal
5+
// in the Software without restriction, including without limitation the rights
6+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7+
// copies of the Software, and to permit persons to whom the Software is
8+
// furnished to do so, subject to the following conditions:
9+
//
10+
// The above copyright notice and this permission notice shall be included in
11+
// all copies or substantial portions of the Software.
12+
//
13+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19+
// THE SOFTWARE.
20+
21+
import React from 'react';
22+
import { shallow } from 'enzyme';
23+
24+
import GraphTicks from './GraphTicks';
25+
26+
describe('<GraphTicks>', () => {
27+
const defaultProps = {
28+
items: [
29+
{ valueWidth: 100, valueOffset: 25, serviceName: 'a' },
30+
{ valueWidth: 100, valueOffset: 50, serviceName: 'b' },
31+
],
32+
valueWidth: 200,
33+
numTicks: 4,
34+
};
35+
36+
let ticksG;
37+
38+
beforeEach(() => {
39+
const wrapper = shallow(<GraphTicks {...defaultProps} />);
40+
ticksG = wrapper.find('[data-test="ticks"]');
41+
});
42+
43+
it('creates a <g> for ticks', () => {
44+
expect(ticksG.length).toBe(1);
45+
});
46+
47+
it('creates a line for each ticks excluding the first and last', () => {
48+
expect(ticksG.find('line').length).toBe(defaultProps.numTicks - 1);
49+
});
50+
});
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/*
2+
Copyright (c) 2017 Uber Technologies, Inc.
3+
4+
Permission is hereby granted, free of charge, to any person obtaining a copy
5+
of this software and associated documentation files (the "Software"), to deal
6+
in the Software without restriction, including without limitation the rights
7+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8+
copies of the Software, and to permit persons to whom the Software is
9+
furnished to do so, subject to the following conditions:
10+
11+
The above copyright notice and this permission notice shall be included in
12+
all copies or substantial portions of the Software.
13+
14+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20+
THE SOFTWARE.
21+
*/
22+
23+
.timeline-scrubber {
24+
cursor: ew-resize;
25+
}
26+
27+
.timeline-scrubber__line {
28+
stroke: #999;
29+
stroke-width: 1;
30+
}
31+
32+
.timeline-scrubber:hover .timeline-scrubber__line {
33+
stroke: #777;
34+
}
35+
36+
.timeline-scrubber__handle {
37+
stroke: #999;
38+
fill: #fff;
39+
}
40+
41+
.timeline-scrubber:hover .timeline-scrubber__handle {
42+
stroke: #777;
43+
}
44+
45+
.timeline-scrubber__handle--grip {
46+
fill: #bbb;
47+
}
48+
.timeline-scrubber:hover .timeline-scrubber__handle--grip {
49+
fill: #999;
50+
}

src/components/TracePage/TimelineScrubber.js renamed to src/components/TracePage/SpanGraph/Scrubber.js

Lines changed: 16 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -21,36 +21,25 @@
2121
import PropTypes from 'prop-types';
2222
import React from 'react';
2323

24-
import { getTraceTimestamp, getTraceDuration } from '../../selectors/trace';
25-
import { getPercentageOfInterval } from '../../utils/date';
24+
import './Scrubber.css';
2625

2726
const HANDLE_WIDTH = 6;
2827
const HANDLE_HEIGHT = 20;
2928
const HANDLE_TOP_OFFSET = 0;
3029

31-
export default function TimelineScrubber({
32-
trace,
33-
timestamp,
30+
export default function Scrubber({
31+
position,
3432
onMouseDown,
3533
handleTopOffset = HANDLE_TOP_OFFSET,
3634
handleWidth = HANDLE_WIDTH,
3735
handleHeight = HANDLE_HEIGHT,
3836
}) {
39-
const initialTimestamp = getTraceTimestamp(trace);
40-
const totalDuration = getTraceDuration(trace);
41-
const xPercentage = getPercentageOfInterval(timestamp, initialTimestamp, totalDuration);
42-
37+
const xPercent = `${position * 100}%`;
4338
return (
4439
<g className="timeline-scrubber" onMouseDown={onMouseDown}>
45-
<line
46-
className="timeline-scrubber__line"
47-
y1={0}
48-
y2="100%"
49-
x1={`${xPercentage}%`}
50-
x2={`${xPercentage}%`}
51-
/>
40+
<line className="timeline-scrubber__line" y2="100%" x1={xPercent} x2={xPercent} />
5241
<rect
53-
x={`${xPercentage}%`}
42+
x={xPercent}
5443
y={handleTopOffset}
5544
className="timeline-scrubber__handle"
5645
style={{ transform: `translate(${-(handleWidth / 2)}px)` }}
@@ -62,24 +51,25 @@ export default function TimelineScrubber({
6251
<circle
6352
className="timeline-scrubber__handle--grip"
6453
style={{ transform: `translateY(${handleHeight / 4}px)` }}
65-
cx={`${xPercentage}%`}
66-
cy={'50%'}
54+
cx={xPercent}
55+
cy="50%"
56+
r="2"
6757
/>
68-
<circle className="timeline-scrubber__handle--grip" cx={`${xPercentage}%`} cy={'50%'} />
58+
<circle className="timeline-scrubber__handle--grip" cx={xPercent} cy="50%" r="2" />
6959
<circle
7060
className="timeline-scrubber__handle--grip"
71-
style={{ transform: `translateY(${-(handleHeight / 4)}px)` }}
72-
cx={`${xPercentage}%`}
73-
cy={'50%'}
61+
style={{ transform: `translateY(${-handleHeight / 4}px)` }}
62+
cx={xPercent}
63+
cy="50%"
64+
r="2"
7465
/>
7566
</g>
7667
);
7768
}
7869

79-
TimelineScrubber.propTypes = {
70+
Scrubber.propTypes = {
8071
onMouseDown: PropTypes.func,
81-
trace: PropTypes.object,
82-
timestamp: PropTypes.number.isRequired,
72+
position: PropTypes.number.isRequired,
8373
handleTopOffset: PropTypes.number,
8474
handleWidth: PropTypes.number,
8575
handleHeight: PropTypes.number,

src/components/TracePage/TimelineScrubber.test.js renamed to src/components/TracePage/SpanGraph/Scrubber.test.js

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -22,23 +22,18 @@ import React from 'react';
2222
import { shallow } from 'enzyme';
2323
import sinon from 'sinon';
2424

25-
import TimelineScrubber from '../../../src/components/TracePage/TimelineScrubber';
26-
import traceGenerator from '../../../src/demo/trace-generators';
25+
import Scrubber from './Scrubber';
2726

28-
import { getTraceTimestamp, getTraceDuration } from '../../../src/selectors/trace';
29-
30-
describe('<TimelineScrubber>', () => {
31-
const generatedTrace = traceGenerator.trace({ numberOfSpans: 45 });
27+
describe('<Scrubber>', () => {
3228
const defaultProps = {
3329
onMouseDown: sinon.spy(),
34-
trace: generatedTrace,
35-
timestamp: getTraceTimestamp(generatedTrace),
30+
position: 0,
3631
};
3732

3833
let wrapper;
3934

4035
beforeEach(() => {
41-
wrapper = shallow(<TimelineScrubber {...defaultProps} />);
36+
wrapper = shallow(<Scrubber {...defaultProps} />);
4237
});
4338

4439
it('contains the proper svg components', () => {
@@ -56,8 +51,7 @@ describe('<TimelineScrubber>', () => {
5651
});
5752

5853
it('calculates the correct x% for a timestamp', () => {
59-
const timestamp = getTraceDuration(generatedTrace) * 0.5 + getTraceTimestamp(generatedTrace);
60-
wrapper = shallow(<TimelineScrubber {...defaultProps} timestamp={timestamp} />);
54+
wrapper = shallow(<Scrubber {...defaultProps} position={0.5} />);
6155
const line = wrapper.find('line').first();
6256
const rect = wrapper.find('rect').first();
6357
expect(line.prop('x1')).toBe('50%');
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*
2+
Copyright (c) 2017 Uber Technologies, Inc.
3+
4+
Permission is hereby granted, free of charge, to any person obtaining a copy
5+
of this software and associated documentation files (the "Software"), to deal
6+
in the Software without restriction, including without limitation the rights
7+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8+
copies of the Software, and to permit persons to whom the Software is
9+
furnished to do so, subject to the following conditions:
10+
11+
The above copyright notice and this permission notice shall be included in
12+
all copies or substantial portions of the Software.
13+
14+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20+
THE SOFTWARE.
21+
*/
22+
23+
.TickLabels {
24+
height: 1.25rem;
25+
position: relative;
26+
}
27+
28+
.TickLabels--label {
29+
color: #717171;
30+
font-size: 0.8rem;
31+
position: absolute;
32+
user-select: none;
33+
}

0 commit comments

Comments
 (0)