mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
* Refactor service colors * Calculate duration from full waterfall * Ensure timeline label is not truncated * Adjust child if it starts after parent has ended * Add mark for traceRootDuration instead of xMax * Fix tests
This commit is contained in:
parent
9dbc08b32f
commit
9b04e556be
13 changed files with 285 additions and 152 deletions
|
@ -10,6 +10,7 @@ import styled from 'styled-components';
|
|||
import { px, unit } from '../../../../../style/variables';
|
||||
// @ts-ignore
|
||||
import Legend from '../../../../shared/charts/Legend';
|
||||
import { IServiceColors } from './Waterfall/waterfall_helpers/waterfall_helpers';
|
||||
|
||||
const Legends = styled.div`
|
||||
display: flex;
|
||||
|
@ -23,9 +24,7 @@ const Legends = styled.div`
|
|||
`;
|
||||
|
||||
interface Props {
|
||||
serviceColors: {
|
||||
[key: string]: string;
|
||||
};
|
||||
serviceColors: IServiceColors;
|
||||
}
|
||||
|
||||
export function ServiceLegends({ serviceColors }: Props) {
|
||||
|
|
|
@ -44,7 +44,7 @@ const SpanLabel = styled<{ left: number }, any>('div')`
|
|||
white-space: nowrap;
|
||||
position: relative;
|
||||
left: ${props => `${props.left}%`};
|
||||
width: ${props => `${100 - props.left}%`};
|
||||
width: ${props => `${Math.max(100 - props.left, 0)}%`};
|
||||
direction: rtl;
|
||||
text-align: left;
|
||||
margin: ${px(units.quarter)} 0 0;
|
||||
|
|
|
@ -19,6 +19,7 @@ import { AgentMark } from '../get_agent_marks';
|
|||
import { SpanFlyout } from './SpanFlyout';
|
||||
import { TransactionFlyout } from './TransactionFlyout';
|
||||
import {
|
||||
IServiceColors,
|
||||
IWaterfall,
|
||||
IWaterfallItem
|
||||
} from './waterfall_helpers/waterfall_helpers';
|
||||
|
@ -42,9 +43,7 @@ interface Props {
|
|||
urlParams: IUrlParams;
|
||||
waterfall: IWaterfall;
|
||||
location: any;
|
||||
serviceColors: {
|
||||
[key: string]: string;
|
||||
};
|
||||
serviceColors: IServiceColors;
|
||||
}
|
||||
|
||||
export class Waterfall extends Component<Props> {
|
||||
|
@ -129,6 +128,7 @@ export class Waterfall extends Component<Props> {
|
|||
<Timeline
|
||||
agentMarks={this.props.agentMarks}
|
||||
duration={waterfall.duration}
|
||||
traceRootDuration={waterfall.traceRootDuration}
|
||||
height={waterfallHeight}
|
||||
margins={TIMELINE_MARGINS}
|
||||
/>
|
||||
|
@ -157,8 +157,3 @@ export class Waterfall extends Component<Props> {
|
|||
});
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: the agent marks and note about dropped spans were removed. Need to be re-added
|
||||
// agentMarks: PropTypes.array,
|
||||
// agentName: PropTypes.string.isRequired,
|
||||
// droppedSpans: PropTypes.number.isRequired,
|
||||
|
|
|
@ -8,6 +8,7 @@ import { groupBy, indexBy } from 'lodash';
|
|||
import { Span } from 'x-pack/plugins/apm/typings/Span';
|
||||
import { Transaction } from 'x-pack/plugins/apm/typings/Transaction';
|
||||
import {
|
||||
getClockSkew,
|
||||
getWaterfallItems,
|
||||
IWaterfallIndex,
|
||||
IWaterfallItem
|
||||
|
@ -101,4 +102,79 @@ describe('waterfall_helpers', () => {
|
|||
).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
describe('getClockSkew', () => {
|
||||
it('should adjust when child starts before parent', () => {
|
||||
const item = {
|
||||
docType: 'transaction',
|
||||
timestamp: 0,
|
||||
duration: 50
|
||||
} as IWaterfallItem;
|
||||
|
||||
const parentItem = {
|
||||
timestamp: 100,
|
||||
skew: 5,
|
||||
duration: 100
|
||||
} as IWaterfallItem;
|
||||
const parentTransactionSkew = 1337;
|
||||
|
||||
expect(getClockSkew(item, parentItem, parentTransactionSkew)).toBe(130);
|
||||
});
|
||||
|
||||
it('should adjust when child starts after parent has ended', () => {
|
||||
const item = {
|
||||
docType: 'transaction',
|
||||
timestamp: 250,
|
||||
duration: 50
|
||||
} as IWaterfallItem;
|
||||
|
||||
const parentItem = {
|
||||
timestamp: 100,
|
||||
skew: 5,
|
||||
duration: 100
|
||||
} as IWaterfallItem;
|
||||
const parentTransactionSkew = 1337;
|
||||
|
||||
expect(getClockSkew(item, parentItem, parentTransactionSkew)).toBe(-120);
|
||||
});
|
||||
|
||||
it('should not adjust when child starts within parent duration', () => {
|
||||
const item = {
|
||||
docType: 'transaction',
|
||||
timestamp: 150,
|
||||
duration: 50
|
||||
} as IWaterfallItem;
|
||||
|
||||
const parentItem = {
|
||||
timestamp: 100,
|
||||
skew: 5,
|
||||
duration: 100
|
||||
} as IWaterfallItem;
|
||||
const parentTransactionSkew = 1337;
|
||||
|
||||
expect(getClockSkew(item, parentItem, parentTransactionSkew)).toBe(0);
|
||||
});
|
||||
|
||||
it('should return parentTransactionSkew for spans', () => {
|
||||
const item = {
|
||||
docType: 'span'
|
||||
} as IWaterfallItem;
|
||||
|
||||
const parentItem = {} as IWaterfallItem;
|
||||
const parentTransactionSkew = 1337;
|
||||
|
||||
expect(getClockSkew(item, parentItem, parentTransactionSkew)).toBe(1337);
|
||||
});
|
||||
|
||||
it('should handle missing parentItem', () => {
|
||||
const item = {
|
||||
docType: 'transaction'
|
||||
} as IWaterfallItem;
|
||||
|
||||
const parentItem = undefined;
|
||||
const parentTransactionSkew = 1337;
|
||||
|
||||
expect(getClockSkew(item, parentItem, parentTransactionSkew)).toBe(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -11,8 +11,10 @@ import {
|
|||
indexBy,
|
||||
isEmpty,
|
||||
sortBy,
|
||||
uniq
|
||||
uniq,
|
||||
zipObject
|
||||
} from 'lodash';
|
||||
import { colors } from 'x-pack/plugins/apm/public/style/variables';
|
||||
import { Span } from '../../../../../../../../typings/Span';
|
||||
import { Transaction } from '../../../../../../../../typings/Transaction';
|
||||
|
||||
|
@ -26,12 +28,17 @@ export interface IWaterfallGroup {
|
|||
|
||||
export interface IWaterfall {
|
||||
traceRoot?: Transaction;
|
||||
traceRootDuration?: number;
|
||||
duration?: number;
|
||||
traceRootDuration: number;
|
||||
|
||||
/**
|
||||
* Duration in us
|
||||
*/
|
||||
duration: number;
|
||||
services: string[];
|
||||
items: IWaterfallItem[];
|
||||
itemsById: IWaterfallIndex;
|
||||
getTransactionById: (id?: IWaterfallItem['id']) => Transaction | undefined;
|
||||
serviceColors: IServiceColors;
|
||||
}
|
||||
|
||||
interface IWaterfallItemBase {
|
||||
|
@ -39,9 +46,25 @@ interface IWaterfallItemBase {
|
|||
parentId?: string;
|
||||
serviceName: string;
|
||||
name: string;
|
||||
|
||||
/**
|
||||
* Duration in us
|
||||
*/
|
||||
duration: number;
|
||||
|
||||
/**
|
||||
* start timestamp in us
|
||||
*/
|
||||
timestamp: number;
|
||||
|
||||
/**
|
||||
* offset from first item in us
|
||||
*/
|
||||
offset: number;
|
||||
|
||||
/**
|
||||
* skew from timestamp in us
|
||||
*/
|
||||
skew: number;
|
||||
childIds?: Array<IWaterfallItemBase['id']>;
|
||||
}
|
||||
|
@ -120,38 +143,39 @@ function getSpanItem(span: Span): IWaterfallItemSpan {
|
|||
};
|
||||
}
|
||||
|
||||
function getClockSkew(
|
||||
export function getClockSkew(
|
||||
item: IWaterfallItem,
|
||||
itemsById: IWaterfallIndex,
|
||||
parentItem: IWaterfallItem | undefined,
|
||||
parentTransactionSkew: number
|
||||
) {
|
||||
switch (item.docType) {
|
||||
case 'span':
|
||||
return parentTransactionSkew;
|
||||
case 'transaction': {
|
||||
if (!item.parentId) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const parentItem = itemsById[item.parentId];
|
||||
|
||||
// For some reason the parent span and related transactions might be missing.
|
||||
if (!parentItem) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// determine if child starts before the parent, and in that case how much
|
||||
const diff = parentItem.timestamp + parentItem.skew - item.timestamp;
|
||||
const parentStart = parentItem.timestamp + parentItem.skew;
|
||||
const parentEnd = parentStart + parentItem.duration;
|
||||
|
||||
// If child transaction starts after parent span there is no clock skew
|
||||
if (diff < 0) {
|
||||
// determine if child starts before the parent
|
||||
const offsetStart = parentStart - item.timestamp;
|
||||
|
||||
// determine if child starts after the parent has ended
|
||||
const offsetEnd = item.timestamp - parentEnd;
|
||||
|
||||
// child transaction starts before parent OR
|
||||
// child transaction starts after parent has ended
|
||||
if (offsetStart > 0 || offsetEnd > 0) {
|
||||
const latency = Math.max(parentItem.duration - item.duration, 0) / 2;
|
||||
return offsetStart + latency;
|
||||
|
||||
// child transaction starts withing parent duration and no adjustment is needed
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// latency can only be calculated if parent duration is larger than child duration
|
||||
const latency = Math.max(parentItem.duration - item.duration, 0);
|
||||
const skew = diff + latency / 2;
|
||||
return skew;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -165,7 +189,8 @@ export function getWaterfallItems(
|
|||
item: IWaterfallItem,
|
||||
parentTransactionSkew: number
|
||||
): IWaterfallItem[] {
|
||||
const skew = getClockSkew(item, itemsById, parentTransactionSkew);
|
||||
const parentItem = item.parentId ? itemsById[item.parentId] : undefined;
|
||||
const skew = getClockSkew(item, parentItem, parentTransactionSkew);
|
||||
const children = sortBy(childrenByParentId[item.id] || [], 'timestamp');
|
||||
|
||||
item.childIds = children.map(child => child.id);
|
||||
|
@ -193,6 +218,45 @@ function getServices(items: IWaterfallItem[]) {
|
|||
return uniq(serviceNames);
|
||||
}
|
||||
|
||||
export interface IServiceColors {
|
||||
[key: string]: string;
|
||||
}
|
||||
|
||||
function getServiceColors(services: string[]) {
|
||||
const assignedColors = [
|
||||
colors.apmBlue,
|
||||
colors.apmGreen,
|
||||
colors.apmPurple,
|
||||
colors.apmRed2,
|
||||
colors.apmTan,
|
||||
colors.apmOrange,
|
||||
colors.apmYellow
|
||||
];
|
||||
|
||||
return zipObject(services, assignedColors) as IServiceColors;
|
||||
}
|
||||
|
||||
function getDuration(items: IWaterfallItem[]) {
|
||||
const timestampStart = items[0].timestamp;
|
||||
const timestampEnd = Math.max(
|
||||
...items.map(item => item.timestamp + item.duration + item.skew)
|
||||
);
|
||||
return timestampEnd - timestampStart;
|
||||
}
|
||||
|
||||
function createGetTransactionById(itemsById: IWaterfallIndex) {
|
||||
return (id?: IWaterfallItem['id']) => {
|
||||
if (!id) {
|
||||
return;
|
||||
}
|
||||
|
||||
const item = itemsById[id];
|
||||
if (item.docType === 'transaction') {
|
||||
return item.transaction;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function getWaterfall(
|
||||
hits: Array<Span | Transaction>,
|
||||
entryTransaction: Transaction
|
||||
|
@ -200,9 +264,12 @@ export function getWaterfall(
|
|||
if (isEmpty(hits)) {
|
||||
return {
|
||||
services: [],
|
||||
duration: 0,
|
||||
traceRootDuration: 0,
|
||||
items: [],
|
||||
itemsById: {},
|
||||
getTransactionById: () => undefined
|
||||
getTransactionById: () => undefined,
|
||||
serviceColors: {}
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -235,25 +302,22 @@ export function getWaterfall(
|
|||
entryTransactionItem
|
||||
);
|
||||
const traceRoot = getTraceRoot(childrenByParentId);
|
||||
|
||||
const getTransactionById = (id?: IWaterfallItem['id']) => {
|
||||
if (!id) {
|
||||
return;
|
||||
}
|
||||
|
||||
const item = itemsById[id];
|
||||
if (item.docType === 'transaction') {
|
||||
return item.transaction;
|
||||
}
|
||||
};
|
||||
const duration = getDuration(items);
|
||||
const traceRootDuration = traceRoot
|
||||
? traceRoot.transaction.duration.us
|
||||
: duration;
|
||||
const services = getServices(items);
|
||||
const getTransactionById = createGetTransactionById(itemsById);
|
||||
const serviceColors = getServiceColors(services);
|
||||
|
||||
return {
|
||||
traceRoot,
|
||||
traceRootDuration: traceRoot && traceRoot.transaction.duration.us,
|
||||
duration: entryTransaction.transaction.duration.us,
|
||||
services: getServices(items),
|
||||
traceRootDuration,
|
||||
duration,
|
||||
services,
|
||||
items,
|
||||
itemsById,
|
||||
getTransactionById
|
||||
getTransactionById,
|
||||
serviceColors
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,26 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { zipObject } from 'lodash';
|
||||
import { colors } from '../../../../../style/variables';
|
||||
|
||||
interface IServiceColors {
|
||||
[key: string]: string;
|
||||
}
|
||||
|
||||
export function getServiceColors(services: string[]): IServiceColors {
|
||||
const assignedColors = [
|
||||
colors.apmBlue,
|
||||
colors.apmGreen,
|
||||
colors.apmPurple,
|
||||
colors.apmRed2,
|
||||
colors.apmTan,
|
||||
colors.apmOrange,
|
||||
colors.apmYellow
|
||||
];
|
||||
|
||||
return zipObject(services, assignedColors);
|
||||
}
|
|
@ -17,7 +17,6 @@ import { EuiBadge, EuiFlexGroup, EuiFlexItem, EuiToolTip } from '@elastic/eui';
|
|||
|
||||
import { IUrlParams } from 'x-pack/plugins/apm/public/store/urlParams';
|
||||
import { getAgentMarks } from './get_agent_marks';
|
||||
import { getServiceColors } from './getServiceColors';
|
||||
import { ServiceLegends } from './ServiceLegends';
|
||||
import { Waterfall } from './Waterfall';
|
||||
import { IWaterfall } from './Waterfall/waterfall_helpers/waterfall_helpers';
|
||||
|
@ -39,13 +38,12 @@ export function WaterfallContainer({
|
|||
if (!waterfall) {
|
||||
return null;
|
||||
}
|
||||
const serviceColors = getServiceColors(waterfall.services);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<EuiFlexGroup justifyContent="spaceBetween">
|
||||
<EuiFlexItem>
|
||||
<ServiceLegends serviceColors={serviceColors} />
|
||||
<ServiceLegends serviceColors={waterfall.serviceColors} />
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiToolTip
|
||||
|
@ -59,7 +57,7 @@ export function WaterfallContainer({
|
|||
<Waterfall
|
||||
agentMarks={agentMarks}
|
||||
location={location}
|
||||
serviceColors={serviceColors}
|
||||
serviceColors={waterfall.serviceColors}
|
||||
urlParams={urlParams}
|
||||
waterfall={waterfall}
|
||||
/>
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import _ from 'lodash';
|
||||
import { inRange } from 'lodash';
|
||||
import { Sticky } from 'react-sticky';
|
||||
import { XYPlot, XAxis } from 'react-vis';
|
||||
import LastTickValue from './LastTickValue';
|
||||
|
@ -14,14 +14,26 @@ import AgentMarker from './AgentMarker';
|
|||
import { colors, px } from '../../../../style/variables';
|
||||
import { getTimeFormatter } from '../../../../utils/formatters';
|
||||
|
||||
// Remove last tick if it's too close to xMax
|
||||
const getXAxisTickValues = (tickValues, xMax) =>
|
||||
_.last(tickValues) * 1.05 > xMax ? tickValues.slice(0, -1) : tickValues;
|
||||
// Remove any tick that is too close to traceRootDuration
|
||||
const getXAxisTickValues = (tickValues, traceRootDuration) => {
|
||||
if (!tickValues) {
|
||||
return [];
|
||||
}
|
||||
|
||||
function TimelineAxis({ plotValues, agentMarks }) {
|
||||
const padding = (tickValues[1] - tickValues[0]) / 2;
|
||||
const lowerBound = traceRootDuration - padding;
|
||||
const upperBound = traceRootDuration + padding;
|
||||
|
||||
return tickValues.filter(value => {
|
||||
const isInRange = inRange(value, lowerBound, upperBound);
|
||||
return !isInRange && value !== traceRootDuration;
|
||||
});
|
||||
};
|
||||
|
||||
function TimelineAxis({ plotValues, agentMarks, traceRootDuration }) {
|
||||
const { margins, tickValues, width, xDomain, xMax, xScale } = plotValues;
|
||||
const tickFormat = getTimeFormatter(xMax);
|
||||
const xAxisTickValues = getXAxisTickValues(tickValues, xMax);
|
||||
const xAxisTickValues = getXAxisTickValues(tickValues, traceRootDuration);
|
||||
|
||||
return (
|
||||
<Sticky disableCompensation>
|
||||
|
@ -62,8 +74,8 @@ function TimelineAxis({ plotValues, agentMarks }) {
|
|||
/>
|
||||
|
||||
<LastTickValue
|
||||
x={xScale(xMax)}
|
||||
value={tickFormat(xMax)}
|
||||
x={xScale(traceRootDuration)}
|
||||
value={tickFormat(traceRootDuration)}
|
||||
marginTop={28}
|
||||
/>
|
||||
|
||||
|
|
|
@ -11,13 +11,13 @@ import { colors } from '../../../../style/variables';
|
|||
|
||||
class VerticalLines extends PureComponent {
|
||||
render() {
|
||||
const { traceRootDuration } = this.props;
|
||||
const {
|
||||
width,
|
||||
height,
|
||||
margins,
|
||||
xDomain,
|
||||
tickValues,
|
||||
xMax
|
||||
tickValues
|
||||
} = this.props.plotValues;
|
||||
|
||||
const agentMarkTimes = this.props.agentMarks.map(({ us }) => us);
|
||||
|
@ -43,7 +43,7 @@ class VerticalLines extends PureComponent {
|
|||
/>
|
||||
|
||||
<VerticalGridLines
|
||||
tickValues={[...agentMarkTimes, xMax]}
|
||||
tickValues={[...agentMarkTimes, traceRootDuration]}
|
||||
style={{ stroke: colors.gray3 }}
|
||||
/>
|
||||
</XYPlot>
|
||||
|
|
|
@ -9,7 +9,6 @@ import { mount } from 'enzyme';
|
|||
import { StickyContainer } from 'react-sticky';
|
||||
|
||||
import Timeline from '../index';
|
||||
import props from './props.json';
|
||||
import { mockMoment, toJson } from '../../../../../utils/testHelpers';
|
||||
|
||||
describe('Timeline', () => {
|
||||
|
@ -18,9 +17,28 @@ describe('Timeline', () => {
|
|||
});
|
||||
|
||||
it('should render with data', () => {
|
||||
const props = {
|
||||
traceRootDuration: 200000,
|
||||
width: 1000,
|
||||
duration: 200000,
|
||||
height: 116,
|
||||
margins: {
|
||||
top: 100,
|
||||
left: 50,
|
||||
right: 50,
|
||||
bottom: 0
|
||||
},
|
||||
animation: null,
|
||||
agentMarks: [
|
||||
{ name: 'timeToFirstByte', us: 100000 },
|
||||
{ name: 'domInteractive', us: 110000 },
|
||||
{ name: 'domComplete', us: 190000 }
|
||||
]
|
||||
};
|
||||
|
||||
const wrapper = mount(
|
||||
<StickyContainer>
|
||||
<Timeline header={<div>Hello - i am a header</div>} {...props} />
|
||||
<Timeline {...props} />
|
||||
</StickyContainer>
|
||||
);
|
||||
|
||||
|
|
|
@ -144,7 +144,7 @@ exports[`Timeline should render with data 1`] = `
|
|||
},
|
||||
}
|
||||
}
|
||||
transform="translate(87.9408646541237, 0)"
|
||||
transform="translate(90, 0)"
|
||||
>
|
||||
<line
|
||||
className="rv-xy-plot__axis__tick__line"
|
||||
|
@ -186,7 +186,7 @@ exports[`Timeline should render with data 1`] = `
|
|||
},
|
||||
}
|
||||
}
|
||||
transform="translate(175.8817293082474, 0)"
|
||||
transform="translate(180, 0)"
|
||||
>
|
||||
<line
|
||||
className="rv-xy-plot__axis__tick__line"
|
||||
|
@ -228,7 +228,7 @@ exports[`Timeline should render with data 1`] = `
|
|||
},
|
||||
}
|
||||
}
|
||||
transform="translate(263.82259396237106, 0)"
|
||||
transform="translate(270, 0)"
|
||||
>
|
||||
<line
|
||||
className="rv-xy-plot__axis__tick__line"
|
||||
|
@ -270,7 +270,7 @@ exports[`Timeline should render with data 1`] = `
|
|||
},
|
||||
}
|
||||
}
|
||||
transform="translate(351.7634586164948, 0)"
|
||||
transform="translate(360, 0)"
|
||||
>
|
||||
<line
|
||||
className="rv-xy-plot__axis__tick__line"
|
||||
|
@ -312,7 +312,7 @@ exports[`Timeline should render with data 1`] = `
|
|||
},
|
||||
}
|
||||
}
|
||||
transform="translate(439.7043232706185, 0)"
|
||||
transform="translate(450, 0)"
|
||||
>
|
||||
<line
|
||||
className="rv-xy-plot__axis__tick__line"
|
||||
|
@ -354,7 +354,7 @@ exports[`Timeline should render with data 1`] = `
|
|||
},
|
||||
}
|
||||
}
|
||||
transform="translate(527.6451879247421, 0)"
|
||||
transform="translate(540, 0)"
|
||||
>
|
||||
<line
|
||||
className="rv-xy-plot__axis__tick__line"
|
||||
|
@ -396,7 +396,7 @@ exports[`Timeline should render with data 1`] = `
|
|||
},
|
||||
}
|
||||
}
|
||||
transform="translate(615.5860525788659, 0)"
|
||||
transform="translate(630, 0)"
|
||||
>
|
||||
<line
|
||||
className="rv-xy-plot__axis__tick__line"
|
||||
|
@ -438,7 +438,7 @@ exports[`Timeline should render with data 1`] = `
|
|||
},
|
||||
}
|
||||
}
|
||||
transform="translate(703.5269172329896, 0)"
|
||||
transform="translate(720, 0)"
|
||||
>
|
||||
<line
|
||||
className="rv-xy-plot__axis__tick__line"
|
||||
|
@ -480,7 +480,7 @@ exports[`Timeline should render with data 1`] = `
|
|||
},
|
||||
}
|
||||
}
|
||||
transform="translate(791.4677818871132, 0)"
|
||||
transform="translate(810, 0)"
|
||||
>
|
||||
<line
|
||||
className="rv-xy-plot__axis__tick__line"
|
||||
|
@ -523,7 +523,7 @@ exports[`Timeline should render with data 1`] = `
|
|||
textAnchor="middle"
|
||||
transform="translate(0, -8)"
|
||||
>
|
||||
205 ms
|
||||
200 ms
|
||||
</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
@ -531,7 +531,7 @@ exports[`Timeline should render with data 1`] = `
|
|||
style={
|
||||
Object {
|
||||
"bottom": 0,
|
||||
"left": "484.2043232706185px",
|
||||
"left": "494.5px",
|
||||
"position": "absolute",
|
||||
}
|
||||
}
|
||||
|
@ -561,7 +561,7 @@ exports[`Timeline should render with data 1`] = `
|
|||
style={
|
||||
Object {
|
||||
"bottom": 0,
|
||||
"left": "528.1747555976804px",
|
||||
"left": "539.5px",
|
||||
"position": "absolute",
|
||||
}
|
||||
}
|
||||
|
@ -591,7 +591,7 @@ exports[`Timeline should render with data 1`] = `
|
|||
style={
|
||||
Object {
|
||||
"bottom": 0,
|
||||
"left": "879.9382142141751px",
|
||||
"left": "899.5px",
|
||||
"position": "absolute",
|
||||
}
|
||||
}
|
||||
|
@ -673,8 +673,8 @@ exports[`Timeline should render with data 1`] = `
|
|||
"stroke": "#f5f5f5",
|
||||
}
|
||||
}
|
||||
x1={87.9408646541237}
|
||||
x2={87.9408646541237}
|
||||
x1={90}
|
||||
x2={90}
|
||||
y1={0}
|
||||
y2={116}
|
||||
/>
|
||||
|
@ -685,8 +685,8 @@ exports[`Timeline should render with data 1`] = `
|
|||
"stroke": "#f5f5f5",
|
||||
}
|
||||
}
|
||||
x1={175.8817293082474}
|
||||
x2={175.8817293082474}
|
||||
x1={180}
|
||||
x2={180}
|
||||
y1={0}
|
||||
y2={116}
|
||||
/>
|
||||
|
@ -697,8 +697,8 @@ exports[`Timeline should render with data 1`] = `
|
|||
"stroke": "#f5f5f5",
|
||||
}
|
||||
}
|
||||
x1={263.82259396237106}
|
||||
x2={263.82259396237106}
|
||||
x1={270}
|
||||
x2={270}
|
||||
y1={0}
|
||||
y2={116}
|
||||
/>
|
||||
|
@ -709,8 +709,8 @@ exports[`Timeline should render with data 1`] = `
|
|||
"stroke": "#f5f5f5",
|
||||
}
|
||||
}
|
||||
x1={351.7634586164948}
|
||||
x2={351.7634586164948}
|
||||
x1={360}
|
||||
x2={360}
|
||||
y1={0}
|
||||
y2={116}
|
||||
/>
|
||||
|
@ -721,8 +721,8 @@ exports[`Timeline should render with data 1`] = `
|
|||
"stroke": "#f5f5f5",
|
||||
}
|
||||
}
|
||||
x1={439.7043232706185}
|
||||
x2={439.7043232706185}
|
||||
x1={450}
|
||||
x2={450}
|
||||
y1={0}
|
||||
y2={116}
|
||||
/>
|
||||
|
@ -733,8 +733,8 @@ exports[`Timeline should render with data 1`] = `
|
|||
"stroke": "#f5f5f5",
|
||||
}
|
||||
}
|
||||
x1={527.6451879247421}
|
||||
x2={527.6451879247421}
|
||||
x1={540}
|
||||
x2={540}
|
||||
y1={0}
|
||||
y2={116}
|
||||
/>
|
||||
|
@ -745,8 +745,8 @@ exports[`Timeline should render with data 1`] = `
|
|||
"stroke": "#f5f5f5",
|
||||
}
|
||||
}
|
||||
x1={615.5860525788659}
|
||||
x2={615.5860525788659}
|
||||
x1={630}
|
||||
x2={630}
|
||||
y1={0}
|
||||
y2={116}
|
||||
/>
|
||||
|
@ -757,8 +757,8 @@ exports[`Timeline should render with data 1`] = `
|
|||
"stroke": "#f5f5f5",
|
||||
}
|
||||
}
|
||||
x1={703.5269172329896}
|
||||
x2={703.5269172329896}
|
||||
x1={720}
|
||||
x2={720}
|
||||
y1={0}
|
||||
y2={116}
|
||||
/>
|
||||
|
@ -769,8 +769,8 @@ exports[`Timeline should render with data 1`] = `
|
|||
"stroke": "#f5f5f5",
|
||||
}
|
||||
}
|
||||
x1={791.4677818871132}
|
||||
x2={791.4677818871132}
|
||||
x1={810}
|
||||
x2={810}
|
||||
y1={0}
|
||||
y2={116}
|
||||
/>
|
||||
|
@ -781,8 +781,8 @@ exports[`Timeline should render with data 1`] = `
|
|||
"stroke": "#f5f5f5",
|
||||
}
|
||||
}
|
||||
x1={879.408646541237}
|
||||
x2={879.408646541237}
|
||||
x1={900}
|
||||
x2={900}
|
||||
y1={0}
|
||||
y2={116}
|
||||
/>
|
||||
|
@ -798,8 +798,8 @@ exports[`Timeline should render with data 1`] = `
|
|||
"stroke": "#999999",
|
||||
}
|
||||
}
|
||||
x1={439.7043232706185}
|
||||
x2={439.7043232706185}
|
||||
x1={450}
|
||||
x2={450}
|
||||
y1={0}
|
||||
y2={116}
|
||||
/>
|
||||
|
@ -810,8 +810,8 @@ exports[`Timeline should render with data 1`] = `
|
|||
"stroke": "#999999",
|
||||
}
|
||||
}
|
||||
x1={483.6747555976803}
|
||||
x2={483.6747555976803}
|
||||
x1={495.00000000000006}
|
||||
x2={495.00000000000006}
|
||||
y1={0}
|
||||
y2={116}
|
||||
/>
|
||||
|
@ -822,8 +822,8 @@ exports[`Timeline should render with data 1`] = `
|
|||
"stroke": "#999999",
|
||||
}
|
||||
}
|
||||
x1={835.4382142141751}
|
||||
x2={835.4382142141751}
|
||||
x1={855}
|
||||
x2={855}
|
||||
y1={0}
|
||||
y2={116}
|
||||
/>
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
{
|
||||
"width": 1000,
|
||||
"duration": 204683,
|
||||
"height": 116,
|
||||
"margins": {
|
||||
"top": 100,
|
||||
"left": 50,
|
||||
"right": 50,
|
||||
"bottom": 0
|
||||
},
|
||||
"animation": null,
|
||||
"agentMarks": [
|
||||
{ "name": "timeToFirstByte", "us": 100000 },
|
||||
{ "name": "domInteractive", "us": 110000 },
|
||||
{ "name": "domComplete", "us": 190000 }
|
||||
]
|
||||
}
|
|
@ -14,17 +14,31 @@ import VerticalLines from './VerticalLines';
|
|||
|
||||
class Timeline extends PureComponent {
|
||||
render() {
|
||||
const { width, duration, agentMarks, height, margins } = this.props;
|
||||
const {
|
||||
width,
|
||||
duration,
|
||||
agentMarks,
|
||||
traceRootDuration,
|
||||
height,
|
||||
margins
|
||||
} = this.props;
|
||||
if (duration == null || !width) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const plotValues = getPlotValues({ width, duration, height, margins });
|
||||
|
||||
return (
|
||||
<div>
|
||||
<TimelineAxis plotValues={plotValues} agentMarks={agentMarks} />
|
||||
<VerticalLines plotValues={plotValues} agentMarks={agentMarks} />
|
||||
<TimelineAxis
|
||||
plotValues={plotValues}
|
||||
agentMarks={agentMarks}
|
||||
traceRootDuration={traceRootDuration}
|
||||
/>
|
||||
<VerticalLines
|
||||
plotValues={plotValues}
|
||||
agentMarks={agentMarks}
|
||||
traceRootDuration={traceRootDuration}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue