Loading src/app/common/common.module.ts +7 −0 Original line number Diff line number Diff line Loading @@ -113,6 +113,9 @@ import { MarketingComponent } from './components/marketing/marketing.component'; import { MarketingFooterComponent } from './components/marketing/footer.component'; import { ToggleComponent } from './components/toggle/toggle.component'; import { MarketingAsFeaturedInComponent } from './components/marketing/as-featured-in.component'; import { SidebarMenuComponent } from './components/sidebar-menu/sidebar-menu.component'; import { ChartV2Component } from './components/chart-v2/chart-v2.component'; import { MiniChartComponent } from './components/mini-chart/mini-chart.component'; @NgModule({ imports: [ Loading Loading @@ -215,6 +218,9 @@ import { MarketingAsFeaturedInComponent } from './components/marketing/as-featur MarketingComponent, MarketingFooterComponent, MarketingAsFeaturedInComponent, SidebarMenuComponent, ChartV2Component, MiniChartComponent, ], exports: [ MINDS_PIPES, Loading Loading @@ -305,6 +311,7 @@ import { MarketingAsFeaturedInComponent } from './components/marketing/as-featur ToggleComponent, MarketingComponent, MarketingAsFeaturedInComponent, SidebarMenuComponent, ], providers: [ SiteService, Loading src/app/common/components/chart-v2/chart-v2.component.html 0 → 100644 +61 −0 Original line number Diff line number Diff line <!-- <div #chartContainer class="m-chartV2__chartContainer" [ngClass]="{ isTouchDevice: isTouchDevice }" > <plotly-plot *ngIf="init" #graphDiv id="graphDiv" [data]="data" [layout]="layout" [config]="config" [useResizeHandler]="true" [style]="{ position: 'relative' }" (hover)="onHover($event)" (unhover)="onUnhover($event)" (plotly_click)="onClick($event)" > </plotly-plot> </div> <div #hoverInfoDiv id="hoverInfoDiv" class="m-chartV2__hoverInfoDiv"> <i *ngIf="isTouchDevice" class="material-icons" (click)="onUnhover($event)" >close</i > <div class="m-chartV2__hoverInfo__row"> {{ hoverInfo.date | utcDate | date: datePipe }} </div> <div [ngSwitch]="selectedMetric?.unit" class="m-chartV2__hoverInfo__row--primary" > <ng-template ngSwitchCase="number"> {{ hoverInfo.value | number }} {{ selectedMetric.label | lowercase }} </ng-template> <ng-template ngSwitchCase="usd"> {{ hoverInfo.value | currency }} USD </ng-template> <ng-template ngSwitchDefault> {{ hoverInfo.value | number: '1.1-3' }} {{ selectedMetric?.unit }} </ng-template> </div> <div class="m-chartV2__hoverInfo__row" *ngIf="isComparison"> vs <ng-container [ngSwitch]="selectedMetric?.unit" class="m-chartV2__hoverInfo__row" > <ng-template ngSwitchCase="number"> {{ hoverInfo.comparisonValue | number }} </ng-template> <ng-template ngSwitchCase="usd"> {{ hoverInfo.comparisonValue | currency }} </ng-template> <ng-template ngSwitchDefault> {{ hoverInfo.comparisonValue | number: '1.1-3' }} </ng-template> </ng-container> on {{ hoverInfo.comparisonDate | utcDate | date: datePipe }} </div> </div> --> src/app/modules/analytics/v2/layouts/layout-table/table.component.scss→src/app/common/components/chart-v2/chart-v2.component.scss +0 −0 File moved. src/app/modules/analytics/v2/components/menu/menu.component.spec.ts→src/app/common/components/chart-v2/chart-v2.component.spec.ts +24 −0 Original line number Diff line number Diff line import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { AnalyticsMenuComponent } from './menu.component'; import { ChartV2Component } from './chart-v2.component'; describe('AnalyticsMenuComponent', () => { let component: AnalyticsMenuComponent; let fixture: ComponentFixture<AnalyticsMenuComponent>; describe('ChartV2Component', () => { let component: ChartV2Component; let fixture: ComponentFixture<ChartV2Component>; beforeEach(async(() => { TestBed.configureTestingModule({ declarations: [AnalyticsMenuComponent], declarations: [ChartV2Component], }).compileComponents(); })); beforeEach(() => { fixture = TestBed.createComponent(AnalyticsMenuComponent); fixture = TestBed.createComponent(ChartV2Component); component = fixture.componentInstance; fixture.detectChanges(); }); xit('should create', () => { it('should create', () => { expect(component).toBeTruthy(); }); }); src/app/common/components/chart-v2/chart-v2.component.ts 0 → 100644 +504 −0 Original line number Diff line number Diff line import { Component, OnInit, OnDestroy, HostListener, ChangeDetectionStrategy, ChangeDetectorRef, Input, ViewChild, ElementRef, } from '@angular/core'; // import { Subscription } from 'rxjs'; // import { map } from 'rxjs/operators'; // import { // AnalyticsDashboardService, // Timespan as TimespanBase, // Buckets, // } from '../../dashboard.service'; // import * as Plotly from 'plotly.js'; // import chartPalette from '../../chart-palette.default'; // import { ThemeService } from '../../../../../common/services/theme.service'; // import isMobileOrTablet from '../../../../../helpers/is-mobile-or-tablet'; @Component({ selector: 'm-chartV2', templateUrl: './chart-v2.component.html', }) export class ChartV2Component implements OnInit { constructor() {} ngOnInit() {} } // ------------------------------------------------------------------------- // interface TimespanExtended extends TimespanBase { // xTickFormat?: string; // datePipe?: string; // } // export { TimespanExtended as Timespan }; // @Component({ // selector: 'm-analytics__chart', // templateUrl: 'chart.component.html', // changeDetection: ChangeDetectionStrategy.OnPush, // }) // export class AnalyticsChartComponent implements OnDestroy, OnInit { // @ViewChild('graphDiv', { static: true }) graphDiv; // @ViewChild('hoverInfoDiv', { static: true }) hoverInfoDivEl: ElementRef; // @ViewChild('chartContainer', { static: true }) chartContainer: ElementRef; // isTouchDevice: boolean; // init: boolean = false; // hoverInfoDiv: any; // hoverInfo: any = {}; // metricSubscription: Subscription; // selectedMetric$ = this.analyticsService.metrics$.pipe( // map(metrics => { // return metrics.find(metric => metric.visualisation !== null); // }) // ); // selectedMetric; // timespansSubscription: Subscription; // selectedTimespan; // themeSubscription: Subscription; // isDark: boolean = false; // segments: Buckets[]; // isComparison: boolean = false; // data = []; // layout; // config = { // displayModeBar: false, // // responsive: true, // }; // pointsPerSegment = 1; // hoverPoint: number; // lineRange: Array<any>; // newLineRange = true; // markerFills; // shapes = []; // timespanFormats = [ // { interval: 'day', xTickFormat: '%m/%d', datePipe: 'EEE MMM d, y' }, // { interval: 'month', xTickFormat: '%m/%Y', datePipe: 'MMM y' }, // ]; // datePipe: string = this.timespanFormats[0].datePipe; // xTickFormat: string = this.timespanFormats[0].xTickFormat; // // yTickPrefix: string = ''; // yTickFormat: string = ''; // // *********************************************************** // constructor( // private analyticsService: AnalyticsDashboardService, // private themeService: ThemeService, // protected cd: ChangeDetectorRef // ) {} // ngOnInit() { // this.isTouchDevice = isMobileOrTablet(); // this.hoverInfoDiv = this.hoverInfoDivEl.nativeElement; // this.timespansSubscription = this.analyticsService.timespans$.subscribe( // timespans => { // this.selectedTimespan = timespans.find( // timespan => timespan.selected === true // ); // const timespanFormat = // this.timespanFormats.find( // t => t.interval === this.selectedTimespan.interval // ) || this.timespanFormats[0]; // this.xTickFormat = timespanFormat.xTickFormat; // this.datePipe = timespanFormat.datePipe; // if (this.init) { // this.layout.xaxis.tickformat = this.xTickFormat; // } // this.detectChanges(); // } // ); // this.themeSubscription = this.themeService.isDark$.subscribe(isDark => { // this.isDark = isDark; // if (this.init) { // this.getData(); // this.getLayout(); // } // this.detectChanges(); // }); // this.metricSubscription = this.selectedMetric$.subscribe(metric => { // this.init = false; // this.selectedMetric = metric; // if (metric.unit && metric.unit === 'usd') { // this.yTickFormat = '$.2f'; // } // try { // this.initPlot(); // } catch (err) { // console.log(err); // } // this.detectChanges(); // }); // } // swapSegmentColors() { // const tempPaletteItem = chartPalette.segmentColorIds[0]; // chartPalette.segmentColorIds[0] = chartPalette.segmentColorIds[1]; // chartPalette.segmentColorIds[1] = tempPaletteItem; // } // initPlot() { // this.segments = this.selectedMetric.visualisation.segments; // if (this.segments.length === 2) { // this.isComparison = true; // // Reverse the segments so comparison line is layered behind current line // this.segments.reverse(); // console.log(this.segments); // // Current line should be blue // this.swapSegmentColors(); // } // this.pointsPerSegment = this.segments[0].buckets.length; // for (let i = 0; i < this.pointsPerSegment; i++) { // this.shapes[i] = { // type: 'line', // layer: 'below', // x0: this.segments[0].buckets[i].date, // y0: 0, // x1: this.segments[0].buckets[i].date, // y1: 0, // line: { // color: 'rgba(0, 0, 0, 0)', // width: 2, // }, // }; // } // this.getData(); // this.getLayout(); // this.init = true; // this.detectChanges(); // } // getData() { // this.markerFills = []; // this.segments.forEach((segment, index) => { // const segmentMarkerFills = []; // for (let i = 0; i < this.pointsPerSegment; i++) { // segmentMarkerFills[i] = this.getColor('m-white'); // } // this.markerFills.push(segmentMarkerFills); // }); // const globalSegmentSettings = { // type: 'scatter', // mode: 'lines+markers', // line: { // width: 1, // dash: 'solid', // }, // marker: { // size: 7, // }, // showlegend: false, // hoverinfo: 'text', // x: this.unpack(this.segments[0].buckets, 'date'), // }; // this.segments.forEach((s, i) => { // const segment = { // ...globalSegmentSettings, // line: { // ...globalSegmentSettings.line, // color: this.getColor(chartPalette.segmentColorIds[i]), // }, // marker: { // ...globalSegmentSettings.marker, // color: this.markerFills[i], // line: { // color: this.getColor(chartPalette.segmentColorIds[i]), // width: 1, // }, // }, // y: this.unpack(this.segments[i].buckets, 'value'), // }; // this.data[i] = segment; // }); // if (this.isComparison) { // this.data[0].line.dash = 'dot'; // } // } // getLayout() { // this.layout = { // width: 0, // height: 0, // autoexpand: 'true', // autosize: 'true', // hovermode: 'x', // paper_bgcolor: this.getColor('m-white'), // plot_bgcolor: this.getColor('m-white'), // font: { // family: 'Roboto', // }, // xaxis: { // tickformat: this.xTickFormat, // tickmode: 'array', // tickson: 'labels', // tickcolor: this.getColor('m-grey-130'), // tickangle: -45, // tickfont: { // color: this.getColor('m-grey-130'), // }, // showgrid: false, // showline: true, // linecolor: this.getColor('m-grey-300'), // linewidth: 1, // zeroline: false, // fixedrange: true, // // automargin: true, // // rangemode: 'nonnegative', // }, // yaxis: { // ticks: '', // tickformat: this.yTickFormat, // tickmode: 'array', // tickson: 'labels', // showgrid: true, // gridcolor: this.getColor('m-grey-70'), // zeroline: false, // visible: true, // side: 'right', // tickfont: { // color: this.getColor('m-grey-130'), // }, // fixedrange: true, // // automargin: true, // // rangemode: 'nonnegative', // }, // margin: { // t: 16, // b: 80, // l: 0, // r: 80, // pad: 16, // }, // shapes: this.shapes, // }; // } // onHover($event) { // console.log($event); // this.hoverPoint = $event.points[0].pointIndex; // this.addMarkerFill(); // this.showShape($event); // this.positionHoverInfo($event); // this.populateHoverInfo(); // this.hoverInfoDiv.style.opacity = 1; // this.detectChanges(); // } // onUnhover($event) { // this.emptyMarkerFill(); // this.hideShape(); // this.hoverInfoDiv.style.opacity = 0; // this.detectChanges(); // } // onClick($event) { // if (!this.isTouchDevice) { // return; // } // // TODO: use this for non-hover devices // } // addMarkerFill() { // this.data.forEach((segment, i) => { // this.markerFills[i][this.hoverPoint] = this.getColor( // chartPalette.segmentColorIds[i] // ); // }); // } // emptyMarkerFill() { // this.data.forEach((segment, i) => { // this.markerFills[i][this.hoverPoint] = this.getColor('m-white'); // segment.marker.color = this.markerFills[i]; // }); // } // showShape($event) { // const hoverLine = this.shapes[this.hoverPoint]; // // Without this, entire graph resizes on every hover // if (this.newLineRange) { // this.newLineRange = false; // this.lineRange = $event.yaxes[0].range; // } // hoverLine.y0 = this.lineRange[0]; // hoverLine.y1 = this.lineRange[1] * 0.99; // hoverLine.line.color = this.getColor('m-grey-70'); // this.layout.shapes = this.shapes; // } // hideShape() { // this.shapes[this.hoverPoint].line.color = 'rgba(0, 0, 0, 0)'; // this.layout.shapes = this.shapes; // } // populateHoverInfo() { // const pt = this.isComparison ? 1 : 0; // // TODO: format value strings here and remove ngSwitch from template? // this.hoverInfo['date'] = this.segments[pt].buckets[this.hoverPoint].date; // this.hoverInfo['value'] = // this.selectedMetric.unit !== 'usd' // ? this.segments[pt].buckets[this.hoverPoint].value // : this.segments[pt].buckets[this.hoverPoint].value / 100; // if (this.isComparison && this.segments[1]) { // this.hoverInfo['comparisonValue'] = // this.selectedMetric.unit !== 'usd' // ? this.segments[0].buckets[this.hoverPoint].value // : this.segments[0].buckets[this.hoverPoint].value / 100; // this.hoverInfo['comparisonDate'] = this.segments[0].buckets[ // this.hoverPoint // ].date; // } // } // positionHoverInfo($event) { // const pad = 16, // pt = this.isComparison ? 1 : 0, // xAxis = $event.points[pt].xaxis, // yAxis = $event.points[pt].yaxis, // pointXDist = xAxis.d2p($event.points[pt].x) + xAxis._offset, // pointYDist = yAxis.d2p($event.points[pt].y) + yAxis._offset, // plotRect = document // .querySelector('.js-plotly-plot') // .getBoundingClientRect(), // hoverInfoRect = this.hoverInfoDiv.getBoundingClientRect(); // if (pointYDist < plotRect.height / 2) { // // If point is in top half of plot, hoverinfo should go beneath it // this.hoverInfoDiv.style.top = pointYDist + pad + 'px'; // } else { // this.hoverInfoDiv.style.top = // pointYDist - pad - hoverInfoRect.height + 'px'; // } // if (pointXDist < plotRect.width / 2) { // // If point is in left half of plot, hoverinfo should go on the right // this.hoverInfoDiv.style.left = pointXDist + pad + 'px'; // } else { // this.hoverInfoDiv.style.left = // pointXDist - pad - hoverInfoRect.width + 'px'; // } // } // @HostListener('window:resize') // applyDimensions() { // if (this.init) { // console.log( // 'chartcontainer: W ' + // this.chartContainer.nativeElement.clientWidth + // ', H ' + // this.chartContainer.nativeElement.clientHeight // ); // this.layout.width = this.chartContainer.nativeElement.clientWidth - 56; //- 32; // this.layout.height = this.chartContainer.nativeElement.clientHeight; // // this.layout = { // // ...this.layout, // // width: this.chartContainer.nativeElement.clientWidth, // - 32, // // height: this.chartContainer.nativeElement.clientHeight, // - 32, // // }; // this.newLineRange = true; // this.detectChanges(); // } // } // // * UTILITY ----------------------------------- // unpack(rows, key) { // return rows.map(row => { // if (key === 'date') { // return row[key].slice(0, 10); // } else if (this.selectedMetric.unit === 'usd') { // return row[key] / 100; // } else { // return row[key]; // } // }); // } // getColor(colorId) { // const palette = chartPalette.themeMaps; // let colorCode = '#607d8b'; // if (palette.find(color => color.id === colorId)) { // colorCode = palette.find(color => color.id === colorId).themeMap[ // +this.isDark // ]; // } // return colorCode; // } // detectChanges() { // this.cd.markForCheck(); // this.cd.detectChanges(); // } // } ///////////////////////////////////////////////////////////////////// // @Component({ // selector: 'm-graph', // template: ` // <plotly-plot // [data]="data" // [layout]="_layout" // [config]="_config" // ></plotly-plot> // `, // }) // export class Graph { // @Input() data; // @Input() layout; // @Input() config; // get _config() { // return { // ...this.config, // ...{ // displayModeBar: false, // }, // }; // } // get _layout() { // return { // ...this.layout, // /*...{ // margin: { // t: 0, // b: 0, // }, // },*/ // }; // } Loading
src/app/common/common.module.ts +7 −0 Original line number Diff line number Diff line Loading @@ -113,6 +113,9 @@ import { MarketingComponent } from './components/marketing/marketing.component'; import { MarketingFooterComponent } from './components/marketing/footer.component'; import { ToggleComponent } from './components/toggle/toggle.component'; import { MarketingAsFeaturedInComponent } from './components/marketing/as-featured-in.component'; import { SidebarMenuComponent } from './components/sidebar-menu/sidebar-menu.component'; import { ChartV2Component } from './components/chart-v2/chart-v2.component'; import { MiniChartComponent } from './components/mini-chart/mini-chart.component'; @NgModule({ imports: [ Loading Loading @@ -215,6 +218,9 @@ import { MarketingAsFeaturedInComponent } from './components/marketing/as-featur MarketingComponent, MarketingFooterComponent, MarketingAsFeaturedInComponent, SidebarMenuComponent, ChartV2Component, MiniChartComponent, ], exports: [ MINDS_PIPES, Loading Loading @@ -305,6 +311,7 @@ import { MarketingAsFeaturedInComponent } from './components/marketing/as-featur ToggleComponent, MarketingComponent, MarketingAsFeaturedInComponent, SidebarMenuComponent, ], providers: [ SiteService, Loading
src/app/common/components/chart-v2/chart-v2.component.html 0 → 100644 +61 −0 Original line number Diff line number Diff line <!-- <div #chartContainer class="m-chartV2__chartContainer" [ngClass]="{ isTouchDevice: isTouchDevice }" > <plotly-plot *ngIf="init" #graphDiv id="graphDiv" [data]="data" [layout]="layout" [config]="config" [useResizeHandler]="true" [style]="{ position: 'relative' }" (hover)="onHover($event)" (unhover)="onUnhover($event)" (plotly_click)="onClick($event)" > </plotly-plot> </div> <div #hoverInfoDiv id="hoverInfoDiv" class="m-chartV2__hoverInfoDiv"> <i *ngIf="isTouchDevice" class="material-icons" (click)="onUnhover($event)" >close</i > <div class="m-chartV2__hoverInfo__row"> {{ hoverInfo.date | utcDate | date: datePipe }} </div> <div [ngSwitch]="selectedMetric?.unit" class="m-chartV2__hoverInfo__row--primary" > <ng-template ngSwitchCase="number"> {{ hoverInfo.value | number }} {{ selectedMetric.label | lowercase }} </ng-template> <ng-template ngSwitchCase="usd"> {{ hoverInfo.value | currency }} USD </ng-template> <ng-template ngSwitchDefault> {{ hoverInfo.value | number: '1.1-3' }} {{ selectedMetric?.unit }} </ng-template> </div> <div class="m-chartV2__hoverInfo__row" *ngIf="isComparison"> vs <ng-container [ngSwitch]="selectedMetric?.unit" class="m-chartV2__hoverInfo__row" > <ng-template ngSwitchCase="number"> {{ hoverInfo.comparisonValue | number }} </ng-template> <ng-template ngSwitchCase="usd"> {{ hoverInfo.comparisonValue | currency }} </ng-template> <ng-template ngSwitchDefault> {{ hoverInfo.comparisonValue | number: '1.1-3' }} </ng-template> </ng-container> on {{ hoverInfo.comparisonDate | utcDate | date: datePipe }} </div> </div> -->
src/app/modules/analytics/v2/layouts/layout-table/table.component.scss→src/app/common/components/chart-v2/chart-v2.component.scss +0 −0 File moved.
src/app/modules/analytics/v2/components/menu/menu.component.spec.ts→src/app/common/components/chart-v2/chart-v2.component.spec.ts +24 −0 Original line number Diff line number Diff line import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { AnalyticsMenuComponent } from './menu.component'; import { ChartV2Component } from './chart-v2.component'; describe('AnalyticsMenuComponent', () => { let component: AnalyticsMenuComponent; let fixture: ComponentFixture<AnalyticsMenuComponent>; describe('ChartV2Component', () => { let component: ChartV2Component; let fixture: ComponentFixture<ChartV2Component>; beforeEach(async(() => { TestBed.configureTestingModule({ declarations: [AnalyticsMenuComponent], declarations: [ChartV2Component], }).compileComponents(); })); beforeEach(() => { fixture = TestBed.createComponent(AnalyticsMenuComponent); fixture = TestBed.createComponent(ChartV2Component); component = fixture.componentInstance; fixture.detectChanges(); }); xit('should create', () => { it('should create', () => { expect(component).toBeTruthy(); }); });
src/app/common/components/chart-v2/chart-v2.component.ts 0 → 100644 +504 −0 Original line number Diff line number Diff line import { Component, OnInit, OnDestroy, HostListener, ChangeDetectionStrategy, ChangeDetectorRef, Input, ViewChild, ElementRef, } from '@angular/core'; // import { Subscription } from 'rxjs'; // import { map } from 'rxjs/operators'; // import { // AnalyticsDashboardService, // Timespan as TimespanBase, // Buckets, // } from '../../dashboard.service'; // import * as Plotly from 'plotly.js'; // import chartPalette from '../../chart-palette.default'; // import { ThemeService } from '../../../../../common/services/theme.service'; // import isMobileOrTablet from '../../../../../helpers/is-mobile-or-tablet'; @Component({ selector: 'm-chartV2', templateUrl: './chart-v2.component.html', }) export class ChartV2Component implements OnInit { constructor() {} ngOnInit() {} } // ------------------------------------------------------------------------- // interface TimespanExtended extends TimespanBase { // xTickFormat?: string; // datePipe?: string; // } // export { TimespanExtended as Timespan }; // @Component({ // selector: 'm-analytics__chart', // templateUrl: 'chart.component.html', // changeDetection: ChangeDetectionStrategy.OnPush, // }) // export class AnalyticsChartComponent implements OnDestroy, OnInit { // @ViewChild('graphDiv', { static: true }) graphDiv; // @ViewChild('hoverInfoDiv', { static: true }) hoverInfoDivEl: ElementRef; // @ViewChild('chartContainer', { static: true }) chartContainer: ElementRef; // isTouchDevice: boolean; // init: boolean = false; // hoverInfoDiv: any; // hoverInfo: any = {}; // metricSubscription: Subscription; // selectedMetric$ = this.analyticsService.metrics$.pipe( // map(metrics => { // return metrics.find(metric => metric.visualisation !== null); // }) // ); // selectedMetric; // timespansSubscription: Subscription; // selectedTimespan; // themeSubscription: Subscription; // isDark: boolean = false; // segments: Buckets[]; // isComparison: boolean = false; // data = []; // layout; // config = { // displayModeBar: false, // // responsive: true, // }; // pointsPerSegment = 1; // hoverPoint: number; // lineRange: Array<any>; // newLineRange = true; // markerFills; // shapes = []; // timespanFormats = [ // { interval: 'day', xTickFormat: '%m/%d', datePipe: 'EEE MMM d, y' }, // { interval: 'month', xTickFormat: '%m/%Y', datePipe: 'MMM y' }, // ]; // datePipe: string = this.timespanFormats[0].datePipe; // xTickFormat: string = this.timespanFormats[0].xTickFormat; // // yTickPrefix: string = ''; // yTickFormat: string = ''; // // *********************************************************** // constructor( // private analyticsService: AnalyticsDashboardService, // private themeService: ThemeService, // protected cd: ChangeDetectorRef // ) {} // ngOnInit() { // this.isTouchDevice = isMobileOrTablet(); // this.hoverInfoDiv = this.hoverInfoDivEl.nativeElement; // this.timespansSubscription = this.analyticsService.timespans$.subscribe( // timespans => { // this.selectedTimespan = timespans.find( // timespan => timespan.selected === true // ); // const timespanFormat = // this.timespanFormats.find( // t => t.interval === this.selectedTimespan.interval // ) || this.timespanFormats[0]; // this.xTickFormat = timespanFormat.xTickFormat; // this.datePipe = timespanFormat.datePipe; // if (this.init) { // this.layout.xaxis.tickformat = this.xTickFormat; // } // this.detectChanges(); // } // ); // this.themeSubscription = this.themeService.isDark$.subscribe(isDark => { // this.isDark = isDark; // if (this.init) { // this.getData(); // this.getLayout(); // } // this.detectChanges(); // }); // this.metricSubscription = this.selectedMetric$.subscribe(metric => { // this.init = false; // this.selectedMetric = metric; // if (metric.unit && metric.unit === 'usd') { // this.yTickFormat = '$.2f'; // } // try { // this.initPlot(); // } catch (err) { // console.log(err); // } // this.detectChanges(); // }); // } // swapSegmentColors() { // const tempPaletteItem = chartPalette.segmentColorIds[0]; // chartPalette.segmentColorIds[0] = chartPalette.segmentColorIds[1]; // chartPalette.segmentColorIds[1] = tempPaletteItem; // } // initPlot() { // this.segments = this.selectedMetric.visualisation.segments; // if (this.segments.length === 2) { // this.isComparison = true; // // Reverse the segments so comparison line is layered behind current line // this.segments.reverse(); // console.log(this.segments); // // Current line should be blue // this.swapSegmentColors(); // } // this.pointsPerSegment = this.segments[0].buckets.length; // for (let i = 0; i < this.pointsPerSegment; i++) { // this.shapes[i] = { // type: 'line', // layer: 'below', // x0: this.segments[0].buckets[i].date, // y0: 0, // x1: this.segments[0].buckets[i].date, // y1: 0, // line: { // color: 'rgba(0, 0, 0, 0)', // width: 2, // }, // }; // } // this.getData(); // this.getLayout(); // this.init = true; // this.detectChanges(); // } // getData() { // this.markerFills = []; // this.segments.forEach((segment, index) => { // const segmentMarkerFills = []; // for (let i = 0; i < this.pointsPerSegment; i++) { // segmentMarkerFills[i] = this.getColor('m-white'); // } // this.markerFills.push(segmentMarkerFills); // }); // const globalSegmentSettings = { // type: 'scatter', // mode: 'lines+markers', // line: { // width: 1, // dash: 'solid', // }, // marker: { // size: 7, // }, // showlegend: false, // hoverinfo: 'text', // x: this.unpack(this.segments[0].buckets, 'date'), // }; // this.segments.forEach((s, i) => { // const segment = { // ...globalSegmentSettings, // line: { // ...globalSegmentSettings.line, // color: this.getColor(chartPalette.segmentColorIds[i]), // }, // marker: { // ...globalSegmentSettings.marker, // color: this.markerFills[i], // line: { // color: this.getColor(chartPalette.segmentColorIds[i]), // width: 1, // }, // }, // y: this.unpack(this.segments[i].buckets, 'value'), // }; // this.data[i] = segment; // }); // if (this.isComparison) { // this.data[0].line.dash = 'dot'; // } // } // getLayout() { // this.layout = { // width: 0, // height: 0, // autoexpand: 'true', // autosize: 'true', // hovermode: 'x', // paper_bgcolor: this.getColor('m-white'), // plot_bgcolor: this.getColor('m-white'), // font: { // family: 'Roboto', // }, // xaxis: { // tickformat: this.xTickFormat, // tickmode: 'array', // tickson: 'labels', // tickcolor: this.getColor('m-grey-130'), // tickangle: -45, // tickfont: { // color: this.getColor('m-grey-130'), // }, // showgrid: false, // showline: true, // linecolor: this.getColor('m-grey-300'), // linewidth: 1, // zeroline: false, // fixedrange: true, // // automargin: true, // // rangemode: 'nonnegative', // }, // yaxis: { // ticks: '', // tickformat: this.yTickFormat, // tickmode: 'array', // tickson: 'labels', // showgrid: true, // gridcolor: this.getColor('m-grey-70'), // zeroline: false, // visible: true, // side: 'right', // tickfont: { // color: this.getColor('m-grey-130'), // }, // fixedrange: true, // // automargin: true, // // rangemode: 'nonnegative', // }, // margin: { // t: 16, // b: 80, // l: 0, // r: 80, // pad: 16, // }, // shapes: this.shapes, // }; // } // onHover($event) { // console.log($event); // this.hoverPoint = $event.points[0].pointIndex; // this.addMarkerFill(); // this.showShape($event); // this.positionHoverInfo($event); // this.populateHoverInfo(); // this.hoverInfoDiv.style.opacity = 1; // this.detectChanges(); // } // onUnhover($event) { // this.emptyMarkerFill(); // this.hideShape(); // this.hoverInfoDiv.style.opacity = 0; // this.detectChanges(); // } // onClick($event) { // if (!this.isTouchDevice) { // return; // } // // TODO: use this for non-hover devices // } // addMarkerFill() { // this.data.forEach((segment, i) => { // this.markerFills[i][this.hoverPoint] = this.getColor( // chartPalette.segmentColorIds[i] // ); // }); // } // emptyMarkerFill() { // this.data.forEach((segment, i) => { // this.markerFills[i][this.hoverPoint] = this.getColor('m-white'); // segment.marker.color = this.markerFills[i]; // }); // } // showShape($event) { // const hoverLine = this.shapes[this.hoverPoint]; // // Without this, entire graph resizes on every hover // if (this.newLineRange) { // this.newLineRange = false; // this.lineRange = $event.yaxes[0].range; // } // hoverLine.y0 = this.lineRange[0]; // hoverLine.y1 = this.lineRange[1] * 0.99; // hoverLine.line.color = this.getColor('m-grey-70'); // this.layout.shapes = this.shapes; // } // hideShape() { // this.shapes[this.hoverPoint].line.color = 'rgba(0, 0, 0, 0)'; // this.layout.shapes = this.shapes; // } // populateHoverInfo() { // const pt = this.isComparison ? 1 : 0; // // TODO: format value strings here and remove ngSwitch from template? // this.hoverInfo['date'] = this.segments[pt].buckets[this.hoverPoint].date; // this.hoverInfo['value'] = // this.selectedMetric.unit !== 'usd' // ? this.segments[pt].buckets[this.hoverPoint].value // : this.segments[pt].buckets[this.hoverPoint].value / 100; // if (this.isComparison && this.segments[1]) { // this.hoverInfo['comparisonValue'] = // this.selectedMetric.unit !== 'usd' // ? this.segments[0].buckets[this.hoverPoint].value // : this.segments[0].buckets[this.hoverPoint].value / 100; // this.hoverInfo['comparisonDate'] = this.segments[0].buckets[ // this.hoverPoint // ].date; // } // } // positionHoverInfo($event) { // const pad = 16, // pt = this.isComparison ? 1 : 0, // xAxis = $event.points[pt].xaxis, // yAxis = $event.points[pt].yaxis, // pointXDist = xAxis.d2p($event.points[pt].x) + xAxis._offset, // pointYDist = yAxis.d2p($event.points[pt].y) + yAxis._offset, // plotRect = document // .querySelector('.js-plotly-plot') // .getBoundingClientRect(), // hoverInfoRect = this.hoverInfoDiv.getBoundingClientRect(); // if (pointYDist < plotRect.height / 2) { // // If point is in top half of plot, hoverinfo should go beneath it // this.hoverInfoDiv.style.top = pointYDist + pad + 'px'; // } else { // this.hoverInfoDiv.style.top = // pointYDist - pad - hoverInfoRect.height + 'px'; // } // if (pointXDist < plotRect.width / 2) { // // If point is in left half of plot, hoverinfo should go on the right // this.hoverInfoDiv.style.left = pointXDist + pad + 'px'; // } else { // this.hoverInfoDiv.style.left = // pointXDist - pad - hoverInfoRect.width + 'px'; // } // } // @HostListener('window:resize') // applyDimensions() { // if (this.init) { // console.log( // 'chartcontainer: W ' + // this.chartContainer.nativeElement.clientWidth + // ', H ' + // this.chartContainer.nativeElement.clientHeight // ); // this.layout.width = this.chartContainer.nativeElement.clientWidth - 56; //- 32; // this.layout.height = this.chartContainer.nativeElement.clientHeight; // // this.layout = { // // ...this.layout, // // width: this.chartContainer.nativeElement.clientWidth, // - 32, // // height: this.chartContainer.nativeElement.clientHeight, // - 32, // // }; // this.newLineRange = true; // this.detectChanges(); // } // } // // * UTILITY ----------------------------------- // unpack(rows, key) { // return rows.map(row => { // if (key === 'date') { // return row[key].slice(0, 10); // } else if (this.selectedMetric.unit === 'usd') { // return row[key] / 100; // } else { // return row[key]; // } // }); // } // getColor(colorId) { // const palette = chartPalette.themeMaps; // let colorCode = '#607d8b'; // if (palette.find(color => color.id === colorId)) { // colorCode = palette.find(color => color.id === colorId).themeMap[ // +this.isDark // ]; // } // return colorCode; // } // detectChanges() { // this.cd.markForCheck(); // this.cd.detectChanges(); // } // } ///////////////////////////////////////////////////////////////////// // @Component({ // selector: 'm-graph', // template: ` // <plotly-plot // [data]="data" // [layout]="_layout" // [config]="_config" // ></plotly-plot> // `, // }) // export class Graph { // @Input() data; // @Input() layout; // @Input() config; // get _config() { // return { // ...this.config, // ...{ // displayModeBar: false, // }, // }; // } // get _layout() { // return { // ...this.layout, // /*...{ // margin: { // t: 0, // b: 0, // }, // },*/ // }; // }