Commit 680f081b authored by Mark Harding's avatar Mark Harding

(feat): fixes graph to read production data

1 merge request!579WIP: Entity centric metrics (analytics v2)
Pipeline #87050651 failed with stages
in 7 minutes and 1 second
......@@ -3,6 +3,7 @@ m-analytics__chart {
.js-plotly-plot,
.plot-container {
height: 44vh;
display: block;
}
}
#graphDiv {
......
......@@ -11,6 +11,7 @@ import {
Input,
} from '@angular/core';
import { Observable, Subscription } from 'rxjs';
import { map } from 'rxjs/operators';
import {
AnalyticsDashboardService,
Category,
......@@ -38,14 +39,17 @@ import { ThemeService } from '../../../../../common/services/theme.service';
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class AnalyticsChartComponent implements OnInit, OnDestroy {
// @Input('buckets') set bucket(buckets) {
// this.x = buckets.map((row) => row.date)); // or key(ms)?
// this.y = buckets.map((row) => row.value));
// };
subscription: Subscription;
vm$: Observable<UserState> = this.analyticsService.vm$;
vm: UserState;
selectedMetric$ = this.analyticsService.metrics$.pipe(
map(metrics => {
console.log(
metrics,
metrics.find(metric => metric.visualisation !== null)
);
return metrics.find(metric => metric.visualisation !== null);
})
);
selectedMetric;
themeSubscription: Subscription;
isDark: boolean = false;
......@@ -88,7 +92,14 @@ export class AnalyticsChartComponent implements OnInit, OnDestroy {
) {}
ngOnInit() {
this.subscription = this.vm$.subscribe(viewModel => (this.vm = viewModel));
this.subscription = this.selectedMetric$.subscribe(metric => {
this.selectedMetric = metric;
try {
this.updateGraph();
} catch (err) {
console.log(err);
}
});
this.themeService.isDark$.subscribe(isDark => (this.isDark = isDark));
......@@ -102,16 +113,20 @@ export class AnalyticsChartComponent implements OnInit, OnDestroy {
this.hoverInfoComparisonXyDiv = document.getElementById(
'hoverInfo__comparisonXy'
);
}
this.segments = this.vm.metrics.find(
metric => metric.id === this.vm.metric
).visualisation.segments;
updateGraph() {
this.data = [];
this.shapes = [];
this.markerOpacities = [];
this.segments = this.selectedMetric.visualisation.segments;
console.log('segments', this.segments);
this.segmentLength = this.segments[0].buckets.length;
this.timespan = this.vm.timespans.find(
timespan => timespan.id === this.vm.timespan
);
// this.timespan = this.vm.timespans.find(
// timespan => timespan.id === this.vm.timespan
// );
// ----------------------------------------------
for (let i = 0; i < this.segmentLength; i++) {
......@@ -120,16 +135,17 @@ export class AnalyticsChartComponent implements OnInit, OnDestroy {
this.shapes[i] = {
type: 'line',
layer: 'below',
x0: i,
x0: this.segments[0].buckets[i].date.slice(0, 10),
y0: 0,
x1: i,
y1: 0,
x1: this.segments[0].buckets[i].date.slice(0, 10),
y1: this.segments[0].buckets[i].value,
line: {
color: this.getColor('m-transparent'),
width: 2,
},
};
}
// ----------------------------------------------
// LAYOUT
......@@ -228,17 +244,25 @@ export class AnalyticsChartComponent implements OnInit, OnDestroy {
this.data[1].line.dash = 'dot';
}
// Plotly.newPlot('graphDiv', this.data, this.layout);
this.cd.markForCheck();
this.cd.detectChanges();
//Plotly.purge('graphDiv');
//Plotly.newPlot('graphDiv', this.data, this.layout, { displayModeBar: false });
}
restyle() {
const dataUpdate = this.data;
Plotly.restyle('graphDiv', dataUpdate);
// Plotly.restyle('graphDiv', dataUpdate);
this.cd.markForCheck();
this.cd.detectChanges();
}
relayout() {
const layoutUpdate = this.layout;
Plotly.relayout('graphDiv', layoutUpdate);
//const layoutUpdate = this.layout;
//Plotly.relayout('graphDiv', layoutUpdate);
this.cd.markForCheck();
this.cd.detectChanges();
}
drawGraph() {}
......@@ -295,9 +319,8 @@ export class AnalyticsChartComponent implements OnInit, OnDestroy {
// SHOW VERTICAL LINE
this.shapes[this.hoverPoint].line.color = this.getColor('m-grey-50');
this.layout.shapes[this.hoverPoint].line.color = this.getColor('m-grey-50');
// this.updateGraph();
this.restyle();
this.relayout();
}
......@@ -306,12 +329,14 @@ export class AnalyticsChartComponent implements OnInit, OnDestroy {
this.shapes[this.hoverPoint].line.color = this.getColor(
'm-grey-50-transparent'
);
// this.layout.shapes[this.hoverPoint].line.color = this.getColor(
// 'm-grey-50-transparent'
// );
// HIDE MARKER
this.hoverInfoDiv.style.opacity = 0;
this.markerOpacities[this.hoverPoint] = 0;
this.restyle();
this.relayout();
}
......
<div
class="filterWrapper"
*ngIf="vm$ | async as vm"
[ngClass]="{ expanded: expanded }"
>
<div class="filterWrapper" [ngClass]="{ expanded: expanded }">
<div class="filterHeader" (click)="expanded = !expanded">
<span class="filterLabel">{{ filter.label }}</span>
<span class="option option--selected">
......@@ -12,11 +8,10 @@
<i class="material-icons" *ngIf="expanded">keyboard_arrow_up</i>
</div>
<div class="unselectedOptionsContainer">
<ng-container *ngFor="let option of options">
<ng-container *ngFor="let option of filter.options">
<div
class="option"
(click)="updateFilter(option)"
*ngIf="option.label !== selectedOption.label"
[ngClass]="{
unavailable: option.available === false
}"
......
m-analytics__filter {
position: relative;
margin: 16px 16px 0 0;
z-index: 1;
}
.filterWrapper {
......
......@@ -36,25 +36,22 @@ export class AnalyticsFilterComponent implements OnInit, OnDestroy {
options: Array<any> = [];
selectedOption: Option;
subscription;
vm$: Observable<UserState> = this.analyticsService.vm$;
vm: UserState;
constructor(private analyticsService: AnalyticsDashboardService) {}
ngOnInit() {
this.subscription = this.vm$.subscribe(viewModel => (this.vm = viewModel));
this.options = this.filter.options;
this.subscription = this.analyticsService.timespan$.subscribe(timespan => {
if (this.filter.id === 'timespan') {
this.selectedOption =
this.filter.options.find(option => option.id === timespan) ||
this.filter.options[0];
if (this.filter.id === 'timespan') {
this.selectedOption =
this.options.find(option => option.id === this.vm.timespan) ||
this.options[0];
// TODO: make selected option at top of array?
} else {
this.selectedOption =
this.options.find(option => option.selected === true) ||
this.options[0];
}
// TODO: make selected option at top of array?
} else {
this.selectedOption =
this.filter.options.find(option => option.selected === true) ||
this.filter.options[0];
}
});
}
updateFilter(option: Option) {
......@@ -71,37 +68,6 @@ export class AnalyticsFilterComponent implements OnInit, OnDestroy {
}
const selectedFilterStr = `${this.filter.id}::${option.id}`;
this.analyticsService.updateFilter(selectedFilterStr);
// if (
// this.vm.filter.includes(selectedFilterStr) ||
// !this.selectedOption.available
// ) {
// return;
// }
// console.log(this.vm.filter);
// const filterArr = this.vm.filter;
// const activeFilterIds = filterArr.map(filterStr => {
// return filterStr.split('::')[0];
// });
// console.log(activeFilterIds);
// const filterIndex = activeFilterIds.findIndex(
// filterId => filterId === this.filter.id
// );
// console.log(filterIndex);
// if (activeFilterIds.includes(selectedFilterStr)) {
// filterArr.splice(filterIndex, 1, selectedFilterStr);
// } else {
// filterArr.push(selectedFilterStr);
// }
// console.log(filterArr);
// //TODO make incoming string filterStr instead of option
// // const filterStr = somethingToDoWith_optionLabel;
// this.analyticsService.updateFilter(filterArr);
}
ngOnDestroy() {
......
<div class="filtersContainer">
<ng-container *ngFor="let filter of (filters$ | async)">
<ng-container *ngFor="let filter of filters$ | async">
<m-analytics__filter class="filter" [filter]="filter"></m-analytics__filter>
</ng-container>
</div>
......@@ -37,6 +37,5 @@ export class AnalyticsFiltersComponent implements OnInit, OnDestroy {
// TODO: might even be fine to just get rid of this component and put it in dashboard.ts
}
ngOnDestroy() {
}
ngOnDestroy() {}
}
......@@ -15,7 +15,7 @@
<section class="main">
<div class="mainHeader">
<h3 class="selectedCatLabel">
{{ selectedCat?.label }}
{{ category$ | async }}
</h3>
<div class="globalFilters">
<!-- TODO enable only show to admins -->
......@@ -40,11 +40,11 @@
></m-analytics__layout--chart>
<!-- <m-analytics__layout--table
class="m-analytics__layout"
*ngIf="selectedCat?.type === 'table'"
*ngIf="(category$ | async).type === 'table'"
></m-analytics__layout--table>
<m-analytics__layout--summary
class="m-analytics__layout"
*ngIf="selectedCat?.type === 'summary'"
*ngIf="(category$ | async).type === 'summary'"
></m-analytics__layout--summary> -->
</div>
</section>
......
......@@ -4,6 +4,7 @@ import {
OnDestroy,
Input,
ChangeDetectionStrategy,
ChangeDetectorRef,
} from '@angular/core';
import { FormControl } from '@angular/forms';
import { ActivatedRoute, Router } from '@angular/router';
......@@ -44,16 +45,15 @@ export class AnalyticsDashboardComponent implements OnInit, OnDestroy {
subscription: Subscription;
paramsSubscription: Subscription;
category$ = this.analyticsService.category$;
selectedCat: Category;
selectedTimespan; //string? or Timespan?
timespanFilter: Filter = {
id: 'timespan',
label: 'Timespan',
options: [],
};
vm$: Observable<UserState> = this.analyticsService.vm$;
ready$: Observable<boolean> = this.analyticsService.ready$;
vm: UserState;
constructor(
public client: Client,
......@@ -61,7 +61,8 @@ export class AnalyticsDashboardComponent implements OnInit, OnDestroy {
private router: Router,
public session: Session,
public title: MindsTitle,
public analyticsService: AnalyticsDashboardService
public analyticsService: AnalyticsDashboardService,
private cd: ChangeDetectorRef
) {}
ngOnInit() {
......@@ -81,17 +82,19 @@ export class AnalyticsDashboardComponent implements OnInit, OnDestroy {
// const {channelGuid} = this.analyticsService.getStateSnapshot();
// this.searchTerm = this.analyticsService.buildSearchTermControl();
// this.searchTerm.patchValue(channelGuid, { emitEvent: false });
this.subscription = this.vm$.subscribe(viewModel => (this.vm = viewModel));
this.paramsSubscription = this.route.queryParams.subscribe(params => {
// TODO: do the same filter, metric, channel
if (params['timespan'] && params['timespan'] !== this.vm.timespan) {
this.updateTimespan(params['timespan']);
}
this.selectedCat = this.cats.find(cat => cat.id === this.vm.category);
//if (params['timespan'] && params['timespan'] !== this.vm.timespan) {
// this.updateTimespan(params['timespan']);
//}
//this.selectedCat = this.cats.find(cat => cat.id === this.vm.category);
});
this.timespanFilter.options = this.vm.timespans;
this.analyticsService.timespans$.subscribe(timespans => {
this.timespanFilter.options = timespans;
this.detectChanges();
});
}
updateTimespan(timespanId) {
......@@ -106,8 +109,12 @@ export class AnalyticsDashboardComponent implements OnInit, OnDestroy {
// this.analyticsService.updateCategory(categoryId);
}
detectChanges() {
this.cd.markForCheck();
this.cd.detectChanges();
}
ngOnDestroy() {
this.subscription.unsubscribe();
this.paramsSubscription.unsubscribe();
}
}
......@@ -111,7 +111,7 @@ export interface UserState {
let _state: UserState = {
loading: false,
category: 'traffic',
timespan: '1y',
timespan: '30d',
timespans: [
{
id: '30d',
......@@ -291,47 +291,47 @@ export class AnalyticsDashboardService {
// that are emitted only when something inside changes
category$ = this.state$.pipe(
map(state => state.category),
distinctUntilChanged(deepDiff),
tap(category => console.log('category changed', category))
distinctUntilChanged(deepDiff)
//tap(category => console.log('category changed', category))
);
timespan$ = this.state$.pipe(
map(state => state.timespan),
distinctUntilChanged(deepDiff),
tap(timespan => console.log('timespan changed', timespan))
distinctUntilChanged(deepDiff)
//tap(timespan => console.log('timespan changed', timespan))
);
timespans$ = this.state$.pipe(
map(state => state.timespans),
distinctUntilChanged(deepDiff),
tap(timespans => console.log('timespans changed', timespans))
distinctUntilChanged(deepDiff)
//tap(timespans => console.log('timespans changed', timespans))
);
metric$ = this.state$.pipe(
map(state => state.metric),
//distinctUntilChanged(deepDiff),
distinctUntilChanged((prev, curr) => {
console.log('distinctUntilChanged() on metric$');
console.log(JSON.stringify(prev), JSON.stringify(curr));
return deepDiff(prev, curr);
}),
tap(metric => console.log('metric changed', metric))
distinctUntilChanged(deepDiff)
//distinctUntilChanged((prev, curr) => {
// console.log('distinctUntilChanged() on metric$');
// console.log(JSON.stringify(prev), JSON.stringify(curr));
// return deepDiff(prev, curr);
//}),
//tap(metric => console.log('metric changed', metric))
);
metrics$ = this.state$.pipe(
map(state => state.metrics),
//distinctUntilChanged(deepDiff),
distinctUntilChanged((prev, curr) => {
console.log(JSON.stringify(prev), JSON.stringify(curr));
//console.log(JSON.stringify(prev), JSON.stringify(curr));
return deepDiff(prev, curr);
}),
tap(metrics => console.log('metrics changed', metrics))
);
filter$ = this.state$.pipe(
map(state => state.filter),
distinctUntilChanged(deepDiff),
tap(filter => console.log('filter changed', filter))
distinctUntilChanged(deepDiff)
//tap(filter => console.log('filter changed', filter))
);
filters$ = this.state$.pipe(
map(state => state.filters),
distinctUntilChanged(deepDiff),
tap(filters => console.log('filters changed', filters))
distinctUntilChanged(deepDiff)
//tap(filters => console.log('filters changed', filters))
);
loading$ = this.state$.pipe(
map(state => state.loading),
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment