externo
+1
-1
@@ -7,7 +7,7 @@ module.exports = function(defaults) {
|
|||||||
vendorNpmFiles: [
|
vendorNpmFiles: [
|
||||||
'socket.io-client/socket.io.js',
|
'socket.io-client/socket.io.js',
|
||||||
'smoothie/smoothie.js',
|
'smoothie/smoothie.js',
|
||||||
'chart.js/Chart.js',
|
'chart.js/dist/Chart.bundle.js',
|
||||||
'ng2-charts/bundles/ng2-charts.js',
|
'ng2-charts/bundles/ng2-charts.js',
|
||||||
'chroma-js/chroma.js',
|
'chroma-js/chroma.js',
|
||||||
'plotly.js/dist/plotly.js',
|
'plotly.js/dist/plotly.js',
|
||||||
|
|||||||
+2
-2
@@ -41,14 +41,14 @@
|
|||||||
"@angular/platform-browser-dynamic": "2.0.0-rc.1",
|
"@angular/platform-browser-dynamic": "2.0.0-rc.1",
|
||||||
"@angular/router": "2.0.0-rc.1",
|
"@angular/router": "2.0.0-rc.1",
|
||||||
"brainbrowser": "^2.3.0",
|
"brainbrowser": "^2.3.0",
|
||||||
"chart.js": "^1.0.2",
|
"chart.js": "^2.1.4",
|
||||||
"chroma-js": "^1.1.1",
|
"chroma-js": "^1.1.1",
|
||||||
"dsp.js": "neurojs/dsp.js",
|
"dsp.js": "neurojs/dsp.js",
|
||||||
"es6-shim": "^0.35.0",
|
"es6-shim": "^0.35.0",
|
||||||
"express": "^4.13.4",
|
"express": "^4.13.4",
|
||||||
"fili": "^1.2.1",
|
"fili": "^1.2.1",
|
||||||
"jstat": "^1.5.2",
|
"jstat": "^1.5.2",
|
||||||
"ng2-charts": "^1.0.3",
|
"ng2-charts": "^1.1.0",
|
||||||
"nodemon": "^1.9.1",
|
"nodemon": "^1.9.1",
|
||||||
"openbci-sdk": "^0.3.4",
|
"openbci-sdk": "^0.3.4",
|
||||||
"plotly.js": "^1.10.2",
|
"plotly.js": "^1.10.2",
|
||||||
|
|||||||
@@ -4,8 +4,8 @@
|
|||||||
<h1>{{ title }}</h1>
|
<h1>{{ title }}</h1>
|
||||||
<nav>
|
<nav>
|
||||||
<a [routerLink]="['/time-series']">Time Series</a>
|
<a [routerLink]="['/time-series']">Time Series</a>
|
||||||
<a [routerLink]="['/frequency/line', { type: 'Line' }]">Frequency Line</a>
|
<a [routerLink]="['/frequency/line', { type: 'line' }]">Frequency Line</a>
|
||||||
<a [routerLink]="['/frequency/radar', { type: 'Radar' }]">Frequency Radar</a>
|
<a [routerLink]="['/frequency/radar', { type: 'radar' }]">Frequency Radar</a>
|
||||||
<a [routerLink]="['/frequency/bands']">Frequency Bands</a>
|
<a [routerLink]="['/frequency/bands']">Frequency Bands</a>
|
||||||
<a [routerLink]="['/motion']">Motion</a>
|
<a [routerLink]="['/motion']">Motion</a>
|
||||||
<a [routerLink]="['/topo']">Topo</a>
|
<a [routerLink]="['/topo']">Topo</a>
|
||||||
|
|||||||
@@ -1,4 +1,10 @@
|
|||||||
|
|
||||||
|
.chart {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
:host {
|
:host {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
margin: 0 0 20px 20px;
|
margin: 0 0 20px 20px;
|
||||||
@@ -22,4 +28,9 @@ h2 {
|
|||||||
|
|
||||||
.capitalize {
|
.capitalize {
|
||||||
text-transform: capitalize;
|
text-transform: capitalize;
|
||||||
|
}
|
||||||
|
|
||||||
|
.frequency-band {
|
||||||
|
height: 100%;
|
||||||
|
padding-top: 40px;
|
||||||
}
|
}
|
||||||
@@ -1,10 +1,11 @@
|
|||||||
<section class="frequency-band" [ngClass]="{ 'loading': !data }">
|
<section class="frequency-band" [ngClass]="{ 'loading': !data }">
|
||||||
<h2 class="capitalize">{{ band }} {{ type }}</h2>
|
<h2 class="capitalize">{{ band }} {{ type }}</h2>
|
||||||
<base-chart class="chart"
|
<base-chart class="chart"
|
||||||
[data]="data"
|
[datasets]="data"
|
||||||
[labels]="channels"
|
[labels]="channels"
|
||||||
[options]="options"
|
[options]="options"
|
||||||
[colours]="colors"
|
[colors]="colors"
|
||||||
|
[legend]="false"
|
||||||
[series]="channels"
|
[series]="channels"
|
||||||
[chartType]="type">
|
[chartType]="type">
|
||||||
</base-chart>
|
</base-chart>
|
||||||
|
|||||||
@@ -24,17 +24,20 @@ export class FrequencyBandComponent implements OnInit {
|
|||||||
@Input() public band:string;
|
@Input() public band:string;
|
||||||
@Input() public color:number;
|
@Input() public color:number;
|
||||||
|
|
||||||
private data:Array<any> = [[]];
|
private data:Array<any> = [{ data: [], label: [] }];
|
||||||
private colors:Array<any>;
|
private colors:Array<any>;
|
||||||
private channels:Array<string> = this.chartService.getChannels();
|
private channels:Array<string> = this.chartService.getChannels();
|
||||||
private options:any = this.chartService.getChartJSDefaults({
|
private options:any = this.chartService.getChartJSBarDefaults();
|
||||||
responsive: false
|
|
||||||
});
|
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.colors = this.chartService.getColorByIndex(this.color);
|
this.colors = this.chartService.getColorByIndex(this.color);
|
||||||
this.socket.on(this.constants.socket.events.fft, (data) => {
|
this.socket.on(this.constants.socket.events.fft, (data) => {
|
||||||
this.data = data[this.band || 'data'];
|
this.data = [];
|
||||||
|
data[this.band || 'data'].forEach((dataset, index) => {
|
||||||
|
this.data.push({
|
||||||
|
data: dataset
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
<section>
|
<section>
|
||||||
<bci-frequency-band [type]="'Bar'" [band]="'delta'" [color]="1"></bci-frequency-band>
|
<bci-frequency-band type="bar" band="delta" [color]="1"></bci-frequency-band>
|
||||||
<bci-frequency-band [type]="'Bar'" [band]="'theta'" [color]="2"></bci-frequency-band>
|
<bci-frequency-band type="bar" band="theta" [color]="2"></bci-frequency-band>
|
||||||
</section>
|
</section>
|
||||||
<section>
|
<section>
|
||||||
<bci-frequency-band [type]="'Bar'" [band]="'alpha'" [color]="3"></bci-frequency-band>
|
<bci-frequency-band type="bar" band="alpha" [color]="3"></bci-frequency-band>
|
||||||
<bci-frequency-band [type]="'Bar'" [band]="'beta'" [color]="4"></bci-frequency-band>
|
<bci-frequency-band type="bar" band="beta" [color]="4"></bci-frequency-band>
|
||||||
<bci-frequency-band [type]="'Bar'" [band]="'gamma'" [color]="5"></bci-frequency-band>
|
<bci-frequency-band type="bar" band="gamma" [color]="5"></bci-frequency-band>
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
|
|
||||||
.chart {
|
.chart {
|
||||||
display: block;
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
:host {
|
:host {
|
||||||
@@ -10,7 +12,7 @@
|
|||||||
box-shadow: 0 0 5px rgba(0,0,0,0.3);
|
box-shadow: 0 0 5px rgba(0,0,0,0.3);
|
||||||
background-color: #333333;
|
background-color: #333333;
|
||||||
position: relative;
|
position: relative;
|
||||||
height: 100%;
|
height: 600px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -20,4 +22,9 @@ h2 {
|
|||||||
top: 10px;
|
top: 10px;
|
||||||
right: 20px;
|
right: 20px;
|
||||||
font-weight: 300;
|
font-weight: 300;
|
||||||
|
}
|
||||||
|
|
||||||
|
.frequency {
|
||||||
|
height: 100%;
|
||||||
|
padding-top: 40px;
|
||||||
}
|
}
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
<section class="frequency" [ngClass]="{ 'loading': !data }">
|
<section class="frequency" [ngClass]="{ 'loading': !data }">
|
||||||
<h2>Frequency {{ type }}</h2>
|
<h2>Frequency {{ type }}</h2>
|
||||||
<base-chart class="chart"
|
<base-chart class="chart"
|
||||||
[data]="data"
|
[datasets]="data"
|
||||||
[labels]="labels"
|
[labels]="labels"
|
||||||
[options]="options"
|
[options]="options"
|
||||||
[colours]="colors"
|
[colors]="colors"
|
||||||
[series]="channels"
|
[series]="channels"
|
||||||
[chartType]="type">
|
[chartType]="type">
|
||||||
</base-chart>
|
</base-chart>
|
||||||
|
|||||||
@@ -21,20 +21,40 @@ export class FrequencyComponent implements OnInit {
|
|||||||
private segment: RouteSegment,
|
private segment: RouteSegment,
|
||||||
private constants: Constants) {
|
private constants: Constants) {
|
||||||
this.socket = io(constants.socket.url);
|
this.socket = io(constants.socket.url);
|
||||||
this.type = segment.getParam('type') || 'Line';
|
this.type = segment.getParam('type') || 'line';
|
||||||
|
|
||||||
|
this.setOptions(this.type);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Input() type:string;
|
@Input() type:string;
|
||||||
|
|
||||||
private data:Array<any> = [[]];
|
private data:Array<any> = [{ data: [], label: [] }];
|
||||||
private labels:Array<any> = [];
|
private labels:Array<any> = [];
|
||||||
private colors:Array<any> = this.chartService.getColors();
|
private colors:Array<any> = this.chartService.getColors();
|
||||||
private channels:Array<string> = this.chartService.getChannels();
|
private channels:Array<string> = this.chartService.getChannels();
|
||||||
private options:any = this.chartService.getChartJSDefaults();
|
private options:any;
|
||||||
|
|
||||||
|
setOptions (type) {
|
||||||
|
if (type === 'line') {
|
||||||
|
this.options = this.chartService.getChartJSLineDefaults();
|
||||||
|
}
|
||||||
|
if (type === 'radar') {
|
||||||
|
this.options = this.chartService.getChartJSRadarDefaults();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.socket.on(this.constants.socket.events.fft, (data) => {
|
this.socket.on(this.constants.socket.events.fft, (data) => {
|
||||||
this.data = data.data;
|
this.data = [];
|
||||||
|
data.data.forEach((dataset, index) => {
|
||||||
|
this.data.push({
|
||||||
|
data: dataset,
|
||||||
|
label: this.channels[index],
|
||||||
|
borderWidth: 1,
|
||||||
|
pointRadius: 0,
|
||||||
|
fill: false
|
||||||
|
});
|
||||||
|
});
|
||||||
this.labels = data.labels;
|
this.labels = data.labels;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,26 +44,92 @@ export class ChartService {
|
|||||||
}, overrides);
|
}, overrides);
|
||||||
}
|
}
|
||||||
|
|
||||||
getChartJSDefaults (overrides: any = {}): any {
|
getChartJSGlobalDefaults (overrides: any = {}): any {
|
||||||
return Object.assign({
|
return Object.assign({
|
||||||
responsive: true,
|
responsive: true,
|
||||||
animation: false,
|
animation: false,
|
||||||
animationSteps: 15,
|
legend: {
|
||||||
datasetStrokeWidth: 1,
|
display: true,
|
||||||
pointDot: false,
|
position: 'bottom'
|
||||||
pointDotRadius: 1,
|
},
|
||||||
pointDotStrokeWidth: 0,
|
|
||||||
datasetFill: false,
|
|
||||||
scaleOverride: true,
|
|
||||||
scaleStartValue: -2,
|
|
||||||
scaleStepWidth: 1,
|
|
||||||
scaleSteps: 6,
|
|
||||||
barShowStroke: false,
|
|
||||||
barValueSpacing: 1,
|
|
||||||
barStrokeWidth: 1
|
|
||||||
}, overrides);
|
}, overrides);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getChartJSLineDefaults (overrides: any = {}): any {
|
||||||
|
return Object.assign({
|
||||||
|
scales: {
|
||||||
|
xAxes: [{
|
||||||
|
gridLines: {
|
||||||
|
display: true
|
||||||
|
},
|
||||||
|
ticks: {
|
||||||
|
max: 3,
|
||||||
|
min: -2,
|
||||||
|
stepSize: 0.5
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
yAxes: [{
|
||||||
|
gridLines: {
|
||||||
|
display: true
|
||||||
|
},
|
||||||
|
ticks: {
|
||||||
|
max: 3,
|
||||||
|
min: -2,
|
||||||
|
stepSize: 0.5
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
}, this.getChartJSGlobalDefaults());
|
||||||
|
}
|
||||||
|
|
||||||
|
getChartJSBarDefaults (overrides: any = {}): any {
|
||||||
|
return Object.assign({
|
||||||
|
scales: {
|
||||||
|
xAxes: [{
|
||||||
|
gridLines: {
|
||||||
|
display: false
|
||||||
|
},
|
||||||
|
ticks: {
|
||||||
|
max: 2,
|
||||||
|
min: 0,
|
||||||
|
stepSize: 0.5
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
yAxes: [{
|
||||||
|
gridLines: {
|
||||||
|
display: false
|
||||||
|
},
|
||||||
|
ticks: {
|
||||||
|
max: 2,
|
||||||
|
min: 0,
|
||||||
|
stepSize: 0.5
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
}, this.getChartJSGlobalDefaults({
|
||||||
|
legend: {
|
||||||
|
display: false
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
getChartJSRadarDefaults (overrides: any = {}): any {
|
||||||
|
return Object.assign({
|
||||||
|
scale: {
|
||||||
|
lineArc: false,
|
||||||
|
angleLines: {
|
||||||
|
display: true
|
||||||
|
},
|
||||||
|
ticks: {
|
||||||
|
max: 2,
|
||||||
|
min: -2,
|
||||||
|
stepSize: 0.5,
|
||||||
|
showLabelBackdrop: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, this.getChartJSGlobalDefaults());
|
||||||
|
}
|
||||||
|
|
||||||
getChartSmoothieDefaults (overrides: any = {}): any {
|
getChartSmoothieDefaults (overrides: any = {}): any {
|
||||||
return Object.assign({
|
return Object.assign({
|
||||||
millisPerLine: 3000,
|
millisPerLine: 3000,
|
||||||
@@ -88,14 +154,14 @@ export class ChartService {
|
|||||||
|
|
||||||
getColors (): Array<any> {
|
getColors (): Array<any> {
|
||||||
return [
|
return [
|
||||||
{ strokeColor: 'rgba(112,185,252,1)', fillColor: 'rgba(112,185,252,1)' },
|
{ borderColor: 'rgba(112,185,252,1)', backgroundColor: 'rgba(112,185,252,1)' },
|
||||||
{ strokeColor: 'rgba(116,150,161,1)', fillColor: 'rgba(116,150,161,1)' },
|
{ borderColor: 'rgba(116,150,161,1)', backgroundColor: 'rgba(116,150,161,1)' },
|
||||||
{ strokeColor: 'rgba(162,86,178,1)', fillColor: 'rgba(162,86,178,1)' },
|
{ borderColor: 'rgba(162,86,178,1)', backgroundColor: 'rgba(162,86,178,1)' },
|
||||||
{ strokeColor: 'rgba(144,132,246,1)', fillColor: 'rgba(144,132,246,1)' },
|
{ borderColor: 'rgba(144,132,246,1)', backgroundColor: 'rgba(144,132,246,1)' },
|
||||||
{ strokeColor: 'rgba(138,219,229,1)', fillColor: 'rgba(138,219,229,1)' },
|
{ borderColor: 'rgba(138,219,229,1)', backgroundColor: 'rgba(138,219,229,1)' },
|
||||||
{ strokeColor: 'rgba(232,223,133,1)', fillColor: 'rgba(232,223,133,1)' },
|
{ borderColor: 'rgba(232,223,133,1)', backgroundColor: 'rgba(232,223,133,1)' },
|
||||||
{ strokeColor: 'rgba(148,159,177,1)', fillColor: 'rgba(148,159,177,1)' },
|
{ borderColor: 'rgba(148,159,177,1)', backgroundColor: 'rgba(148,159,177,1)' },
|
||||||
{ strokeColor: 'rgba(77,83,96,1)', fillColor: 'rgba(77,83,96,1)' }
|
{ borderColor: 'rgba(77,83,96,1)', backgroundColor: 'rgba(77,83,96,1)' }
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+227
-204
@@ -1,119 +1,51 @@
|
|||||||
import {
|
import {
|
||||||
Component, OnDestroy, OnInit, OnChanges,
|
Component, OnDestroy, OnInit, OnChanges, EventEmitter, ElementRef, Input,
|
||||||
EventEmitter, ElementRef, Input
|
Output
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
import {CORE_DIRECTIVES, FORM_DIRECTIVES, NgClass} from '@angular/common';
|
import {CORE_DIRECTIVES, FORM_DIRECTIVES, NgClass} from '@angular/common';
|
||||||
|
|
||||||
declare var Chart:any;
|
declare var Chart:any;
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'chart',
|
|
||||||
template: `<canvas></canvas>`,
|
|
||||||
directives: [CORE_DIRECTIVES, NgClass]
|
|
||||||
})
|
|
||||||
export class ChartsComponent {}
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'base-chart',
|
selector: 'base-chart',
|
||||||
properties: [
|
template: `<canvas style="width: 100%; height: 100%;"></canvas>`,
|
||||||
'data',
|
|
||||||
'labels',
|
|
||||||
'series',
|
|
||||||
'colours',
|
|
||||||
'chartType',
|
|
||||||
'legend',
|
|
||||||
'options'
|
|
||||||
],
|
|
||||||
events: ['chartClick', 'chartHover'],
|
|
||||||
template: `
|
|
||||||
<canvas style="width: 100%; height: 100%;" (click)="click($event)" (mousemove)="hover($event)"></canvas>
|
|
||||||
`,
|
|
||||||
directives: [CORE_DIRECTIVES, FORM_DIRECTIVES, NgClass]
|
directives: [CORE_DIRECTIVES, FORM_DIRECTIVES, NgClass]
|
||||||
})
|
})
|
||||||
export class BaseChartComponent implements OnInit, OnDestroy, OnChanges {
|
export class BaseChartComponent implements OnDestroy, OnChanges, OnInit {
|
||||||
@Input() public data:Array<any> = [];
|
public static defaultColors:Array<number[]> = [
|
||||||
|
[255, 99, 132],
|
||||||
|
[54, 162, 235],
|
||||||
|
[255, 206, 86],
|
||||||
|
[231, 233, 237],
|
||||||
|
[75, 192, 192],
|
||||||
|
[151, 187, 205],
|
||||||
|
[220, 220, 220],
|
||||||
|
[247, 70, 74],
|
||||||
|
[70, 191, 189],
|
||||||
|
[253, 180, 92],
|
||||||
|
[148, 159, 177],
|
||||||
|
[77, 83, 96]
|
||||||
|
];
|
||||||
|
|
||||||
|
@Input() public data:number[] | Array<number[]>;
|
||||||
|
@Input() public datasets:any[];
|
||||||
@Input() public labels:Array<any> = [];
|
@Input() public labels:Array<any> = [];
|
||||||
@Input() public options:any = {responsive: true};
|
@Input() public options:any = {responsive: true};
|
||||||
@Input() public chartType:string;
|
@Input() public chartType:string;
|
||||||
@Input() public series:Array<any> = [];
|
@Input() public colors:Array<any>;
|
||||||
@Input() public colours:Array<any> = [];
|
|
||||||
@Input() public legend:boolean;
|
@Input() public legend:boolean;
|
||||||
|
|
||||||
|
@Output() public chartClick:EventEmitter<any> = new EventEmitter();
|
||||||
|
@Output() public chartHover:EventEmitter<any> = new EventEmitter();
|
||||||
|
|
||||||
private ctx:any;
|
private ctx:any;
|
||||||
private cvs:any;
|
private cvs:any;
|
||||||
private parent:any;
|
private parent:any;
|
||||||
private chart:any;
|
private chart:any;
|
||||||
private legendTemplate:any;
|
|
||||||
private initFlag:boolean = false;
|
private initFlag:boolean = false;
|
||||||
private chartClick:EventEmitter<any> = new EventEmitter();
|
|
||||||
private chartHover:EventEmitter<any> = new EventEmitter();
|
|
||||||
private defaultsColours:Array<any> = [
|
|
||||||
{
|
|
||||||
fillColor: 'rgba(151,187,205,0.2)',
|
|
||||||
strokeColor: 'rgba(151,187,205,1)',
|
|
||||||
pointColor: 'rgba(151,187,205,1)',
|
|
||||||
pointStrokeColor: '#fff',
|
|
||||||
pointHighlightFill: '#fff',
|
|
||||||
pointHighlightStroke: 'rgba(151,187,205,0.8)',
|
|
||||||
color: 'rgba(151,187,205,1)',
|
|
||||||
highlight: 'rgba(151,187,205,0.8)'
|
|
||||||
}, {
|
|
||||||
fillColor: 'rgba(220,220,220,0.2)',
|
|
||||||
strokeColor: 'rgba(220,220,220,1)',
|
|
||||||
pointColor: 'rgba(220,220,220,1)',
|
|
||||||
pointStrokeColor: '#fff',
|
|
||||||
pointHighlightFill: '#fff',
|
|
||||||
pointHighlightStroke: 'rgba(220,220,220,0.8)',
|
|
||||||
color: 'rgba(220,220,220,1)',
|
|
||||||
highlight: 'rgba(220,220,220,0.8)'
|
|
||||||
}, {
|
|
||||||
fillColor: 'rgba(247,70,74,0.2)',
|
|
||||||
strokeColor: 'rgba(247,70,74,1)',
|
|
||||||
pointColor: 'rgba(247,70,74,1)',
|
|
||||||
pointStrokeColor: '#fff',
|
|
||||||
pointHighlightFill: '#fff',
|
|
||||||
pointHighlightStroke: 'rgba(247,70,74,0.8)',
|
|
||||||
color: 'rgba(247,70,74,1)',
|
|
||||||
highlight: 'rgba(247,70,74,0.8)'
|
|
||||||
}, {
|
|
||||||
fillColor: 'rgba(70,191,189,0.2)',
|
|
||||||
strokeColor: 'rgba(70,191,189,1)',
|
|
||||||
pointColor: 'rgba(70,191,189,1)',
|
|
||||||
pointStrokeColor: '#fff',
|
|
||||||
pointHighlightFill: '#fff',
|
|
||||||
pointHighlightStroke: 'rgba(70,191,189,0.8)',
|
|
||||||
color: 'rgba(70,191,189,1)',
|
|
||||||
highlight: 'rgba(70,191,189,0.8)'
|
|
||||||
}, {
|
|
||||||
fillColor: 'rgba(253,180,92,0.2)',
|
|
||||||
strokeColor: 'rgba(253,180,92,1)',
|
|
||||||
pointColor: 'rgba(253,180,92,1)',
|
|
||||||
pointStrokeColor: '#fff',
|
|
||||||
pointHighlightFill: '#fff',
|
|
||||||
pointHighlightStroke: 'rgba(253,180,92,0.8)',
|
|
||||||
color: 'rgba(253,180,92,1)',
|
|
||||||
highlight: 'rgba(253,180,92,0.8)'
|
|
||||||
}, {
|
|
||||||
fillColor: 'rgba(148,159,177,0.2)',
|
|
||||||
strokeColor: 'rgba(148,159,177,1)',
|
|
||||||
pointColor: 'rgba(148,159,177,1)',
|
|
||||||
pointStrokeColor: '#fff',
|
|
||||||
pointHighlightFill: '#fff',
|
|
||||||
pointHighlightStroke: 'rgba(148,159,177,0.8)',
|
|
||||||
color: 'rgba(148,159,177,1)',
|
|
||||||
highlight: 'rgba(148,159,177,0.8)'
|
|
||||||
}, {
|
|
||||||
fillColor: 'rgba(77,83,96,0.2)',
|
|
||||||
strokeColor: 'rgba(77,83,96,1)',
|
|
||||||
pointColor: 'rgba(77,83,96,1)',
|
|
||||||
pointStrokeColor: '#fff',
|
|
||||||
pointHighlightFill: '#fff',
|
|
||||||
pointHighlightStroke: 'rgba(77,83,96,0.8)',
|
|
||||||
color: 'rgba(77,83,96,1)',
|
|
||||||
highlight: 'rgba(77,83,96,0.8)'
|
|
||||||
}];
|
|
||||||
|
|
||||||
private element:ElementRef;
|
private element:ElementRef;
|
||||||
|
|
||||||
public constructor(element:ElementRef) {
|
public constructor(element:ElementRef) {
|
||||||
this.element = element;
|
this.element = element;
|
||||||
}
|
}
|
||||||
@@ -122,8 +54,10 @@ export class BaseChartComponent implements OnInit, OnDestroy, OnChanges {
|
|||||||
this.ctx = this.element.nativeElement.children[0].getContext('2d');
|
this.ctx = this.element.nativeElement.children[0].getContext('2d');
|
||||||
this.cvs = this.element.nativeElement.children[0];
|
this.cvs = this.element.nativeElement.children[0];
|
||||||
this.parent = this.element.nativeElement;
|
this.parent = this.element.nativeElement;
|
||||||
this.refresh();
|
|
||||||
this.initFlag = true;
|
this.initFlag = true;
|
||||||
|
if (this.data || this.datasets) {
|
||||||
|
this.refresh();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ngOnChanges():any {
|
public ngOnChanges():any {
|
||||||
@@ -137,129 +71,218 @@ export class BaseChartComponent implements OnInit, OnDestroy, OnChanges {
|
|||||||
this.chart.destroy();
|
this.chart.destroy();
|
||||||
this.chart = void 0;
|
this.chart = void 0;
|
||||||
}
|
}
|
||||||
if (this.legendTemplate) {
|
|
||||||
this.legendTemplate.destroy();
|
|
||||||
this.legendTemplate = void 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public setLegend():void {
|
public getChartBuilder(ctx:any/*, data:Array<any>, options:any*/):any {
|
||||||
let list = this.parent.getElementsByTagName('ul');
|
let datasets:any = void 0;
|
||||||
if (list.length) {
|
|
||||||
list[0].remove();
|
|
||||||
this.parent.insertAdjacentHTML('beforeend', this.chart.generateLegend());
|
|
||||||
} else {
|
|
||||||
this.parent.insertAdjacentHTML('beforeend', this.chart.generateLegend());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public getColour(colour:Array<number>):any {
|
// in case if datasets is not provided, but data is present
|
||||||
return {
|
if (!this.datasets || !this.datasets.length && (this.data && this.data.length)) {
|
||||||
fillColor: this.rgba(colour, 0.2),
|
if (Array.isArray(this.data[0])) {
|
||||||
strokeColor: this.rgba(colour, 1),
|
datasets = (this.data as Array<number[]>).map((data:number[], index:number) => {
|
||||||
pointColor: this.rgba(colour, 1),
|
return {data, label: this.labels[index] || `Label ${index}`};
|
||||||
pointStrokeColor: '#fff',
|
});
|
||||||
pointHighlightFill: '#fff',
|
} else {
|
||||||
pointHighlightStroke: this.rgba(colour, 0.8),
|
datasets = [{data: this.data, label: `Label 0`}];
|
||||||
color: this.rgba(colour, 1),
|
}
|
||||||
highlight: this.rgba(colour, 0.8)
|
}
|
||||||
|
|
||||||
|
if (this.datasets && this.datasets.length ||
|
||||||
|
(datasets && datasets.length)) {
|
||||||
|
datasets = (this.datasets || datasets)
|
||||||
|
.map((elm:number, index:number) => {
|
||||||
|
let newElm:any = Object.assign({}, elm);
|
||||||
|
if (this.colors && this.colors.length) {
|
||||||
|
Object.assign(newElm, this.colors[index]);
|
||||||
|
} else {
|
||||||
|
Object.assign(newElm, getColors(this.chartType, index, newElm.data.length));
|
||||||
|
}
|
||||||
|
return newElm;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!datasets) {
|
||||||
|
throw new Error(`ng-charts configuration error,
|
||||||
|
data or datasets field are required to render char ${this.chartType}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
let options:any = Object.assign({}, this.options);
|
||||||
|
// hock for onHover and onClick events
|
||||||
|
options.hover = options.hover || {};
|
||||||
|
if (!options.hover.onHover) {
|
||||||
|
options.hover.onHover = (active:Array<any>) => {
|
||||||
|
if (active && !active.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.chartHover.emit({active});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!options.onClick) {
|
||||||
|
options.onClick = (event:any, active:Array<any>) => {
|
||||||
|
this.chartClick.emit({event, active});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
let opts = {
|
||||||
|
type: this.chartType,
|
||||||
|
data: {
|
||||||
|
labels: this.labels,
|
||||||
|
datasets: datasets
|
||||||
|
},
|
||||||
|
options: options
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
public getRandomInt(min:number, max:number):number {
|
if (typeof Chart === 'undefined') {
|
||||||
return Math.floor(Math.random() * (max - min + 1)) + min;
|
throw new Error('ng2-charts configuration issue: Embedding Chart.js lib is mandatory');
|
||||||
}
|
|
||||||
|
|
||||||
public rgba(colour:Array<number>, alpha:number):string {
|
|
||||||
return 'rgba(' + colour.concat(alpha).join(',') + ')';
|
|
||||||
}
|
|
||||||
|
|
||||||
public click(evt:any):void {
|
|
||||||
let atEvent = this.chart.getPointsAtEvent || this.chart.getBarsAtEvent || this.chart.getSegmentsAtEvent;
|
|
||||||
let activePoints = atEvent.call(this.chart, evt);
|
|
||||||
if (activePoints.length > 0) {
|
|
||||||
let activeLabel = activePoints[0].label;
|
|
||||||
this.chartClick.emit({activePoints: activePoints, activeLabel: activeLabel});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public hover(evt:any):void {
|
|
||||||
let atEvent = this.chart.getPointsAtEvent || this.chart.getBarsAtEvent || this.chart.getSegmentsAtEvent;
|
|
||||||
let activePoints = atEvent.call(this.chart, evt);
|
|
||||||
if (activePoints.length > 0) {
|
|
||||||
let activeLabel = activePoints[0].label;
|
|
||||||
let activePoint = activePoints[0].value;
|
|
||||||
this.chartHover.emit({activePoints: activePoints, activePoint: activePoint, activeLabel: activeLabel});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public getChartBuilder(ctx:any, data:Array<any>, options:any):any {
|
|
||||||
return new Chart(ctx)[this.chartType](data, options);
|
|
||||||
}
|
|
||||||
|
|
||||||
public getDataObject(label:string, value:any):any {
|
|
||||||
if (this.chartType === 'Line'
|
|
||||||
|| this.chartType === 'Bar'
|
|
||||||
|| this.chartType === 'Radar') {
|
|
||||||
return {
|
|
||||||
label: label,
|
|
||||||
data: value
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.chartType === 'Pie'
|
return new Chart(ctx, opts);
|
||||||
|| this.chartType === 'Doughnut'
|
|
||||||
|| this.chartType === 'PolarArea') {
|
|
||||||
return {
|
|
||||||
label: label,
|
|
||||||
value: value
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return void 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public getChartData(labels:any, dataObject:any):any {
|
|
||||||
if (this.chartType === 'Line'
|
|
||||||
|| this.chartType === 'Bar'
|
|
||||||
|| this.chartType === 'Radar') {
|
|
||||||
return {
|
|
||||||
labels: labels,
|
|
||||||
datasets: dataObject
|
|
||||||
};
|
|
||||||
}
|
|
||||||
if (this.chartType === 'Pie'
|
|
||||||
|| this.chartType === 'Doughnut'
|
|
||||||
|| this.chartType === 'PolarArea') {
|
|
||||||
return dataObject;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private refresh():any {
|
private refresh():any {
|
||||||
if (this.options.responsive && this.parent.clientHeight === 0) {
|
if (this.options && this.options.responsive && this.parent.clientHeight === 0) {
|
||||||
return setTimeout(() => this.refresh(), 50);
|
return setTimeout(() => this.refresh(), 50);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// todo: remove this line, it is producing flickering
|
||||||
this.ngOnDestroy();
|
this.ngOnDestroy();
|
||||||
let dataset:Array<any> = [];
|
this.chart = this.getChartBuilder(this.ctx/*, data, this.options*/);
|
||||||
|
|
||||||
for (let i = 0; i < this.data.length; i++) {
|
|
||||||
let colourDesc:Array<number> = [this.getRandomInt(0, 255), this.getRandomInt(0, 255), this.getRandomInt(0, 255)];
|
|
||||||
let colour = i < this.colours.length ? this.colours[i] : this.defaultsColours[i] || this.getColour(colourDesc);
|
|
||||||
|
|
||||||
let data:any = Object.assign(colour,
|
|
||||||
this.getDataObject(this.series[i] || this.labels[i], this.data[i]));
|
|
||||||
|
|
||||||
dataset.push(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
let data:any = this.getChartData(this.labels, dataset);
|
|
||||||
this.chart = this.getChartBuilder(this.ctx, data, this.options);
|
|
||||||
|
|
||||||
if (this.legend) {
|
|
||||||
this.setLegend();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const CHART_DIRECTIVES:Array<any> = [ChartsComponent, BaseChartComponent];
|
// private helper functions
|
||||||
|
export interface Color {
|
||||||
|
backgroundColor?:string | string[];
|
||||||
|
borderWidth?:number | number[];
|
||||||
|
borderColor?:string | string[];
|
||||||
|
borderCapStyle?:string;
|
||||||
|
borderDash?:number[];
|
||||||
|
borderDashOffset?:number;
|
||||||
|
borderJoinStyle?:string;
|
||||||
|
|
||||||
|
pointBorderColor?:string | string[];
|
||||||
|
pointBackgroundColor?:string | string[];
|
||||||
|
pointBorderWidth?:number | number[];
|
||||||
|
|
||||||
|
pointRadius?:number | number[];
|
||||||
|
pointHoverRadius?:number | number[];
|
||||||
|
pointHitRadius?:number | number[];
|
||||||
|
|
||||||
|
pointHoverBackgroundColor?:string | string[];
|
||||||
|
pointHoverBorderColor?:string | string[];
|
||||||
|
pointHoverBorderWidth?:number | number[];
|
||||||
|
pointStyle?:string | string[];
|
||||||
|
|
||||||
|
hoverBackgroundColor?:string | string[];
|
||||||
|
hoverBorderColor?:string | string[];
|
||||||
|
hoverBorderWidth?:number;
|
||||||
|
}
|
||||||
|
|
||||||
|
// pie | doughnut
|
||||||
|
export interface Colors extends Color {
|
||||||
|
data?:number[];
|
||||||
|
label?:string;
|
||||||
|
}
|
||||||
|
|
||||||
|
function rgba(colour:Array<number>, alpha:number):string {
|
||||||
|
return 'rgba(' + colour.concat(alpha).join(',') + ')';
|
||||||
|
}
|
||||||
|
|
||||||
|
function getRandomInt(min:number, max:number):number {
|
||||||
|
return Math.floor(Math.random() * (max - min + 1)) + min;
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatLineColor(colors:Array<number>):Color {
|
||||||
|
return {
|
||||||
|
backgroundColor: rgba(colors, 0.4),
|
||||||
|
borderColor: rgba(colors, 1),
|
||||||
|
pointBackgroundColor: rgba(colors, 1),
|
||||||
|
pointBorderColor: '#fff',
|
||||||
|
pointHoverBackgroundColor: '#fff',
|
||||||
|
pointHoverBorderColor: rgba(colors, 0.8)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatBarColor(colors:Array<number>):Color {
|
||||||
|
return {
|
||||||
|
backgroundColor: rgba(colors, 0.6),
|
||||||
|
borderColor: rgba(colors, 1),
|
||||||
|
hoverBackgroundColor: rgba(colors, 0.8),
|
||||||
|
hoverBorderColor: rgba(colors, 1)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatPieColors(colors:Array<number[]>):Colors {
|
||||||
|
return {
|
||||||
|
backgroundColor: colors.map((color:number[]) => rgba(color, 0.6)),
|
||||||
|
borderColor: colors.map(() => '#fff'),
|
||||||
|
pointBackgroundColor: colors.map((color:number[]) => rgba(color, 1)),
|
||||||
|
pointBorderColor: colors.map(() => '#fff'),
|
||||||
|
pointHoverBackgroundColor: colors.map((color:number[]) => rgba(color, 1)),
|
||||||
|
pointHoverBorderColor: colors.map((color:number[]) => rgba(color, 1))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatPolarAreaColors(colors:Array<number[]>):Color {
|
||||||
|
return {
|
||||||
|
backgroundColor: colors.map((color:number[]) => rgba(color, 0.6)),
|
||||||
|
borderColor: colors.map((color:number[]) => rgba(color, 1)),
|
||||||
|
hoverBackgroundColor: colors.map((color:number[]) => rgba(color, 0.8)),
|
||||||
|
hoverBorderColor: colors.map((color:number[]) => rgba(color, 1))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function getRandomColor():number[] {
|
||||||
|
return [getRandomInt(0, 255), getRandomInt(0, 255), getRandomInt(0, 255)];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate colors for line|bar charts
|
||||||
|
* @param index
|
||||||
|
* @returns {number[]|Color}
|
||||||
|
*/
|
||||||
|
function generateColor(index:number):number[] {
|
||||||
|
return BaseChartComponent.defaultColors[index] || getRandomColor();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate colors for pie|doughnut charts
|
||||||
|
* @param count
|
||||||
|
* @returns {Colors}
|
||||||
|
*/
|
||||||
|
function generateColors(count:number):Array<number[]> {
|
||||||
|
let colorsArr:Array<number[]> = new Array(count);
|
||||||
|
for (let i = 0; i < count; i++) {
|
||||||
|
colorsArr[i] = BaseChartComponent.defaultColors[i] || getRandomColor();
|
||||||
|
}
|
||||||
|
return colorsArr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate colors by chart type
|
||||||
|
* @param chartType
|
||||||
|
* @param index
|
||||||
|
* @param count
|
||||||
|
* @returns {Color}
|
||||||
|
*/
|
||||||
|
function getColors(chartType:string, index:number, count:number):Color {
|
||||||
|
if (chartType === 'pie' || chartType === 'doughnut') {
|
||||||
|
return formatPieColors(generateColors(count));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chartType === 'polarArea') {
|
||||||
|
return formatPolarAreaColors(generateColors(count));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chartType === 'line' || chartType === 'radar') {
|
||||||
|
return formatLineColor(generateColor(index));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chartType === 'bar') {
|
||||||
|
return formatBarColor(generateColor(index));
|
||||||
|
}
|
||||||
|
return generateColor(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const CHART_DIRECTIVES:Array<any> = [BaseChartComponent];
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
<aside class="time-series-channels">
|
<aside class="time-series-channels">
|
||||||
<ul>
|
<ul>
|
||||||
<li *ngFor="let channel of channels, let i = index"
|
<li *ngFor="let channel of channels, let i = index"
|
||||||
[ngStyle]="{ 'color': colors[i].strokeColor }">
|
[ngStyle]="{ 'color': colors[i].borderColor }">
|
||||||
{{ channel }}
|
{{ channel }}
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
@@ -12,7 +12,7 @@
|
|||||||
<aside class="time-series-amplitudes">
|
<aside class="time-series-amplitudes">
|
||||||
<ul>
|
<ul>
|
||||||
<li *ngFor="let amplitude of amplitudes, let i = index"
|
<li *ngFor="let amplitude of amplitudes, let i = index"
|
||||||
[ngStyle]="{ 'color': colors[i].strokeColor }">
|
[ngStyle]="{ 'color': colors[i].borderColor }">
|
||||||
{{ amplitude }}
|
{{ amplitude }}
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ export class TimeSeriesComponent implements OnInit {
|
|||||||
addTimeSeriesLines () {
|
addTimeSeriesLines () {
|
||||||
this.lines.forEach((line, index) => {
|
this.lines.forEach((line, index) => {
|
||||||
this.timeSeries.addTimeSeries(line, {
|
this.timeSeries.addTimeSeries(line, {
|
||||||
strokeStyle: this.colors[index].strokeColor
|
strokeStyle: this.colors[index].borderColor
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -33,7 +33,7 @@
|
|||||||
<body>
|
<body>
|
||||||
<bci-dashboard>Loading...</bci-dashboard>
|
<bci-dashboard>Loading...</bci-dashboard>
|
||||||
|
|
||||||
<script src="vendor/chart.js/Chart.js"></script>
|
<script src="vendor/chart.js/dist/Chart.bundle.js"></script>
|
||||||
<script src="vendor/chroma-js/chroma.js"></script>
|
<script src="vendor/chroma-js/chroma.js"></script>
|
||||||
<script src="vendor/plotly.js/dist/plotly.js"></script>
|
<script src="vendor/plotly.js/dist/plotly.js"></script>
|
||||||
<script src="vendor/brainbrowser/build/brainbrowser-2.3.0/brainbrowser.surface-viewer.min.js"></script>
|
<script src="vendor/brainbrowser/build/brainbrowser-2.3.0/brainbrowser.surface-viewer.min.js"></script>
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ module.exports = {
|
|||||||
scale: {
|
scale: {
|
||||||
global: 1.5,
|
global: 1.5,
|
||||||
simulated: 4,
|
simulated: 4,
|
||||||
skipLabels: 8
|
skipLabels: 4
|
||||||
},
|
},
|
||||||
units: {
|
units: {
|
||||||
hertz: 'Hz',
|
hertz: 'Hz',
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
/** Map relative paths to URLs. */
|
/** Map relative paths to URLs. */
|
||||||
const map: any = {
|
const map: any = {
|
||||||
'smoothie': 'vendor/smoothie/smoothie.js',
|
'smoothie': 'vendor/smoothie/smoothie.js',
|
||||||
|
'chartjs': 'vendor/chart.js/dist/Chart.bundle.js',
|
||||||
'ng2-charts': 'vendor/ng2-charts/bundles/ng2-charts.js',
|
'ng2-charts': 'vendor/ng2-charts/bundles/ng2-charts.js',
|
||||||
'socket.io-client': 'vendor/socket.io-client/socket.io.js',
|
'socket.io-client': 'vendor/socket.io-client/socket.io.js',
|
||||||
'chroma-js': 'vendor/chroma-js/chroma.js',
|
'chroma-js': 'vendor/chroma-js/chroma.js',
|
||||||
|
|||||||
Referência em uma Nova Issue
Bloquear um usuário