Skip to content
This repository has been archived by the owner on Aug 21, 2023. It is now read-only.

Commit

Permalink
Merge pull request #104 from azavea/feature/MultiChartScrubber
Browse files Browse the repository at this point in the history
Feature/multi chart scrubber
  • Loading branch information
fungjj92 authored Oct 24, 2016
2 parents 07a97e6 + 465d08c commit 6db09e3
Show file tree
Hide file tree
Showing 7 changed files with 78 additions and 16 deletions.
3 changes: 2 additions & 1 deletion src/app/charts/chart.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ <h2 class="chart-label">
[max]="chart.showMaximum"
[minVal]="chart.minimumValue"
[maxVal]="chart.maximumValue"
[hover]="isHover">
[hover]="isHover"
[multiChartScrubber]="multiChartScrubber">
</line-graph>
<div class="chart-options" *ngIf="chart.showSettings">
<h4 class="margin-top-0 h5">Options</h4>
Expand Down
7 changes: 5 additions & 2 deletions src/app/charts/chart.component.ts
Original file line number Diff line number Diff line change
@@ -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';
Expand Down Expand Up @@ -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,
Expand Down
54 changes: 44 additions & 10 deletions src/app/charts/line-graph.component.ts
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -13,10 +15,10 @@ import * as $ from 'jquery';
selector: 'line-graph',
encapsulation: ViewEncapsulation.None,
template: `<ng-content></ng-content>`,
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<DataPoint>;
Expand All @@ -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
Expand All @@ -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 = {
Expand All @@ -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();
Expand All @@ -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));
Expand Down Expand Up @@ -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 + ')');
}

Expand Down
1 change: 1 addition & 0 deletions src/app/lab/lab.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
[city]="project.city"
[models]="project.models"
[scenario]="project.scenario"
[multiChartScrubber]="project.multiChartScrubber"
(onRemoveChart)="removeChart($event)"
(onChartSettingChanged)="chartSettingChanged()"></chart>
</div>
Expand Down
4 changes: 3 additions & 1 deletion src/app/models/project.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export class Project {
allModels: boolean = true;
models: ClimateModel[] = [];
charts: Chart[] = [];
multiChartScrubber: boolean = false;

constructor(object: Object) {
Object.assign(this, object);
Expand All @@ -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
};
}

Expand Down
6 changes: 6 additions & 0 deletions src/app/project/add-edit-project.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,12 @@ <h3 *ngIf="edit">Edit project</h3>
<model-modal [project]="model.project"></model-modal>
</div>
</div>
<div class="row">
<label>
<input type="checkbox" name="multiChartScrubber" [(ngModel)]="model.project.multiChartScrubber">
Multi-Chart Scrubber
</label>
</div>
<div class="row align-center">
<button type="submit"
class="button button-primary"
Expand Down
19 changes: 17 additions & 2 deletions src/app/services/chart.service.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {Injectable} from '@angular/core';
import 'rxjs/Rx';
import { Injectable } from '@angular/core';
import { Subject } from 'rxjs/Subject';

import { ChartData, MultiDataPoint } from '../models/chart';

Expand All @@ -13,8 +13,23 @@ import * as _ from 'lodash';
@Injectable()
export class ChartService {

private _multiChartScrubberInfo = new Subject();
private _multiChartScrubberHover = new Subject<Boolean>();

public multiChartScrubberInfoObservable = this._multiChartScrubberInfo.asObservable();
public multiChartScrubberHoverObservable = this._multiChartScrubberHover.asObservable();

constructor() {}

// receive and ship mousemove event
updateMultiChartScrubberInfo(event) {
this._multiChartScrubberInfo.next(event);
}
// receive and ship overlay mouseover status
detectMultiChartHover(bool: Boolean) {
this._multiChartScrubberHover.next(bool);
}

// return an array of date strings for each day in the given year
getDaysInYear(year: number): string[] {
var oneDate = moment.utc(+year + '-01-01', 'YYYY-MM-DD', true);
Expand Down

0 comments on commit 6db09e3

Please sign in to comment.