diff --git a/src/app/charts/chart.component.html b/src/app/charts/chart.component.html index 9f394ea3..d8d2e862 100644 --- a/src/app/charts/chart.component.html +++ b/src/app/charts/chart.component.html @@ -41,7 +41,8 @@

[max]="chart.showMaximum" [minVal]="chart.minimumValue" [maxVal]="chart.maximumValue" - [hover]="isHover"> + [hover]="isHover" + [multiChartScrubber]="multiChartScrubber">

Options

diff --git a/src/app/charts/chart.component.ts b/src/app/charts/chart.component.ts index ae9b37b3..244744cb 100644 --- a/src/app/charts/chart.component.ts +++ b/src/app/charts/chart.component.ts @@ -1,4 +1,4 @@ -import { Component, EventEmitter, Input, OnChanges, Output, HostListener } from '@angular/core'; +import { Component, EventEmitter, OnChanges, Input, Output, HostListener } from '@angular/core'; import { Chart, ChartData } from '../models/chart'; import { City } from '../models/city'; @@ -26,15 +26,18 @@ export class ChartComponent implements OnChanges { @Input() scenario: Scenario; @Input() models: ClimateModel[]; @Input() city: City; + @Input() multiChartScrubber: Boolean; private chartData: ChartData[]; private isHover: Boolean = false; // Mousemove event must be at this level to listen to mousing over rect#overlay - // Should be configurable to make a cross-chart scrubber @HostListener('mouseover', ['$event']) onMouseOver(event) { this.isHover = event.target.id === 'overlay' ? true : false; + if (this.multiChartScrubber) { + this.chartService.detectMultiChartHover(this.isHover); + } } constructor(private chartService: ChartService, diff --git a/src/app/charts/line-graph.component.ts b/src/app/charts/line-graph.component.ts index ec237c1e..4a143674 100644 --- a/src/app/charts/line-graph.component.ts +++ b/src/app/charts/line-graph.component.ts @@ -1,10 +1,12 @@ -import { Component, ViewEncapsulation, ElementRef, HostListener } from '@angular/core'; +import { Component, ViewEncapsulation, ElementRef, HostListener, OnInit, OnDestroy } from '@angular/core'; import { ChartData, DataPoint } from '../models/chart'; import { Indicator } from '../models/indicator.models'; import * as D3 from 'd3'; import * as _ from 'lodash'; import * as $ from 'jquery'; +import { ChartService } from '../services/chart.service'; + /* * Line graph component * Contains all logic for drawing a line graph @@ -13,10 +15,10 @@ import * as $ from 'jquery'; selector: 'line-graph', encapsulation: ViewEncapsulation.None, template: ``, - inputs: [ 'data', 'indicator', 'trendline', 'min', 'max', 'minVal', 'maxVal', 'hover' ] + inputs: [ 'data', 'indicator', 'trendline', 'min', 'max', 'minVal', 'maxVal', 'hover', 'multiChartScrubber' ] }) -export class LineGraphComponent { +export class LineGraphComponent implements OnInit, OnDestroy { public data: ChartData[]; public extractedData: Array; @@ -27,6 +29,7 @@ export class LineGraphComponent { public minVal: number; public maxVal: number; public hover: Boolean; + public multiChartScrubber: Boolean; private host; // D3 object referebcing host dom object private svg; // SVG in which we will print our chart @@ -49,11 +52,13 @@ export class LineGraphComponent { // Not a perfect solution should the random int and indicator be the same // However, this is quite unlikely (1/10000, and even less likely by way of app use) + private multiChartScrubberHoverSubscription; + private multiChartScrubberInfoSubscription; /* We request angular for the element reference * and then we create a D3 Wrapper for our host element */ - constructor(private element: ElementRef) { + constructor(private element: ElementRef, private chartService: ChartService) { this.htmlElement = this.element.nativeElement; this.host = D3.select(this.element.nativeElement); this.timeOptions = { @@ -64,18 +69,23 @@ export class LineGraphComponent { @HostListener('window:resize', ['$event']) onResize(event) { - this.ngOnChanges(); + this.ngOnChanges(); } // If the chart is being hovered over, handle mouse movements @HostListener('mousemove', ['$event']) onMouseMove(event) { - if (this.hover) { - this.redrawScrubber(event); - } + // for single-chart scrubber + if (this.hover && !this.multiChartScrubber) { + this.redrawScrubber(event); + } + // for multi-chart scrubber + if (this.multiChartScrubber) { + this.chartService.updateMultiChartScrubberInfo(event); + } } - /* Will Update on every @Input change */ + /* Executes on every @Input change */ ngOnChanges(): void { if (!this.data || this.data.length === 0) return; this.filterData(); @@ -92,6 +102,30 @@ export class LineGraphComponent { this.drawScrubber(); } + ngOnInit(): void { + // Set up global chart mouseover communication chain if set to multi-chart scrubber + // ** CURRENTLY ONLY FOR YEARLY INDICATORS** + if (this.multiChartScrubber && this.indicator.time_aggregation === 'yearly') { + this.multiChartScrubberHoverSubscription = this.chartService.multiChartScrubberHoverObservable.subscribe(data => { + this.hover = data; + this.hover ? $('.' + this.id).toggleClass('hidden', false) : $('.' + this.id).toggleClass('hidden', true); + }); + this.multiChartScrubberInfoSubscription = this.chartService.multiChartScrubberInfoObservable.subscribe(event => { + // Only redraw if a chart is moused over + if (this.hover) { + this.redrawScrubber(event) + } + }); + } + } + + ngOnDestroy(): void { + if (this.multiChartScrubber && this.indicator.time_aggregation === 'yearly') { + this.multiChartScrubberInfoSubscription.unsubscribe(); + this.multiChartScrubberHoverSubscription.unsubscribe(); + } + } + private filterData(): void { // Preserves parent data by fresh copying indicator data that will undergo processing let clippedData = _.cloneDeep(_.find(this.data, obj => obj.indicator.name === this.indicator.name)); @@ -372,7 +406,7 @@ export class LineGraphComponent { // Update text box length D3.select('.scrubber-box.' + this.id) - .attr('width', textSVG.node().getBBox().width + 10) + .attr('width', labelWidth + 10) .attr('transform', 'translate(' + -(labelWidth/2 + 5) + ',' + -30 + ')'); } diff --git a/src/app/lab/lab.component.html b/src/app/lab/lab.component.html index da9ef60f..4fbf9aed 100755 --- a/src/app/lab/lab.component.html +++ b/src/app/lab/lab.component.html @@ -27,6 +27,7 @@ [city]="project.city" [models]="project.models" [scenario]="project.scenario" + [multiChartScrubber]="project.multiChartScrubber" (onRemoveChart)="removeChart($event)" (onChartSettingChanged)="chartSettingChanged()">
diff --git a/src/app/models/project.ts b/src/app/models/project.ts index b66d74dd..92dc4b53 100644 --- a/src/app/models/project.ts +++ b/src/app/models/project.ts @@ -18,6 +18,7 @@ export class Project { allModels: boolean = true; models: ClimateModel[] = []; charts: Chart[] = []; + multiChartScrubber: boolean = false; constructor(object: Object) { Object.assign(this, object); @@ -36,7 +37,8 @@ export class Project { scenario: this.scenario, allModels: this.allModels, models: this.models, - charts: this.charts + charts: this.charts, + multiChartScrubber: this.multiChartScrubber }; } diff --git a/src/app/project/add-edit-project.component.html b/src/app/project/add-edit-project.component.html index 0711a606..c8025edb 100644 --- a/src/app/project/add-edit-project.component.html +++ b/src/app/project/add-edit-project.component.html @@ -33,6 +33,12 @@

Edit project

+
+ +