mirror of
https://github.com/kemko/nomad.git
synced 2026-01-04 17:35:43 +03:00
Add annotations to the line chart component
This commit is contained in:
@@ -14,7 +14,7 @@ import d3Format from 'd3-format';
|
||||
import d3TimeFormat from 'd3-time-format';
|
||||
import WindowResizable from 'nomad-ui/mixins/window-resizable';
|
||||
import styleStringProperty from 'nomad-ui/utils/properties/style-string';
|
||||
import { classNames } from '@ember-decorators/component';
|
||||
import { classNames, classNameBindings } from '@ember-decorators/component';
|
||||
import classic from 'ember-classic-decorator';
|
||||
|
||||
// Returns a new array with the specified number of points linearly
|
||||
@@ -31,12 +31,25 @@ const lerp = ([low, high], numPoints) => {
|
||||
// Round a number or an array of numbers
|
||||
const nice = val => (val instanceof Array ? val.map(nice) : Math.round(val));
|
||||
|
||||
const iconFor = {
|
||||
error: 'cancel-circle-fill',
|
||||
info: 'info-circle-fill',
|
||||
};
|
||||
|
||||
const iconClassFor = {
|
||||
error: 'is-danger',
|
||||
info: '',
|
||||
};
|
||||
|
||||
@classic
|
||||
@classNames('chart', 'line-chart')
|
||||
@classNameBindings('annotations.length:with-annotations')
|
||||
export default class LineChart extends Component.extend(WindowResizable) {
|
||||
// Public API
|
||||
|
||||
data = null;
|
||||
annotations = null;
|
||||
onAnnotationClick() {}
|
||||
xProp = null;
|
||||
yProp = null;
|
||||
timeseries = false;
|
||||
@@ -100,6 +113,14 @@ export default class LineChart extends Component.extend(WindowResizable) {
|
||||
tooltipPosition = null;
|
||||
@styleStringProperty('tooltipPosition') tooltipStyle;
|
||||
|
||||
@computed('xAxisOffset')
|
||||
get chartAnnotationBounds() {
|
||||
return {
|
||||
height: this.xAxisOffset,
|
||||
};
|
||||
}
|
||||
@styleStringProperty('chartAnnotationBounds') chartAnnotationsStyle;
|
||||
|
||||
@computed('data.[]', 'xProp', 'timeseries', 'yAxisOffset')
|
||||
get xScale() {
|
||||
const xProp = this.xProp;
|
||||
@@ -244,6 +265,26 @@ export default class LineChart extends Component.extend(WindowResizable) {
|
||||
return area(this.data);
|
||||
}
|
||||
|
||||
@computed('annotations.[]', 'xScale', 'xProp', 'timeseries')
|
||||
get processedAnnotations() {
|
||||
const { xScale, xProp, annotations, timeseries } = this;
|
||||
|
||||
if (!annotations || !annotations.length) return null;
|
||||
|
||||
return annotations.map(annotation => {
|
||||
const x = xScale(annotation[xProp]);
|
||||
const y = 0; // TODO: prevent overlap by staggering y-offset
|
||||
const time = this.xFormat(timeseries)(annotation[xProp]);
|
||||
return {
|
||||
annotation,
|
||||
style: `transform:translate(${x}px,${y}px)`,
|
||||
icon: iconFor[annotation.type],
|
||||
iconClass: iconClassFor[annotation.type],
|
||||
label: `${annotation.type} event at ${time}`,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
didInsertElement() {
|
||||
this.updateDimensions();
|
||||
|
||||
@@ -344,6 +385,10 @@ export default class LineChart extends Component.extend(WindowResizable) {
|
||||
}
|
||||
}
|
||||
|
||||
annotationClick(annotation) {
|
||||
this.onAnnotationClick(annotation);
|
||||
}
|
||||
|
||||
windowResizeHandler() {
|
||||
run.once(this, this.updateDimensions);
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
@import './charts/line-chart';
|
||||
@import './charts/tooltip';
|
||||
@import './charts/colors';
|
||||
@import './charts/chart-annotation.scss';
|
||||
|
||||
.inline-chart {
|
||||
height: 1.5rem;
|
||||
|
||||
46
ui/app/styles/charts/chart-annotation.scss
Normal file
46
ui/app/styles/charts/chart-annotation.scss
Normal file
@@ -0,0 +1,46 @@
|
||||
.chart-annotation {
|
||||
position: absolute;
|
||||
height: 100%;
|
||||
|
||||
.indicator {
|
||||
color: $grey;
|
||||
display: block;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
padding: 0;
|
||||
border: none;
|
||||
background: transparent;
|
||||
margin-left: -10px;
|
||||
margin-top: -10px;
|
||||
cursor: pointer;
|
||||
pointer-events: auto;
|
||||
|
||||
.icon {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
@each $name, $pair in $colors {
|
||||
$color: nth($pair, 1);
|
||||
|
||||
&.is-#{$name} .indicator {
|
||||
color: $color;
|
||||
|
||||
&:hover,
|
||||
&.is-hovered {
|
||||
color: darken($color, 2.5%);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.line {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 8px;
|
||||
width: 1px;
|
||||
height: calc(100% - 8px);
|
||||
background: $grey;
|
||||
z-index: -1;
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,13 @@
|
||||
.chart.line-chart {
|
||||
display: block;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
|
||||
svg {
|
||||
&.with-annotations {
|
||||
margin-top: 1.5em;
|
||||
}
|
||||
|
||||
& > svg {
|
||||
display: block;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
@@ -43,6 +48,15 @@
|
||||
}
|
||||
}
|
||||
|
||||
.line-chart-annotations {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
left: 0;
|
||||
top: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
@each $name, $pair in $colors {
|
||||
$color: nth($pair, 1);
|
||||
|
||||
|
||||
@@ -72,6 +72,7 @@
|
||||
}
|
||||
|
||||
.label {
|
||||
white-space: nowrap;
|
||||
font-weight: $weight-bold;
|
||||
color: $black;
|
||||
margin: 0;
|
||||
@@ -80,6 +81,10 @@
|
||||
color: rgba($grey, 0.6);
|
||||
}
|
||||
}
|
||||
|
||||
.value {
|
||||
padding-left: 1em;
|
||||
}
|
||||
}
|
||||
|
||||
ol > li {
|
||||
|
||||
@@ -26,6 +26,20 @@
|
||||
<g aria-hidden="true" class="x-axis axis" transform="translate(0, {{this.xAxisOffset}})"></g>
|
||||
<g aria-hidden="true" class="y-axis axis" transform="translate({{this.yAxisOffset}}, 0)"></g>
|
||||
</svg>
|
||||
<div data-test-annotations class="line-chart-annotations" style={{this.chartAnnotationsStyle}}>
|
||||
{{#each this.processedAnnotations as |annotation|}}
|
||||
<div class="chart-annotation {{annotation.iconClass}}" style={{annotation.style}}>
|
||||
<button
|
||||
type="button"
|
||||
class="indicator"
|
||||
title={{annotation.label}}
|
||||
onclick={{action this.annotationClick annotation.annotation}}>
|
||||
{{x-icon annotation.icon}}
|
||||
</button>
|
||||
<div class="line" />
|
||||
</div>
|
||||
{{/each}}
|
||||
</div>
|
||||
<div class="chart-tooltip is-snappy {{if this.isActive "active" "inactive"}}" style={{this.tooltipStyle}}>
|
||||
<p>
|
||||
<span class="label">
|
||||
|
||||
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 2.3 KiB |
1
ui/app/templates/components/scale-events-chart.hbs
Normal file
1
ui/app/templates/components/scale-events-chart.hbs
Normal file
@@ -0,0 +1 @@
|
||||
<LineChart @data={{this.data}} @annotations={{this.annotations}} @timeseries={{true}} />
|
||||
Reference in New Issue
Block a user