problems timeline: use SVG
This commit is contained in:
@@ -42,6 +42,7 @@ export default class ProblemTimeline extends PureComponent<ProblemTimelineProps,
|
|||||||
if (!this.rootRef) {
|
if (!this.rootRef) {
|
||||||
return <div className="event-timeline" ref={this.setRootRef} />;
|
return <div className="event-timeline" ref={this.setRootRef} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { events, timeRange } = this.props;
|
const { events, timeRange } = this.props;
|
||||||
const { timeFrom, timeTo } = timeRange;
|
const { timeFrom, timeTo } = timeRange;
|
||||||
const range = timeTo - timeFrom;
|
const range = timeTo - timeFrom;
|
||||||
@@ -52,13 +53,14 @@ export default class ProblemTimeline extends PureComponent<ProblemTimelineProps,
|
|||||||
const firstTs = events.length ? Number(events[0].clock) : timeTo;
|
const firstTs = events.length ? Number(events[0].clock) : timeTo;
|
||||||
const duration = (firstTs - timeFrom) / range;
|
const duration = (firstTs - timeFrom) / range;
|
||||||
const firstEventColor = events[0].value !== '1' ? this.props.problemColor : this.props.okColor;
|
const firstEventColor = events[0].value !== '1' ? this.props.problemColor : this.props.okColor;
|
||||||
const firstEventStyle: React.CSSProperties = {
|
const firstEventAttributes = {
|
||||||
width: duration * width,
|
width: duration * width,
|
||||||
left: 0,
|
x: 0,
|
||||||
background: firstEventColor,
|
y: 0,
|
||||||
|
fill: firstEventColor,
|
||||||
};
|
};
|
||||||
firstItem = (
|
firstItem = (
|
||||||
<div key='0' className="problem-event-interval" style={firstEventStyle}></div>
|
<rect key='0' className="problem-event-interval" {...firstEventAttributes}></rect>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,14 +70,15 @@ export default class ProblemTimeline extends PureComponent<ProblemTimelineProps,
|
|||||||
const duration = (nextTs - ts) / range;
|
const duration = (nextTs - ts) / range;
|
||||||
const posLeft = (ts - timeFrom) / range * width;
|
const posLeft = (ts - timeFrom) / range * width;
|
||||||
const eventColor = event.value === '1' ? this.props.problemColor : this.props.okColor;
|
const eventColor = event.value === '1' ? this.props.problemColor : this.props.okColor;
|
||||||
const styles: React.CSSProperties = {
|
const attributes = {
|
||||||
width: duration * width,
|
width: duration * width,
|
||||||
left: posLeft,
|
x: posLeft,
|
||||||
background: eventColor,
|
y: 0,
|
||||||
|
fill: eventColor,
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div key={event.eventid} className="problem-event-interval" style={styles}></div>
|
<rect key={event.eventid} className="problem-event-interval" {...attributes} />
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -83,23 +86,97 @@ export default class ProblemTimeline extends PureComponent<ProblemTimelineProps,
|
|||||||
const ts = Number(event.clock);
|
const ts = Number(event.clock);
|
||||||
const posLeft = (ts - timeFrom) / range * width - EVENT_ITEM_SIZE / 2;
|
const posLeft = (ts - timeFrom) / range * width - EVENT_ITEM_SIZE / 2;
|
||||||
const eventColor = event.value === '1' ? this.props.problemColor : this.props.okColor;
|
const eventColor = event.value === '1' ? this.props.problemColor : this.props.okColor;
|
||||||
const styles: React.CSSProperties = {
|
|
||||||
transform: `translate(${posLeft}px, -2px)`,
|
|
||||||
// background: eventColor,
|
|
||||||
borderColor: eventColor,
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div key={event.eventid} className="problem-event-item" style={styles}></div>
|
<TimelinePoint
|
||||||
|
key={event.eventid}
|
||||||
|
className="problem-event-item"
|
||||||
|
x={posLeft}
|
||||||
|
r={10}
|
||||||
|
color={eventColor}
|
||||||
|
/>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="event-timeline" ref={this.setRootRef}>
|
<div className="event-timeline" ref={this.setRootRef}>
|
||||||
{firstItem}
|
<svg className="event-timeline-canvas" viewBox={`0 0 ${width} 40`}>
|
||||||
{eventsIntervalItems}
|
<defs>
|
||||||
{eventsItems}
|
<filter id="dropShadow" x="-50%" y="-50%" width="200%" height="200%">
|
||||||
|
<feGaussianBlur in="SourceAlpha" stdDeviation="2" />
|
||||||
|
<feOffset dx="1" dy="1" />
|
||||||
|
<feMerge>
|
||||||
|
<feMergeNode />
|
||||||
|
<feMergeNode in="SourceGraphic" />
|
||||||
|
</feMerge>
|
||||||
|
</filter>
|
||||||
|
<filter id="glowShadow" x="-50%" y="-50%" width="200%" height="200%">
|
||||||
|
<feGaussianBlur in="SourceGraphic" stdDeviation="2" />
|
||||||
|
<feMerge>
|
||||||
|
<feMergeNode />
|
||||||
|
<feMergeNode in="SourceGraphic" />
|
||||||
|
</feMerge>
|
||||||
|
</filter>
|
||||||
|
<filter id="timelinePointBlur" x="-50%" y="-50%" width="200%" height="200%">
|
||||||
|
<feGaussianBlur in="SourceGraphic" stdDeviation="2" result="blurOut" />
|
||||||
|
</filter>
|
||||||
|
</defs>
|
||||||
|
<g className="event-timeline-group">
|
||||||
|
<g className="event-timeline-regions">
|
||||||
|
{firstItem}
|
||||||
|
{eventsIntervalItems}
|
||||||
|
</g>
|
||||||
|
<g className="timeline-points" transform={`translate(0, 6)`}>
|
||||||
|
{eventsItems}
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function TimelineRegion(props) {
|
||||||
|
return (
|
||||||
|
<rect></rect>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
interface TimelinePointProps {
|
||||||
|
x: number;
|
||||||
|
r: number;
|
||||||
|
color: string;
|
||||||
|
className?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
class TimelinePoint extends PureComponent<TimelinePointProps, any> {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = { r: this.props.r };
|
||||||
|
}
|
||||||
|
|
||||||
|
handleMouseOver = () => {
|
||||||
|
this.setState({ r: this.props.r * 1.2 });
|
||||||
|
}
|
||||||
|
|
||||||
|
handleMouseLeave = () => {
|
||||||
|
this.setState({ r: this.props.r });
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { x, color, className } = this.props;
|
||||||
|
const r = this.state.r;
|
||||||
|
const cx = x + this.props.r;
|
||||||
|
const rInner = Math.floor(r * 0.6);
|
||||||
|
return (
|
||||||
|
<g className={className}
|
||||||
|
transform={`translate(${cx}, 0)`}
|
||||||
|
filter="url(#dropShadow)"
|
||||||
|
onMouseOver={this.handleMouseOver}
|
||||||
|
onMouseLeave={this.handleMouseLeave}>
|
||||||
|
<circle cx={0} cy={0} r={r} fill={color} className="point-border" />
|
||||||
|
<circle cx={0} cy={0} r={rInner} fill="#000000" className="point-core" />
|
||||||
|
</g>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -343,32 +343,41 @@
|
|||||||
margin: 1.6rem 0;
|
margin: 1.6rem 0;
|
||||||
// margin-top: auto;
|
// margin-top: auto;
|
||||||
|
|
||||||
|
svg.event-timeline-canvas {
|
||||||
|
height: 40px;
|
||||||
|
|
||||||
|
g.event-timeline-group {
|
||||||
|
height: 40px;
|
||||||
|
transform: translate(0px, 14px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.problem-event-interval {
|
.problem-event-interval {
|
||||||
height: 12px;
|
height: 12px;
|
||||||
position: absolute;
|
// transition: all 0.2s ease-out;
|
||||||
// opacity: 0.7;
|
// opacity: 0.7;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
// opacity: 1;
|
// opacity: 1;
|
||||||
border: 1px solid $blue;
|
stroke: $zbx-text-highlighted;
|
||||||
box-shadow: 0px 0px 5px rgba($blue, 0.5);
|
filter: url(#glowShadow);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.problem-event-item {
|
.problem-event-item {
|
||||||
position: absolute;
|
circle {
|
||||||
width: 16px;
|
transition: all 0.2s ease-out;
|
||||||
height: 16px;
|
}
|
||||||
// transform: translate(0px, -2px);
|
|
||||||
background: $problem-statusbar-background;
|
|
||||||
border: 4px solid $blue;
|
|
||||||
border-radius: 16px;
|
|
||||||
z-index: 10;
|
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
box-shadow: 0px 0px 6px 1px rgba($orange, 1);
|
circle.point-border {
|
||||||
background-color: $zbx-text-highlighted;
|
stroke: $zbx-text-highlighted;
|
||||||
z-index: 11;
|
stroke-width: 1;
|
||||||
|
filter: url(#glowShadow);
|
||||||
|
}
|
||||||
|
.point-core {
|
||||||
|
fill: $zbx-text-highlighted;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user