File

libs/d3/src/lib/d3-timeseries-graph/controls/d3-graph-overview-selection/d3-graph-overview-selection.component.ts

Extends

D3TimeseriesGraphControl

Metadata

encapsulation ViewEncapsulation.None
selector n52-d3-graph-overview-selection
styleUrls ./d3-graph-overview-selection.component.scss

Index

Properties
Methods
Inputs

Constructor

constructor(graphId: D3GraphId, graphs: D3Graphs, graphHelper: D3GraphHelperService)
Parameters :
Name Type Optional
graphId D3GraphId No
graphs D3Graphs No
graphHelper D3GraphHelperService No

Inputs

mainTimeInterval
Type : Timespan

Methods

Public adjustBackground
adjustBackground(background: d3.Selection, graphExtent: D3GraphExtent, preparedData: InternalDataEntry[], graph: d3.Selection, timespan: Timespan)
Parameters :
Name Type Optional
background d3.Selection<SVGSVGElement | any | any | any> No
graphExtent D3GraphExtent No
preparedData InternalDataEntry[] No
graph d3.Selection<SVGSVGElement | any | any | any> No
timespan Timespan No
Returns : void
Private getTimestampByCoord
getTimestampByCoord(minCalcBrush: number, maxCalcBrush: number, timespan: Timespan, width: number)

Function that calculates and returns the timestamp for the main diagram calculated by the selected coordinate of the brush range.

Parameters :
Name Type Optional Description
minCalcBrush number No

Number with the minimum coordinate of the selected brush range.

maxCalcBrush number No

Number with the maximum coordinate of the selected brush range.

timespan Timespan No
width number No
Private getXDomainByTimestamp
getXDomainByTimestamp(timespan: Timespan, width: number)

Function that calculates and returns the x diagram coordinate for the brush range for the overview diagram by the selected time interval of the main diagram. Calculate to get brush extent when main diagram time interval changes.

Parameters :
Name Type Optional
timespan Timespan No
width number No
Public graphInitialized
graphInitialized(graph: D3TimeseriesGraphComponent)
Parameters :
Name Type Optional
graph D3TimeseriesGraphComponent No
Returns : void
Public Optional adjustYAxis
adjustYAxis(axis: YAxis)
Inherited from D3TimeseriesGraphControl
Parameters :
Name Type Optional
axis YAxis No
Returns : void
Public Abstract graphInitialized
graphInitialized(graph: D3TimeseriesGraphComponent)
Inherited from D3TimeseriesGraphControl
Parameters :
Name Type Optional
graph D3TimeseriesGraphComponent No
Returns : any
Public ngAfterViewInit
ngAfterViewInit()
Inherited from D3TimeseriesGraphControl
Returns : void
Public ngOnDestroy
ngOnDestroy()
Inherited from D3TimeseriesGraphControl
Returns : void

Properties

drawLayer
Type : d3.Selection<SVGGElement | any | any | any>
Private graphComp
Type : D3TimeseriesGraphComponent
Private mousedownBrush
Type : boolean
overview
Type : d3.Selection<SVGSVGElement | any | any | any>
import { Component, Input, ViewEncapsulation } from '@angular/core';
import { Timespan } from '@helgoland/core';
import * as d3 from 'd3';

import { D3GraphHelperService } from '../../../helper/d3-graph-helper.service';
import { D3GraphId } from '../../../helper/d3-graph-id.service';
import { D3Graphs } from '../../../helper/d3-graphs.service';
import { InternalDataEntry } from '../../../model/d3-general';
import { D3GraphExtent, D3TimeseriesGraphControl } from '../../d3-timeseries-graph-control';
import { D3TimeseriesGraphComponent } from '../../d3-timeseries-graph.component';

@Component({
  selector: 'n52-d3-graph-overview-selection',
  template: '',
  styleUrls: ['./d3-graph-overview-selection.component.scss'],
  encapsulation: ViewEncapsulation.None
})
export class D3GraphOverviewSelectionComponent extends D3TimeseriesGraphControl {

  // difference to timespan/timeInterval --> if brush, then this is the timespan of the main-diagram
  @Input() public mainTimeInterval: Timespan;

  private mousedownBrush: boolean;
  private graphComp: D3TimeseriesGraphComponent;
  overview: d3.Selection<SVGSVGElement, any, any, any>;
  drawLayer: d3.Selection<SVGGElement, any, any, any>;

  constructor(
    protected graphId: D3GraphId,
    protected graphs: D3Graphs,
    protected graphHelper: D3GraphHelperService
  ) {
    super(graphId, graphs, graphHelper);
  }

  public graphInitialized(graph: D3TimeseriesGraphComponent) {
    this.graphComp = graph;
  }

  public adjustBackground(
    background: d3.Selection<SVGSVGElement, any, any, any>,
    graphExtent: D3GraphExtent,
    preparedData: InternalDataEntry[],
    graph: d3.Selection<SVGSVGElement, any, any, any>,
    timespan: Timespan
  ) {
    if (!this.drawLayer) {
      this.drawLayer = this.graphComp.getDrawingLayer('overview-layer', true);
    }

    this.drawLayer.selectAll('*').remove();
    this.drawLayer.append<SVGSVGElement>('svg:rect')
      .attr('width', graphExtent.width - graphExtent.leftOffset)
      .attr('height', graphExtent.height)
      .attr('id', 'backgroundRect')
      .attr('fill', 'none')
      .attr('stroke', 'none')
      .attr('pointer-events', 'all')
      .attr('transform', 'translate(' + graphExtent.leftOffset + ', 0)');

    const interval: [number, number] = this.getXDomainByTimestamp(timespan, graphExtent.width);
    const overviewTimespanInterval = [interval[0], interval[1]];

    // create brush
    const brush = d3.brushX()
      .extent([[0, 0], [graphExtent.width, graphExtent.height]])
      .on('end', () => {
        // on mouseclick change time after brush was moved
        if (this.mousedownBrush) {
          const timeByCoord: [number, number] = this.getTimestampByCoord(d3.event.selection[0], d3.event.selection[1], timespan, graphExtent.width);
          this.graphComp.changeTime(timeByCoord[0], timeByCoord[1]);
        }
        this.mousedownBrush = false;
      });

    // add brush to svg
    this.overview = this.drawLayer.append<SVGSVGElement>('g')
      .attr('width', graphExtent.width)
      .attr('height', graphExtent.height)
      .attr('pointer-events', 'all')
      .attr('class', 'brush')
      .call(brush)
      .call(brush.move, overviewTimespanInterval);

    /**
     * add event to selection to prevent unnecessary re-rendering of brush
     * add style of brush selection here
     * e.g. 'fill' for color,
     * 'stroke' for borderline-color,
     * 'stroke-dasharray' for customizing borderline-style
     */
    this.overview.selectAll('.selection')
      .attr('stroke', 'none')
      .on('mousedown', () => this.mousedownBrush = true);

    // do not allow clear selection
    this.overview.selectAll('.overlay').remove();

    // add event to resizing handle to allow change time on resize
    this.overview.selectAll('.handle')
      .attr('stroke', 'none')
      .on('mousedown', () => this.mousedownBrush = true);
  }

  /**
   * Function that calculates and returns the x diagram coordinate for the brush range
   * for the overview diagram by the selected time interval of the main diagram.
   * Calculate to get brush extent when main diagram time interval changes.
   */
  private getXDomainByTimestamp(timespan: Timespan, width: number): [number, number] {
    /**
     * calculate range of brush with timestamp and not diagram coordinates
     * formula:
     * brush_min =
     * (overview_width / (overview_max - overview_min)) * (brush_min - overview_min)
     * brus_max =
     * (overview_width / (overview_max - overview_min)) * (brush_max - overview_min)
     */

    const minOverviewTimeInterval = timespan.from;
    const maxOverviewTimeInterval = timespan.to;
    const minDiagramTimestamp = this.mainTimeInterval.from;
    const maxDiagramTimestamp = this.mainTimeInterval.to;

    const diffOverviewTimeInterval = maxOverviewTimeInterval - minOverviewTimeInterval;
    const divOverviewTimeWidth = width / diffOverviewTimeInterval;
    const minCalcBrush: number = divOverviewTimeWidth * (minDiagramTimestamp - minOverviewTimeInterval);
    const maxCalcBrush: number = divOverviewTimeWidth * (maxDiagramTimestamp - minOverviewTimeInterval);

    return [minCalcBrush, maxCalcBrush];
  }

  /**
   * Function that calculates and returns the timestamp for the main diagram calculated
   * by the selected coordinate of the brush range.
   * @param minCalcBrush {Number} Number with the minimum coordinate of the selected brush range.
   * @param maxCalcBrush {Number} Number with the maximum coordinate of the selected brush range.
   */
  private getTimestampByCoord(minCalcBrush: number, maxCalcBrush: number, timespan: Timespan, width: number): [number, number] {
    /**
     * calculate range of brush with timestamp and not diagram coordinates
     * formula:
     * minDiagramTimestamp =
     * ((minCalcBrush / overview_width) * (overview_max - overview_min)) + overview_min
     * maxDiagramTimestamp =
     * ((maxCalcBrush / overview_width) * (overview_max - overview_min)) + overview_min
     */

    const minOverviewTimeInterval = timespan.from;
    const maxOverviewTimeInterval = timespan.to;

    const diffOverviewTimeInterval = maxOverviewTimeInterval - minOverviewTimeInterval;
    const minDiagramTimestamp: number = ((minCalcBrush / width) * diffOverviewTimeInterval) + minOverviewTimeInterval;
    const maxDiagramTimestamp: number = ((maxCalcBrush / width) * diffOverviewTimeInterval) + minOverviewTimeInterval;

    return [minDiagramTimestamp, maxDiagramTimestamp];
  }

}

./d3-graph-overview-selection.component.scss

#overview-layer {
    .brush {
        .selection {
            fill: rgb(120, 120, 120);
            fill-opacity: 0.2;
        }

        .handle {
            fill: rgb(200, 0, 0);
            opacity: 0.3;
        }
    }
}
Legend
Html element
Component
Html element with directive

result-matching ""

    No results matching ""