New web ui
This commit is contained in:
parent
e09d5cb4ec
commit
9c651ae913
105 changed files with 7314 additions and 5514 deletions
7
webui/src/app/charts/bar-chart/bar-chart.component.html
Normal file
7
webui/src/app/charts/bar-chart/bar-chart.component.html
Normal file
|
@ -0,0 +1,7 @@
|
|||
<div class="bar-chart" [class.is-hidden]="loading"></div>
|
||||
<div class="loading-text" [class.is-hidden]="!loading">
|
||||
<span>
|
||||
<span>Loading, please wait...</span>
|
||||
<img src="./assets/images/loader.svg" class="main-loader">
|
||||
</span>
|
||||
</div>
|
25
webui/src/app/charts/bar-chart/bar-chart.component.spec.ts
Normal file
25
webui/src/app/charts/bar-chart/bar-chart.component.spec.ts
Normal file
|
@ -0,0 +1,25 @@
|
|||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { BarChartComponent } from './bar-chart.component';
|
||||
|
||||
describe('BarChartComponent', () => {
|
||||
let component: BarChartComponent;
|
||||
let fixture: ComponentFixture<BarChartComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ BarChartComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(BarChartComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
114
webui/src/app/charts/bar-chart/bar-chart.component.ts
Normal file
114
webui/src/app/charts/bar-chart/bar-chart.component.ts
Normal file
|
@ -0,0 +1,114 @@
|
|||
import { Component, Input, OnInit, ElementRef, OnChanges, SimpleChanges } from '@angular/core';
|
||||
import { WindowService } from '../../services/window.service';
|
||||
import {
|
||||
min,
|
||||
max,
|
||||
easeLinear,
|
||||
select,
|
||||
axisLeft,
|
||||
axisBottom,
|
||||
scaleBand,
|
||||
scaleLinear
|
||||
} from 'd3';
|
||||
|
||||
@Component({
|
||||
selector: 'app-bar-chart',
|
||||
templateUrl: './bar-chart.component.html'
|
||||
})
|
||||
export class BarChartComponent implements OnInit, OnChanges {
|
||||
@Input() value: any;
|
||||
|
||||
barChartEl: HTMLElement;
|
||||
svg: any;
|
||||
x: any;
|
||||
y: any;
|
||||
g: any;
|
||||
bars: any;
|
||||
width: number;
|
||||
height: number;
|
||||
margin = { top: 40, right: 40, bottom: 40, left: 40 };
|
||||
loading: boolean;
|
||||
data: any[];
|
||||
|
||||
constructor(public elementRef: ElementRef, public windowService: WindowService) {
|
||||
this.loading = true;
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.barChartEl = this.elementRef.nativeElement.querySelector('.bar-chart');
|
||||
this.setup();
|
||||
setTimeout(() => this.loading = false, 4000);
|
||||
|
||||
this.windowService.resize.subscribe(w => this.draw());
|
||||
}
|
||||
|
||||
ngOnChanges(changes: SimpleChanges) {
|
||||
if (!this.value || !this.svg) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.data = this.value;
|
||||
this.draw();
|
||||
}
|
||||
|
||||
setup(): void {
|
||||
this.width = this.barChartEl.clientWidth - this.margin.left - this.margin.right;
|
||||
this.height = this.barChartEl.clientHeight - this.margin.top - this.margin.bottom;
|
||||
|
||||
this.svg = select(this.barChartEl).append('svg')
|
||||
.attr('width', this.width + this.margin.left + this.margin.right)
|
||||
.attr('height', this.height + this.margin.top + this.margin.bottom);
|
||||
|
||||
this.g = this.svg.append('g')
|
||||
.attr('transform', `translate(${this.margin.left}, ${this.margin.top})`);
|
||||
|
||||
this.x = scaleBand().padding(0.05);
|
||||
this.y = scaleLinear();
|
||||
|
||||
this.g.append('g')
|
||||
.attr('class', 'axis axis--x');
|
||||
|
||||
this.g.append('g')
|
||||
.attr('class', 'axis axis--y');
|
||||
}
|
||||
|
||||
draw(): void {
|
||||
this.x.domain(this.data.map((d: any) => d.code));
|
||||
this.y.domain([0, max(this.data, (d: any) => d.count)]);
|
||||
|
||||
this.width = this.barChartEl.clientWidth - this.margin.left - this.margin.right;
|
||||
this.height = this.barChartEl.clientHeight - this.margin.top - this.margin.bottom;
|
||||
|
||||
this.svg
|
||||
.attr('width', this.width + this.margin.left + this.margin.right)
|
||||
.attr('height', this.height + this.margin.top + this.margin.bottom);
|
||||
|
||||
this.x.rangeRound([0, this.width]);
|
||||
this.y.rangeRound([this.height, 0]);
|
||||
|
||||
this.g.select('.axis--x')
|
||||
.attr('transform', `translate(0, ${this.height})`)
|
||||
.call(axisBottom(this.x));
|
||||
|
||||
this.g.select('.axis--y')
|
||||
.call(axisLeft(this.y).tickSize(-this.width));
|
||||
|
||||
const bars = this.g.selectAll('.bar').data(this.data);
|
||||
|
||||
bars.enter()
|
||||
.append('rect')
|
||||
.attr('class', 'bar')
|
||||
.attr('x', (d: any) => d.code)
|
||||
.attr('y', (d: any) => d.count)
|
||||
.attr('width', this.x.bandwidth())
|
||||
.attr('height', (d: any) => (this.height - this.y(d.count)) < 0 ? 0 : this.height - this.y(d.count));
|
||||
|
||||
bars.attr('x', (d: any) => this.x(d.code))
|
||||
.attr('y', (d: any) => this.y(d.count))
|
||||
.attr('width', this.x.bandwidth())
|
||||
.attr('height', (d: any) => (this.height - this.y(d.count)) < 0 ? 0 : this.height - this.y(d.count));
|
||||
|
||||
bars.exit().remove();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
<div class="line-chart" [class.is-hidden]="loading"></div>
|
||||
<div class="loading-text" [class.is-hidden]="!loading">
|
||||
<span>
|
||||
<span>Loading, please wait...</span>
|
||||
<img src="./assets/images/loader.svg" class="main-loader">
|
||||
</span>
|
||||
</div>
|
162
webui/src/app/charts/line-chart/line-chart.component.ts
Normal file
162
webui/src/app/charts/line-chart/line-chart.component.ts
Normal file
|
@ -0,0 +1,162 @@
|
|||
import { Component, Input, OnInit, ElementRef, OnChanges, SimpleChanges } from '@angular/core';
|
||||
import { WindowService } from '../../services/window.service';
|
||||
import {
|
||||
range,
|
||||
scaleTime,
|
||||
scaleLinear,
|
||||
min,
|
||||
max,
|
||||
curveLinear,
|
||||
line,
|
||||
easeLinear,
|
||||
select,
|
||||
axisLeft,
|
||||
axisBottom,
|
||||
timeSecond,
|
||||
timeFormat
|
||||
} from 'd3';
|
||||
|
||||
@Component({
|
||||
selector: 'app-line-chart',
|
||||
templateUrl: 'line-chart.component.html'
|
||||
})
|
||||
export class LineChartComponent implements OnChanges, OnInit {
|
||||
@Input() value: { count: number, date: string };
|
||||
|
||||
lineChartEl: HTMLElement;
|
||||
svg: any;
|
||||
g: any;
|
||||
line: any;
|
||||
path: any;
|
||||
x: any;
|
||||
y: any;
|
||||
data: number[];
|
||||
now: Date;
|
||||
duration: number;
|
||||
limit: number;
|
||||
options: any;
|
||||
xAxis: any;
|
||||
yAxis: any;
|
||||
height: number;
|
||||
width: number;
|
||||
margin = { top: 40, right: 40, bottom: 60, left: 60 };
|
||||
loading = true;
|
||||
|
||||
constructor(private elementRef: ElementRef, public windowService: WindowService) { }
|
||||
|
||||
ngOnInit() {
|
||||
this.lineChartEl = this.elementRef.nativeElement.querySelector('.line-chart');
|
||||
this.limit = 40;
|
||||
this.duration = 3000;
|
||||
this.now = new Date(Date.now() - this.duration);
|
||||
|
||||
this.options = {
|
||||
title: '',
|
||||
color: '#3A84C5'
|
||||
};
|
||||
|
||||
this.render();
|
||||
setTimeout(() => this.loading = false, 4000);
|
||||
this.windowService.resize.subscribe(w => {
|
||||
if (this.svg) {
|
||||
const el = this.lineChartEl.querySelector('svg');
|
||||
el.parentNode.removeChild(el);
|
||||
this.render();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
this.width = this.lineChartEl.clientWidth - this.margin.left - this.margin.right;
|
||||
this.height = this.lineChartEl.clientHeight - this.margin.top - this.margin.bottom;
|
||||
|
||||
this.svg = select(this.lineChartEl).append('svg')
|
||||
.attr('width', this.width + this.margin.left + this.margin.right)
|
||||
.attr('height', this.height + this.margin.top + this.margin.bottom)
|
||||
.append('g')
|
||||
.attr('transform', `translate(${this.margin.left}, ${this.margin.top})`);
|
||||
|
||||
if (!this.data) {
|
||||
this.data = range(this.limit).map(i => 0);
|
||||
}
|
||||
|
||||
this.x = scaleTime().range([0, this.width]);
|
||||
this.y = scaleLinear().range([this.height, 0]);
|
||||
|
||||
this.x.domain([<any>this.now - (this.limit - 2), <any>this.now - this.duration]);
|
||||
this.y.domain([0, max(this.data, (d: any) => d)]);
|
||||
|
||||
this.line = line()
|
||||
.x((d: any, i: number) => this.x(<any>this.now - (this.limit - 1 - i) * this.duration))
|
||||
.y((d: any) => this.y(d))
|
||||
.curve(curveLinear);
|
||||
|
||||
this.svg.append('defs').append('clipPath')
|
||||
.attr('id', 'clip')
|
||||
.append('rect')
|
||||
.attr('width', this.width)
|
||||
.attr('height', this.height);
|
||||
|
||||
this.xAxis = this.svg.append('g')
|
||||
.attr('class', 'x axis')
|
||||
.attr('transform', `translate(0, ${this.height})`)
|
||||
.call(axisBottom(this.x).tickSize(-this.height).ticks(timeSecond, 5).tickFormat(timeFormat('%H:%M:%S')));
|
||||
|
||||
this.yAxis = this.svg.append('g')
|
||||
.attr('class', 'y axis')
|
||||
.call(axisLeft(this.y).tickSize(-this.width));
|
||||
|
||||
this.path = this.svg.append('g')
|
||||
.attr('clip-path', 'url(#clip)')
|
||||
.append('path')
|
||||
.data([this.data])
|
||||
.attr('class', 'line');
|
||||
}
|
||||
|
||||
ngOnChanges(changes: SimpleChanges) {
|
||||
if (!this.value || !this.svg) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.updateData(this.value.count);
|
||||
}
|
||||
|
||||
updateData = (value: number) => {
|
||||
this.data.push(value * 1000000);
|
||||
this.now = new Date();
|
||||
|
||||
this.x.domain([<any>this.now - (this.limit - 2) * this.duration, <any>this.now - this.duration]);
|
||||
const minv = min(this.data, (d: any) => d) > 0 ? min(this.data, (d: any) => d) - 4 : 0;
|
||||
const maxv = max(this.data, (d: any) => d) + 4;
|
||||
this.y.domain([minv, maxv]);
|
||||
|
||||
this.xAxis
|
||||
.transition()
|
||||
.duration(this.duration)
|
||||
.ease(easeLinear)
|
||||
.call(axisBottom(this.x).tickSize(-this.height).ticks(timeSecond, 5).tickFormat(timeFormat('%H:%M:%S')))
|
||||
.selectAll('text')
|
||||
.style('text-anchor', 'end')
|
||||
.attr('dx', '-.8em')
|
||||
.attr('dy', '.15em')
|
||||
.attr('transform', 'rotate(-65)');
|
||||
|
||||
this.yAxis
|
||||
.transition()
|
||||
.duration(500)
|
||||
.ease(easeLinear)
|
||||
.call(axisLeft(this.y).tickSize(-this.width));
|
||||
|
||||
this.path
|
||||
.transition()
|
||||
.duration(0)
|
||||
.attr('d', this.line(this.data))
|
||||
.attr('transform', null)
|
||||
.transition()
|
||||
.duration(this.duration)
|
||||
.ease(easeLinear)
|
||||
.attr('transform', `translate(${this.x(<any>this.now - (this.limit - 1) * this.duration)})`);
|
||||
|
||||
this.data.shift();
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue