Skip to content

Commit

Permalink
Merge pull request #57 from gisaia/feature/selection-on-detailed-time…
Browse files Browse the repository at this point in the history
…line

Add brush selection on detailed timeline
  • Loading branch information
MohamedHamouGisaia committed Jul 23, 2018
2 parents 89cec5e + d406ca4 commit 22c3b2d
Show file tree
Hide file tree
Showing 11 changed files with 465 additions and 278 deletions.
321 changes: 164 additions & 157 deletions package-lock.json

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions package-release.json
Expand Up @@ -23,8 +23,8 @@
"@ngx-translate/core": "^8.0.0",
"@ngx-translate/http-loader": "^2.0.1",
"ajv": "^5.5.2",
"arlas-web-components": "7.1.*",
"arlas-web-contributors": "7.1.*",
"arlas-web-components": "7.2.*",
"arlas-web-contributors": "7.2.*",
"cli-color": "^1.2.0",
"core-js": "^2.4.1",
"rxjs": "^5.5.6",
Expand Down
4 changes: 2 additions & 2 deletions package.json
Expand Up @@ -34,8 +34,8 @@
"@ngx-translate/core": "^8.0.0",
"@ngx-translate/http-loader": "^2.0.1",
"ajv": "^5.5.2",
"arlas-web-components": "7.1.*",
"arlas-web-contributors": "7.1.*",
"arlas-web-components": "7.2.*",
"arlas-web-contributors": "7.2.*",
"cli-color": "^1.2.0",
"core-js": "^2.4.1",
"rxjs": "^5.5.6",
Expand Down
7 changes: 7 additions & 0 deletions src/app/components/timeline/timeline.component.css
Expand Up @@ -21,3 +21,10 @@
padding: 0 0 5px 5px;
}

.show-detailedtimeline-true {
visibility: visible;
}
.show-detailedtimeline-false {
visibility: hidden;
height: 0;
}
81 changes: 79 additions & 2 deletions src/app/components/timeline/timeline.component.html
Expand Up @@ -3,6 +3,83 @@
<arlas-timeline-shortcut [timelineComponent]="timelineComponent"></arlas-timeline-shortcut>
</div>
<div class="arlas-timeline--timelines">
<arlas-tool-widget *ngIf="detailedTimelineComponent && showDetailedTimeline" [contributorId]="detailedTimelineComponent?.contributorId" [componentParams]="detailedTimelineComponent?.input"></arlas-tool-widget>
<arlas-tool-widget #timeline *ngIf="timelineComponent" [contributorId]="timelineComponent?.contributorId" [componentParams]="timelineComponent?.input"></arlas-tool-widget>
<div *ngIf="detailedTimelineComponent" class="show-detailedtimeline-{{showDetailedTimeline.valueOf()}}">
<arlas-histogram #histogram
[data]="detailedTimelineContributor?.chartData"
[intervalSelection]="detailedTimelineIntervalSelection"
(dataPlottedEvent)="afterDetailedDataPlotted($event)"
(valuesListChangedEvent)="onDetailedIntervalBrushed($event)"
[id]="detailedTimelineComponent?.input?.id"
[displayOnlyIntervalsWithData]=true
[dataType]="detailedTimelineComponent?.input?.dataType"
[dataUnit]="detailedTimelineComponent?.input?.dataUnit"
[valuesDateFormat]="detailedTimelineComponent?.input?.valuesDateFormat"
[isHistogramSelectable]="detailedTimelineComponent?.input?.isHistogramSelectable"
[multiselectable]="detailedTimelineComponent?.input?.multiselectable"
[topOffsetRemoveInterval]="detailedTimelineComponent?.input?.topOffsetRemoveInterval"
[leftOffsetRemoveInterval]="detailedTimelineComponent?.input?.leftOffsetRemoveInterval"
[brushHandlesHeightWeight]="detailedTimelineComponent?.input?.brushHandlesHeightWeight"
[chartType]="detailedTimelineComponent?.input?.chartType"
[chartTitle]="detailedTimelineComponent?.input?.chartTitle"
[chartWidth]="detailedTimelineComponent?.input?.chartWidth"
[chartHeight]="detailedTimelineComponent?.input?.chartHeight"
[customizedCssClass]="detailedTimelineComponent?.input?.customizedCssClass"
[xAxisPosition]="detailedTimelineComponent?.input?.xAxisPosition"
[descriptionPosition]="detailedTimelineComponent?.input?.descriptionPosition"
[xTicks]="detailedTimelineComponent?.input?.xTicks"
[yTicks]="detailedTimelineComponent?.input?.yTicks"
[xLabels]="detailedTimelineComponent?.input?.xLabels"
[yLabels]="detailedTimelineComponent?.input?.yLabels"
[showXTicks]="detailedTimelineComponent?.input?.showXTicks"
[showYTicks]="detailedTimelineComponent?.input?.showYTicks"
[showXLabels]="detailedTimelineComponent?.input?.showXLabels"
[showYLabels]="detailedTimelineComponent?.input?.showYLabels"
[ticksDateFormat]="detailedTimelineComponent?.input?.ticksDateFormat"
[isSmoothedCurve]="detailedTimelineComponent?.input?.isSmoothedCurve"
[barWeight]="detailedTimelineComponent?.input?.barWeight"
[paletteColors]="detailedTimelineComponent?.input?.paletteColors"
[applyOffsetOnAreaChart]="detailedTimelineComponent?.input?.applyOffsetOnAreaChart"
[displayOnlyIntervalsWithData]="detailedTimelineComponent?.input?.displayOnlyIntervalsWithData"
[yAxisStartsFromZero]="detailedTimelineComponent?.input?.yAxisStartsFromZero"
[showStripes]="detailedTimelineComponent?.input?.showStripes"

></arlas-histogram>
</div>
<div *ngIf="timelineComponent">
<arlas-histogram #timeline [intervalListSelection]="timelineContributor?.intervalListSelection" [intervalSelection]="timelineContributor?.intervalSelection"
[data]="timelineContributor?.chartData" (valuesListChangedEvent)="onTimelineIntervalBrushed($event)"
[id]="timelineComponent?.input?.id"
[dataType]="timelineComponent?.input?.dataType"
[dataUnit]="timelineComponent?.input?.dataUnit"
[valuesDateFormat]="timelineComponent?.input?.valuesDateFormat"
[isHistogramSelectable]="timelineComponent?.input?.isHistogramSelectable"
[multiselectable]="timelineComponent?.input?.multiselectable"
[topOffsetRemoveInterval]="timelineComponent?.input?.topOffsetRemoveInterval"
[leftOffsetRemoveInterval]="timelineComponent?.input?.leftOffsetRemoveInterval"
[brushHandlesHeightWeight]="timelineComponent?.input?.brushHandlesHeightWeight"
[chartType]="timelineComponent?.input?.chartType"
[chartTitle]="timelineComponent?.input?.chartTitle"
[chartWidth]="timelineComponent?.input?.chartWidth"
[chartHeight]="timelineComponent?.input?.chartHeight"
[customizedCssClass]="timelineComponent?.input?.customizedCssClass"
[xAxisPosition]="timelineComponent?.input?.xAxisPosition"
[descriptionPosition]="timelineComponent?.input?.descriptionPosition"
[xTicks]="timelineComponent?.input?.xTicks"
[yTicks]="timelineComponent?.input?.yTicks"
[xLabels]="timelineComponent?.input?.xLabels"
[yLabels]="timelineComponent?.input?.yLabels"
[showXTicks]="timelineComponent?.input?.showXTicks"
[showYTicks]="timelineComponent?.input?.showYTicks"
[showXLabels]="timelineComponent?.input?.showXLabels"
[showYLabels]="timelineComponent?.input?.showYLabels"
[ticksDateFormat]="timelineComponent?.input?.ticksDateFormat"
[isSmoothedCurve]="timelineComponent?.input?.isSmoothedCurve"
[barWeight]="timelineComponent?.input?.barWeight"
[paletteColors]="timelineComponent?.input?.paletteColors"
[applyOffsetOnAreaChart]="timelineComponent?.input?.applyOffsetOnAreaChart"
[displayOnlyIntervalsWithData]="timelineComponent?.input?.displayOnlyIntervalsWithData"
[yAxisStartsFromZero]="timelineComponent?.input?.yAxisStartsFromZero"
[showStripes]="timelineComponent?.input?.showStripes"
></arlas-histogram>
</div>
</div>
125 changes: 95 additions & 30 deletions src/app/components/timeline/timeline.component.ts
Expand Up @@ -17,14 +17,15 @@
* under the License.
*/

import { Component, Input, OnInit, ViewChild } from '@angular/core';
import { HistogramContributor } from 'arlas-web-contributors';
import { OperationEnum, Contributor } from 'arlas-web-core';
import { Component, Input, OnInit, ViewChild, ChangeDetectorRef } from '@angular/core';
import { HistogramContributor, DetailedHistogramContributor } from 'arlas-web-contributors';
import { OperationEnum } from 'arlas-web-core';
import { ArlasCollaborativesearchService, ArlasStartupService } from './../../services/startup/startup.service';
import { StringifiedTimeShortcut, TimeShortcut, SelectedOutputValues } from 'arlas-web-contributors/models/models';
import { StringifiedTimeShortcut, SelectedOutputValues } from 'arlas-web-contributors/models/models';
import * as d3 from 'd3';
import { WidgetComponent } from '../widget/widget.component';
import { TranslateService } from '@ngx-translate/core';
import { ChartType, DataType, Position } from 'arlas-d3';
import { HistogramComponent } from 'arlas-web-components';

@Component({
selector: 'arlas-timeline',
Expand All @@ -35,64 +36,128 @@ export class TimelineComponent implements OnInit {

@Input() public detailedTimelineComponent: any;
@Input() public timelineComponent: any;
@ViewChild('timeline') private timelineWidget: WidgetComponent;
@ViewChild('timeline') public timelineHistogramComponent: HistogramComponent;

public showDetailedTimeline = false;
private timelineIsFiltered = false;
public detailedTimelineContributor: DetailedHistogramContributor;
public timelineContributor: HistogramContributor;
public detailedTimelineIntervalSelection: SelectedOutputValues;

private isDetailedIntervalBrushed = false;
private applicationFirstLoad = false;
private timelineIsFiltered = false;

constructor(private arlasCollaborativesearchService: ArlasCollaborativesearchService, private arlasStartupService: ArlasStartupService) {
constructor(private arlasCollaborativesearchService: ArlasCollaborativesearchService, private cdr: ChangeDetectorRef,
private arlasStartupService: ArlasStartupService) {
}

public ngOnInit() {
if (this.timelineComponent && this.detailedTimelineComponent) {
this.detailedTimelineComponent.input.isHistogramSelectable = false;
this.resetHistogramsInputs(this.timelineComponent.input);
this.resetHistogramsInputs(this.detailedTimelineComponent.input);
this.detailedTimelineContributor = this.arlasStartupService.contributorRegistry.get(this.detailedTimelineComponent.contributorId);
this.timelineContributor = this.arlasStartupService.contributorRegistry.get(this.timelineComponent.contributorId);
this.showDetailedTimelineOnCollaborationEnd();
} else if (this.timelineComponent) {
this.resetHistogramsInputs(this.timelineComponent.input);
this.timelineContributor = this.arlasStartupService.contributorRegistry.get(this.timelineComponent.contributorId);
}
}

/**
* Recalculates the new data of detailed timeline and resets its own current selection.
* @param selections List containing only the current selection of detailed timeline
*/
public onDetailedIntervalBrushed(selections: SelectedOutputValues[]): void {
this.isDetailedIntervalBrushed = true;
this.detailedTimelineIntervalSelection = {startvalue: selections[0].startvalue, endvalue: selections[0].endvalue};
this.timelineContributor.valueChanged(this.timelineContributor.intervalListSelection.concat(selections));
}

/**
* Runs when the selection is brushed on timeline.
* @param selections List containing only the current selection of detailed timeline
*/
public onTimelineIntervalBrushed(selections: SelectedOutputValues[]): void {
this.timelineContributor.valueChanged(selections);
}

/**
* Runs when the detailed timeline is plotted.
* Sets current selection of detailed timeline after it is plotted
* Applies the current selection of detailed timeline on the main timeline
*/
public afterDetailedDataPlotted() {
if (this.isDetailedIntervalBrushed) { // If detailed timeline is replotted after moving its own brush.
// Reset current selection of detailed timeline after it is plotted
this.detailedTimelineIntervalSelection = { startvalue: this.detailedTimelineIntervalSelection.startvalue,
endvalue: this.detailedTimelineIntervalSelection.endvalue };
// Apply the current selection of detailed timeline on the main timeline
this.timelineContributor.intervalSelection = { startvalue: this.detailedTimelineIntervalSelection.startvalue,
endvalue: this.detailedTimelineIntervalSelection.endvalue };
} else { // If detailed timeline is replotted after moving the brush of the main timeline or when the app is loaded.
const selection = this.timelineContributor.intervalSelection;
if (selection) {
this.detailedTimelineIntervalSelection = { startvalue: selection.startvalue, endvalue: selection.endvalue };
} else {
this.applicationFirstLoad = true;
}
}
this.isDetailedIntervalBrushed = false;
this.cdr.detectChanges();
}

private showDetailedTimelineOnCollaborationEnd(): void {
this.arlasCollaborativesearchService.collaborationBus.filter(c => (c.id === this.timelineComponent.contributorId || c.all))
.subscribe(c => {
if (c.operation === OperationEnum.remove) {
this.timelineIsFiltered = false;
this.showDetailedTimeline = false;
this.timelineWidget.histogramComponent.histogram.histogramParams.chartHeight = this.timelineComponent.input.chartHeight;
this.timelineWidget.histogramComponent.resizeHistogram();
this.timelineHistogramComponent.histogram.histogramParams.chartHeight = this.timelineComponent.input.chartHeight;
this.timelineHistogramComponent.resizeHistogram();
} else if (c.operation === OperationEnum.add ) {
this.timelineIsFiltered = true;
}
});

this.arlasCollaborativesearchService.ongoingSubscribe.subscribe(nb => {
if (this.arlasCollaborativesearchService.totalSubscribe === 0 && this.timelineIsFiltered) {
const timelineRange = (<HistogramContributor>this.arlasCollaborativesearchService.registry
.get(this.timelineComponent.contributorId)).range;
const detailedTimelineRange = (<HistogramContributor>this.arlasCollaborativesearchService.registry
.get(this.detailedTimelineComponent.contributorId)).range;
const timelineRange = this.timelineContributor.range;
const detailedTimelineRange = this.detailedTimelineContributor.range;
if (timelineRange && detailedTimelineRange) {
// For timeline : calculate the range of data + selections
let min = timelineRange.min;
let max = timelineRange.max;
const timelineContributor = this.arlasStartupService.contributorRegistry.get(this.timelineComponent.contributorId);
timelineContributor.intervalListSelection.forEach( intervalSelection => {
min = (min > intervalSelection.startvalue) ? intervalSelection.startvalue : min;
max = (max < intervalSelection.endvalue) ? intervalSelection.endvalue : max;
});
min = (min > timelineContributor.intervalSelection.startvalue) ? timelineContributor.intervalSelection.startvalue : min;
max = (max < timelineContributor.intervalSelection.endvalue) ? timelineContributor.intervalSelection.endvalue : max;
this.showDetailedTimeline = ((detailedTimelineRange.max - detailedTimelineRange.min) <= 0.2 * (max - min));
this.timelineWidget.histogramComponent.histogram.histogramParams.chartHeight = (this.showDetailedTimeline) ?
this.showDetailedTimeline = ((detailedTimelineRange.max - detailedTimelineRange.min) <=
(0.2 * (timelineRange.max - timelineRange.min)));
this.timelineHistogramComponent.histogram.histogramParams.chartHeight = (this.showDetailedTimeline) ?
this.detailedTimelineComponent.input.chartHeight : this.timelineComponent.input.chartHeight;
this.timelineWidget.histogramComponent.resizeHistogram();
this.timelineHistogramComponent.resizeHistogram();
if (this.applicationFirstLoad) {
// Sets current selection of detailed timeline
const select = this.timelineContributor.intervalSelection;
this.detailedTimelineIntervalSelection = { startvalue: select.startvalue, endvalue: select.endvalue };
this.applicationFirstLoad = false;
}
} else {
this.showDetailedTimeline = false;
this.timelineWidget.histogramComponent.histogram.histogramParams.chartHeight = this.timelineComponent.input.chartHeight;
this.timelineWidget.histogramComponent.resizeHistogram();
this.timelineHistogramComponent.histogram.histogramParams.chartHeight = this.timelineComponent.input.chartHeight;
this.timelineHistogramComponent.resizeHistogram();
}
}
});
}

private resetHistogramsInputs(inputs: any) {
Object.keys(inputs).forEach(key => {
if (key === 'chartType') {
inputs[key] = ChartType[inputs[key]];
} else if (key === 'dataType') {
inputs[key] = DataType[inputs[key]];
} else if (key === 'xAxisPosition') {
inputs[key] = Position[inputs[key]];
} else if (key === 'descriptionPosition') {
inputs = Position[inputs[key]];
}
});
}
}

@Component({
Expand Down
13 changes: 8 additions & 5 deletions src/app/components/widget/widget.component.html
Expand Up @@ -29,7 +29,10 @@
[isSmoothedCurve]="graphParam?.isSmoothedCurve"
[barWeight]="graphParam?.barWeight"
[paletteColors]="graphParam?.paletteColors"

[applyOffsetOnAreaChart]="graphParam?.applyOffsetOnAreaChart"
[displayOnlyIntervalsWithData]="graphParam?.displayOnlyIntervalsWithData"
[yAxisStartsFromZero]="graphParam?.yAxisStartsFromZero"
[showStripes]="graphParam?.showStripes"
></arlas-histogram>
</div>
<div *ngIf="componentType === 'swimlane'">
Expand Down Expand Up @@ -73,7 +76,7 @@
[swimLaneLabelsWidth]="graphParam?.swimLaneLabelsWidth"
[swimlaneBorderRadius]="graphParam?.swimlaneBorderRadius"
[swimlaneHeight]="graphParam?.swimlaneHeight"

[displayOnlyIntervalsWithData]="graphParam?.displayOnlyIntervalsWithData"
></arlas-histogram>
</div>
<div *ngIf="componentType === 'powerbars'">
Expand All @@ -99,13 +102,12 @@
[fieldsConfiguration]="contributor?.fieldsConfiguration"
[fieldsList]="contributor?.fieldsList"
[filtersMap]="contributor?.filtersMap"
[dropDownMapValues]="contributor?.dropDownMapValues"
(sortColumnEvent)="contributor?.sortColumn($event)"
(moreDataEvent)="contributor?.getMoreData($event)"
(setFiltersEvent)="contributor?.setFilters($event)"

[tableWidth]="graphParam.tableWidth"
[globalActionsList]="graphParam.globalActionsList"

[searchSize]="graphParam.searchSize"
[nLastLines]="graphParam.nLastLines"
[detailedGridHeight]="graphParam.detailedGridHeight"
Expand All @@ -115,7 +117,8 @@
[defautMode]="graphParam.defautMode"
[displayFilters]="graphParam.displayFilters"
[isBodyHidden]="graphParam.isBodyHidden"
[isGeoSortActived]="graphParam.isGeoSortActived"
[isGeoSortActived]="graphParam?.isGeoSortActived"
[isAutoGeoSortActived]="graphParam?.isAutoGeoSortActived"
(geoSortEvent)="emitEvent(contributorId, 'geoSortEvent', $event)"
(selectedItemsEvent)="emitEvent(contributorId, 'selectedItemsEvent', $event)"
(consultedItemEvent)="emitEvent(contributorId, 'consultedItemEvent', $event)"
Expand Down
7 changes: 7 additions & 0 deletions src/app/services/startup/arlasconfig.schema.json
Expand Up @@ -24,6 +24,13 @@
}
]
},
"^(detailedhistogram\\$).*$": {
"allOf": [
{
"$ref": "detailedHistogramContributorConf.schema.json#"
}
]
},
"^(powerbars\\$).*$": {
"allOf": [
{
Expand Down

0 comments on commit 22c3b2d

Please sign in to comment.